UBUNTU: ubuntu: AUFS -- aufs2-standalone.patch aufs2.1-36-UNRELEASED-20101103
[linux-flexiantxendom0-natty.git] / fs / statfs.c
1 #include <linux/syscalls.h>
2 #include <linux/module.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
11 static int flags_by_mnt(int mnt_flags)
12 {
13         int flags = 0;
14
15         if (mnt_flags & MNT_READONLY)
16                 flags |= ST_RDONLY;
17         if (mnt_flags & MNT_NOSUID)
18                 flags |= ST_NOSUID;
19         if (mnt_flags & MNT_NODEV)
20                 flags |= ST_NODEV;
21         if (mnt_flags & MNT_NOEXEC)
22                 flags |= ST_NOEXEC;
23         if (mnt_flags & MNT_NOATIME)
24                 flags |= ST_NOATIME;
25         if (mnt_flags & MNT_NODIRATIME)
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;
62         return retval;
63 }
64 EXPORT_SYMBOL_GPL(statfs_by_dentry);
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 static int do_statfs_native(struct path *path, struct statfs *buf)
78 {
79         struct kstatfs st;
80         int retval;
81
82         retval = vfs_statfs(path, &st);
83         if (retval)
84                 return retval;
85
86         if (sizeof(*buf) == sizeof(st))
87                 memcpy(buf, &st, sizeof(st));
88         else {
89                 if (sizeof buf->f_blocks == 4) {
90                         if ((st.f_blocks | st.f_bfree | st.f_bavail |
91                              st.f_bsize | st.f_frsize) &
92                             0xffffffff00000000ULL)
93                                 return -EOVERFLOW;
94                         /*
95                          * f_files and f_ffree may be -1; it's okay to stuff
96                          * that into 32 bits
97                          */
98                         if (st.f_files != -1 &&
99                             (st.f_files & 0xffffffff00000000ULL))
100                                 return -EOVERFLOW;
101                         if (st.f_ffree != -1 &&
102                             (st.f_ffree & 0xffffffff00000000ULL))
103                                 return -EOVERFLOW;
104                 }
105
106                 buf->f_type = st.f_type;
107                 buf->f_bsize = st.f_bsize;
108                 buf->f_blocks = st.f_blocks;
109                 buf->f_bfree = st.f_bfree;
110                 buf->f_bavail = st.f_bavail;
111                 buf->f_files = st.f_files;
112                 buf->f_ffree = st.f_ffree;
113                 buf->f_fsid = st.f_fsid;
114                 buf->f_namelen = st.f_namelen;
115                 buf->f_frsize = st.f_frsize;
116                 buf->f_flags = st.f_flags;
117                 memset(buf->f_spare, 0, sizeof(buf->f_spare));
118         }
119         return 0;
120 }
121
122 static int do_statfs64(struct path *path, struct statfs64 *buf)
123 {
124         struct kstatfs st;
125         int retval;
126
127         retval = vfs_statfs(path, &st);
128         if (retval)
129                 return retval;
130
131         if (sizeof(*buf) == sizeof(st))
132                 memcpy(buf, &st, sizeof(st));
133         else {
134                 buf->f_type = st.f_type;
135                 buf->f_bsize = st.f_bsize;
136                 buf->f_blocks = st.f_blocks;
137                 buf->f_bfree = st.f_bfree;
138                 buf->f_bavail = st.f_bavail;
139                 buf->f_files = st.f_files;
140                 buf->f_ffree = st.f_ffree;
141                 buf->f_fsid = st.f_fsid;
142                 buf->f_namelen = st.f_namelen;
143                 buf->f_frsize = st.f_frsize;
144                 buf->f_flags = st.f_flags;
145                 memset(buf->f_spare, 0, sizeof(buf->f_spare));
146         }
147         return 0;
148 }
149
150 SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
151 {
152         struct path path;
153         int error;
154
155         error = user_path(pathname, &path);
156         if (!error) {
157                 struct statfs tmp;
158                 error = do_statfs_native(&path, &tmp);
159                 if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
160                         error = -EFAULT;
161                 path_put(&path);
162         }
163         return error;
164 }
165
166 SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
167 {
168         struct path path;
169         long error;
170
171         if (sz != sizeof(*buf))
172                 return -EINVAL;
173         error = user_path(pathname, &path);
174         if (!error) {
175                 struct statfs64 tmp;
176                 error = do_statfs64(&path, &tmp);
177                 if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
178                         error = -EFAULT;
179                 path_put(&path);
180         }
181         return error;
182 }
183
184 SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
185 {
186         struct file *file;
187         struct statfs tmp;
188         int error;
189
190         error = -EBADF;
191         file = fget(fd);
192         if (!file)
193                 goto out;
194         error = do_statfs_native(&file->f_path, &tmp);
195         if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
196                 error = -EFAULT;
197         fput(file);
198 out:
199         return error;
200 }
201
202 SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
203 {
204         struct file *file;
205         struct statfs64 tmp;
206         int error;
207
208         if (sz != sizeof(*buf))
209                 return -EINVAL;
210
211         error = -EBADF;
212         file = fget(fd);
213         if (!file)
214                 goto out;
215         error = do_statfs64(&file->f_path, &tmp);
216         if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
217                 error = -EFAULT;
218         fput(file);
219 out:
220         return error;
221 }
222
223 SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
224 {
225         struct super_block *s;
226         struct ustat tmp;
227         struct kstatfs sbuf;
228         int err;
229
230         s = user_get_super(new_decode_dev(dev));
231         if (!s)
232                 return -EINVAL;
233
234         err = statfs_by_dentry(s->s_root, &sbuf);
235         drop_super(s);
236         if (err)
237                 return err;
238
239         memset(&tmp,0,sizeof(struct ustat));
240         tmp.f_tfree = sbuf.f_bfree;
241         tmp.f_tinode = sbuf.f_ffree;
242
243         return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
244 }