162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/syscalls.h>
362306a36Sopenharmony_ci#include <linux/export.h>
462306a36Sopenharmony_ci#include <linux/fs.h>
562306a36Sopenharmony_ci#include <linux/file.h>
662306a36Sopenharmony_ci#include <linux/mount.h>
762306a36Sopenharmony_ci#include <linux/namei.h>
862306a36Sopenharmony_ci#include <linux/statfs.h>
962306a36Sopenharmony_ci#include <linux/security.h>
1062306a36Sopenharmony_ci#include <linux/uaccess.h>
1162306a36Sopenharmony_ci#include <linux/compat.h>
1262306a36Sopenharmony_ci#include "internal.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic int flags_by_mnt(int mnt_flags)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	int flags = 0;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	if (mnt_flags & MNT_READONLY)
1962306a36Sopenharmony_ci		flags |= ST_RDONLY;
2062306a36Sopenharmony_ci	if (mnt_flags & MNT_NOSUID)
2162306a36Sopenharmony_ci		flags |= ST_NOSUID;
2262306a36Sopenharmony_ci	if (mnt_flags & MNT_NODEV)
2362306a36Sopenharmony_ci		flags |= ST_NODEV;
2462306a36Sopenharmony_ci	if (mnt_flags & MNT_NOEXEC)
2562306a36Sopenharmony_ci		flags |= ST_NOEXEC;
2662306a36Sopenharmony_ci	if (mnt_flags & MNT_NOATIME)
2762306a36Sopenharmony_ci		flags |= ST_NOATIME;
2862306a36Sopenharmony_ci	if (mnt_flags & MNT_NODIRATIME)
2962306a36Sopenharmony_ci		flags |= ST_NODIRATIME;
3062306a36Sopenharmony_ci	if (mnt_flags & MNT_RELATIME)
3162306a36Sopenharmony_ci		flags |= ST_RELATIME;
3262306a36Sopenharmony_ci	if (mnt_flags & MNT_NOSYMFOLLOW)
3362306a36Sopenharmony_ci		flags |= ST_NOSYMFOLLOW;
3462306a36Sopenharmony_ci	return flags;
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int flags_by_sb(int s_flags)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	int flags = 0;
4062306a36Sopenharmony_ci	if (s_flags & SB_SYNCHRONOUS)
4162306a36Sopenharmony_ci		flags |= ST_SYNCHRONOUS;
4262306a36Sopenharmony_ci	if (s_flags & SB_MANDLOCK)
4362306a36Sopenharmony_ci		flags |= ST_MANDLOCK;
4462306a36Sopenharmony_ci	if (s_flags & SB_RDONLY)
4562306a36Sopenharmony_ci		flags |= ST_RDONLY;
4662306a36Sopenharmony_ci	return flags;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int calculate_f_flags(struct vfsmount *mnt)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
5262306a36Sopenharmony_ci		flags_by_sb(mnt->mnt_sb->s_flags);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	int retval;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (!dentry->d_sb->s_op->statfs)
6062306a36Sopenharmony_ci		return -ENOSYS;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	memset(buf, 0, sizeof(*buf));
6362306a36Sopenharmony_ci	retval = security_sb_statfs(dentry);
6462306a36Sopenharmony_ci	if (retval)
6562306a36Sopenharmony_ci		return retval;
6662306a36Sopenharmony_ci	retval = dentry->d_sb->s_op->statfs(dentry, buf);
6762306a36Sopenharmony_ci	if (retval == 0 && buf->f_frsize == 0)
6862306a36Sopenharmony_ci		buf->f_frsize = buf->f_bsize;
6962306a36Sopenharmony_ci	return retval;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ciint vfs_get_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct kstatfs st;
7562306a36Sopenharmony_ci	int error;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	error = statfs_by_dentry(dentry, &st);
7862306a36Sopenharmony_ci	if (error)
7962306a36Sopenharmony_ci		return error;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	*fsid = st.f_fsid;
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_get_fsid);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciint vfs_statfs(const struct path *path, struct kstatfs *buf)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	int error;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	error = statfs_by_dentry(path->dentry, buf);
9162306a36Sopenharmony_ci	if (!error)
9262306a36Sopenharmony_ci		buf->f_flags = calculate_f_flags(path->mnt);
9362306a36Sopenharmony_ci	return error;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_statfs);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ciint user_statfs(const char __user *pathname, struct kstatfs *st)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct path path;
10062306a36Sopenharmony_ci	int error;
10162306a36Sopenharmony_ci	unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
10262306a36Sopenharmony_ciretry:
10362306a36Sopenharmony_ci	error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
10462306a36Sopenharmony_ci	if (!error) {
10562306a36Sopenharmony_ci		error = vfs_statfs(&path, st);
10662306a36Sopenharmony_ci		path_put(&path);
10762306a36Sopenharmony_ci		if (retry_estale(error, lookup_flags)) {
10862306a36Sopenharmony_ci			lookup_flags |= LOOKUP_REVAL;
10962306a36Sopenharmony_ci			goto retry;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	return error;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciint fd_statfs(int fd, struct kstatfs *st)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct fd f = fdget_raw(fd);
11862306a36Sopenharmony_ci	int error = -EBADF;
11962306a36Sopenharmony_ci	if (f.file) {
12062306a36Sopenharmony_ci		error = vfs_statfs(&f.file->f_path, st);
12162306a36Sopenharmony_ci		fdput(f);
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci	return error;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct statfs buf;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (sizeof(buf) == sizeof(*st))
13162306a36Sopenharmony_ci		memcpy(&buf, st, sizeof(*st));
13262306a36Sopenharmony_ci	else {
13362306a36Sopenharmony_ci		memset(&buf, 0, sizeof(buf));
13462306a36Sopenharmony_ci		if (sizeof buf.f_blocks == 4) {
13562306a36Sopenharmony_ci			if ((st->f_blocks | st->f_bfree | st->f_bavail |
13662306a36Sopenharmony_ci			     st->f_bsize | st->f_frsize) &
13762306a36Sopenharmony_ci			    0xffffffff00000000ULL)
13862306a36Sopenharmony_ci				return -EOVERFLOW;
13962306a36Sopenharmony_ci			/*
14062306a36Sopenharmony_ci			 * f_files and f_ffree may be -1; it's okay to stuff
14162306a36Sopenharmony_ci			 * that into 32 bits
14262306a36Sopenharmony_ci			 */
14362306a36Sopenharmony_ci			if (st->f_files != -1 &&
14462306a36Sopenharmony_ci			    (st->f_files & 0xffffffff00000000ULL))
14562306a36Sopenharmony_ci				return -EOVERFLOW;
14662306a36Sopenharmony_ci			if (st->f_ffree != -1 &&
14762306a36Sopenharmony_ci			    (st->f_ffree & 0xffffffff00000000ULL))
14862306a36Sopenharmony_ci				return -EOVERFLOW;
14962306a36Sopenharmony_ci		}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		buf.f_type = st->f_type;
15262306a36Sopenharmony_ci		buf.f_bsize = st->f_bsize;
15362306a36Sopenharmony_ci		buf.f_blocks = st->f_blocks;
15462306a36Sopenharmony_ci		buf.f_bfree = st->f_bfree;
15562306a36Sopenharmony_ci		buf.f_bavail = st->f_bavail;
15662306a36Sopenharmony_ci		buf.f_files = st->f_files;
15762306a36Sopenharmony_ci		buf.f_ffree = st->f_ffree;
15862306a36Sopenharmony_ci		buf.f_fsid = st->f_fsid;
15962306a36Sopenharmony_ci		buf.f_namelen = st->f_namelen;
16062306a36Sopenharmony_ci		buf.f_frsize = st->f_frsize;
16162306a36Sopenharmony_ci		buf.f_flags = st->f_flags;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	if (copy_to_user(p, &buf, sizeof(buf)))
16462306a36Sopenharmony_ci		return -EFAULT;
16562306a36Sopenharmony_ci	return 0;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct statfs64 buf;
17162306a36Sopenharmony_ci	if (sizeof(buf) == sizeof(*st))
17262306a36Sopenharmony_ci		memcpy(&buf, st, sizeof(*st));
17362306a36Sopenharmony_ci	else {
17462306a36Sopenharmony_ci		memset(&buf, 0, sizeof(buf));
17562306a36Sopenharmony_ci		buf.f_type = st->f_type;
17662306a36Sopenharmony_ci		buf.f_bsize = st->f_bsize;
17762306a36Sopenharmony_ci		buf.f_blocks = st->f_blocks;
17862306a36Sopenharmony_ci		buf.f_bfree = st->f_bfree;
17962306a36Sopenharmony_ci		buf.f_bavail = st->f_bavail;
18062306a36Sopenharmony_ci		buf.f_files = st->f_files;
18162306a36Sopenharmony_ci		buf.f_ffree = st->f_ffree;
18262306a36Sopenharmony_ci		buf.f_fsid = st->f_fsid;
18362306a36Sopenharmony_ci		buf.f_namelen = st->f_namelen;
18462306a36Sopenharmony_ci		buf.f_frsize = st->f_frsize;
18562306a36Sopenharmony_ci		buf.f_flags = st->f_flags;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci	if (copy_to_user(p, &buf, sizeof(buf)))
18862306a36Sopenharmony_ci		return -EFAULT;
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciSYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct kstatfs st;
19562306a36Sopenharmony_ci	int error = user_statfs(pathname, &st);
19662306a36Sopenharmony_ci	if (!error)
19762306a36Sopenharmony_ci		error = do_statfs_native(&st, buf);
19862306a36Sopenharmony_ci	return error;
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ciSYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct kstatfs st;
20462306a36Sopenharmony_ci	int error;
20562306a36Sopenharmony_ci	if (sz != sizeof(*buf))
20662306a36Sopenharmony_ci		return -EINVAL;
20762306a36Sopenharmony_ci	error = user_statfs(pathname, &st);
20862306a36Sopenharmony_ci	if (!error)
20962306a36Sopenharmony_ci		error = do_statfs64(&st, buf);
21062306a36Sopenharmony_ci	return error;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ciSYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct kstatfs st;
21662306a36Sopenharmony_ci	int error = fd_statfs(fd, &st);
21762306a36Sopenharmony_ci	if (!error)
21862306a36Sopenharmony_ci		error = do_statfs_native(&st, buf);
21962306a36Sopenharmony_ci	return error;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ciSYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	struct kstatfs st;
22562306a36Sopenharmony_ci	int error;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (sz != sizeof(*buf))
22862306a36Sopenharmony_ci		return -EINVAL;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	error = fd_statfs(fd, &st);
23162306a36Sopenharmony_ci	if (!error)
23262306a36Sopenharmony_ci		error = do_statfs64(&st, buf);
23362306a36Sopenharmony_ci	return error;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct super_block *s = user_get_super(dev, false);
23962306a36Sopenharmony_ci	int err;
24062306a36Sopenharmony_ci	if (!s)
24162306a36Sopenharmony_ci		return -EINVAL;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	err = statfs_by_dentry(s->s_root, sbuf);
24462306a36Sopenharmony_ci	drop_super(s);
24562306a36Sopenharmony_ci	return err;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ciSYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct ustat tmp;
25162306a36Sopenharmony_ci	struct kstatfs sbuf;
25262306a36Sopenharmony_ci	int err = vfs_ustat(new_decode_dev(dev), &sbuf);
25362306a36Sopenharmony_ci	if (err)
25462306a36Sopenharmony_ci		return err;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	memset(&tmp,0,sizeof(struct ustat));
25762306a36Sopenharmony_ci	tmp.f_tfree = sbuf.f_bfree;
25862306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_ARCH_32BIT_USTAT_F_TINODE))
25962306a36Sopenharmony_ci		tmp.f_tinode = min_t(u64, sbuf.f_ffree, UINT_MAX);
26062306a36Sopenharmony_ci	else
26162306a36Sopenharmony_ci		tmp.f_tinode = sbuf.f_ffree;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
26762306a36Sopenharmony_cistatic int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct compat_statfs buf;
27062306a36Sopenharmony_ci	if (sizeof ubuf->f_blocks == 4) {
27162306a36Sopenharmony_ci		if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
27262306a36Sopenharmony_ci		     kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
27362306a36Sopenharmony_ci			return -EOVERFLOW;
27462306a36Sopenharmony_ci		/* f_files and f_ffree may be -1; it's okay
27562306a36Sopenharmony_ci		 * to stuff that into 32 bits */
27662306a36Sopenharmony_ci		if (kbuf->f_files != 0xffffffffffffffffULL
27762306a36Sopenharmony_ci		 && (kbuf->f_files & 0xffffffff00000000ULL))
27862306a36Sopenharmony_ci			return -EOVERFLOW;
27962306a36Sopenharmony_ci		if (kbuf->f_ffree != 0xffffffffffffffffULL
28062306a36Sopenharmony_ci		 && (kbuf->f_ffree & 0xffffffff00000000ULL))
28162306a36Sopenharmony_ci			return -EOVERFLOW;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci	memset(&buf, 0, sizeof(struct compat_statfs));
28462306a36Sopenharmony_ci	buf.f_type = kbuf->f_type;
28562306a36Sopenharmony_ci	buf.f_bsize = kbuf->f_bsize;
28662306a36Sopenharmony_ci	buf.f_blocks = kbuf->f_blocks;
28762306a36Sopenharmony_ci	buf.f_bfree = kbuf->f_bfree;
28862306a36Sopenharmony_ci	buf.f_bavail = kbuf->f_bavail;
28962306a36Sopenharmony_ci	buf.f_files = kbuf->f_files;
29062306a36Sopenharmony_ci	buf.f_ffree = kbuf->f_ffree;
29162306a36Sopenharmony_ci	buf.f_namelen = kbuf->f_namelen;
29262306a36Sopenharmony_ci	buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
29362306a36Sopenharmony_ci	buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
29462306a36Sopenharmony_ci	buf.f_frsize = kbuf->f_frsize;
29562306a36Sopenharmony_ci	buf.f_flags = kbuf->f_flags;
29662306a36Sopenharmony_ci	if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs)))
29762306a36Sopenharmony_ci		return -EFAULT;
29862306a36Sopenharmony_ci	return 0;
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci/*
30262306a36Sopenharmony_ci * The following statfs calls are copies of code from fs/statfs.c and
30362306a36Sopenharmony_ci * should be checked against those from time to time
30462306a36Sopenharmony_ci */
30562306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct kstatfs tmp;
30862306a36Sopenharmony_ci	int error = user_statfs(pathname, &tmp);
30962306a36Sopenharmony_ci	if (!error)
31062306a36Sopenharmony_ci		error = put_compat_statfs(buf, &tmp);
31162306a36Sopenharmony_ci	return error;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct kstatfs tmp;
31762306a36Sopenharmony_ci	int error = fd_statfs(fd, &tmp);
31862306a36Sopenharmony_ci	if (!error)
31962306a36Sopenharmony_ci		error = put_compat_statfs(buf, &tmp);
32062306a36Sopenharmony_ci	return error;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct compat_statfs64 buf;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if ((kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
32862306a36Sopenharmony_ci		return -EOVERFLOW;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	memset(&buf, 0, sizeof(struct compat_statfs64));
33162306a36Sopenharmony_ci	buf.f_type = kbuf->f_type;
33262306a36Sopenharmony_ci	buf.f_bsize = kbuf->f_bsize;
33362306a36Sopenharmony_ci	buf.f_blocks = kbuf->f_blocks;
33462306a36Sopenharmony_ci	buf.f_bfree = kbuf->f_bfree;
33562306a36Sopenharmony_ci	buf.f_bavail = kbuf->f_bavail;
33662306a36Sopenharmony_ci	buf.f_files = kbuf->f_files;
33762306a36Sopenharmony_ci	buf.f_ffree = kbuf->f_ffree;
33862306a36Sopenharmony_ci	buf.f_namelen = kbuf->f_namelen;
33962306a36Sopenharmony_ci	buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
34062306a36Sopenharmony_ci	buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
34162306a36Sopenharmony_ci	buf.f_frsize = kbuf->f_frsize;
34262306a36Sopenharmony_ci	buf.f_flags = kbuf->f_flags;
34362306a36Sopenharmony_ci	if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs64)))
34462306a36Sopenharmony_ci		return -EFAULT;
34562306a36Sopenharmony_ci	return 0;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ciint kcompat_sys_statfs64(const char __user * pathname, compat_size_t sz, struct compat_statfs64 __user * buf)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	struct kstatfs tmp;
35162306a36Sopenharmony_ci	int error;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (sz != sizeof(*buf))
35462306a36Sopenharmony_ci		return -EINVAL;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	error = user_statfs(pathname, &tmp);
35762306a36Sopenharmony_ci	if (!error)
35862306a36Sopenharmony_ci		error = put_compat_statfs64(buf, &tmp);
35962306a36Sopenharmony_ci	return error;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	return kcompat_sys_statfs64(pathname, sz, buf);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ciint kcompat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user * buf)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct kstatfs tmp;
37062306a36Sopenharmony_ci	int error;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (sz != sizeof(*buf))
37362306a36Sopenharmony_ci		return -EINVAL;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	error = fd_statfs(fd, &tmp);
37662306a36Sopenharmony_ci	if (!error)
37762306a36Sopenharmony_ci		error = put_compat_statfs64(buf, &tmp);
37862306a36Sopenharmony_ci	return error;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	return kcompat_sys_fstatfs64(fd, sz, buf);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/*
38762306a36Sopenharmony_ci * This is a copy of sys_ustat, just dealing with a structure layout.
38862306a36Sopenharmony_ci * Given how simple this syscall is that apporach is more maintainable
38962306a36Sopenharmony_ci * than the various conversion hacks.
39062306a36Sopenharmony_ci */
39162306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	struct compat_ustat tmp;
39462306a36Sopenharmony_ci	struct kstatfs sbuf;
39562306a36Sopenharmony_ci	int err = vfs_ustat(new_decode_dev(dev), &sbuf);
39662306a36Sopenharmony_ci	if (err)
39762306a36Sopenharmony_ci		return err;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	memset(&tmp, 0, sizeof(struct compat_ustat));
40062306a36Sopenharmony_ci	tmp.f_tfree = sbuf.f_bfree;
40162306a36Sopenharmony_ci	tmp.f_tinode = sbuf.f_ffree;
40262306a36Sopenharmony_ci	if (copy_to_user(u, &tmp, sizeof(struct compat_ustat)))
40362306a36Sopenharmony_ci		return -EFAULT;
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci#endif
407