1 #include <linux/syscalls.h>
2 #include <linux/module.h>
4 #include <linux/file.h>
5 #include <linux/mount.h>
6 #include <linux/namei.h>
7 #include <linux/statfs.h>
8 #include <linux/security.h>
9 #include <linux/uaccess.h>
11 static int flags_by_mnt(int mnt_flags
)
15 if (mnt_flags
& MNT_READONLY
)
17 if (mnt_flags
& MNT_NOSUID
)
19 if (mnt_flags
& MNT_NODEV
)
21 if (mnt_flags
& MNT_NOEXEC
)
23 if (mnt_flags
& MNT_NOATIME
)
25 if (mnt_flags
& MNT_NODIRATIME
)
26 flags
|= ST_NODIRATIME
;
27 if (mnt_flags
& MNT_RELATIME
)
32 static int flags_by_sb(int s_flags
)
35 if (s_flags
& MS_SYNCHRONOUS
)
36 flags
|= ST_SYNCHRONOUS
;
37 if (s_flags
& MS_MANDLOCK
)
42 static int calculate_f_flags(struct vfsmount
*mnt
)
44 return ST_VALID
| flags_by_mnt(mnt
->mnt_flags
) |
45 flags_by_sb(mnt
->mnt_sb
->s_flags
);
48 int statfs_by_dentry(struct dentry
*dentry
, struct kstatfs
*buf
)
52 if (!dentry
->d_sb
->s_op
->statfs
)
55 memset(buf
, 0, sizeof(*buf
));
56 retval
= security_sb_statfs(dentry
);
59 retval
= dentry
->d_sb
->s_op
->statfs(dentry
, buf
);
60 if (retval
== 0 && buf
->f_frsize
== 0)
61 buf
->f_frsize
= buf
->f_bsize
;
65 int vfs_statfs(struct path
*path
, struct kstatfs
*buf
)
69 error
= statfs_by_dentry(path
->dentry
, buf
);
71 buf
->f_flags
= calculate_f_flags(path
->mnt
);
74 EXPORT_SYMBOL(vfs_statfs
);
76 static int do_statfs_native(struct path
*path
, struct statfs
*buf
)
81 retval
= vfs_statfs(path
, &st
);
85 if (sizeof(*buf
) == sizeof(st
))
86 memcpy(buf
, &st
, sizeof(st
));
88 if (sizeof buf
->f_blocks
== 4) {
89 if ((st
.f_blocks
| st
.f_bfree
| st
.f_bavail
|
90 st
.f_bsize
| st
.f_frsize
) &
91 0xffffffff00000000ULL
)
94 * f_files and f_ffree may be -1; it's okay to stuff
97 if (st
.f_files
!= -1 &&
98 (st
.f_files
& 0xffffffff00000000ULL
))
100 if (st
.f_ffree
!= -1 &&
101 (st
.f_ffree
& 0xffffffff00000000ULL
))
105 buf
->f_type
= st
.f_type
;
106 buf
->f_bsize
= st
.f_bsize
;
107 buf
->f_blocks
= st
.f_blocks
;
108 buf
->f_bfree
= st
.f_bfree
;
109 buf
->f_bavail
= st
.f_bavail
;
110 buf
->f_files
= st
.f_files
;
111 buf
->f_ffree
= st
.f_ffree
;
112 buf
->f_fsid
= st
.f_fsid
;
113 buf
->f_namelen
= st
.f_namelen
;
114 buf
->f_frsize
= st
.f_frsize
;
115 buf
->f_flags
= st
.f_flags
;
116 memset(buf
->f_spare
, 0, sizeof(buf
->f_spare
));
121 static int do_statfs64(struct path
*path
, struct statfs64
*buf
)
126 retval
= vfs_statfs(path
, &st
);
130 if (sizeof(*buf
) == sizeof(st
))
131 memcpy(buf
, &st
, sizeof(st
));
133 buf
->f_type
= st
.f_type
;
134 buf
->f_bsize
= st
.f_bsize
;
135 buf
->f_blocks
= st
.f_blocks
;
136 buf
->f_bfree
= st
.f_bfree
;
137 buf
->f_bavail
= st
.f_bavail
;
138 buf
->f_files
= st
.f_files
;
139 buf
->f_ffree
= st
.f_ffree
;
140 buf
->f_fsid
= st
.f_fsid
;
141 buf
->f_namelen
= st
.f_namelen
;
142 buf
->f_frsize
= st
.f_frsize
;
143 buf
->f_flags
= st
.f_flags
;
144 memset(buf
->f_spare
, 0, sizeof(buf
->f_spare
));
149 SYSCALL_DEFINE2(statfs
, const char __user
*, pathname
, struct statfs __user
*, buf
)
154 error
= user_path(pathname
, &path
);
157 error
= do_statfs_native(&path
, &tmp
);
158 if (!error
&& copy_to_user(buf
, &tmp
, sizeof(tmp
)))
165 SYSCALL_DEFINE3(statfs64
, const char __user
*, pathname
, size_t, sz
, struct statfs64 __user
*, buf
)
170 if (sz
!= sizeof(*buf
))
172 error
= user_path(pathname
, &path
);
175 error
= do_statfs64(&path
, &tmp
);
176 if (!error
&& copy_to_user(buf
, &tmp
, sizeof(tmp
)))
183 SYSCALL_DEFINE2(fstatfs
, unsigned int, fd
, struct statfs __user
*, buf
)
193 error
= do_statfs_native(&file
->f_path
, &tmp
);
194 if (!error
&& copy_to_user(buf
, &tmp
, sizeof(tmp
)))
201 SYSCALL_DEFINE3(fstatfs64
, unsigned int, fd
, size_t, sz
, struct statfs64 __user
*, buf
)
207 if (sz
!= sizeof(*buf
))
214 error
= do_statfs64(&file
->f_path
, &tmp
);
215 if (!error
&& copy_to_user(buf
, &tmp
, sizeof(tmp
)))
222 SYSCALL_DEFINE2(ustat
, unsigned, dev
, struct ustat __user
*, ubuf
)
224 struct super_block
*s
;
229 s
= user_get_super(new_decode_dev(dev
));
233 err
= statfs_by_dentry(s
->s_root
, &sbuf
);
238 memset(&tmp
,0,sizeof(struct ustat
));
239 tmp
.f_tfree
= sbuf
.f_bfree
;
240 tmp
.f_tinode
= sbuf
.f_ffree
;
242 return copy_to_user(ubuf
, &tmp
, sizeof(struct ustat
)) ? -EFAULT
: 0;