]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - fs/statfs.c
1 #include <linux/syscalls.h>
2 #include <linux/export.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>
13 static int flags_by_mnt(int mnt_flags
)
17 if (mnt_flags
& MNT_READONLY
)
19 if (mnt_flags
& MNT_NOSUID
)
21 if (mnt_flags
& MNT_NODEV
)
23 if (mnt_flags
& MNT_NOEXEC
)
25 if (mnt_flags
& MNT_NOATIME
)
27 if (mnt_flags
& MNT_NODIRATIME
)
28 flags
|= ST_NODIRATIME
;
29 if (mnt_flags
& MNT_RELATIME
)
34 static int flags_by_sb(int s_flags
)
37 if (s_flags
& MS_SYNCHRONOUS
)
38 flags
|= ST_SYNCHRONOUS
;
39 if (s_flags
& MS_MANDLOCK
)
44 static int calculate_f_flags(struct vfsmount
*mnt
)
46 return ST_VALID
| flags_by_mnt(mnt
->mnt_flags
) |
47 flags_by_sb(mnt
->mnt_sb
->s_flags
);
50 static int statfs_by_dentry(struct dentry
*dentry
, struct kstatfs
*buf
)
54 if (!dentry
->d_sb
->s_op
->statfs
)
57 memset(buf
, 0, sizeof(*buf
));
58 retval
= security_sb_statfs(dentry
);
61 retval
= dentry
->d_sb
->s_op
->statfs(dentry
, buf
);
62 if (retval
== 0 && buf
->f_frsize
== 0)
63 buf
->f_frsize
= buf
->f_bsize
;
67 int vfs_statfs(const struct path
*path
, struct kstatfs
*buf
)
71 error
= statfs_by_dentry(path
->dentry
, buf
);
73 buf
->f_flags
= calculate_f_flags(path
->mnt
);
76 EXPORT_SYMBOL(vfs_statfs
);
78 int user_statfs(const char __user
*pathname
, struct kstatfs
*st
)
82 unsigned int lookup_flags
= LOOKUP_FOLLOW
|LOOKUP_AUTOMOUNT
;
84 error
= user_path_at(AT_FDCWD
, pathname
, lookup_flags
, &path
);
86 error
= vfs_statfs(&path
, st
);
88 if (retry_estale(error
, lookup_flags
)) {
89 lookup_flags
|= LOOKUP_REVAL
;
96 int fd_statfs(int fd
, struct kstatfs
*st
)
98 struct fd f
= fdget_raw(fd
);
101 error
= vfs_statfs(&f
.file
->f_path
, st
);
107 static int do_statfs_native(struct kstatfs
*st
, struct statfs __user
*p
)
111 if (sizeof(buf
) == sizeof(*st
))
112 memcpy(&buf
, st
, sizeof(*st
));
114 if (sizeof buf
.f_blocks
== 4) {
115 if ((st
->f_blocks
| st
->f_bfree
| st
->f_bavail
|
116 st
->f_bsize
| st
->f_frsize
) &
117 0xffffffff00000000ULL
)
120 * f_files and f_ffree may be -1; it's okay to stuff
123 if (st
->f_files
!= -1 &&
124 (st
->f_files
& 0xffffffff00000000ULL
))
126 if (st
->f_ffree
!= -1 &&
127 (st
->f_ffree
& 0xffffffff00000000ULL
))
131 buf
.f_type
= st
->f_type
;
132 buf
.f_bsize
= st
->f_bsize
;
133 buf
.f_blocks
= st
->f_blocks
;
134 buf
.f_bfree
= st
->f_bfree
;
135 buf
.f_bavail
= st
->f_bavail
;
136 buf
.f_files
= st
->f_files
;
137 buf
.f_ffree
= st
->f_ffree
;
138 buf
.f_fsid
= st
->f_fsid
;
139 buf
.f_namelen
= st
->f_namelen
;
140 buf
.f_frsize
= st
->f_frsize
;
141 buf
.f_flags
= st
->f_flags
;
142 memset(buf
.f_spare
, 0, sizeof(buf
.f_spare
));
144 if (copy_to_user(p
, &buf
, sizeof(buf
)))
149 static int do_statfs64(struct kstatfs
*st
, struct statfs64 __user
*p
)
152 if (sizeof(buf
) == sizeof(*st
))
153 memcpy(&buf
, st
, sizeof(*st
));
155 buf
.f_type
= st
->f_type
;
156 buf
.f_bsize
= st
->f_bsize
;
157 buf
.f_blocks
= st
->f_blocks
;
158 buf
.f_bfree
= st
->f_bfree
;
159 buf
.f_bavail
= st
->f_bavail
;
160 buf
.f_files
= st
->f_files
;
161 buf
.f_ffree
= st
->f_ffree
;
162 buf
.f_fsid
= st
->f_fsid
;
163 buf
.f_namelen
= st
->f_namelen
;
164 buf
.f_frsize
= st
->f_frsize
;
165 buf
.f_flags
= st
->f_flags
;
166 memset(buf
.f_spare
, 0, sizeof(buf
.f_spare
));
168 if (copy_to_user(p
, &buf
, sizeof(buf
)))
173 SYSCALL_DEFINE2(statfs
, const char __user
*, pathname
, struct statfs __user
*, buf
)
176 int error
= user_statfs(pathname
, &st
);
178 error
= do_statfs_native(&st
, buf
);
182 SYSCALL_DEFINE3(statfs64
, const char __user
*, pathname
, size_t, sz
, struct statfs64 __user
*, buf
)
186 if (sz
!= sizeof(*buf
))
188 error
= user_statfs(pathname
, &st
);
190 error
= do_statfs64(&st
, buf
);
194 SYSCALL_DEFINE2(fstatfs
, unsigned int, fd
, struct statfs __user
*, buf
)
197 int error
= fd_statfs(fd
, &st
);
199 error
= do_statfs_native(&st
, buf
);
203 SYSCALL_DEFINE3(fstatfs64
, unsigned int, fd
, size_t, sz
, struct statfs64 __user
*, buf
)
208 if (sz
!= sizeof(*buf
))
211 error
= fd_statfs(fd
, &st
);
213 error
= do_statfs64(&st
, buf
);
217 int vfs_ustat(dev_t dev
, struct kstatfs
*sbuf
)
219 struct super_block
*s
= user_get_super(dev
);
224 err
= statfs_by_dentry(s
->s_root
, sbuf
);
229 SYSCALL_DEFINE2(ustat
, unsigned, dev
, struct ustat __user
*, ubuf
)
233 int err
= vfs_ustat(new_decode_dev(dev
), &sbuf
);
237 memset(&tmp
,0,sizeof(struct ustat
));
238 tmp
.f_tfree
= sbuf
.f_bfree
;
239 tmp
.f_tinode
= sbuf
.f_ffree
;
241 return copy_to_user(ubuf
, &tmp
, sizeof(struct ustat
)) ? -EFAULT
: 0;
245 static int put_compat_statfs(struct compat_statfs __user
*ubuf
, struct kstatfs
*kbuf
)
247 if (sizeof ubuf
->f_blocks
== 4) {
248 if ((kbuf
->f_blocks
| kbuf
->f_bfree
| kbuf
->f_bavail
|
249 kbuf
->f_bsize
| kbuf
->f_frsize
) & 0xffffffff00000000ULL
)
251 /* f_files and f_ffree may be -1; it's okay
252 * to stuff that into 32 bits */
253 if (kbuf
->f_files
!= 0xffffffffffffffffULL
254 && (kbuf
->f_files
& 0xffffffff00000000ULL
))
256 if (kbuf
->f_ffree
!= 0xffffffffffffffffULL
257 && (kbuf
->f_ffree
& 0xffffffff00000000ULL
))
260 if (!access_ok(VERIFY_WRITE
, ubuf
, sizeof(*ubuf
)) ||
261 __put_user(kbuf
->f_type
, &ubuf
->f_type
) ||
262 __put_user(kbuf
->f_bsize
, &ubuf
->f_bsize
) ||
263 __put_user(kbuf
->f_blocks
, &ubuf
->f_blocks
) ||
264 __put_user(kbuf
->f_bfree
, &ubuf
->f_bfree
) ||
265 __put_user(kbuf
->f_bavail
, &ubuf
->f_bavail
) ||
266 __put_user(kbuf
->f_files
, &ubuf
->f_files
) ||
267 __put_user(kbuf
->f_ffree
, &ubuf
->f_ffree
) ||
268 __put_user(kbuf
->f_namelen
, &ubuf
->f_namelen
) ||
269 __put_user(kbuf
->f_fsid
.val
[0], &ubuf
->f_fsid
.val
[0]) ||
270 __put_user(kbuf
->f_fsid
.val
[1], &ubuf
->f_fsid
.val
[1]) ||
271 __put_user(kbuf
->f_frsize
, &ubuf
->f_frsize
) ||
272 __put_user(kbuf
->f_flags
, &ubuf
->f_flags
) ||
273 __clear_user(ubuf
->f_spare
, sizeof(ubuf
->f_spare
)))
279 * The following statfs calls are copies of code from fs/statfs.c and
280 * should be checked against those from time to time
282 COMPAT_SYSCALL_DEFINE2(statfs
, const char __user
*, pathname
, struct compat_statfs __user
*, buf
)
285 int error
= user_statfs(pathname
, &tmp
);
287 error
= put_compat_statfs(buf
, &tmp
);
291 COMPAT_SYSCALL_DEFINE2(fstatfs
, unsigned int, fd
, struct compat_statfs __user
*, buf
)
294 int error
= fd_statfs(fd
, &tmp
);
296 error
= put_compat_statfs(buf
, &tmp
);
300 static int put_compat_statfs64(struct compat_statfs64 __user
*ubuf
, struct kstatfs
*kbuf
)
302 if (sizeof(ubuf
->f_bsize
) == 4) {
303 if ((kbuf
->f_type
| kbuf
->f_bsize
| kbuf
->f_namelen
|
304 kbuf
->f_frsize
| kbuf
->f_flags
) & 0xffffffff00000000ULL
)
306 /* f_files and f_ffree may be -1; it's okay
307 * to stuff that into 32 bits */
308 if (kbuf
->f_files
!= 0xffffffffffffffffULL
309 && (kbuf
->f_files
& 0xffffffff00000000ULL
))
311 if (kbuf
->f_ffree
!= 0xffffffffffffffffULL
312 && (kbuf
->f_ffree
& 0xffffffff00000000ULL
))
315 if (!access_ok(VERIFY_WRITE
, ubuf
, sizeof(*ubuf
)) ||
316 __put_user(kbuf
->f_type
, &ubuf
->f_type
) ||
317 __put_user(kbuf
->f_bsize
, &ubuf
->f_bsize
) ||
318 __put_user(kbuf
->f_blocks
, &ubuf
->f_blocks
) ||
319 __put_user(kbuf
->f_bfree
, &ubuf
->f_bfree
) ||
320 __put_user(kbuf
->f_bavail
, &ubuf
->f_bavail
) ||
321 __put_user(kbuf
->f_files
, &ubuf
->f_files
) ||
322 __put_user(kbuf
->f_ffree
, &ubuf
->f_ffree
) ||
323 __put_user(kbuf
->f_namelen
, &ubuf
->f_namelen
) ||
324 __put_user(kbuf
->f_fsid
.val
[0], &ubuf
->f_fsid
.val
[0]) ||
325 __put_user(kbuf
->f_fsid
.val
[1], &ubuf
->f_fsid
.val
[1]) ||
326 __put_user(kbuf
->f_frsize
, &ubuf
->f_frsize
) ||
327 __put_user(kbuf
->f_flags
, &ubuf
->f_flags
) ||
328 __clear_user(ubuf
->f_spare
, sizeof(ubuf
->f_spare
)))
333 COMPAT_SYSCALL_DEFINE3(statfs64
, const char __user
*, pathname
, compat_size_t
, sz
, struct compat_statfs64 __user
*, buf
)
338 if (sz
!= sizeof(*buf
))
341 error
= user_statfs(pathname
, &tmp
);
343 error
= put_compat_statfs64(buf
, &tmp
);
347 COMPAT_SYSCALL_DEFINE3(fstatfs64
, unsigned int, fd
, compat_size_t
, sz
, struct compat_statfs64 __user
*, buf
)
352 if (sz
!= sizeof(*buf
))
355 error
= fd_statfs(fd
, &tmp
);
357 error
= put_compat_statfs64(buf
, &tmp
);
362 * This is a copy of sys_ustat, just dealing with a structure layout.
363 * Given how simple this syscall is that apporach is more maintainable
364 * than the various conversion hacks.
366 COMPAT_SYSCALL_DEFINE2(ustat
, unsigned, dev
, struct compat_ustat __user
*, u
)
368 struct compat_ustat tmp
;
370 int err
= vfs_ustat(new_decode_dev(dev
), &sbuf
);
374 memset(&tmp
, 0, sizeof(struct compat_ustat
));
375 tmp
.f_tfree
= sbuf
.f_bfree
;
376 tmp
.f_tinode
= sbuf
.f_ffree
;
377 if (copy_to_user(u
, &tmp
, sizeof(struct compat_ustat
)))