xref: /openbmc/linux/fs/statfs.c (revision 365b18189789bfa1acd9939e6312b8a4b4577b28)
17ed1ee61SAl Viro #include <linux/syscalls.h>
27ed1ee61SAl Viro #include <linux/module.h>
37ed1ee61SAl Viro #include <linux/fs.h>
47ed1ee61SAl Viro #include <linux/file.h>
5*365b1818SChristoph 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>
107ed1ee61SAl Viro 
11*365b1818SChristoph Hellwig static int flags_by_mnt(int mnt_flags)
12*365b1818SChristoph Hellwig {
13*365b1818SChristoph Hellwig 	int flags = 0;
14*365b1818SChristoph Hellwig 
15*365b1818SChristoph Hellwig 	if (mnt_flags & MNT_READONLY)
16*365b1818SChristoph Hellwig 		flags |= ST_RDONLY;
17*365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NOSUID)
18*365b1818SChristoph Hellwig 		flags |= ST_NOSUID;
19*365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NODEV)
20*365b1818SChristoph Hellwig 		flags |= ST_NODEV;
21*365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NOEXEC)
22*365b1818SChristoph Hellwig 		flags |= ST_NOEXEC;
23*365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NOATIME)
24*365b1818SChristoph Hellwig 		flags |= ST_NOATIME;
25*365b1818SChristoph Hellwig 	if (mnt_flags & MNT_NODIRATIME)
26*365b1818SChristoph Hellwig 		flags |= ST_NODIRATIME;
27*365b1818SChristoph Hellwig 	if (mnt_flags & MNT_RELATIME)
28*365b1818SChristoph Hellwig 		flags |= ST_RELATIME;
29*365b1818SChristoph Hellwig 	return flags;
30*365b1818SChristoph Hellwig }
31*365b1818SChristoph Hellwig 
32*365b1818SChristoph Hellwig static int flags_by_sb(int s_flags)
33*365b1818SChristoph Hellwig {
34*365b1818SChristoph Hellwig 	int flags = 0;
35*365b1818SChristoph Hellwig 	if (s_flags & MS_SYNCHRONOUS)
36*365b1818SChristoph Hellwig 		flags |= ST_SYNCHRONOUS;
37*365b1818SChristoph Hellwig 	if (s_flags & MS_MANDLOCK)
38*365b1818SChristoph Hellwig 		flags |= ST_MANDLOCK;
39*365b1818SChristoph Hellwig 	return flags;
40*365b1818SChristoph Hellwig }
41*365b1818SChristoph Hellwig 
42*365b1818SChristoph Hellwig static int calculate_f_flags(struct vfsmount *mnt)
43*365b1818SChristoph Hellwig {
44*365b1818SChristoph Hellwig 	return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
45*365b1818SChristoph Hellwig 		flags_by_sb(mnt->mnt_sb->s_flags);
46*365b1818SChristoph Hellwig }
47*365b1818SChristoph Hellwig 
48ebabe9a9SChristoph Hellwig int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
497ed1ee61SAl Viro {
50ebabe9a9SChristoph Hellwig 	int retval;
517ed1ee61SAl Viro 
52ebabe9a9SChristoph Hellwig 	if (!dentry->d_sb->s_op->statfs)
53ebabe9a9SChristoph Hellwig 		return -ENOSYS;
54ebabe9a9SChristoph Hellwig 
557ed1ee61SAl Viro 	memset(buf, 0, sizeof(*buf));
567ed1ee61SAl Viro 	retval = security_sb_statfs(dentry);
577ed1ee61SAl Viro 	if (retval)
587ed1ee61SAl Viro 		return retval;
597ed1ee61SAl Viro 	retval = dentry->d_sb->s_op->statfs(dentry, buf);
607ed1ee61SAl Viro 	if (retval == 0 && buf->f_frsize == 0)
617ed1ee61SAl Viro 		buf->f_frsize = buf->f_bsize;
627ed1ee61SAl Viro 	return retval;
637ed1ee61SAl Viro }
647ed1ee61SAl Viro 
65ebabe9a9SChristoph Hellwig int vfs_statfs(struct path *path, struct kstatfs *buf)
66ebabe9a9SChristoph Hellwig {
67*365b1818SChristoph Hellwig 	int error;
68*365b1818SChristoph Hellwig 
69*365b1818SChristoph Hellwig 	error = statfs_by_dentry(path->dentry, buf);
70*365b1818SChristoph Hellwig 	if (!error)
71*365b1818SChristoph Hellwig 		buf->f_flags = calculate_f_flags(path->mnt);
72*365b1818SChristoph Hellwig 	return error;
73ebabe9a9SChristoph Hellwig }
747ed1ee61SAl Viro EXPORT_SYMBOL(vfs_statfs);
757ed1ee61SAl Viro 
76ebabe9a9SChristoph Hellwig static int do_statfs_native(struct path *path, struct statfs *buf)
777ed1ee61SAl Viro {
787ed1ee61SAl Viro 	struct kstatfs st;
797ed1ee61SAl Viro 	int retval;
807ed1ee61SAl Viro 
81ebabe9a9SChristoph Hellwig 	retval = vfs_statfs(path, &st);
827ed1ee61SAl Viro 	if (retval)
837ed1ee61SAl Viro 		return retval;
847ed1ee61SAl Viro 
857ed1ee61SAl Viro 	if (sizeof(*buf) == sizeof(st))
867ed1ee61SAl Viro 		memcpy(buf, &st, sizeof(st));
877ed1ee61SAl Viro 	else {
887ed1ee61SAl Viro 		if (sizeof buf->f_blocks == 4) {
897ed1ee61SAl Viro 			if ((st.f_blocks | st.f_bfree | st.f_bavail |
907ed1ee61SAl Viro 			     st.f_bsize | st.f_frsize) &
917ed1ee61SAl Viro 			    0xffffffff00000000ULL)
927ed1ee61SAl Viro 				return -EOVERFLOW;
937ed1ee61SAl Viro 			/*
947ed1ee61SAl Viro 			 * f_files and f_ffree may be -1; it's okay to stuff
957ed1ee61SAl Viro 			 * that into 32 bits
967ed1ee61SAl Viro 			 */
977ed1ee61SAl Viro 			if (st.f_files != -1 &&
987ed1ee61SAl Viro 			    (st.f_files & 0xffffffff00000000ULL))
997ed1ee61SAl Viro 				return -EOVERFLOW;
1007ed1ee61SAl Viro 			if (st.f_ffree != -1 &&
1017ed1ee61SAl Viro 			    (st.f_ffree & 0xffffffff00000000ULL))
1027ed1ee61SAl Viro 				return -EOVERFLOW;
1037ed1ee61SAl Viro 		}
1047ed1ee61SAl Viro 
1057ed1ee61SAl Viro 		buf->f_type = st.f_type;
1067ed1ee61SAl Viro 		buf->f_bsize = st.f_bsize;
1077ed1ee61SAl Viro 		buf->f_blocks = st.f_blocks;
1087ed1ee61SAl Viro 		buf->f_bfree = st.f_bfree;
1097ed1ee61SAl Viro 		buf->f_bavail = st.f_bavail;
1107ed1ee61SAl Viro 		buf->f_files = st.f_files;
1117ed1ee61SAl Viro 		buf->f_ffree = st.f_ffree;
1127ed1ee61SAl Viro 		buf->f_fsid = st.f_fsid;
1137ed1ee61SAl Viro 		buf->f_namelen = st.f_namelen;
1147ed1ee61SAl Viro 		buf->f_frsize = st.f_frsize;
115*365b1818SChristoph Hellwig 		buf->f_flags = st.f_flags;
1167ed1ee61SAl Viro 		memset(buf->f_spare, 0, sizeof(buf->f_spare));
1177ed1ee61SAl Viro 	}
1187ed1ee61SAl Viro 	return 0;
1197ed1ee61SAl Viro }
1207ed1ee61SAl Viro 
121ebabe9a9SChristoph Hellwig static int do_statfs64(struct path *path, struct statfs64 *buf)
1227ed1ee61SAl Viro {
1237ed1ee61SAl Viro 	struct kstatfs st;
1247ed1ee61SAl Viro 	int retval;
1257ed1ee61SAl Viro 
126ebabe9a9SChristoph Hellwig 	retval = vfs_statfs(path, &st);
1277ed1ee61SAl Viro 	if (retval)
1287ed1ee61SAl Viro 		return retval;
1297ed1ee61SAl Viro 
1307ed1ee61SAl Viro 	if (sizeof(*buf) == sizeof(st))
1317ed1ee61SAl Viro 		memcpy(buf, &st, sizeof(st));
1327ed1ee61SAl Viro 	else {
1337ed1ee61SAl Viro 		buf->f_type = st.f_type;
1347ed1ee61SAl Viro 		buf->f_bsize = st.f_bsize;
1357ed1ee61SAl Viro 		buf->f_blocks = st.f_blocks;
1367ed1ee61SAl Viro 		buf->f_bfree = st.f_bfree;
1377ed1ee61SAl Viro 		buf->f_bavail = st.f_bavail;
1387ed1ee61SAl Viro 		buf->f_files = st.f_files;
1397ed1ee61SAl Viro 		buf->f_ffree = st.f_ffree;
1407ed1ee61SAl Viro 		buf->f_fsid = st.f_fsid;
1417ed1ee61SAl Viro 		buf->f_namelen = st.f_namelen;
1427ed1ee61SAl Viro 		buf->f_frsize = st.f_frsize;
143*365b1818SChristoph Hellwig 		buf->f_flags = st.f_flags;
1447ed1ee61SAl Viro 		memset(buf->f_spare, 0, sizeof(buf->f_spare));
1457ed1ee61SAl Viro 	}
1467ed1ee61SAl Viro 	return 0;
1477ed1ee61SAl Viro }
1487ed1ee61SAl Viro 
1497ed1ee61SAl Viro SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
1507ed1ee61SAl Viro {
1517ed1ee61SAl Viro 	struct path path;
1527ed1ee61SAl Viro 	int error;
1537ed1ee61SAl Viro 
1547ed1ee61SAl Viro 	error = user_path(pathname, &path);
1557ed1ee61SAl Viro 	if (!error) {
1567ed1ee61SAl Viro 		struct statfs tmp;
157ebabe9a9SChristoph Hellwig 		error = do_statfs_native(&path, &tmp);
1587ed1ee61SAl Viro 		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
1597ed1ee61SAl Viro 			error = -EFAULT;
1607ed1ee61SAl Viro 		path_put(&path);
1617ed1ee61SAl Viro 	}
1627ed1ee61SAl Viro 	return error;
1637ed1ee61SAl Viro }
1647ed1ee61SAl Viro 
1657ed1ee61SAl Viro SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
1667ed1ee61SAl Viro {
1677ed1ee61SAl Viro 	struct path path;
1687ed1ee61SAl Viro 	long error;
1697ed1ee61SAl Viro 
1707ed1ee61SAl Viro 	if (sz != sizeof(*buf))
1717ed1ee61SAl Viro 		return -EINVAL;
1727ed1ee61SAl Viro 	error = user_path(pathname, &path);
1737ed1ee61SAl Viro 	if (!error) {
1747ed1ee61SAl Viro 		struct statfs64 tmp;
175ebabe9a9SChristoph Hellwig 		error = do_statfs64(&path, &tmp);
1767ed1ee61SAl Viro 		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
1777ed1ee61SAl Viro 			error = -EFAULT;
1787ed1ee61SAl Viro 		path_put(&path);
1797ed1ee61SAl Viro 	}
1807ed1ee61SAl Viro 	return error;
1817ed1ee61SAl Viro }
1827ed1ee61SAl Viro 
1837ed1ee61SAl Viro SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
1847ed1ee61SAl Viro {
1857ed1ee61SAl Viro 	struct file *file;
1867ed1ee61SAl Viro 	struct statfs tmp;
1877ed1ee61SAl Viro 	int error;
1887ed1ee61SAl Viro 
1897ed1ee61SAl Viro 	error = -EBADF;
1907ed1ee61SAl Viro 	file = fget(fd);
1917ed1ee61SAl Viro 	if (!file)
1927ed1ee61SAl Viro 		goto out;
193ebabe9a9SChristoph Hellwig 	error = do_statfs_native(&file->f_path, &tmp);
1947ed1ee61SAl Viro 	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
1957ed1ee61SAl Viro 		error = -EFAULT;
1967ed1ee61SAl Viro 	fput(file);
1977ed1ee61SAl Viro out:
1987ed1ee61SAl Viro 	return error;
1997ed1ee61SAl Viro }
2007ed1ee61SAl Viro 
2017ed1ee61SAl Viro SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
2027ed1ee61SAl Viro {
2037ed1ee61SAl Viro 	struct file *file;
2047ed1ee61SAl Viro 	struct statfs64 tmp;
2057ed1ee61SAl Viro 	int error;
2067ed1ee61SAl Viro 
2077ed1ee61SAl Viro 	if (sz != sizeof(*buf))
2087ed1ee61SAl Viro 		return -EINVAL;
2097ed1ee61SAl Viro 
2107ed1ee61SAl Viro 	error = -EBADF;
2117ed1ee61SAl Viro 	file = fget(fd);
2127ed1ee61SAl Viro 	if (!file)
2137ed1ee61SAl Viro 		goto out;
214ebabe9a9SChristoph Hellwig 	error = do_statfs64(&file->f_path, &tmp);
2157ed1ee61SAl Viro 	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
2167ed1ee61SAl Viro 		error = -EFAULT;
2177ed1ee61SAl Viro 	fput(file);
2187ed1ee61SAl Viro out:
2197ed1ee61SAl Viro 	return error;
2207ed1ee61SAl Viro }
2217ed1ee61SAl Viro 
2227ed1ee61SAl Viro SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
2237ed1ee61SAl Viro {
2247ed1ee61SAl Viro 	struct super_block *s;
2257ed1ee61SAl Viro 	struct ustat tmp;
2267ed1ee61SAl Viro 	struct kstatfs sbuf;
2277ed1ee61SAl Viro 	int err;
2287ed1ee61SAl Viro 
2297ed1ee61SAl Viro 	s = user_get_super(new_decode_dev(dev));
2307ed1ee61SAl Viro 	if (!s)
2317ed1ee61SAl Viro 		return -EINVAL;
2327ed1ee61SAl Viro 
233ebabe9a9SChristoph Hellwig 	err = statfs_by_dentry(s->s_root, &sbuf);
2347ed1ee61SAl Viro 	drop_super(s);
2357ed1ee61SAl Viro 	if (err)
2367ed1ee61SAl Viro 		return err;
2377ed1ee61SAl Viro 
2387ed1ee61SAl Viro 	memset(&tmp,0,sizeof(struct ustat));
2397ed1ee61SAl Viro 	tmp.f_tfree = sbuf.f_bfree;
2407ed1ee61SAl Viro 	tmp.f_tinode = sbuf.f_ffree;
2417ed1ee61SAl Viro 
2427ed1ee61SAl Viro 	return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
2437ed1ee61SAl Viro }
244