xref: /openbmc/linux/fs/statfs.c (revision 96948fc6069b68380abac2944b8b02b43a2e2057)
17ed1ee61SAl Viro #include <linux/syscalls.h>
2630d9c47SPaul Gortmaker #include <linux/export.h>
37ed1ee61SAl Viro #include <linux/fs.h>
47ed1ee61SAl Viro #include <linux/file.h>
5365b1818SChristoph Hellwig #include <linux/mount.h>
67ed1ee61SAl Viro #include <linux/namei.h>
77ed1ee61SAl Viro #include <linux/statfs.h>
87ed1ee61SAl Viro #include <linux/security.h>
97ed1ee61SAl Viro #include <linux/uaccess.h>
10cf31e70dSAl Viro #include "internal.h"
117ed1ee61SAl Viro 
12365b1818SChristoph Hellwig static int flags_by_mnt(int mnt_flags)
13365b1818SChristoph Hellwig {
14365b1818SChristoph Hellwig 	int flags = 0;
15365b1818SChristoph Hellwig 
16365b1818SChristoph Hellwig 	if (mnt_flags & MNT_READONLY)
17365b1818SChristoph Hellwig 		flags |= ST_RDONLY;
18365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NOSUID)
19365b1818SChristoph Hellwig 		flags |= ST_NOSUID;
20365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NODEV)
21365b1818SChristoph Hellwig 		flags |= ST_NODEV;
22365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NOEXEC)
23365b1818SChristoph Hellwig 		flags |= ST_NOEXEC;
24365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NOATIME)
25365b1818SChristoph Hellwig 		flags |= ST_NOATIME;
26365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NODIRATIME)
27365b1818SChristoph Hellwig 		flags |= ST_NODIRATIME;
28365b1818SChristoph Hellwig 	if (mnt_flags & MNT_RELATIME)
29365b1818SChristoph Hellwig 		flags |= ST_RELATIME;
30365b1818SChristoph Hellwig 	return flags;
31365b1818SChristoph Hellwig }
32365b1818SChristoph Hellwig 
33365b1818SChristoph Hellwig static int flags_by_sb(int s_flags)
34365b1818SChristoph Hellwig {
35365b1818SChristoph Hellwig 	int flags = 0;
36365b1818SChristoph Hellwig 	if (s_flags & MS_SYNCHRONOUS)
37365b1818SChristoph Hellwig 		flags |= ST_SYNCHRONOUS;
38365b1818SChristoph Hellwig 	if (s_flags & MS_MANDLOCK)
39365b1818SChristoph Hellwig 		flags |= ST_MANDLOCK;
40365b1818SChristoph Hellwig 	return flags;
41365b1818SChristoph Hellwig }
42365b1818SChristoph Hellwig 
43365b1818SChristoph Hellwig static int calculate_f_flags(struct vfsmount *mnt)
44365b1818SChristoph Hellwig {
45365b1818SChristoph Hellwig 	return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
46365b1818SChristoph Hellwig 		flags_by_sb(mnt->mnt_sb->s_flags);
47365b1818SChristoph Hellwig }
48365b1818SChristoph Hellwig 
49cf31e70dSAl Viro static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
507ed1ee61SAl Viro {
51ebabe9a9SChristoph Hellwig 	int retval;
527ed1ee61SAl Viro 
53ebabe9a9SChristoph Hellwig 	if (!dentry->d_sb->s_op->statfs)
54ebabe9a9SChristoph Hellwig 		return -ENOSYS;
55ebabe9a9SChristoph Hellwig 
567ed1ee61SAl Viro 	memset(buf, 0, sizeof(*buf));
577ed1ee61SAl Viro 	retval = security_sb_statfs(dentry);
587ed1ee61SAl Viro 	if (retval)
597ed1ee61SAl Viro 		return retval;
607ed1ee61SAl Viro 	retval = dentry->d_sb->s_op->statfs(dentry, buf);
617ed1ee61SAl Viro 	if (retval == 0 && buf->f_frsize == 0)
627ed1ee61SAl Viro 		buf->f_frsize = buf->f_bsize;
637ed1ee61SAl Viro 	return retval;
647ed1ee61SAl Viro }
657ed1ee61SAl Viro 
66ebabe9a9SChristoph Hellwig int vfs_statfs(struct path *path, struct kstatfs *buf)
67ebabe9a9SChristoph Hellwig {
68365b1818SChristoph Hellwig 	int error;
69365b1818SChristoph Hellwig 
70365b1818SChristoph Hellwig 	error = statfs_by_dentry(path->dentry, buf);
71365b1818SChristoph Hellwig 	if (!error)
72365b1818SChristoph Hellwig 		buf->f_flags = calculate_f_flags(path->mnt);
73365b1818SChristoph Hellwig 	return error;
74ebabe9a9SChristoph Hellwig }
757ed1ee61SAl Viro EXPORT_SYMBOL(vfs_statfs);
767ed1ee61SAl Viro 
77c8b91accSAl Viro int user_statfs(const char __user *pathname, struct kstatfs *st)
787ed1ee61SAl Viro {
79c8b91accSAl Viro 	struct path path;
80*96948fc6SJeff Layton 	int error;
81*96948fc6SJeff Layton 	unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
82*96948fc6SJeff Layton retry:
83*96948fc6SJeff Layton 	error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
84c8b91accSAl Viro 	if (!error) {
85c8b91accSAl Viro 		error = vfs_statfs(&path, st);
86c8b91accSAl Viro 		path_put(&path);
87*96948fc6SJeff Layton 		if (retry_estale(error, lookup_flags)) {
88*96948fc6SJeff Layton 			lookup_flags |= LOOKUP_REVAL;
89*96948fc6SJeff Layton 			goto retry;
90*96948fc6SJeff Layton 		}
91c8b91accSAl Viro 	}
92c8b91accSAl Viro 	return error;
93c8b91accSAl Viro }
947ed1ee61SAl Viro 
95c8b91accSAl Viro int fd_statfs(int fd, struct kstatfs *st)
96c8b91accSAl Viro {
972903ff01SAl Viro 	struct fd f = fdget(fd);
98c8b91accSAl Viro 	int error = -EBADF;
992903ff01SAl Viro 	if (f.file) {
1002903ff01SAl Viro 		error = vfs_statfs(&f.file->f_path, st);
1012903ff01SAl Viro 		fdput(f);
102c8b91accSAl Viro 	}
103c8b91accSAl Viro 	return error;
104c8b91accSAl Viro }
1057ed1ee61SAl Viro 
106c8b91accSAl Viro static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
107c8b91accSAl Viro {
108c8b91accSAl Viro 	struct statfs buf;
109c8b91accSAl Viro 
110c8b91accSAl Viro 	if (sizeof(buf) == sizeof(*st))
111c8b91accSAl Viro 		memcpy(&buf, st, sizeof(*st));
1127ed1ee61SAl Viro 	else {
113c8b91accSAl Viro 		if (sizeof buf.f_blocks == 4) {
114c8b91accSAl Viro 			if ((st->f_blocks | st->f_bfree | st->f_bavail |
115c8b91accSAl Viro 			     st->f_bsize | st->f_frsize) &
1167ed1ee61SAl Viro 			    0xffffffff00000000ULL)
1177ed1ee61SAl Viro 				return -EOVERFLOW;
1187ed1ee61SAl Viro 			/*
1197ed1ee61SAl Viro 			 * f_files and f_ffree may be -1; it's okay to stuff
1207ed1ee61SAl Viro 			 * that into 32 bits
1217ed1ee61SAl Viro 			 */
122c8b91accSAl Viro 			if (st->f_files != -1 &&
123c8b91accSAl Viro 			    (st->f_files & 0xffffffff00000000ULL))
1247ed1ee61SAl Viro 				return -EOVERFLOW;
125c8b91accSAl Viro 			if (st->f_ffree != -1 &&
126c8b91accSAl Viro 			    (st->f_ffree & 0xffffffff00000000ULL))
1277ed1ee61SAl Viro 				return -EOVERFLOW;
1287ed1ee61SAl Viro 		}
1297ed1ee61SAl Viro 
130c8b91accSAl Viro 		buf.f_type = st->f_type;
131c8b91accSAl Viro 		buf.f_bsize = st->f_bsize;
132c8b91accSAl Viro 		buf.f_blocks = st->f_blocks;
133c8b91accSAl Viro 		buf.f_bfree = st->f_bfree;
134c8b91accSAl Viro 		buf.f_bavail = st->f_bavail;
135c8b91accSAl Viro 		buf.f_files = st->f_files;
136c8b91accSAl Viro 		buf.f_ffree = st->f_ffree;
137c8b91accSAl Viro 		buf.f_fsid = st->f_fsid;
138c8b91accSAl Viro 		buf.f_namelen = st->f_namelen;
139c8b91accSAl Viro 		buf.f_frsize = st->f_frsize;
140c8b91accSAl Viro 		buf.f_flags = st->f_flags;
141c8b91accSAl Viro 		memset(buf.f_spare, 0, sizeof(buf.f_spare));
1427ed1ee61SAl Viro 	}
143c8b91accSAl Viro 	if (copy_to_user(p, &buf, sizeof(buf)))
144c8b91accSAl Viro 		return -EFAULT;
1457ed1ee61SAl Viro 	return 0;
1467ed1ee61SAl Viro }
1477ed1ee61SAl Viro 
148c8b91accSAl Viro static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
1497ed1ee61SAl Viro {
150c8b91accSAl Viro 	struct statfs64 buf;
151c8b91accSAl Viro 	if (sizeof(buf) == sizeof(*st))
152c8b91accSAl Viro 		memcpy(&buf, st, sizeof(*st));
1537ed1ee61SAl Viro 	else {
154c8b91accSAl Viro 		buf.f_type = st->f_type;
155c8b91accSAl Viro 		buf.f_bsize = st->f_bsize;
156c8b91accSAl Viro 		buf.f_blocks = st->f_blocks;
157c8b91accSAl Viro 		buf.f_bfree = st->f_bfree;
158c8b91accSAl Viro 		buf.f_bavail = st->f_bavail;
159c8b91accSAl Viro 		buf.f_files = st->f_files;
160c8b91accSAl Viro 		buf.f_ffree = st->f_ffree;
161c8b91accSAl Viro 		buf.f_fsid = st->f_fsid;
162c8b91accSAl Viro 		buf.f_namelen = st->f_namelen;
163c8b91accSAl Viro 		buf.f_frsize = st->f_frsize;
164c8b91accSAl Viro 		buf.f_flags = st->f_flags;
165c8b91accSAl Viro 		memset(buf.f_spare, 0, sizeof(buf.f_spare));
1667ed1ee61SAl Viro 	}
167c8b91accSAl Viro 	if (copy_to_user(p, &buf, sizeof(buf)))
168c8b91accSAl Viro 		return -EFAULT;
1697ed1ee61SAl Viro 	return 0;
1707ed1ee61SAl Viro }
1717ed1ee61SAl Viro 
1727ed1ee61SAl Viro SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
1737ed1ee61SAl Viro {
174c8b91accSAl Viro 	struct kstatfs st;
175c8b91accSAl Viro 	int error = user_statfs(pathname, &st);
176c8b91accSAl Viro 	if (!error)
177c8b91accSAl Viro 		error = do_statfs_native(&st, buf);
1787ed1ee61SAl Viro 	return error;
1797ed1ee61SAl Viro }
1807ed1ee61SAl Viro 
1817ed1ee61SAl Viro SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
1827ed1ee61SAl Viro {
183c8b91accSAl Viro 	struct kstatfs st;
184c8b91accSAl Viro 	int error;
1857ed1ee61SAl Viro 	if (sz != sizeof(*buf))
1867ed1ee61SAl Viro 		return -EINVAL;
187c8b91accSAl Viro 	error = user_statfs(pathname, &st);
188c8b91accSAl Viro 	if (!error)
189c8b91accSAl Viro 		error = do_statfs64(&st, buf);
1907ed1ee61SAl Viro 	return error;
1917ed1ee61SAl Viro }
1927ed1ee61SAl Viro 
1937ed1ee61SAl Viro SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
1947ed1ee61SAl Viro {
195c8b91accSAl Viro 	struct kstatfs st;
196c8b91accSAl Viro 	int error = fd_statfs(fd, &st);
197c8b91accSAl Viro 	if (!error)
198c8b91accSAl Viro 		error = do_statfs_native(&st, buf);
1997ed1ee61SAl Viro 	return error;
2007ed1ee61SAl Viro }
2017ed1ee61SAl Viro 
2027ed1ee61SAl Viro SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
2037ed1ee61SAl Viro {
204c8b91accSAl Viro 	struct kstatfs st;
2057ed1ee61SAl Viro 	int error;
2067ed1ee61SAl Viro 
2077ed1ee61SAl Viro 	if (sz != sizeof(*buf))
2087ed1ee61SAl Viro 		return -EINVAL;
2097ed1ee61SAl Viro 
210c8b91accSAl Viro 	error = fd_statfs(fd, &st);
211c8b91accSAl Viro 	if (!error)
212c8b91accSAl Viro 		error = do_statfs64(&st, buf);
2137ed1ee61SAl Viro 	return error;
2147ed1ee61SAl Viro }
2157ed1ee61SAl Viro 
216cf31e70dSAl Viro int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
2177ed1ee61SAl Viro {
218cf31e70dSAl Viro 	struct super_block *s = user_get_super(dev);
2197ed1ee61SAl Viro 	int err;
2207ed1ee61SAl Viro 	if (!s)
2217ed1ee61SAl Viro 		return -EINVAL;
2227ed1ee61SAl Viro 
223cf31e70dSAl Viro 	err = statfs_by_dentry(s->s_root, sbuf);
2247ed1ee61SAl Viro 	drop_super(s);
225cf31e70dSAl Viro 	return err;
226cf31e70dSAl Viro }
227cf31e70dSAl Viro 
228cf31e70dSAl Viro SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
229cf31e70dSAl Viro {
230cf31e70dSAl Viro 	struct ustat tmp;
231cf31e70dSAl Viro 	struct kstatfs sbuf;
232cf31e70dSAl Viro 	int err = vfs_ustat(new_decode_dev(dev), &sbuf);
2337ed1ee61SAl Viro 	if (err)
2347ed1ee61SAl Viro 		return err;
2357ed1ee61SAl Viro 
2367ed1ee61SAl Viro 	memset(&tmp,0,sizeof(struct ustat));
2377ed1ee61SAl Viro 	tmp.f_tfree = sbuf.f_bfree;
2387ed1ee61SAl Viro 	tmp.f_tinode = sbuf.f_ffree;
2397ed1ee61SAl Viro 
2407ed1ee61SAl Viro 	return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
2417ed1ee61SAl Viro }
242