Root/
1 | #include <linux/syscalls.h> |
2 | #include <linux/export.h> |
3 | #include <linux/fs.h> |
4 | #include <linux/file.h> |
5 | #include <linux/mount.h> |
6 | #include <linux/namei.h> |
7 | #include <linux/statfs.h> |
8 | #include <linux/security.h> |
9 | #include <linux/uaccess.h> |
10 | #include "internal.h" |
11 | |
12 | static int flags_by_mnt(int mnt_flags) |
13 | { |
14 | int flags = 0; |
15 | |
16 | if (mnt_flags & MNT_READONLY) |
17 | flags |= ST_RDONLY; |
18 | if (mnt_flags & MNT_NOSUID) |
19 | flags |= ST_NOSUID; |
20 | if (mnt_flags & MNT_NODEV) |
21 | flags |= ST_NODEV; |
22 | if (mnt_flags & MNT_NOEXEC) |
23 | flags |= ST_NOEXEC; |
24 | if (mnt_flags & MNT_NOATIME) |
25 | flags |= ST_NOATIME; |
26 | if (mnt_flags & MNT_NODIRATIME) |
27 | flags |= ST_NODIRATIME; |
28 | if (mnt_flags & MNT_RELATIME) |
29 | flags |= ST_RELATIME; |
30 | return flags; |
31 | } |
32 | |
33 | static int flags_by_sb(int s_flags) |
34 | { |
35 | int flags = 0; |
36 | if (s_flags & MS_SYNCHRONOUS) |
37 | flags |= ST_SYNCHRONOUS; |
38 | if (s_flags & MS_MANDLOCK) |
39 | flags |= ST_MANDLOCK; |
40 | return flags; |
41 | } |
42 | |
43 | static int calculate_f_flags(struct vfsmount *mnt) |
44 | { |
45 | return ST_VALID | flags_by_mnt(mnt->mnt_flags) | |
46 | flags_by_sb(mnt->mnt_sb->s_flags); |
47 | } |
48 | |
49 | static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) |
50 | { |
51 | int retval; |
52 | |
53 | if (!dentry->d_sb->s_op->statfs) |
54 | return -ENOSYS; |
55 | |
56 | memset(buf, 0, sizeof(*buf)); |
57 | retval = security_sb_statfs(dentry); |
58 | if (retval) |
59 | return retval; |
60 | retval = dentry->d_sb->s_op->statfs(dentry, buf); |
61 | if (retval == 0 && buf->f_frsize == 0) |
62 | buf->f_frsize = buf->f_bsize; |
63 | return retval; |
64 | } |
65 | |
66 | int vfs_statfs(struct path *path, struct kstatfs *buf) |
67 | { |
68 | int error; |
69 | |
70 | error = statfs_by_dentry(path->dentry, buf); |
71 | if (!error) |
72 | buf->f_flags = calculate_f_flags(path->mnt); |
73 | return error; |
74 | } |
75 | EXPORT_SYMBOL(vfs_statfs); |
76 | |
77 | int user_statfs(const char __user *pathname, struct kstatfs *st) |
78 | { |
79 | struct path path; |
80 | int error; |
81 | unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT; |
82 | retry: |
83 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); |
84 | if (!error) { |
85 | error = vfs_statfs(&path, st); |
86 | path_put(&path); |
87 | if (retry_estale(error, lookup_flags)) { |
88 | lookup_flags |= LOOKUP_REVAL; |
89 | goto retry; |
90 | } |
91 | } |
92 | return error; |
93 | } |
94 | |
95 | int fd_statfs(int fd, struct kstatfs *st) |
96 | { |
97 | struct fd f = fdget_raw(fd); |
98 | int error = -EBADF; |
99 | if (f.file) { |
100 | error = vfs_statfs(&f.file->f_path, st); |
101 | fdput(f); |
102 | } |
103 | return error; |
104 | } |
105 | |
106 | static int do_statfs_native(struct kstatfs *st, struct statfs __user *p) |
107 | { |
108 | struct statfs buf; |
109 | |
110 | if (sizeof(buf) == sizeof(*st)) |
111 | memcpy(&buf, st, sizeof(*st)); |
112 | else { |
113 | if (sizeof buf.f_blocks == 4) { |
114 | if ((st->f_blocks | st->f_bfree | st->f_bavail | |
115 | st->f_bsize | st->f_frsize) & |
116 | 0xffffffff00000000ULL) |
117 | return -EOVERFLOW; |
118 | /* |
119 | * f_files and f_ffree may be -1; it's okay to stuff |
120 | * that into 32 bits |
121 | */ |
122 | if (st->f_files != -1 && |
123 | (st->f_files & 0xffffffff00000000ULL)) |
124 | return -EOVERFLOW; |
125 | if (st->f_ffree != -1 && |
126 | (st->f_ffree & 0xffffffff00000000ULL)) |
127 | return -EOVERFLOW; |
128 | } |
129 | |
130 | buf.f_type = st->f_type; |
131 | buf.f_bsize = st->f_bsize; |
132 | buf.f_blocks = st->f_blocks; |
133 | buf.f_bfree = st->f_bfree; |
134 | buf.f_bavail = st->f_bavail; |
135 | buf.f_files = st->f_files; |
136 | buf.f_ffree = st->f_ffree; |
137 | buf.f_fsid = st->f_fsid; |
138 | buf.f_namelen = st->f_namelen; |
139 | buf.f_frsize = st->f_frsize; |
140 | buf.f_flags = st->f_flags; |
141 | memset(buf.f_spare, 0, sizeof(buf.f_spare)); |
142 | } |
143 | if (copy_to_user(p, &buf, sizeof(buf))) |
144 | return -EFAULT; |
145 | return 0; |
146 | } |
147 | |
148 | static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p) |
149 | { |
150 | struct statfs64 buf; |
151 | if (sizeof(buf) == sizeof(*st)) |
152 | memcpy(&buf, st, sizeof(*st)); |
153 | else { |
154 | buf.f_type = st->f_type; |
155 | buf.f_bsize = st->f_bsize; |
156 | buf.f_blocks = st->f_blocks; |
157 | buf.f_bfree = st->f_bfree; |
158 | buf.f_bavail = st->f_bavail; |
159 | buf.f_files = st->f_files; |
160 | buf.f_ffree = st->f_ffree; |
161 | buf.f_fsid = st->f_fsid; |
162 | buf.f_namelen = st->f_namelen; |
163 | buf.f_frsize = st->f_frsize; |
164 | buf.f_flags = st->f_flags; |
165 | memset(buf.f_spare, 0, sizeof(buf.f_spare)); |
166 | } |
167 | if (copy_to_user(p, &buf, sizeof(buf))) |
168 | return -EFAULT; |
169 | return 0; |
170 | } |
171 | |
172 | SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf) |
173 | { |
174 | struct kstatfs st; |
175 | int error = user_statfs(pathname, &st); |
176 | if (!error) |
177 | error = do_statfs_native(&st, buf); |
178 | return error; |
179 | } |
180 | |
181 | SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf) |
182 | { |
183 | struct kstatfs st; |
184 | int error; |
185 | if (sz != sizeof(*buf)) |
186 | return -EINVAL; |
187 | error = user_statfs(pathname, &st); |
188 | if (!error) |
189 | error = do_statfs64(&st, buf); |
190 | return error; |
191 | } |
192 | |
193 | SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf) |
194 | { |
195 | struct kstatfs st; |
196 | int error = fd_statfs(fd, &st); |
197 | if (!error) |
198 | error = do_statfs_native(&st, buf); |
199 | return error; |
200 | } |
201 | |
202 | SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf) |
203 | { |
204 | struct kstatfs st; |
205 | int error; |
206 | |
207 | if (sz != sizeof(*buf)) |
208 | return -EINVAL; |
209 | |
210 | error = fd_statfs(fd, &st); |
211 | if (!error) |
212 | error = do_statfs64(&st, buf); |
213 | return error; |
214 | } |
215 | |
216 | int vfs_ustat(dev_t dev, struct kstatfs *sbuf) |
217 | { |
218 | struct super_block *s = user_get_super(dev); |
219 | int err; |
220 | if (!s) |
221 | return -EINVAL; |
222 | |
223 | err = statfs_by_dentry(s->s_root, sbuf); |
224 | drop_super(s); |
225 | return err; |
226 | } |
227 | |
228 | SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) |
229 | { |
230 | struct ustat tmp; |
231 | struct kstatfs sbuf; |
232 | int err = vfs_ustat(new_decode_dev(dev), &sbuf); |
233 | if (err) |
234 | return err; |
235 | |
236 | memset(&tmp,0,sizeof(struct ustat)); |
237 | tmp.f_tfree = sbuf.f_bfree; |
238 | tmp.f_tinode = sbuf.f_ffree; |
239 | |
240 | return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0; |
241 | } |
242 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9