xref: /openbmc/linux/fs/statfs.c (revision 2903ff019b346ab8d36ebbf54853c3aaf6590608)
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;
805c8a0fbbSDan McGee 	int error = user_path_at(AT_FDCWD, pathname, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
81c8b91accSAl Viro 	if (!error) {
82c8b91accSAl Viro 		error = vfs_statfs(&path, st);
83c8b91accSAl Viro 		path_put(&path);
84c8b91accSAl Viro 	}
85c8b91accSAl Viro 	return error;
86c8b91accSAl Viro }
877ed1ee61SAl Viro 
88c8b91accSAl Viro int fd_statfs(int fd, struct kstatfs *st)
89c8b91accSAl Viro {
90*2903ff01SAl Viro 	struct fd f = fdget(fd);
91c8b91accSAl Viro 	int error = -EBADF;
92*2903ff01SAl Viro 	if (f.file) {
93*2903ff01SAl Viro 		error = vfs_statfs(&f.file->f_path, st);
94*2903ff01SAl Viro 		fdput(f);
95c8b91accSAl Viro 	}
96c8b91accSAl Viro 	return error;
97c8b91accSAl Viro }
987ed1ee61SAl Viro 
99c8b91accSAl Viro static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
100c8b91accSAl Viro {
101c8b91accSAl Viro 	struct statfs buf;
102c8b91accSAl Viro 
103c8b91accSAl Viro 	if (sizeof(buf) == sizeof(*st))
104c8b91accSAl Viro 		memcpy(&buf, st, sizeof(*st));
1057ed1ee61SAl Viro 	else {
106c8b91accSAl Viro 		if (sizeof buf.f_blocks == 4) {
107c8b91accSAl Viro 			if ((st->f_blocks | st->f_bfree | st->f_bavail |
108c8b91accSAl Viro 			     st->f_bsize | st->f_frsize) &
1097ed1ee61SAl Viro 			    0xffffffff00000000ULL)
1107ed1ee61SAl Viro 				return -EOVERFLOW;
1117ed1ee61SAl Viro 			/*
1127ed1ee61SAl Viro 			 * f_files and f_ffree may be -1; it's okay to stuff
1137ed1ee61SAl Viro 			 * that into 32 bits
1147ed1ee61SAl Viro 			 */
115c8b91accSAl Viro 			if (st->f_files != -1 &&
116c8b91accSAl Viro 			    (st->f_files & 0xffffffff00000000ULL))
1177ed1ee61SAl Viro 				return -EOVERFLOW;
118c8b91accSAl Viro 			if (st->f_ffree != -1 &&
119c8b91accSAl Viro 			    (st->f_ffree & 0xffffffff00000000ULL))
1207ed1ee61SAl Viro 				return -EOVERFLOW;
1217ed1ee61SAl Viro 		}
1227ed1ee61SAl Viro 
123c8b91accSAl Viro 		buf.f_type = st->f_type;
124c8b91accSAl Viro 		buf.f_bsize = st->f_bsize;
125c8b91accSAl Viro 		buf.f_blocks = st->f_blocks;
126c8b91accSAl Viro 		buf.f_bfree = st->f_bfree;
127c8b91accSAl Viro 		buf.f_bavail = st->f_bavail;
128c8b91accSAl Viro 		buf.f_files = st->f_files;
129c8b91accSAl Viro 		buf.f_ffree = st->f_ffree;
130c8b91accSAl Viro 		buf.f_fsid = st->f_fsid;
131c8b91accSAl Viro 		buf.f_namelen = st->f_namelen;
132c8b91accSAl Viro 		buf.f_frsize = st->f_frsize;
133c8b91accSAl Viro 		buf.f_flags = st->f_flags;
134c8b91accSAl Viro 		memset(buf.f_spare, 0, sizeof(buf.f_spare));
1357ed1ee61SAl Viro 	}
136c8b91accSAl Viro 	if (copy_to_user(p, &buf, sizeof(buf)))
137c8b91accSAl Viro 		return -EFAULT;
1387ed1ee61SAl Viro 	return 0;
1397ed1ee61SAl Viro }
1407ed1ee61SAl Viro 
141c8b91accSAl Viro static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
1427ed1ee61SAl Viro {
143c8b91accSAl Viro 	struct statfs64 buf;
144c8b91accSAl Viro 	if (sizeof(buf) == sizeof(*st))
145c8b91accSAl Viro 		memcpy(&buf, st, sizeof(*st));
1467ed1ee61SAl Viro 	else {
147c8b91accSAl Viro 		buf.f_type = st->f_type;
148c8b91accSAl Viro 		buf.f_bsize = st->f_bsize;
149c8b91accSAl Viro 		buf.f_blocks = st->f_blocks;
150c8b91accSAl Viro 		buf.f_bfree = st->f_bfree;
151c8b91accSAl Viro 		buf.f_bavail = st->f_bavail;
152c8b91accSAl Viro 		buf.f_files = st->f_files;
153c8b91accSAl Viro 		buf.f_ffree = st->f_ffree;
154c8b91accSAl Viro 		buf.f_fsid = st->f_fsid;
155c8b91accSAl Viro 		buf.f_namelen = st->f_namelen;
156c8b91accSAl Viro 		buf.f_frsize = st->f_frsize;
157c8b91accSAl Viro 		buf.f_flags = st->f_flags;
158c8b91accSAl Viro 		memset(buf.f_spare, 0, sizeof(buf.f_spare));
1597ed1ee61SAl Viro 	}
160c8b91accSAl Viro 	if (copy_to_user(p, &buf, sizeof(buf)))
161c8b91accSAl Viro 		return -EFAULT;
1627ed1ee61SAl Viro 	return 0;
1637ed1ee61SAl Viro }
1647ed1ee61SAl Viro 
1657ed1ee61SAl Viro SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
1667ed1ee61SAl Viro {
167c8b91accSAl Viro 	struct kstatfs st;
168c8b91accSAl Viro 	int error = user_statfs(pathname, &st);
169c8b91accSAl Viro 	if (!error)
170c8b91accSAl Viro 		error = do_statfs_native(&st, buf);
1717ed1ee61SAl Viro 	return error;
1727ed1ee61SAl Viro }
1737ed1ee61SAl Viro 
1747ed1ee61SAl Viro SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
1757ed1ee61SAl Viro {
176c8b91accSAl Viro 	struct kstatfs st;
177c8b91accSAl Viro 	int error;
1787ed1ee61SAl Viro 	if (sz != sizeof(*buf))
1797ed1ee61SAl Viro 		return -EINVAL;
180c8b91accSAl Viro 	error = user_statfs(pathname, &st);
181c8b91accSAl Viro 	if (!error)
182c8b91accSAl Viro 		error = do_statfs64(&st, buf);
1837ed1ee61SAl Viro 	return error;
1847ed1ee61SAl Viro }
1857ed1ee61SAl Viro 
1867ed1ee61SAl Viro SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
1877ed1ee61SAl Viro {
188c8b91accSAl Viro 	struct kstatfs st;
189c8b91accSAl Viro 	int error = fd_statfs(fd, &st);
190c8b91accSAl Viro 	if (!error)
191c8b91accSAl Viro 		error = do_statfs_native(&st, buf);
1927ed1ee61SAl Viro 	return error;
1937ed1ee61SAl Viro }
1947ed1ee61SAl Viro 
1957ed1ee61SAl Viro SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
1967ed1ee61SAl Viro {
197c8b91accSAl Viro 	struct kstatfs st;
1987ed1ee61SAl Viro 	int error;
1997ed1ee61SAl Viro 
2007ed1ee61SAl Viro 	if (sz != sizeof(*buf))
2017ed1ee61SAl Viro 		return -EINVAL;
2027ed1ee61SAl Viro 
203c8b91accSAl Viro 	error = fd_statfs(fd, &st);
204c8b91accSAl Viro 	if (!error)
205c8b91accSAl Viro 		error = do_statfs64(&st, buf);
2067ed1ee61SAl Viro 	return error;
2077ed1ee61SAl Viro }
2087ed1ee61SAl Viro 
209cf31e70dSAl Viro int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
2107ed1ee61SAl Viro {
211cf31e70dSAl Viro 	struct super_block *s = user_get_super(dev);
2127ed1ee61SAl Viro 	int err;
2137ed1ee61SAl Viro 	if (!s)
2147ed1ee61SAl Viro 		return -EINVAL;
2157ed1ee61SAl Viro 
216cf31e70dSAl Viro 	err = statfs_by_dentry(s->s_root, sbuf);
2177ed1ee61SAl Viro 	drop_super(s);
218cf31e70dSAl Viro 	return err;
219cf31e70dSAl Viro }
220cf31e70dSAl Viro 
221cf31e70dSAl Viro SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
222cf31e70dSAl Viro {
223cf31e70dSAl Viro 	struct ustat tmp;
224cf31e70dSAl Viro 	struct kstatfs sbuf;
225cf31e70dSAl Viro 	int err = vfs_ustat(new_decode_dev(dev), &sbuf);
2267ed1ee61SAl Viro 	if (err)
2277ed1ee61SAl Viro 		return err;
2287ed1ee61SAl Viro 
2297ed1ee61SAl Viro 	memset(&tmp,0,sizeof(struct ustat));
2307ed1ee61SAl Viro 	tmp.f_tfree = sbuf.f_bfree;
2317ed1ee61SAl Viro 	tmp.f_tinode = sbuf.f_ffree;
2327ed1ee61SAl Viro 
2337ed1ee61SAl Viro 	return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
2347ed1ee61SAl Viro }
235