Blame view

fs/statfs.c 5.16 KB
7ed1ee611   Al Viro   Take statfs varia...
1
2
3
4
  #include <linux/syscalls.h>
  #include <linux/module.h>
  #include <linux/fs.h>
  #include <linux/file.h>
365b18189   Christoph Hellwig   add f_flags to st...
5
  #include <linux/mount.h>
7ed1ee611   Al Viro   Take statfs varia...
6
7
8
9
  #include <linux/namei.h>
  #include <linux/statfs.h>
  #include <linux/security.h>
  #include <linux/uaccess.h>
365b18189   Christoph Hellwig   add f_flags to st...
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  static int flags_by_mnt(int mnt_flags)
  {
  	int flags = 0;
  
  	if (mnt_flags & MNT_READONLY)
  		flags |= ST_RDONLY;
  	if (mnt_flags & MNT_NOSUID)
  		flags |= ST_NOSUID;
  	if (mnt_flags & MNT_NODEV)
  		flags |= ST_NODEV;
  	if (mnt_flags & MNT_NOEXEC)
  		flags |= ST_NOEXEC;
  	if (mnt_flags & MNT_NOATIME)
  		flags |= ST_NOATIME;
  	if (mnt_flags & MNT_NODIRATIME)
  		flags |= ST_NODIRATIME;
  	if (mnt_flags & MNT_RELATIME)
  		flags |= ST_RELATIME;
  	return flags;
  }
  
  static int flags_by_sb(int s_flags)
  {
  	int flags = 0;
  	if (s_flags & MS_SYNCHRONOUS)
  		flags |= ST_SYNCHRONOUS;
  	if (s_flags & MS_MANDLOCK)
  		flags |= ST_MANDLOCK;
  	return flags;
  }
  
  static int calculate_f_flags(struct vfsmount *mnt)
  {
  	return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
  		flags_by_sb(mnt->mnt_sb->s_flags);
  }
ebabe9a90   Christoph Hellwig   pass a struct pat...
46
  int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
7ed1ee611   Al Viro   Take statfs varia...
47
  {
ebabe9a90   Christoph Hellwig   pass a struct pat...
48
49
50
51
52
53
54
55
56
57
58
59
  	int retval;
  
  	if (!dentry->d_sb->s_op->statfs)
  		return -ENOSYS;
  
  	memset(buf, 0, sizeof(*buf));
  	retval = security_sb_statfs(dentry);
  	if (retval)
  		return retval;
  	retval = dentry->d_sb->s_op->statfs(dentry, buf);
  	if (retval == 0 && buf->f_frsize == 0)
  		buf->f_frsize = buf->f_bsize;
7ed1ee611   Al Viro   Take statfs varia...
60
61
  	return retval;
  }
ebabe9a90   Christoph Hellwig   pass a struct pat...
62
63
  int vfs_statfs(struct path *path, struct kstatfs *buf)
  {
365b18189   Christoph Hellwig   add f_flags to st...
64
65
66
67
68
69
  	int error;
  
  	error = statfs_by_dentry(path->dentry, buf);
  	if (!error)
  		buf->f_flags = calculate_f_flags(path->mnt);
  	return error;
ebabe9a90   Christoph Hellwig   pass a struct pat...
70
  }
7ed1ee611   Al Viro   Take statfs varia...
71
  EXPORT_SYMBOL(vfs_statfs);
ebabe9a90   Christoph Hellwig   pass a struct pat...
72
  static int do_statfs_native(struct path *path, struct statfs *buf)
7ed1ee611   Al Viro   Take statfs varia...
73
74
75
  {
  	struct kstatfs st;
  	int retval;
ebabe9a90   Christoph Hellwig   pass a struct pat...
76
  	retval = vfs_statfs(path, &st);
7ed1ee611   Al Viro   Take statfs varia...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  	if (retval)
  		return retval;
  
  	if (sizeof(*buf) == sizeof(st))
  		memcpy(buf, &st, sizeof(st));
  	else {
  		if (sizeof buf->f_blocks == 4) {
  			if ((st.f_blocks | st.f_bfree | st.f_bavail |
  			     st.f_bsize | st.f_frsize) &
  			    0xffffffff00000000ULL)
  				return -EOVERFLOW;
  			/*
  			 * f_files and f_ffree may be -1; it's okay to stuff
  			 * that into 32 bits
  			 */
  			if (st.f_files != -1 &&
  			    (st.f_files & 0xffffffff00000000ULL))
  				return -EOVERFLOW;
  			if (st.f_ffree != -1 &&
  			    (st.f_ffree & 0xffffffff00000000ULL))
  				return -EOVERFLOW;
  		}
  
  		buf->f_type = st.f_type;
  		buf->f_bsize = st.f_bsize;
  		buf->f_blocks = st.f_blocks;
  		buf->f_bfree = st.f_bfree;
  		buf->f_bavail = st.f_bavail;
  		buf->f_files = st.f_files;
  		buf->f_ffree = st.f_ffree;
  		buf->f_fsid = st.f_fsid;
  		buf->f_namelen = st.f_namelen;
  		buf->f_frsize = st.f_frsize;
365b18189   Christoph Hellwig   add f_flags to st...
110
  		buf->f_flags = st.f_flags;
7ed1ee611   Al Viro   Take statfs varia...
111
112
113
114
  		memset(buf->f_spare, 0, sizeof(buf->f_spare));
  	}
  	return 0;
  }
ebabe9a90   Christoph Hellwig   pass a struct pat...
115
  static int do_statfs64(struct path *path, struct statfs64 *buf)
7ed1ee611   Al Viro   Take statfs varia...
116
117
118
  {
  	struct kstatfs st;
  	int retval;
ebabe9a90   Christoph Hellwig   pass a struct pat...
119
  	retval = vfs_statfs(path, &st);
7ed1ee611   Al Viro   Take statfs varia...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  	if (retval)
  		return retval;
  
  	if (sizeof(*buf) == sizeof(st))
  		memcpy(buf, &st, sizeof(st));
  	else {
  		buf->f_type = st.f_type;
  		buf->f_bsize = st.f_bsize;
  		buf->f_blocks = st.f_blocks;
  		buf->f_bfree = st.f_bfree;
  		buf->f_bavail = st.f_bavail;
  		buf->f_files = st.f_files;
  		buf->f_ffree = st.f_ffree;
  		buf->f_fsid = st.f_fsid;
  		buf->f_namelen = st.f_namelen;
  		buf->f_frsize = st.f_frsize;
365b18189   Christoph Hellwig   add f_flags to st...
136
  		buf->f_flags = st.f_flags;
7ed1ee611   Al Viro   Take statfs varia...
137
138
139
140
141
142
143
144
145
146
147
148
149
  		memset(buf->f_spare, 0, sizeof(buf->f_spare));
  	}
  	return 0;
  }
  
  SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
  {
  	struct path path;
  	int error;
  
  	error = user_path(pathname, &path);
  	if (!error) {
  		struct statfs tmp;
ebabe9a90   Christoph Hellwig   pass a struct pat...
150
  		error = do_statfs_native(&path, &tmp);
7ed1ee611   Al Viro   Take statfs varia...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
  			error = -EFAULT;
  		path_put(&path);
  	}
  	return error;
  }
  
  SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
  {
  	struct path path;
  	long error;
  
  	if (sz != sizeof(*buf))
  		return -EINVAL;
  	error = user_path(pathname, &path);
  	if (!error) {
  		struct statfs64 tmp;
ebabe9a90   Christoph Hellwig   pass a struct pat...
168
  		error = do_statfs64(&path, &tmp);
7ed1ee611   Al Viro   Take statfs varia...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
  			error = -EFAULT;
  		path_put(&path);
  	}
  	return error;
  }
  
  SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
  {
  	struct file *file;
  	struct statfs tmp;
  	int error;
  
  	error = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
ebabe9a90   Christoph Hellwig   pass a struct pat...
186
  	error = do_statfs_native(&file->f_path, &tmp);
7ed1ee611   Al Viro   Take statfs varia...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
  		error = -EFAULT;
  	fput(file);
  out:
  	return error;
  }
  
  SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
  {
  	struct file *file;
  	struct statfs64 tmp;
  	int error;
  
  	if (sz != sizeof(*buf))
  		return -EINVAL;
  
  	error = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
ebabe9a90   Christoph Hellwig   pass a struct pat...
207
  	error = do_statfs64(&file->f_path, &tmp);
7ed1ee611   Al Viro   Take statfs varia...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
  		error = -EFAULT;
  	fput(file);
  out:
  	return error;
  }
  
  SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
  {
  	struct super_block *s;
  	struct ustat tmp;
  	struct kstatfs sbuf;
  	int err;
  
  	s = user_get_super(new_decode_dev(dev));
  	if (!s)
  		return -EINVAL;
ebabe9a90   Christoph Hellwig   pass a struct pat...
225
  	err = statfs_by_dentry(s->s_root, &sbuf);
7ed1ee611   Al Viro   Take statfs varia...
226
227
228
229
230
231
232
233
234
235
  	drop_super(s);
  	if (err)
  		return err;
  
  	memset(&tmp,0,sizeof(struct ustat));
  	tmp.f_tfree = sbuf.f_bfree;
  	tmp.f_tinode = sbuf.f_ffree;
  
  	return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
  }