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