Import 2.2.8pre2
[davej-history.git] / fs / read_write.c
blob7b9bf0bf759393d09479411abad843d2b6ac87ef
1 /*
2 * linux/fs/read_write.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/malloc.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>
14 #include <asm/uaccess.h>
16 static loff_t default_llseek(struct file *file, loff_t offset, int origin)
18 long long retval;
20 switch (origin) {
21 case 2:
22 offset += file->f_dentry->d_inode->i_size;
23 break;
24 case 1:
25 offset += file->f_pos;
27 retval = -EINVAL;
28 if (offset >= 0) {
29 if (offset != file->f_pos) {
30 file->f_pos = offset;
31 file->f_reada = 0;
32 file->f_version = ++event;
34 retval = offset;
36 return retval;
39 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
41 loff_t (*fn)(struct file *, loff_t, int);
43 fn = default_llseek;
44 if (file->f_op && file->f_op->llseek)
45 fn = file->f_op->llseek;
46 return fn(file, offset, origin);
49 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
51 off_t retval;
52 struct file * file;
53 struct dentry * dentry;
54 struct inode * inode;
56 lock_kernel();
57 retval = -EBADF;
58 file = fget(fd);
59 if (!file)
60 goto bad;
61 /* N.B. Shouldn't this be ENOENT?? */
62 if (!(dentry = file->f_dentry) ||
63 !(inode = dentry->d_inode))
64 goto out_putf;
65 retval = -EINVAL;
66 if (origin <= 2)
67 retval = llseek(file, offset, origin);
68 out_putf:
69 fput(file);
70 bad:
71 unlock_kernel();
72 return retval;
75 #if !defined(__alpha__)
76 asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
77 unsigned long offset_low, loff_t * result,
78 unsigned int origin)
80 int retval;
81 struct file * file;
82 struct dentry * dentry;
83 struct inode * inode;
84 loff_t offset;
86 lock_kernel();
87 retval = -EBADF;
88 file = fget(fd);
89 if (!file)
90 goto bad;
91 /* N.B. Shouldn't this be ENOENT?? */
92 if (!(dentry = file->f_dentry) ||
93 !(inode = dentry->d_inode))
94 goto out_putf;
95 retval = -EINVAL;
96 if (origin > 2)
97 goto out_putf;
99 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
100 origin);
102 retval = (int)offset;
103 if (offset >= 0) {
104 retval = -EFAULT;
105 if (!copy_to_user(result, &offset, sizeof(offset)))
106 retval = 0;
108 out_putf:
109 fput(file);
110 bad:
111 unlock_kernel();
112 return retval;
114 #endif
116 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
118 ssize_t ret;
119 struct file * file;
120 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
122 lock_kernel();
124 ret = -EBADF;
125 file = fget(fd);
126 if (!file)
127 goto bad_file;
128 if (!(file->f_mode & FMODE_READ))
129 goto out;
130 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
131 file, file->f_pos, count);
132 if (ret)
133 goto out;
134 ret = -EINVAL;
135 if (!file->f_op || !(read = file->f_op->read))
136 goto out;
137 ret = read(file, buf, count, &file->f_pos);
138 out:
139 fput(file);
140 bad_file:
141 unlock_kernel();
142 return ret;
145 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
147 ssize_t ret;
148 struct file * file;
149 struct inode * inode;
150 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
152 lock_kernel();
154 ret = -EBADF;
155 file = fget(fd);
156 if (!file)
157 goto bad_file;
158 if (!(file->f_mode & FMODE_WRITE))
159 goto out;
160 inode = file->f_dentry->d_inode;
161 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
162 file->f_pos, count);
163 if (ret)
164 goto out;
165 ret = -EINVAL;
166 if (!file->f_op || !(write = file->f_op->write))
167 goto out;
169 down(&inode->i_sem);
170 ret = write(file, buf, count, &file->f_pos);
171 up(&inode->i_sem);
172 out:
173 fput(file);
174 bad_file:
175 unlock_kernel();
176 return ret;
180 static ssize_t do_readv_writev(int type, struct file *file,
181 const struct iovec * vector,
182 unsigned long count)
184 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
186 size_t tot_len;
187 struct iovec iovstack[UIO_FASTIOV];
188 struct iovec *iov=iovstack;
189 ssize_t ret, i;
190 io_fn_t fn;
191 struct inode *inode;
194 * First get the "struct iovec" from user memory and
195 * verify all the pointers
197 ret = 0;
198 if (!count)
199 goto out_nofree;
200 ret = -EINVAL;
201 if (count > UIO_MAXIOV)
202 goto out_nofree;
203 if (count > UIO_FASTIOV) {
204 ret = -ENOMEM;
205 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
206 if (!iov)
207 goto out_nofree;
209 ret = -EFAULT;
210 if (copy_from_user(iov, vector, count*sizeof(*vector)))
211 goto out;
213 tot_len = 0;
214 for (i = 0 ; i < count ; i++)
215 tot_len += iov[i].iov_len;
217 inode = file->f_dentry->d_inode;
218 /* VERIFY_WRITE actually means a read, as we write to user space */
219 ret = locks_verify_area((type == VERIFY_WRITE
220 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
221 inode, file, file->f_pos, tot_len);
222 if (ret) goto out;
225 * Then do the actual IO. Note that sockets need to be handled
226 * specially as they have atomicity guarantees and can handle
227 * iovec's natively
229 if (inode->i_sock) {
230 ret = sock_readv_writev(type,inode,file,iov,count,tot_len);
231 goto out;
234 ret = -EINVAL;
235 if (!file->f_op)
236 goto out;
238 /* VERIFY_WRITE actually means a read, as we write to user space */
239 fn = file->f_op->read;
240 if (type == VERIFY_READ)
241 fn = (io_fn_t) file->f_op->write;
243 ret = 0;
244 vector = iov;
245 while (count > 0) {
246 void * base;
247 size_t len;
248 ssize_t nr;
250 base = vector->iov_base;
251 len = vector->iov_len;
252 vector++;
253 count--;
255 nr = fn(file, base, len, &file->f_pos);
257 if (nr < 0) {
258 if (!ret) ret = nr;
259 break;
261 ret += nr;
262 if (nr != len)
263 break;
266 out:
267 if (iov != iovstack)
268 kfree(iov);
269 out_nofree:
270 return ret;
273 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
274 unsigned long count)
276 struct file * file;
277 ssize_t ret;
279 lock_kernel();
281 ret = -EBADF;
282 file = fget(fd);
283 if (!file)
284 goto bad_file;
285 if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ))
286 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
287 fput(file);
289 bad_file:
290 unlock_kernel();
291 return ret;
294 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
295 unsigned long count)
297 struct file * file;
298 ssize_t ret;
300 lock_kernel();
302 ret = -EBADF;
303 file = fget(fd);
304 if (!file)
305 goto bad_file;
306 if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) {
307 down(&file->f_dentry->d_inode->i_sem);
308 ret = do_readv_writev(VERIFY_READ, file, vector, count);
309 up(&file->f_dentry->d_inode->i_sem);
311 fput(file);
313 bad_file:
314 unlock_kernel();
315 return ret;
318 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
319 lseek back to original location. They fail just like lseek does on
320 non-seekable files. */
322 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
323 size_t count, loff_t pos)
325 ssize_t ret;
326 struct file * file;
327 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
329 lock_kernel();
331 ret = -EBADF;
332 file = fget(fd);
333 if (!file)
334 goto bad_file;
335 if (!(file->f_mode & FMODE_READ))
336 goto out;
337 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
338 file, pos, count);
339 if (ret)
340 goto out;
341 ret = -EINVAL;
342 if (!file->f_op || !(read = file->f_op->read))
343 goto out;
344 if (pos < 0)
345 goto out;
346 ret = read(file, buf, count, &pos);
347 out:
348 fput(file);
349 bad_file:
350 unlock_kernel();
351 return ret;
354 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
355 size_t count, loff_t pos)
357 ssize_t ret;
358 struct file * file;
359 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
361 lock_kernel();
363 ret = -EBADF;
364 file = fget(fd);
365 if (!file)
366 goto bad_file;
367 if (!(file->f_mode & FMODE_WRITE))
368 goto out;
369 ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
370 file, pos, count);
371 if (ret)
372 goto out;
373 ret = -EINVAL;
374 if (!file->f_op || !(write = file->f_op->write))
375 goto out;
376 if (pos < 0)
377 goto out;
379 down(&file->f_dentry->d_inode->i_sem);
380 ret = write(file, buf, count, &pos);
381 up(&file->f_dentry->d_inode->i_sem);
383 out:
384 fput(file);
385 bad_file:
386 unlock_kernel();
387 return ret;