diff options
Diffstat (limited to 'fs/statfs.c')
-rw-r--r-- | fs/statfs.c | 95 |
1 files changed, 71 insertions, 24 deletions
diff --git a/fs/statfs.c b/fs/statfs.c index 4ef021f3b612..30ea8c8a996b 100644 --- a/fs/statfs.c +++ b/fs/statfs.c | |||
@@ -2,38 +2,83 @@ | |||
2 | #include <linux/module.h> | 2 | #include <linux/module.h> |
3 | #include <linux/fs.h> | 3 | #include <linux/fs.h> |
4 | #include <linux/file.h> | 4 | #include <linux/file.h> |
5 | #include <linux/mount.h> | ||
5 | #include <linux/namei.h> | 6 | #include <linux/namei.h> |
6 | #include <linux/statfs.h> | 7 | #include <linux/statfs.h> |
7 | #include <linux/security.h> | 8 | #include <linux/security.h> |
8 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
9 | 10 | ||
10 | int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 11 | static int flags_by_mnt(int mnt_flags) |
11 | { | 12 | { |
12 | int retval = -ENODEV; | 13 | int flags = 0; |
13 | 14 | ||
14 | if (dentry) { | 15 | if (mnt_flags & MNT_READONLY) |
15 | retval = -ENOSYS; | 16 | flags |= ST_RDONLY; |
16 | if (dentry->d_sb->s_op->statfs) { | 17 | if (mnt_flags & MNT_NOSUID) |
17 | memset(buf, 0, sizeof(*buf)); | 18 | flags |= ST_NOSUID; |
18 | retval = security_sb_statfs(dentry); | 19 | if (mnt_flags & MNT_NODEV) |
19 | if (retval) | 20 | flags |= ST_NODEV; |
20 | return retval; | 21 | if (mnt_flags & MNT_NOEXEC) |
21 | retval = dentry->d_sb->s_op->statfs(dentry, buf); | 22 | flags |= ST_NOEXEC; |
22 | if (retval == 0 && buf->f_frsize == 0) | 23 | if (mnt_flags & MNT_NOATIME) |
23 | buf->f_frsize = buf->f_bsize; | 24 | flags |= ST_NOATIME; |
24 | } | 25 | if (mnt_flags & MNT_NODIRATIME) |
25 | } | 26 | flags |= ST_NODIRATIME; |
27 | if (mnt_flags & MNT_RELATIME) | ||
28 | flags |= ST_RELATIME; | ||
29 | return flags; | ||
30 | } | ||
31 | |||
32 | static int flags_by_sb(int s_flags) | ||
33 | { | ||
34 | int flags = 0; | ||
35 | if (s_flags & MS_SYNCHRONOUS) | ||
36 | flags |= ST_SYNCHRONOUS; | ||
37 | if (s_flags & MS_MANDLOCK) | ||
38 | flags |= ST_MANDLOCK; | ||
39 | return flags; | ||
40 | } | ||
41 | |||
42 | static int calculate_f_flags(struct vfsmount *mnt) | ||
43 | { | ||
44 | return ST_VALID | flags_by_mnt(mnt->mnt_flags) | | ||
45 | flags_by_sb(mnt->mnt_sb->s_flags); | ||
46 | } | ||
47 | |||
48 | int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) | ||
49 | { | ||
50 | int retval; | ||
51 | |||
52 | if (!dentry->d_sb->s_op->statfs) | ||
53 | return -ENOSYS; | ||
54 | |||
55 | memset(buf, 0, sizeof(*buf)); | ||
56 | retval = security_sb_statfs(dentry); | ||
57 | if (retval) | ||
58 | return retval; | ||
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; | ||
26 | return retval; | 62 | return retval; |
27 | } | 63 | } |
28 | 64 | ||
65 | int vfs_statfs(struct path *path, struct kstatfs *buf) | ||
66 | { | ||
67 | int error; | ||
68 | |||
69 | error = statfs_by_dentry(path->dentry, buf); | ||
70 | if (!error) | ||
71 | buf->f_flags = calculate_f_flags(path->mnt); | ||
72 | return error; | ||
73 | } | ||
29 | EXPORT_SYMBOL(vfs_statfs); | 74 | EXPORT_SYMBOL(vfs_statfs); |
30 | 75 | ||
31 | static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf) | 76 | static int do_statfs_native(struct path *path, struct statfs *buf) |
32 | { | 77 | { |
33 | struct kstatfs st; | 78 | struct kstatfs st; |
34 | int retval; | 79 | int retval; |
35 | 80 | ||
36 | retval = vfs_statfs(dentry, &st); | 81 | retval = vfs_statfs(path, &st); |
37 | if (retval) | 82 | if (retval) |
38 | return retval; | 83 | return retval; |
39 | 84 | ||
@@ -67,17 +112,18 @@ static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf) | |||
67 | buf->f_fsid = st.f_fsid; | 112 | buf->f_fsid = st.f_fsid; |
68 | buf->f_namelen = st.f_namelen; | 113 | buf->f_namelen = st.f_namelen; |
69 | buf->f_frsize = st.f_frsize; | 114 | buf->f_frsize = st.f_frsize; |
115 | buf->f_flags = st.f_flags; | ||
70 | memset(buf->f_spare, 0, sizeof(buf->f_spare)); | 116 | memset(buf->f_spare, 0, sizeof(buf->f_spare)); |
71 | } | 117 | } |
72 | return 0; | 118 | return 0; |
73 | } | 119 | } |
74 | 120 | ||
75 | static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf) | 121 | static int do_statfs64(struct path *path, struct statfs64 *buf) |
76 | { | 122 | { |
77 | struct kstatfs st; | 123 | struct kstatfs st; |
78 | int retval; | 124 | int retval; |
79 | 125 | ||
80 | retval = vfs_statfs(dentry, &st); | 126 | retval = vfs_statfs(path, &st); |
81 | if (retval) | 127 | if (retval) |
82 | return retval; | 128 | return retval; |
83 | 129 | ||
@@ -94,6 +140,7 @@ static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf) | |||
94 | buf->f_fsid = st.f_fsid; | 140 | buf->f_fsid = st.f_fsid; |
95 | buf->f_namelen = st.f_namelen; | 141 | buf->f_namelen = st.f_namelen; |
96 | buf->f_frsize = st.f_frsize; | 142 | buf->f_frsize = st.f_frsize; |
143 | buf->f_flags = st.f_flags; | ||
97 | memset(buf->f_spare, 0, sizeof(buf->f_spare)); | 144 | memset(buf->f_spare, 0, sizeof(buf->f_spare)); |
98 | } | 145 | } |
99 | return 0; | 146 | return 0; |
@@ -107,7 +154,7 @@ SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, b | |||
107 | error = user_path(pathname, &path); | 154 | error = user_path(pathname, &path); |
108 | if (!error) { | 155 | if (!error) { |
109 | struct statfs tmp; | 156 | struct statfs tmp; |
110 | error = vfs_statfs_native(path.dentry, &tmp); | 157 | error = do_statfs_native(&path, &tmp); |
111 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 158 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
112 | error = -EFAULT; | 159 | error = -EFAULT; |
113 | path_put(&path); | 160 | path_put(&path); |
@@ -125,7 +172,7 @@ SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct stat | |||
125 | error = user_path(pathname, &path); | 172 | error = user_path(pathname, &path); |
126 | if (!error) { | 173 | if (!error) { |
127 | struct statfs64 tmp; | 174 | struct statfs64 tmp; |
128 | error = vfs_statfs64(path.dentry, &tmp); | 175 | error = do_statfs64(&path, &tmp); |
129 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 176 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
130 | error = -EFAULT; | 177 | error = -EFAULT; |
131 | path_put(&path); | 178 | path_put(&path); |
@@ -143,7 +190,7 @@ SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf) | |||
143 | file = fget(fd); | 190 | file = fget(fd); |
144 | if (!file) | 191 | if (!file) |
145 | goto out; | 192 | goto out; |
146 | error = vfs_statfs_native(file->f_path.dentry, &tmp); | 193 | error = do_statfs_native(&file->f_path, &tmp); |
147 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 194 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
148 | error = -EFAULT; | 195 | error = -EFAULT; |
149 | fput(file); | 196 | fput(file); |
@@ -164,7 +211,7 @@ SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user | |||
164 | file = fget(fd); | 211 | file = fget(fd); |
165 | if (!file) | 212 | if (!file) |
166 | goto out; | 213 | goto out; |
167 | error = vfs_statfs64(file->f_path.dentry, &tmp); | 214 | error = do_statfs64(&file->f_path, &tmp); |
168 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 215 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
169 | error = -EFAULT; | 216 | error = -EFAULT; |
170 | fput(file); | 217 | fput(file); |
@@ -183,7 +230,7 @@ SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) | |||
183 | if (!s) | 230 | if (!s) |
184 | return -EINVAL; | 231 | return -EINVAL; |
185 | 232 | ||
186 | err = vfs_statfs(s->s_root, &sbuf); | 233 | err = statfs_by_dentry(s->s_root, &sbuf); |
187 | drop_super(s); | 234 | drop_super(s); |
188 | if (err) | 235 | if (err) |
189 | return err; | 236 | return err; |