packaging: install license for rpm package instead of license package
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / fs / statfs.c
1 #include <linux/syscalls.h>
2 #include <linux/export.h>
3 #include <linux/fs.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>
10 #include "internal.h"
11
12 static int flags_by_mnt(int mnt_flags)
13 {
14         int flags = 0;
15
16         if (mnt_flags & MNT_READONLY)
17                 flags |= ST_RDONLY;
18         if (mnt_flags & MNT_NOSUID)
19                 flags |= ST_NOSUID;
20         if (mnt_flags & MNT_NODEV)
21                 flags |= ST_NODEV;
22         if (mnt_flags & MNT_NOEXEC)
23                 flags |= ST_NOEXEC;
24         if (mnt_flags & MNT_NOATIME)
25                 flags |= ST_NOATIME;
26         if (mnt_flags & MNT_NODIRATIME)
27                 flags |= ST_NODIRATIME;
28         if (mnt_flags & MNT_RELATIME)
29                 flags |= ST_RELATIME;
30         return flags;
31 }
32
33 static int flags_by_sb(int s_flags)
34 {
35         int flags = 0;
36         if (s_flags & MS_SYNCHRONOUS)
37                 flags |= ST_SYNCHRONOUS;
38         if (s_flags & MS_MANDLOCK)
39                 flags |= ST_MANDLOCK;
40         return flags;
41 }
42
43 static int calculate_f_flags(struct vfsmount *mnt)
44 {
45         return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
46                 flags_by_sb(mnt->mnt_sb->s_flags);
47 }
48
49 static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
50 {
51         int retval;
52
53         if (!dentry->d_sb->s_op->statfs)
54                 return -ENOSYS;
55
56         memset(buf, 0, sizeof(*buf));
57         retval = security_sb_statfs(dentry);
58         if (retval)
59                 return retval;
60         retval = dentry->d_sb->s_op->statfs(dentry, buf);
61         if (retval == 0 && buf->f_frsize == 0)
62                 buf->f_frsize = buf->f_bsize;
63         return retval;
64 }
65
66 int vfs_statfs(struct path *path, struct kstatfs *buf)
67 {
68         int error;
69
70         error = statfs_by_dentry(path->dentry, buf);
71         if (!error)
72                 buf->f_flags = calculate_f_flags(path->mnt);
73         return error;
74 }
75 EXPORT_SYMBOL(vfs_statfs);
76
77 int user_statfs(const char __user *pathname, struct kstatfs *st)
78 {
79         struct path path;
80         int error, err;
81         unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
82 retry:
83         error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
84         if (!error) {
85                 error = vfs_statfs(&path, st);
86                 path_put(&path);
87                 /*sprd: reserved space is invisible for user*/
88                 err = hide_reserved_space_for_user(st);
89                 if (err) {
90                         pr_err("[user_statfs] error = %d\n", err);
91                         return err;
92                 }
93
94                 if (retry_estale(error, lookup_flags)) {
95                         lookup_flags |= LOOKUP_REVAL;
96                         goto retry;
97                 }
98         }
99         return error;
100 }
101
102 int fd_statfs(int fd, struct kstatfs *st)
103 {
104         struct fd f = fdget_raw(fd);
105         int error = -EBADF, err;
106         if (f.file) {
107                 error = vfs_statfs(&f.file->f_path, st);
108                 fdput(f);
109                 /*sprd: reserved space is invisible for user*/
110                 err = hide_reserved_space_for_user(st);
111                 if (err) {
112                         pr_err("[fd_statfs] error = %d\n", err);
113                         return err;
114                 }
115         }
116         return error;
117 }
118
119 static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
120 {
121         struct statfs buf;
122
123         if (sizeof(buf) == sizeof(*st))
124                 memcpy(&buf, st, sizeof(*st));
125         else {
126                 if (sizeof buf.f_blocks == 4) {
127                         if ((st->f_blocks | st->f_bfree | st->f_bavail |
128                              st->f_bsize | st->f_frsize) &
129                             0xffffffff00000000ULL)
130                                 return -EOVERFLOW;
131                         /*
132                          * f_files and f_ffree may be -1; it's okay to stuff
133                          * that into 32 bits
134                          */
135                         if (st->f_files != -1 &&
136                             (st->f_files & 0xffffffff00000000ULL))
137                                 return -EOVERFLOW;
138                         if (st->f_ffree != -1 &&
139                             (st->f_ffree & 0xffffffff00000000ULL))
140                                 return -EOVERFLOW;
141                 }
142
143                 buf.f_type = st->f_type;
144                 buf.f_bsize = st->f_bsize;
145                 buf.f_blocks = st->f_blocks;
146                 buf.f_bfree = st->f_bfree;
147                 buf.f_bavail = st->f_bavail;
148                 buf.f_files = st->f_files;
149                 buf.f_ffree = st->f_ffree;
150                 buf.f_fsid = st->f_fsid;
151                 buf.f_namelen = st->f_namelen;
152                 buf.f_frsize = st->f_frsize;
153                 buf.f_flags = st->f_flags;
154                 memset(buf.f_spare, 0, sizeof(buf.f_spare));
155         }
156         if (copy_to_user(p, &buf, sizeof(buf)))
157                 return -EFAULT;
158         return 0;
159 }
160
161 static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
162 {
163         struct statfs64 buf;
164         if (sizeof(buf) == sizeof(*st))
165                 memcpy(&buf, st, sizeof(*st));
166         else {
167                 buf.f_type = st->f_type;
168                 buf.f_bsize = st->f_bsize;
169                 buf.f_blocks = st->f_blocks;
170                 buf.f_bfree = st->f_bfree;
171                 buf.f_bavail = st->f_bavail;
172                 buf.f_files = st->f_files;
173                 buf.f_ffree = st->f_ffree;
174                 buf.f_fsid = st->f_fsid;
175                 buf.f_namelen = st->f_namelen;
176                 buf.f_frsize = st->f_frsize;
177                 buf.f_flags = st->f_flags;
178                 memset(buf.f_spare, 0, sizeof(buf.f_spare));
179         }
180         if (copy_to_user(p, &buf, sizeof(buf)))
181                 return -EFAULT;
182         return 0;
183 }
184
185 SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
186 {
187         struct kstatfs st;
188         int error = user_statfs(pathname, &st);
189         if (!error)
190                 error = do_statfs_native(&st, buf);
191         return error;
192 }
193
194 SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
195 {
196         struct kstatfs st;
197         int error;
198         if (sz != sizeof(*buf))
199                 return -EINVAL;
200         error = user_statfs(pathname, &st);
201         if (!error)
202                 error = do_statfs64(&st, buf);
203         return error;
204 }
205
206 SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
207 {
208         struct kstatfs st;
209         int error = fd_statfs(fd, &st);
210         if (!error)
211                 error = do_statfs_native(&st, buf);
212         return error;
213 }
214
215 SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
216 {
217         struct kstatfs st;
218         int error;
219
220         if (sz != sizeof(*buf))
221                 return -EINVAL;
222
223         error = fd_statfs(fd, &st);
224         if (!error)
225                 error = do_statfs64(&st, buf);
226         return error;
227 }
228
229 int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
230 {
231         struct super_block *s = user_get_super(dev);
232         int err;
233         if (!s)
234                 return -EINVAL;
235
236         err = statfs_by_dentry(s->s_root, sbuf);
237         drop_super(s);
238         return err;
239 }
240
241 SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
242 {
243         struct ustat tmp;
244         struct kstatfs sbuf;
245         int err = vfs_ustat(new_decode_dev(dev), &sbuf);
246         if (err)
247                 return err;
248
249         memset(&tmp,0,sizeof(struct ustat));
250         tmp.f_tfree = sbuf.f_bfree;
251         tmp.f_tinode = sbuf.f_ffree;
252
253         return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
254 }