Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[muen/linux.git] / fs / statfs.c
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 <linux/compat.h>
11 #include "internal.h"
12
13 static int flags_by_mnt(int mnt_flags)
14 {
15         int flags = 0;
16
17         if (mnt_flags & MNT_READONLY)
18                 flags |= ST_RDONLY;
19         if (mnt_flags & MNT_NOSUID)
20                 flags |= ST_NOSUID;
21         if (mnt_flags & MNT_NODEV)
22                 flags |= ST_NODEV;
23         if (mnt_flags & MNT_NOEXEC)
24                 flags |= ST_NOEXEC;
25         if (mnt_flags & MNT_NOATIME)
26                 flags |= ST_NOATIME;
27         if (mnt_flags & MNT_NODIRATIME)
28                 flags |= ST_NODIRATIME;
29         if (mnt_flags & MNT_RELATIME)
30                 flags |= ST_RELATIME;
31         return flags;
32 }
33
34 static int flags_by_sb(int s_flags)
35 {
36         int flags = 0;
37         if (s_flags & MS_SYNCHRONOUS)
38                 flags |= ST_SYNCHRONOUS;
39         if (s_flags & MS_MANDLOCK)
40                 flags |= ST_MANDLOCK;
41         if (s_flags & MS_RDONLY)
42                 flags |= ST_RDONLY;
43         return flags;
44 }
45
46 static int calculate_f_flags(struct vfsmount *mnt)
47 {
48         return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
49                 flags_by_sb(mnt->mnt_sb->s_flags);
50 }
51
52 static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
53 {
54         int retval;
55
56         if (!dentry->d_sb->s_op->statfs)
57                 return -ENOSYS;
58
59         memset(buf, 0, sizeof(*buf));
60         retval = security_sb_statfs(dentry);
61         if (retval)
62                 return retval;
63         retval = dentry->d_sb->s_op->statfs(dentry, buf);
64         if (retval == 0 && buf->f_frsize == 0)
65                 buf->f_frsize = buf->f_bsize;
66         return retval;
67 }
68
69 int vfs_statfs(const struct path *path, struct kstatfs *buf)
70 {
71         int error;
72
73         error = statfs_by_dentry(path->dentry, buf);
74         if (!error)
75                 buf->f_flags = calculate_f_flags(path->mnt);
76         return error;
77 }
78 EXPORT_SYMBOL(vfs_statfs);
79
80 int user_statfs(const char __user *pathname, struct kstatfs *st)
81 {
82         struct path path;
83         int error;
84         unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
85 retry:
86         error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
87         if (!error) {
88                 error = vfs_statfs(&path, st);
89                 path_put(&path);
90                 if (retry_estale(error, lookup_flags)) {
91                         lookup_flags |= LOOKUP_REVAL;
92                         goto retry;
93                 }
94         }
95         return error;
96 }
97
98 int fd_statfs(int fd, struct kstatfs *st)
99 {
100         struct fd f = fdget_raw(fd);
101         int error = -EBADF;
102         if (f.file) {
103                 error = vfs_statfs(&f.file->f_path, st);
104                 fdput(f);
105         }
106         return error;
107 }
108
109 static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
110 {
111         struct statfs buf;
112
113         if (sizeof(buf) == sizeof(*st))
114                 memcpy(&buf, st, sizeof(*st));
115         else {
116                 if (sizeof buf.f_blocks == 4) {
117                         if ((st->f_blocks | st->f_bfree | st->f_bavail |
118                              st->f_bsize | st->f_frsize) &
119                             0xffffffff00000000ULL)
120                                 return -EOVERFLOW;
121                         /*
122                          * f_files and f_ffree may be -1; it's okay to stuff
123                          * that into 32 bits
124                          */
125                         if (st->f_files != -1 &&
126                             (st->f_files & 0xffffffff00000000ULL))
127                                 return -EOVERFLOW;
128                         if (st->f_ffree != -1 &&
129                             (st->f_ffree & 0xffffffff00000000ULL))
130                                 return -EOVERFLOW;
131                 }
132
133                 buf.f_type = st->f_type;
134                 buf.f_bsize = st->f_bsize;
135                 buf.f_blocks = st->f_blocks;
136                 buf.f_bfree = st->f_bfree;
137                 buf.f_bavail = st->f_bavail;
138                 buf.f_files = st->f_files;
139                 buf.f_ffree = st->f_ffree;
140                 buf.f_fsid = st->f_fsid;
141                 buf.f_namelen = st->f_namelen;
142                 buf.f_frsize = st->f_frsize;
143                 buf.f_flags = st->f_flags;
144                 memset(buf.f_spare, 0, sizeof(buf.f_spare));
145         }
146         if (copy_to_user(p, &buf, sizeof(buf)))
147                 return -EFAULT;
148         return 0;
149 }
150
151 static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
152 {
153         struct statfs64 buf;
154         if (sizeof(buf) == sizeof(*st))
155                 memcpy(&buf, st, sizeof(*st));
156         else {
157                 buf.f_type = st->f_type;
158                 buf.f_bsize = st->f_bsize;
159                 buf.f_blocks = st->f_blocks;
160                 buf.f_bfree = st->f_bfree;
161                 buf.f_bavail = st->f_bavail;
162                 buf.f_files = st->f_files;
163                 buf.f_ffree = st->f_ffree;
164                 buf.f_fsid = st->f_fsid;
165                 buf.f_namelen = st->f_namelen;
166                 buf.f_frsize = st->f_frsize;
167                 buf.f_flags = st->f_flags;
168                 memset(buf.f_spare, 0, sizeof(buf.f_spare));
169         }
170         if (copy_to_user(p, &buf, sizeof(buf)))
171                 return -EFAULT;
172         return 0;
173 }
174
175 SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
176 {
177         struct kstatfs st;
178         int error = user_statfs(pathname, &st);
179         if (!error)
180                 error = do_statfs_native(&st, buf);
181         return error;
182 }
183
184 SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
185 {
186         struct kstatfs st;
187         int error;
188         if (sz != sizeof(*buf))
189                 return -EINVAL;
190         error = user_statfs(pathname, &st);
191         if (!error)
192                 error = do_statfs64(&st, buf);
193         return error;
194 }
195
196 SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
197 {
198         struct kstatfs st;
199         int error = fd_statfs(fd, &st);
200         if (!error)
201                 error = do_statfs_native(&st, buf);
202         return error;
203 }
204
205 SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
206 {
207         struct kstatfs st;
208         int error;
209
210         if (sz != sizeof(*buf))
211                 return -EINVAL;
212
213         error = fd_statfs(fd, &st);
214         if (!error)
215                 error = do_statfs64(&st, buf);
216         return error;
217 }
218
219 int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
220 {
221         struct super_block *s = user_get_super(dev);
222         int err;
223         if (!s)
224                 return -EINVAL;
225
226         err = statfs_by_dentry(s->s_root, sbuf);
227         drop_super(s);
228         return err;
229 }
230
231 SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
232 {
233         struct ustat tmp;
234         struct kstatfs sbuf;
235         int err = vfs_ustat(new_decode_dev(dev), &sbuf);
236         if (err)
237                 return err;
238
239         memset(&tmp,0,sizeof(struct ustat));
240         tmp.f_tfree = sbuf.f_bfree;
241         tmp.f_tinode = sbuf.f_ffree;
242
243         return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
244 }
245
246 #ifdef CONFIG_COMPAT
247 static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
248 {
249         struct compat_statfs buf;
250         if (sizeof ubuf->f_blocks == 4) {
251                 if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
252                      kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
253                         return -EOVERFLOW;
254                 /* f_files and f_ffree may be -1; it's okay
255                  * to stuff that into 32 bits */
256                 if (kbuf->f_files != 0xffffffffffffffffULL
257                  && (kbuf->f_files & 0xffffffff00000000ULL))
258                         return -EOVERFLOW;
259                 if (kbuf->f_ffree != 0xffffffffffffffffULL
260                  && (kbuf->f_ffree & 0xffffffff00000000ULL))
261                         return -EOVERFLOW;
262         }
263         memset(&buf, 0, sizeof(struct compat_statfs));
264         buf.f_type = kbuf->f_type;
265         buf.f_bsize = kbuf->f_bsize;
266         buf.f_blocks = kbuf->f_blocks;
267         buf.f_bfree = kbuf->f_bfree;
268         buf.f_bavail = kbuf->f_bavail;
269         buf.f_files = kbuf->f_files;
270         buf.f_ffree = kbuf->f_ffree;
271         buf.f_namelen = kbuf->f_namelen;
272         buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
273         buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
274         buf.f_frsize = kbuf->f_frsize;
275         buf.f_flags = kbuf->f_flags;
276         if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs)))
277                 return -EFAULT;
278         return 0;
279 }
280
281 /*
282  * The following statfs calls are copies of code from fs/statfs.c and
283  * should be checked against those from time to time
284  */
285 COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf)
286 {
287         struct kstatfs tmp;
288         int error = user_statfs(pathname, &tmp);
289         if (!error)
290                 error = put_compat_statfs(buf, &tmp);
291         return error;
292 }
293
294 COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf)
295 {
296         struct kstatfs tmp;
297         int error = fd_statfs(fd, &tmp);
298         if (!error)
299                 error = put_compat_statfs(buf, &tmp);
300         return error;
301 }
302
303 static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
304 {
305         struct compat_statfs64 buf;
306         if (sizeof(ubuf->f_bsize) == 4) {
307                 if ((kbuf->f_type | kbuf->f_bsize | kbuf->f_namelen |
308                      kbuf->f_frsize | kbuf->f_flags) & 0xffffffff00000000ULL)
309                         return -EOVERFLOW;
310                 /* f_files and f_ffree may be -1; it's okay
311                  * to stuff that into 32 bits */
312                 if (kbuf->f_files != 0xffffffffffffffffULL
313                  && (kbuf->f_files & 0xffffffff00000000ULL))
314                         return -EOVERFLOW;
315                 if (kbuf->f_ffree != 0xffffffffffffffffULL
316                  && (kbuf->f_ffree & 0xffffffff00000000ULL))
317                         return -EOVERFLOW;
318         }
319         memset(&buf, 0, sizeof(struct compat_statfs64));
320         buf.f_type = kbuf->f_type;
321         buf.f_bsize = kbuf->f_bsize;
322         buf.f_blocks = kbuf->f_blocks;
323         buf.f_bfree = kbuf->f_bfree;
324         buf.f_bavail = kbuf->f_bavail;
325         buf.f_files = kbuf->f_files;
326         buf.f_ffree = kbuf->f_ffree;
327         buf.f_namelen = kbuf->f_namelen;
328         buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
329         buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
330         buf.f_frsize = kbuf->f_frsize;
331         buf.f_flags = kbuf->f_flags;
332         if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs64)))
333                 return -EFAULT;
334         return 0;
335 }
336
337 COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf)
338 {
339         struct kstatfs tmp;
340         int error;
341
342         if (sz != sizeof(*buf))
343                 return -EINVAL;
344
345         error = user_statfs(pathname, &tmp);
346         if (!error)
347                 error = put_compat_statfs64(buf, &tmp);
348         return error;
349 }
350
351 COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf)
352 {
353         struct kstatfs tmp;
354         int error;
355
356         if (sz != sizeof(*buf))
357                 return -EINVAL;
358
359         error = fd_statfs(fd, &tmp);
360         if (!error)
361                 error = put_compat_statfs64(buf, &tmp);
362         return error;
363 }
364
365 /*
366  * This is a copy of sys_ustat, just dealing with a structure layout.
367  * Given how simple this syscall is that apporach is more maintainable
368  * than the various conversion hacks.
369  */
370 COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u)
371 {
372         struct compat_ustat tmp;
373         struct kstatfs sbuf;
374         int err = vfs_ustat(new_decode_dev(dev), &sbuf);
375         if (err)
376                 return err;
377
378         memset(&tmp, 0, sizeof(struct compat_ustat));
379         tmp.f_tfree = sbuf.f_bfree;
380         tmp.f_tinode = sbuf.f_ffree;
381         if (copy_to_user(u, &tmp, sizeof(struct compat_ustat)))
382                 return -EFAULT;
383         return 0;
384 }
385 #endif