File: /usr/src/linux/fs/read_write.c
1 /*
2 * linux/fs/read_write.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7 #include <linux/slab.h>
8 #include <linux/stat.h>
9 #include <linux/fcntl.h>
10 #include <linux/file.h>
11 #include <linux/uio.h>
12 #include <linux/smp_lock.h>
13 #include <linux/dnotify.h>
14
15 #include <asm/uaccess.h>
16
17 struct file_operations generic_ro_fops = {
18 llseek: generic_file_llseek,
19 read: generic_file_read,
20 mmap: generic_file_mmap,
21 };
22
23 ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
24 {
25 return -EISDIR;
26 }
27
28 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
29 {
30 long long retval;
31
32 switch (origin) {
33 case 2:
34 offset += file->f_dentry->d_inode->i_size;
35 break;
36 case 1:
37 offset += file->f_pos;
38 }
39 retval = -EINVAL;
40 if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
41 if (offset != file->f_pos) {
42 file->f_pos = offset;
43 file->f_reada = 0;
44 file->f_version = ++event;
45 }
46 retval = offset;
47 }
48 return retval;
49 }
50
51 loff_t no_llseek(struct file *file, loff_t offset, int origin)
52 {
53 return -ESPIPE;
54 }
55
56 loff_t default_llseek(struct file *file, loff_t offset, int origin)
57 {
58 long long retval;
59
60 switch (origin) {
61 case 2:
62 offset += file->f_dentry->d_inode->i_size;
63 break;
64 case 1:
65 offset += file->f_pos;
66 }
67 retval = -EINVAL;
68 if (offset >= 0) {
69 if (offset != file->f_pos) {
70 file->f_pos = offset;
71 file->f_reada = 0;
72 file->f_version = ++event;
73 }
74 retval = offset;
75 }
76 return retval;
77 }
78
79 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
80 {
81 loff_t (*fn)(struct file *, loff_t, int);
82 loff_t retval;
83
84 fn = default_llseek;
85 if (file->f_op && file->f_op->llseek)
86 fn = file->f_op->llseek;
87 lock_kernel();
88 retval = fn(file, offset, origin);
89 unlock_kernel();
90 return retval;
91 }
92
93 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
94 {
95 off_t retval;
96 struct file * file;
97
98 retval = -EBADF;
99 file = fget(fd);
100 if (!file)
101 goto bad;
102 retval = -EINVAL;
103 if (origin <= 2) {
104 loff_t res = llseek(file, offset, origin);
105 retval = res;
106 if (res != (loff_t)retval)
107 retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
108 }
109 fput(file);
110 bad:
111 return retval;
112 }
113
114 #if !defined(__alpha__)
115 asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
116 unsigned long offset_low, loff_t * result,
117 unsigned int origin)
118 {
119 int retval;
120 struct file * file;
121 loff_t offset;
122
123 retval = -EBADF;
124 file = fget(fd);
125 if (!file)
126 goto bad;
127 retval = -EINVAL;
128 if (origin > 2)
129 goto out_putf;
130
131 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
132 origin);
133
134 retval = (int)offset;
135 if (offset >= 0) {
136 retval = -EFAULT;
137 if (!copy_to_user(result, &offset, sizeof(offset)))
138 retval = 0;
139 }
140 out_putf:
141 fput(file);
142 bad:
143 return retval;
144 }
145 #endif
146
147 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
148 {
149 ssize_t ret;
150 struct file * file;
151
152 ret = -EBADF;
153 file = fget(fd);
154 if (file) {
155 if (file->f_mode & FMODE_READ) {
156 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
157 file, file->f_pos, count);
158 if (!ret) {
159 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
160 ret = -EINVAL;
161 if (file->f_op && (read = file->f_op->read) != NULL)
162 ret = read(file, buf, count, &file->f_pos);
163 }
164 }
165 if (ret > 0)
166 inode_dir_notify(file->f_dentry->d_parent->d_inode,
167 DN_ACCESS);
168 fput(file);
169 }
170 return ret;
171 }
172
173 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
174 {
175 ssize_t ret;
176 struct file * file;
177
178 ret = -EBADF;
179 file = fget(fd);
180 if (file) {
181 if (file->f_mode & FMODE_WRITE) {
182 struct inode *inode = file->f_dentry->d_inode;
183 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
184 file->f_pos, count);
185 if (!ret) {
186 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
187 ret = -EINVAL;
188 if (file->f_op && (write = file->f_op->write) != NULL)
189 ret = write(file, buf, count, &file->f_pos);
190 }
191 }
192 if (ret > 0)
193 inode_dir_notify(file->f_dentry->d_parent->d_inode,
194 DN_MODIFY);
195 fput(file);
196 }
197 return ret;
198 }
199
200
201 static ssize_t do_readv_writev(int type, struct file *file,
202 const struct iovec * vector,
203 unsigned long count)
204 {
205 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
206 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
207
208 size_t tot_len;
209 struct iovec iovstack[UIO_FASTIOV];
210 struct iovec *iov=iovstack;
211 ssize_t ret, i;
212 io_fn_t fn;
213 iov_fn_t fnv;
214 struct inode *inode;
215
216 /*
217 * First get the "struct iovec" from user memory and
218 * verify all the pointers
219 */
220 ret = 0;
221 if (!count)
222 goto out_nofree;
223 ret = -EINVAL;
224 if (count > UIO_MAXIOV)
225 goto out_nofree;
226 if (!file->f_op)
227 goto out_nofree;
228 if (count > UIO_FASTIOV) {
229 ret = -ENOMEM;
230 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
231 if (!iov)
232 goto out_nofree;
233 }
234 ret = -EFAULT;
235 if (copy_from_user(iov, vector, count*sizeof(*vector)))
236 goto out;
237
238 /* BSD readv/writev returns EINVAL if one of the iov_len
239 values < 0 or tot_len overflowed a 32-bit integer. -ink */
240 tot_len = 0;
241 ret = -EINVAL;
242 for (i = 0 ; i < count ; i++) {
243 size_t tmp = tot_len;
244 int len = iov[i].iov_len;
245 if (len < 0)
246 goto out;
247 (u32)tot_len += len;
248 if (tot_len < tmp || tot_len < (u32)len)
249 goto out;
250 }
251
252 inode = file->f_dentry->d_inode;
253 /* VERIFY_WRITE actually means a read, as we write to user space */
254 ret = locks_verify_area((type == VERIFY_WRITE
255 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
256 inode, file, file->f_pos, tot_len);
257 if (ret) goto out;
258
259 fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
260 if (fnv) {
261 ret = fnv(file, iov, count, &file->f_pos);
262 goto out;
263 }
264
265 /* VERIFY_WRITE actually means a read, as we write to user space */
266 fn = (type == VERIFY_WRITE ? file->f_op->read :
267 (io_fn_t) file->f_op->write);
268
269 ret = 0;
270 vector = iov;
271 while (count > 0) {
272 void * base;
273 size_t len;
274 ssize_t nr;
275
276 base = vector->iov_base;
277 len = vector->iov_len;
278 vector++;
279 count--;
280
281 nr = fn(file, base, len, &file->f_pos);
282
283 if (nr < 0) {
284 if (!ret) ret = nr;
285 break;
286 }
287 ret += nr;
288 if (nr != len)
289 break;
290 }
291
292 out:
293 if (iov != iovstack)
294 kfree(iov);
295 out_nofree:
296 /* VERIFY_WRITE actually means a read, as we write to user space */
297 if ((ret + (type == VERIFY_WRITE)) > 0)
298 inode_dir_notify(file->f_dentry->d_parent->d_inode,
299 (type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
300 return ret;
301 }
302
303 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
304 unsigned long count)
305 {
306 struct file * file;
307 ssize_t ret;
308
309
310 ret = -EBADF;
311 file = fget(fd);
312 if (!file)
313 goto bad_file;
314 if (file->f_op && (file->f_mode & FMODE_READ) &&
315 (file->f_op->readv || file->f_op->read))
316 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
317 fput(file);
318
319 bad_file:
320 return ret;
321 }
322
323 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
324 unsigned long count)
325 {
326 struct file * file;
327 ssize_t ret;
328
329
330 ret = -EBADF;
331 file = fget(fd);
332 if (!file)
333 goto bad_file;
334 if (file->f_op && (file->f_mode & FMODE_WRITE) &&
335 (file->f_op->writev || file->f_op->write))
336 ret = do_readv_writev(VERIFY_READ, file, vector, count);
337 fput(file);
338
339 bad_file:
340 return ret;
341 }
342
343 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
344 lseek back to original location. They fail just like lseek does on
345 non-seekable files. */
346
347 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
348 size_t count, loff_t pos)
349 {
350 ssize_t ret;
351 struct file * file;
352 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
353
354 ret = -EBADF;
355 file = fget(fd);
356 if (!file)
357 goto bad_file;
358 if (!(file->f_mode & FMODE_READ))
359 goto out;
360 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
361 file, pos, count);
362 if (ret)
363 goto out;
364 ret = -EINVAL;
365 if (!file->f_op || !(read = file->f_op->read))
366 goto out;
367 if (pos < 0)
368 goto out;
369 ret = read(file, buf, count, &pos);
370 if (ret > 0)
371 inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_ACCESS);
372 out:
373 fput(file);
374 bad_file:
375 return ret;
376 }
377
378 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
379 size_t count, loff_t pos)
380 {
381 ssize_t ret;
382 struct file * file;
383 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
384
385 ret = -EBADF;
386 file = fget(fd);
387 if (!file)
388 goto bad_file;
389 if (!(file->f_mode & FMODE_WRITE))
390 goto out;
391 ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
392 file, pos, count);
393 if (ret)
394 goto out;
395 ret = -EINVAL;
396 if (!file->f_op || !(write = file->f_op->write))
397 goto out;
398 if (pos < 0)
399 goto out;
400
401 ret = write(file, buf, count, &pos);
402 if (ret > 0)
403 inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_MODIFY);
404 out:
405 fput(file);
406 bad_file:
407 return ret;
408 }
409