Import 2.1.112pre1
[davej-history.git] / fs / read_write.c
blobb71f06b49d75089064052292fdb363e08a948bc5
1 /*
2 * linux/fs/read_write.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/types.h>
8 #include <linux/errno.h>
9 #include <linux/stat.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/fcntl.h>
13 #include <linux/file.h>
14 #include <linux/mm.h>
15 #include <linux/uio.h>
16 #include <linux/malloc.h>
17 #include <linux/smp.h>
18 #include <linux/smp_lock.h>
19 #include <linux/limits.h>
21 #include <asm/uaccess.h>
23 static loff_t default_llseek(struct file *file, loff_t offset, int origin)
25 long long retval;
27 switch (origin) {
28 case 2:
29 offset += file->f_dentry->d_inode->i_size;
30 break;
31 case 1:
32 offset += file->f_pos;
34 retval = -EINVAL;
35 if (offset >= 0) {
36 if (offset != file->f_pos) {
37 file->f_pos = offset;
38 file->f_reada = 0;
39 file->f_version = ++event;
41 retval = offset;
43 return retval;
46 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
48 loff_t (*fn)(struct file *, loff_t, int);
50 fn = default_llseek;
51 if (file->f_op && file->f_op->llseek)
52 fn = file->f_op->llseek;
53 return fn(file, offset, origin);
56 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
58 off_t retval;
59 struct file * file;
60 struct dentry * dentry;
61 struct inode * inode;
63 lock_kernel();
64 retval = -EBADF;
65 file = fget(fd);
66 if (!file)
67 goto bad;
68 /* N.B. Shouldn't this be ENOENT?? */
69 if (!(dentry = file->f_dentry) ||
70 !(inode = dentry->d_inode))
71 goto out_putf;
72 retval = -EINVAL;
73 if (origin <= 2)
74 retval = llseek(file, offset, origin);
75 out_putf:
76 fput(file);
77 bad:
78 unlock_kernel();
79 return retval;
82 #if !defined(__alpha__)
83 asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
84 unsigned long offset_low, loff_t * result,
85 unsigned int origin)
87 int retval;
88 struct file * file;
89 struct dentry * dentry;
90 struct inode * inode;
91 loff_t offset;
93 lock_kernel();
94 retval = -EBADF;
95 file = fget(fd);
96 if (!file)
97 goto bad;
98 /* N.B. Shouldn't this be ENOENT?? */
99 if (!(dentry = file->f_dentry) ||
100 !(inode = dentry->d_inode))
101 goto out_putf;
102 retval = -EINVAL;
103 if (origin > 2)
104 goto out_putf;
106 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
107 origin);
109 retval = (int)offset & INT_MAX;
110 if (offset >= 0) {
111 retval = -EFAULT;
112 if (!copy_to_user(result, &offset, sizeof(offset)))
113 retval = 0;
115 out_putf:
116 fput(file);
117 bad:
118 unlock_kernel();
119 return retval;
121 #endif
123 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
125 ssize_t ret;
126 struct file * file;
127 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
129 lock_kernel();
131 ret = -EBADF;
132 file = fget(fd);
133 if (!file)
134 goto bad_file;
135 if (!(file->f_mode & FMODE_READ))
136 goto out;
137 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
138 file, file->f_pos, count);
139 if (ret)
140 goto out;
141 ret = -EINVAL;
142 if (!file->f_op || !(read = file->f_op->read))
143 goto out;
144 ret = read(file, buf, count, &file->f_pos);
145 out:
146 fput(file);
147 bad_file:
148 unlock_kernel();
149 return ret;
152 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
154 ssize_t ret;
155 struct file * file;
156 struct inode * inode;
157 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
159 lock_kernel();
161 ret = -EBADF;
162 file = fget(fd);
163 if (!file)
164 goto bad_file;
165 if (!(file->f_mode & FMODE_WRITE))
166 goto out;
167 inode = file->f_dentry->d_inode;
168 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
169 file->f_pos, count);
170 if (ret)
171 goto out;
172 ret = -EINVAL;
173 if (!file->f_op || !(write = file->f_op->write))
174 goto out;
176 down(&inode->i_sem);
177 ret = write(file, buf, count, &file->f_pos);
178 up(&inode->i_sem);
179 out:
180 fput(file);
181 bad_file:
182 unlock_kernel();
183 return ret;
187 static ssize_t do_readv_writev(int type, struct file *file,
188 const struct iovec * vector,
189 unsigned long count)
191 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
193 size_t tot_len;
194 struct iovec iovstack[UIO_FASTIOV];
195 struct iovec *iov=iovstack;
196 ssize_t ret, i;
197 io_fn_t fn;
198 struct inode *inode;
201 * First get the "struct iovec" from user memory and
202 * verify all the pointers
204 ret = 0;
205 if (!count)
206 goto out_nofree;
207 ret = -EINVAL;
208 if (count > UIO_MAXIOV)
209 goto out_nofree;
210 if (count > UIO_FASTIOV) {
211 ret = -ENOMEM;
212 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
213 if (!iov)
214 goto out_nofree;
216 ret = -EFAULT;
217 if (copy_from_user(iov, vector, count*sizeof(*vector)))
218 goto out;
220 tot_len = 0;
221 for (i = 0 ; i < count ; i++)
222 tot_len += iov[i].iov_len;
224 inode = file->f_dentry->d_inode;
225 ret = locks_verify_area((type == VERIFY_READ
226 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
227 inode, file, file->f_pos, tot_len);
228 if (ret) goto out;
231 * Then do the actual IO. Note that sockets need to be handled
232 * specially as they have atomicity guarantees and can handle
233 * iovec's natively
235 if (inode->i_sock) {
236 ret = sock_readv_writev(type,inode,file,iov,count,tot_len);
237 goto out;
240 ret = -EINVAL;
241 if (!file->f_op)
242 goto out;
244 /* VERIFY_WRITE actually means a read, as we write to user space */
245 fn = file->f_op->read;
246 if (type == VERIFY_READ)
247 fn = (io_fn_t) file->f_op->write;
249 ret = 0;
250 vector = iov;
251 while (count > 0) {
252 void * base;
253 size_t len;
254 ssize_t nr;
256 base = vector->iov_base;
257 len = vector->iov_len;
258 vector++;
259 count--;
261 nr = fn(file, base, len, &file->f_pos);
263 if (nr < 0) {
264 if (!ret) ret = nr;
265 break;
267 ret += nr;
268 if (nr != len)
269 break;
272 out:
273 if (iov != iovstack)
274 kfree(iov);
275 out_nofree:
276 return ret;
279 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
280 unsigned long count)
282 struct file * file;
283 ssize_t ret;
285 lock_kernel();
287 ret = -EBADF;
288 file = fget(fd);
289 if (!file)
290 goto bad_file;
291 if (file->f_mode & FMODE_READ)
292 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
293 fput(file);
295 bad_file:
296 unlock_kernel();
297 return ret;
300 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
301 unsigned long count)
303 struct file * file;
304 ssize_t ret;
306 lock_kernel();
308 ret = -EBADF;
309 file = fget(fd);
310 if (!file)
311 goto bad_file;
312 if (file->f_mode & FMODE_WRITE) {
313 down(&file->f_dentry->d_inode->i_sem);
314 ret = do_readv_writev(VERIFY_READ, file, vector, count);
315 up(&file->f_dentry->d_inode->i_sem);
317 fput(file);
319 bad_file:
320 unlock_kernel();
321 return ret;
324 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
325 lseek back to original location. They fail just like lseek does on
326 non-seekable files. */
328 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
329 size_t count, loff_t pos)
331 ssize_t ret;
332 struct file * file;
333 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
335 lock_kernel();
337 ret = -EBADF;
338 file = fget(fd);
339 if (!file)
340 goto bad_file;
341 if (!(file->f_mode & FMODE_READ))
342 goto out;
343 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
344 file, pos, count);
345 if (ret)
346 goto out;
347 ret = -EINVAL;
348 if (!file->f_op || !(read = file->f_op->read))
349 goto out;
350 if (pos < 0)
351 goto out;
352 ret = read(file, buf, count, &pos);
353 out:
354 fput(file);
355 bad_file:
356 unlock_kernel();
357 return ret;
360 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
361 size_t count, loff_t pos)
363 ssize_t ret;
364 struct file * file;
365 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
367 lock_kernel();
369 ret = -EBADF;
370 file = fget(fd);
371 if (!file)
372 goto bad_file;
373 if (!(file->f_mode & FMODE_WRITE))
374 goto out;
375 ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
376 file, pos, count);
377 if (ret)
378 goto out;
379 ret = -EINVAL;
380 if (!file->f_op || !(write = file->f_op->write))
381 goto out;
382 if (pos < 0)
383 goto out;
385 down(&file->f_dentry->d_inode->i_sem);
386 ret = write(file, buf, count, &pos);
387 up(&file->f_dentry->d_inode->i_sem);
389 out:
390 fput(file);
391 bad_file:
392 unlock_kernel();
393 return ret;