xref: /OK3568_Linux_fs/kernel/fs/statfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/syscalls.h>
3*4882a593Smuzhiyun #include <linux/export.h>
4*4882a593Smuzhiyun #include <linux/fs.h>
5*4882a593Smuzhiyun #include <linux/file.h>
6*4882a593Smuzhiyun #include <linux/mount.h>
7*4882a593Smuzhiyun #include <linux/namei.h>
8*4882a593Smuzhiyun #include <linux/statfs.h>
9*4882a593Smuzhiyun #include <linux/security.h>
10*4882a593Smuzhiyun #include <linux/uaccess.h>
11*4882a593Smuzhiyun #include <linux/compat.h>
12*4882a593Smuzhiyun #include "internal.h"
13*4882a593Smuzhiyun 
flags_by_mnt(int mnt_flags)14*4882a593Smuzhiyun static int flags_by_mnt(int mnt_flags)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun 	int flags = 0;
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun 	if (mnt_flags & MNT_READONLY)
19*4882a593Smuzhiyun 		flags |= ST_RDONLY;
20*4882a593Smuzhiyun 	if (mnt_flags & MNT_NOSUID)
21*4882a593Smuzhiyun 		flags |= ST_NOSUID;
22*4882a593Smuzhiyun 	if (mnt_flags & MNT_NODEV)
23*4882a593Smuzhiyun 		flags |= ST_NODEV;
24*4882a593Smuzhiyun 	if (mnt_flags & MNT_NOEXEC)
25*4882a593Smuzhiyun 		flags |= ST_NOEXEC;
26*4882a593Smuzhiyun 	if (mnt_flags & MNT_NOATIME)
27*4882a593Smuzhiyun 		flags |= ST_NOATIME;
28*4882a593Smuzhiyun 	if (mnt_flags & MNT_NODIRATIME)
29*4882a593Smuzhiyun 		flags |= ST_NODIRATIME;
30*4882a593Smuzhiyun 	if (mnt_flags & MNT_RELATIME)
31*4882a593Smuzhiyun 		flags |= ST_RELATIME;
32*4882a593Smuzhiyun 	if (mnt_flags & MNT_NOSYMFOLLOW)
33*4882a593Smuzhiyun 		flags |= ST_NOSYMFOLLOW;
34*4882a593Smuzhiyun 	return flags;
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun 
flags_by_sb(int s_flags)37*4882a593Smuzhiyun static int flags_by_sb(int s_flags)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	int flags = 0;
40*4882a593Smuzhiyun 	if (s_flags & SB_SYNCHRONOUS)
41*4882a593Smuzhiyun 		flags |= ST_SYNCHRONOUS;
42*4882a593Smuzhiyun 	if (s_flags & SB_MANDLOCK)
43*4882a593Smuzhiyun 		flags |= ST_MANDLOCK;
44*4882a593Smuzhiyun 	if (s_flags & SB_RDONLY)
45*4882a593Smuzhiyun 		flags |= ST_RDONLY;
46*4882a593Smuzhiyun 	return flags;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
calculate_f_flags(struct vfsmount * mnt)49*4882a593Smuzhiyun static int calculate_f_flags(struct vfsmount *mnt)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
52*4882a593Smuzhiyun 		flags_by_sb(mnt->mnt_sb->s_flags);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
statfs_by_dentry(struct dentry * dentry,struct kstatfs * buf)55*4882a593Smuzhiyun static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	int retval;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	if (!dentry->d_sb->s_op->statfs)
60*4882a593Smuzhiyun 		return -ENOSYS;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	memset(buf, 0, sizeof(*buf));
63*4882a593Smuzhiyun 	retval = security_sb_statfs(dentry);
64*4882a593Smuzhiyun 	if (retval)
65*4882a593Smuzhiyun 		return retval;
66*4882a593Smuzhiyun 	retval = dentry->d_sb->s_op->statfs(dentry, buf);
67*4882a593Smuzhiyun 	if (retval == 0 && buf->f_frsize == 0)
68*4882a593Smuzhiyun 		buf->f_frsize = buf->f_bsize;
69*4882a593Smuzhiyun 	return retval;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
vfs_get_fsid(struct dentry * dentry,__kernel_fsid_t * fsid)72*4882a593Smuzhiyun int vfs_get_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	struct kstatfs st;
75*4882a593Smuzhiyun 	int error;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	error = statfs_by_dentry(dentry, &st);
78*4882a593Smuzhiyun 	if (error)
79*4882a593Smuzhiyun 		return error;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	*fsid = st.f_fsid;
82*4882a593Smuzhiyun 	return 0;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun EXPORT_SYMBOL(vfs_get_fsid);
85*4882a593Smuzhiyun 
vfs_statfs(const struct path * path,struct kstatfs * buf)86*4882a593Smuzhiyun int vfs_statfs(const struct path *path, struct kstatfs *buf)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	int error;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	error = statfs_by_dentry(path->dentry, buf);
91*4882a593Smuzhiyun 	if (!error)
92*4882a593Smuzhiyun 		buf->f_flags = calculate_f_flags(path->mnt);
93*4882a593Smuzhiyun 	return error;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun EXPORT_SYMBOL(vfs_statfs);
96*4882a593Smuzhiyun 
user_statfs(const char __user * pathname,struct kstatfs * st)97*4882a593Smuzhiyun int user_statfs(const char __user *pathname, struct kstatfs *st)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	struct path path;
100*4882a593Smuzhiyun 	int error;
101*4882a593Smuzhiyun 	unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
102*4882a593Smuzhiyun retry:
103*4882a593Smuzhiyun 	error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
104*4882a593Smuzhiyun 	if (!error) {
105*4882a593Smuzhiyun 		error = vfs_statfs(&path, st);
106*4882a593Smuzhiyun 		path_put(&path);
107*4882a593Smuzhiyun 		if (retry_estale(error, lookup_flags)) {
108*4882a593Smuzhiyun 			lookup_flags |= LOOKUP_REVAL;
109*4882a593Smuzhiyun 			goto retry;
110*4882a593Smuzhiyun 		}
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 	return error;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
fd_statfs(int fd,struct kstatfs * st)115*4882a593Smuzhiyun int fd_statfs(int fd, struct kstatfs *st)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	struct fd f = fdget_raw(fd);
118*4882a593Smuzhiyun 	int error = -EBADF;
119*4882a593Smuzhiyun 	if (f.file) {
120*4882a593Smuzhiyun 		error = vfs_statfs(&f.file->f_path, st);
121*4882a593Smuzhiyun 		fdput(f);
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 	return error;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
do_statfs_native(struct kstatfs * st,struct statfs __user * p)126*4882a593Smuzhiyun static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	struct statfs buf;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (sizeof(buf) == sizeof(*st))
131*4882a593Smuzhiyun 		memcpy(&buf, st, sizeof(*st));
132*4882a593Smuzhiyun 	else {
133*4882a593Smuzhiyun 		if (sizeof buf.f_blocks == 4) {
134*4882a593Smuzhiyun 			if ((st->f_blocks | st->f_bfree | st->f_bavail |
135*4882a593Smuzhiyun 			     st->f_bsize | st->f_frsize) &
136*4882a593Smuzhiyun 			    0xffffffff00000000ULL)
137*4882a593Smuzhiyun 				return -EOVERFLOW;
138*4882a593Smuzhiyun 			/*
139*4882a593Smuzhiyun 			 * f_files and f_ffree may be -1; it's okay to stuff
140*4882a593Smuzhiyun 			 * that into 32 bits
141*4882a593Smuzhiyun 			 */
142*4882a593Smuzhiyun 			if (st->f_files != -1 &&
143*4882a593Smuzhiyun 			    (st->f_files & 0xffffffff00000000ULL))
144*4882a593Smuzhiyun 				return -EOVERFLOW;
145*4882a593Smuzhiyun 			if (st->f_ffree != -1 &&
146*4882a593Smuzhiyun 			    (st->f_ffree & 0xffffffff00000000ULL))
147*4882a593Smuzhiyun 				return -EOVERFLOW;
148*4882a593Smuzhiyun 		}
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 		buf.f_type = st->f_type;
151*4882a593Smuzhiyun 		buf.f_bsize = st->f_bsize;
152*4882a593Smuzhiyun 		buf.f_blocks = st->f_blocks;
153*4882a593Smuzhiyun 		buf.f_bfree = st->f_bfree;
154*4882a593Smuzhiyun 		buf.f_bavail = st->f_bavail;
155*4882a593Smuzhiyun 		buf.f_files = st->f_files;
156*4882a593Smuzhiyun 		buf.f_ffree = st->f_ffree;
157*4882a593Smuzhiyun 		buf.f_fsid = st->f_fsid;
158*4882a593Smuzhiyun 		buf.f_namelen = st->f_namelen;
159*4882a593Smuzhiyun 		buf.f_frsize = st->f_frsize;
160*4882a593Smuzhiyun 		buf.f_flags = st->f_flags;
161*4882a593Smuzhiyun 		memset(buf.f_spare, 0, sizeof(buf.f_spare));
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 	if (copy_to_user(p, &buf, sizeof(buf)))
164*4882a593Smuzhiyun 		return -EFAULT;
165*4882a593Smuzhiyun 	return 0;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
do_statfs64(struct kstatfs * st,struct statfs64 __user * p)168*4882a593Smuzhiyun static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	struct statfs64 buf;
171*4882a593Smuzhiyun 	if (sizeof(buf) == sizeof(*st))
172*4882a593Smuzhiyun 		memcpy(&buf, st, sizeof(*st));
173*4882a593Smuzhiyun 	else {
174*4882a593Smuzhiyun 		buf.f_type = st->f_type;
175*4882a593Smuzhiyun 		buf.f_bsize = st->f_bsize;
176*4882a593Smuzhiyun 		buf.f_blocks = st->f_blocks;
177*4882a593Smuzhiyun 		buf.f_bfree = st->f_bfree;
178*4882a593Smuzhiyun 		buf.f_bavail = st->f_bavail;
179*4882a593Smuzhiyun 		buf.f_files = st->f_files;
180*4882a593Smuzhiyun 		buf.f_ffree = st->f_ffree;
181*4882a593Smuzhiyun 		buf.f_fsid = st->f_fsid;
182*4882a593Smuzhiyun 		buf.f_namelen = st->f_namelen;
183*4882a593Smuzhiyun 		buf.f_frsize = st->f_frsize;
184*4882a593Smuzhiyun 		buf.f_flags = st->f_flags;
185*4882a593Smuzhiyun 		memset(buf.f_spare, 0, sizeof(buf.f_spare));
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 	if (copy_to_user(p, &buf, sizeof(buf)))
188*4882a593Smuzhiyun 		return -EFAULT;
189*4882a593Smuzhiyun 	return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
SYSCALL_DEFINE2(statfs,const char __user *,pathname,struct statfs __user *,buf)192*4882a593Smuzhiyun SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	struct kstatfs st;
195*4882a593Smuzhiyun 	int error = user_statfs(pathname, &st);
196*4882a593Smuzhiyun 	if (!error)
197*4882a593Smuzhiyun 		error = do_statfs_native(&st, buf);
198*4882a593Smuzhiyun 	return error;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
SYSCALL_DEFINE3(statfs64,const char __user *,pathname,size_t,sz,struct statfs64 __user *,buf)201*4882a593Smuzhiyun SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	struct kstatfs st;
204*4882a593Smuzhiyun 	int error;
205*4882a593Smuzhiyun 	if (sz != sizeof(*buf))
206*4882a593Smuzhiyun 		return -EINVAL;
207*4882a593Smuzhiyun 	error = user_statfs(pathname, &st);
208*4882a593Smuzhiyun 	if (!error)
209*4882a593Smuzhiyun 		error = do_statfs64(&st, buf);
210*4882a593Smuzhiyun 	return error;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
SYSCALL_DEFINE2(fstatfs,unsigned int,fd,struct statfs __user *,buf)213*4882a593Smuzhiyun SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	struct kstatfs st;
216*4882a593Smuzhiyun 	int error = fd_statfs(fd, &st);
217*4882a593Smuzhiyun 	if (!error)
218*4882a593Smuzhiyun 		error = do_statfs_native(&st, buf);
219*4882a593Smuzhiyun 	return error;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
SYSCALL_DEFINE3(fstatfs64,unsigned int,fd,size_t,sz,struct statfs64 __user *,buf)222*4882a593Smuzhiyun SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	struct kstatfs st;
225*4882a593Smuzhiyun 	int error;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	if (sz != sizeof(*buf))
228*4882a593Smuzhiyun 		return -EINVAL;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	error = fd_statfs(fd, &st);
231*4882a593Smuzhiyun 	if (!error)
232*4882a593Smuzhiyun 		error = do_statfs64(&st, buf);
233*4882a593Smuzhiyun 	return error;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
vfs_ustat(dev_t dev,struct kstatfs * sbuf)236*4882a593Smuzhiyun static int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun 	struct super_block *s = user_get_super(dev);
239*4882a593Smuzhiyun 	int err;
240*4882a593Smuzhiyun 	if (!s)
241*4882a593Smuzhiyun 		return -EINVAL;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	err = statfs_by_dentry(s->s_root, sbuf);
244*4882a593Smuzhiyun 	drop_super(s);
245*4882a593Smuzhiyun 	return err;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
SYSCALL_DEFINE2(ustat,unsigned,dev,struct ustat __user *,ubuf)248*4882a593Smuzhiyun SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	struct ustat tmp;
251*4882a593Smuzhiyun 	struct kstatfs sbuf;
252*4882a593Smuzhiyun 	int err = vfs_ustat(new_decode_dev(dev), &sbuf);
253*4882a593Smuzhiyun 	if (err)
254*4882a593Smuzhiyun 		return err;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	memset(&tmp,0,sizeof(struct ustat));
257*4882a593Smuzhiyun 	tmp.f_tfree = sbuf.f_bfree;
258*4882a593Smuzhiyun 	tmp.f_tinode = sbuf.f_ffree;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
put_compat_statfs(struct compat_statfs __user * ubuf,struct kstatfs * kbuf)264*4882a593Smuzhiyun static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	struct compat_statfs buf;
267*4882a593Smuzhiyun 	if (sizeof ubuf->f_blocks == 4) {
268*4882a593Smuzhiyun 		if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
269*4882a593Smuzhiyun 		     kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
270*4882a593Smuzhiyun 			return -EOVERFLOW;
271*4882a593Smuzhiyun 		/* f_files and f_ffree may be -1; it's okay
272*4882a593Smuzhiyun 		 * to stuff that into 32 bits */
273*4882a593Smuzhiyun 		if (kbuf->f_files != 0xffffffffffffffffULL
274*4882a593Smuzhiyun 		 && (kbuf->f_files & 0xffffffff00000000ULL))
275*4882a593Smuzhiyun 			return -EOVERFLOW;
276*4882a593Smuzhiyun 		if (kbuf->f_ffree != 0xffffffffffffffffULL
277*4882a593Smuzhiyun 		 && (kbuf->f_ffree & 0xffffffff00000000ULL))
278*4882a593Smuzhiyun 			return -EOVERFLOW;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 	memset(&buf, 0, sizeof(struct compat_statfs));
281*4882a593Smuzhiyun 	buf.f_type = kbuf->f_type;
282*4882a593Smuzhiyun 	buf.f_bsize = kbuf->f_bsize;
283*4882a593Smuzhiyun 	buf.f_blocks = kbuf->f_blocks;
284*4882a593Smuzhiyun 	buf.f_bfree = kbuf->f_bfree;
285*4882a593Smuzhiyun 	buf.f_bavail = kbuf->f_bavail;
286*4882a593Smuzhiyun 	buf.f_files = kbuf->f_files;
287*4882a593Smuzhiyun 	buf.f_ffree = kbuf->f_ffree;
288*4882a593Smuzhiyun 	buf.f_namelen = kbuf->f_namelen;
289*4882a593Smuzhiyun 	buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
290*4882a593Smuzhiyun 	buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
291*4882a593Smuzhiyun 	buf.f_frsize = kbuf->f_frsize;
292*4882a593Smuzhiyun 	buf.f_flags = kbuf->f_flags;
293*4882a593Smuzhiyun 	if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs)))
294*4882a593Smuzhiyun 		return -EFAULT;
295*4882a593Smuzhiyun 	return 0;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun /*
299*4882a593Smuzhiyun  * The following statfs calls are copies of code from fs/statfs.c and
300*4882a593Smuzhiyun  * should be checked against those from time to time
301*4882a593Smuzhiyun  */
COMPAT_SYSCALL_DEFINE2(statfs,const char __user *,pathname,struct compat_statfs __user *,buf)302*4882a593Smuzhiyun COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	struct kstatfs tmp;
305*4882a593Smuzhiyun 	int error = user_statfs(pathname, &tmp);
306*4882a593Smuzhiyun 	if (!error)
307*4882a593Smuzhiyun 		error = put_compat_statfs(buf, &tmp);
308*4882a593Smuzhiyun 	return error;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
COMPAT_SYSCALL_DEFINE2(fstatfs,unsigned int,fd,struct compat_statfs __user *,buf)311*4882a593Smuzhiyun COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	struct kstatfs tmp;
314*4882a593Smuzhiyun 	int error = fd_statfs(fd, &tmp);
315*4882a593Smuzhiyun 	if (!error)
316*4882a593Smuzhiyun 		error = put_compat_statfs(buf, &tmp);
317*4882a593Smuzhiyun 	return error;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
put_compat_statfs64(struct compat_statfs64 __user * ubuf,struct kstatfs * kbuf)320*4882a593Smuzhiyun static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	struct compat_statfs64 buf;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	if ((kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
325*4882a593Smuzhiyun 		return -EOVERFLOW;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	memset(&buf, 0, sizeof(struct compat_statfs64));
328*4882a593Smuzhiyun 	buf.f_type = kbuf->f_type;
329*4882a593Smuzhiyun 	buf.f_bsize = kbuf->f_bsize;
330*4882a593Smuzhiyun 	buf.f_blocks = kbuf->f_blocks;
331*4882a593Smuzhiyun 	buf.f_bfree = kbuf->f_bfree;
332*4882a593Smuzhiyun 	buf.f_bavail = kbuf->f_bavail;
333*4882a593Smuzhiyun 	buf.f_files = kbuf->f_files;
334*4882a593Smuzhiyun 	buf.f_ffree = kbuf->f_ffree;
335*4882a593Smuzhiyun 	buf.f_namelen = kbuf->f_namelen;
336*4882a593Smuzhiyun 	buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
337*4882a593Smuzhiyun 	buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
338*4882a593Smuzhiyun 	buf.f_frsize = kbuf->f_frsize;
339*4882a593Smuzhiyun 	buf.f_flags = kbuf->f_flags;
340*4882a593Smuzhiyun 	if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs64)))
341*4882a593Smuzhiyun 		return -EFAULT;
342*4882a593Smuzhiyun 	return 0;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
kcompat_sys_statfs64(const char __user * pathname,compat_size_t sz,struct compat_statfs64 __user * buf)345*4882a593Smuzhiyun int kcompat_sys_statfs64(const char __user * pathname, compat_size_t sz, struct compat_statfs64 __user * buf)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 	struct kstatfs tmp;
348*4882a593Smuzhiyun 	int error;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if (sz != sizeof(*buf))
351*4882a593Smuzhiyun 		return -EINVAL;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	error = user_statfs(pathname, &tmp);
354*4882a593Smuzhiyun 	if (!error)
355*4882a593Smuzhiyun 		error = put_compat_statfs64(buf, &tmp);
356*4882a593Smuzhiyun 	return error;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
COMPAT_SYSCALL_DEFINE3(statfs64,const char __user *,pathname,compat_size_t,sz,struct compat_statfs64 __user *,buf)359*4882a593Smuzhiyun COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	return kcompat_sys_statfs64(pathname, sz, buf);
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun 
kcompat_sys_fstatfs64(unsigned int fd,compat_size_t sz,struct compat_statfs64 __user * buf)364*4882a593Smuzhiyun int kcompat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user * buf)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	struct kstatfs tmp;
367*4882a593Smuzhiyun 	int error;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	if (sz != sizeof(*buf))
370*4882a593Smuzhiyun 		return -EINVAL;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	error = fd_statfs(fd, &tmp);
373*4882a593Smuzhiyun 	if (!error)
374*4882a593Smuzhiyun 		error = put_compat_statfs64(buf, &tmp);
375*4882a593Smuzhiyun 	return error;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
COMPAT_SYSCALL_DEFINE3(fstatfs64,unsigned int,fd,compat_size_t,sz,struct compat_statfs64 __user *,buf)378*4882a593Smuzhiyun COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun 	return kcompat_sys_fstatfs64(fd, sz, buf);
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun /*
384*4882a593Smuzhiyun  * This is a copy of sys_ustat, just dealing with a structure layout.
385*4882a593Smuzhiyun  * Given how simple this syscall is that apporach is more maintainable
386*4882a593Smuzhiyun  * than the various conversion hacks.
387*4882a593Smuzhiyun  */
COMPAT_SYSCALL_DEFINE2(ustat,unsigned,dev,struct compat_ustat __user *,u)388*4882a593Smuzhiyun COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	struct compat_ustat tmp;
391*4882a593Smuzhiyun 	struct kstatfs sbuf;
392*4882a593Smuzhiyun 	int err = vfs_ustat(new_decode_dev(dev), &sbuf);
393*4882a593Smuzhiyun 	if (err)
394*4882a593Smuzhiyun 		return err;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	memset(&tmp, 0, sizeof(struct compat_ustat));
397*4882a593Smuzhiyun 	tmp.f_tfree = sbuf.f_bfree;
398*4882a593Smuzhiyun 	tmp.f_tinode = sbuf.f_ffree;
399*4882a593Smuzhiyun 	if (copy_to_user(u, &tmp, sizeof(struct compat_ustat)))
400*4882a593Smuzhiyun 		return -EFAULT;
401*4882a593Smuzhiyun 	return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun #endif
404