Import 2.3.10pre1
[davej-history.git] / fs / read_write.c
blobcf207fed0085c9b65fbebf65d8712d14b51b6ac7
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;
121 ret = -EBADF;
122 file = fget(fd);
123 if (file) {
124 if (file->f_mode & FMODE_READ) {
125 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
126 file, file->f_pos, count);
127 if (!ret) {
128 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
129 ret = -EINVAL;
130 if (file->f_op && (read = file->f_op->read) != NULL)
131 ret = read(file, buf, count, &file->f_pos);
134 fput(file);
136 return ret;
139 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
141 ssize_t ret;
142 struct file * file;
144 ret = -EBADF;
145 file = fget(fd);
146 if (file) {
147 if (file->f_mode & FMODE_WRITE) {
148 struct inode *inode = file->f_dentry->d_inode;
149 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
150 file->f_pos, count);
151 if (!ret) {
152 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
153 ret = -EINVAL;
154 if (file->f_op && (write = file->f_op->write) != NULL)
155 ret = write(file, buf, count, &file->f_pos);
158 fput(file);
160 return ret;
164 static ssize_t do_readv_writev(int type, struct file *file,
165 const struct iovec * vector,
166 unsigned long count)
168 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
170 size_t tot_len;
171 struct iovec iovstack[UIO_FASTIOV];
172 struct iovec *iov=iovstack;
173 ssize_t ret, i;
174 io_fn_t fn;
175 struct inode *inode;
178 * First get the "struct iovec" from user memory and
179 * verify all the pointers
181 ret = 0;
182 if (!count)
183 goto out_nofree;
184 ret = -EINVAL;
185 if (count > UIO_MAXIOV)
186 goto out_nofree;
187 if (count > UIO_FASTIOV) {
188 ret = -ENOMEM;
189 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
190 if (!iov)
191 goto out_nofree;
193 ret = -EFAULT;
194 if (copy_from_user(iov, vector, count*sizeof(*vector)))
195 goto out;
197 tot_len = 0;
198 for (i = 0 ; i < count ; i++)
199 tot_len += iov[i].iov_len;
201 inode = file->f_dentry->d_inode;
202 /* VERIFY_WRITE actually means a read, as we write to user space */
203 ret = locks_verify_area((type == VERIFY_WRITE
204 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
205 inode, file, file->f_pos, tot_len);
206 if (ret) goto out;
209 * Then do the actual IO. Note that sockets need to be handled
210 * specially as they have atomicity guarantees and can handle
211 * iovec's natively
213 if (inode->i_sock) {
214 ret = sock_readv_writev(type,inode,file,iov,count,tot_len);
215 goto out;
218 ret = -EINVAL;
219 if (!file->f_op)
220 goto out;
222 /* VERIFY_WRITE actually means a read, as we write to user space */
223 fn = file->f_op->read;
224 if (type == VERIFY_READ)
225 fn = (io_fn_t) file->f_op->write;
227 ret = 0;
228 vector = iov;
229 while (count > 0) {
230 void * base;
231 size_t len;
232 ssize_t nr;
234 base = vector->iov_base;
235 len = vector->iov_len;
236 vector++;
237 count--;
239 nr = fn(file, base, len, &file->f_pos);
241 if (nr < 0) {
242 if (!ret) ret = nr;
243 break;
245 ret += nr;
246 if (nr != len)
247 break;
250 out:
251 if (iov != iovstack)
252 kfree(iov);
253 out_nofree:
254 return ret;
257 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
258 unsigned long count)
260 struct file * file;
261 ssize_t ret;
263 lock_kernel();
265 ret = -EBADF;
266 file = fget(fd);
267 if (!file)
268 goto bad_file;
269 if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ))
270 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
271 fput(file);
273 bad_file:
274 unlock_kernel();
275 return ret;
278 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
279 unsigned long count)
281 struct file * file;
282 ssize_t ret;
284 lock_kernel();
286 ret = -EBADF;
287 file = fget(fd);
288 if (!file)
289 goto bad_file;
290 if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) {
291 ret = do_readv_writev(VERIFY_READ, file, vector, count);
293 fput(file);
295 bad_file:
296 unlock_kernel();
297 return ret;
300 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
301 lseek back to original location. They fail just like lseek does on
302 non-seekable files. */
304 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
305 size_t count, loff_t pos)
307 ssize_t ret;
308 struct file * file;
309 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
311 lock_kernel();
313 ret = -EBADF;
314 file = fget(fd);
315 if (!file)
316 goto bad_file;
317 if (!(file->f_mode & FMODE_READ))
318 goto out;
319 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
320 file, pos, count);
321 if (ret)
322 goto out;
323 ret = -EINVAL;
324 if (!file->f_op || !(read = file->f_op->read))
325 goto out;
326 if (pos < 0)
327 goto out;
328 ret = read(file, buf, count, &pos);
329 out:
330 fput(file);
331 bad_file:
332 unlock_kernel();
333 return ret;
336 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
337 size_t count, loff_t pos)
339 ssize_t ret;
340 struct file * file;
341 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
343 lock_kernel();
345 ret = -EBADF;
346 file = fget(fd);
347 if (!file)
348 goto bad_file;
349 if (!(file->f_mode & FMODE_WRITE))
350 goto out;
351 ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
352 file, pos, count);
353 if (ret)
354 goto out;
355 ret = -EINVAL;
356 if (!file->f_op || !(write = file->f_op->write))
357 goto out;
358 if (pos < 0)
359 goto out;
361 ret = write(file, buf, count, &pos);
362 out:
363 fput(file);
364 bad_file:
365 unlock_kernel();
366 return ret;