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