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