aboutsummaryrefslogtreecommitdiffstats
path: root/fs/read_write.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/read_write.c')
-rw-r--r--fs/read_write.c101
1 files changed, 67 insertions, 34 deletions
diff --git a/fs/read_write.c b/fs/read_write.c
index 679dd535380f..32d54cca9bd9 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -15,6 +15,7 @@
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/syscalls.h> 16#include <linux/syscalls.h>
17#include <linux/pagemap.h> 17#include <linux/pagemap.h>
18#include "read_write.h"
18 19
19#include <asm/uaccess.h> 20#include <asm/uaccess.h>
20#include <asm/unistd.h> 21#include <asm/unistd.h>
@@ -450,6 +451,62 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
450 451
451EXPORT_UNUSED_SYMBOL(iov_shorten); /* June 2006 */ 452EXPORT_UNUSED_SYMBOL(iov_shorten); /* June 2006 */
452 453
454ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
455 unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
456{
457 struct kiocb kiocb;
458 ssize_t ret;
459
460 init_sync_kiocb(&kiocb, filp);
461 kiocb.ki_pos = *ppos;
462 kiocb.ki_left = len;
463 kiocb.ki_nbytes = len;
464
465 for (;;) {
466 ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos);
467 if (ret != -EIOCBRETRY)
468 break;
469 wait_on_retry_sync_kiocb(&kiocb);
470 }
471
472 if (ret == -EIOCBQUEUED)
473 ret = wait_on_sync_kiocb(&kiocb);
474 *ppos = kiocb.ki_pos;
475 return ret;
476}
477
478/* Do it by hand, with file-ops */
479ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
480 unsigned long nr_segs, loff_t *ppos, io_fn_t fn)
481{
482 struct iovec *vector = iov;
483 ssize_t ret = 0;
484
485 while (nr_segs > 0) {
486 void __user *base;
487 size_t len;
488 ssize_t nr;
489
490 base = vector->iov_base;
491 len = vector->iov_len;
492 vector++;
493 nr_segs--;
494
495 nr = fn(filp, base, len, ppos);
496
497 if (nr < 0) {
498 if (!ret)
499 ret = nr;
500 break;
501 }
502 ret += nr;
503 if (nr != len)
504 break;
505 }
506
507 return ret;
508}
509
453/* A write operation does a read from user space and vice versa */ 510/* A write operation does a read from user space and vice versa */
454#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) 511#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
455 512
@@ -457,12 +514,9 @@ static ssize_t do_readv_writev(int type, struct file *file,
457 const struct iovec __user * uvector, 514 const struct iovec __user * uvector,
458 unsigned long nr_segs, loff_t *pos) 515 unsigned long nr_segs, loff_t *pos)
459{ 516{
460 typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
461 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
462
463 size_t tot_len; 517 size_t tot_len;
464 struct iovec iovstack[UIO_FASTIOV]; 518 struct iovec iovstack[UIO_FASTIOV];
465 struct iovec *iov=iovstack, *vector; 519 struct iovec *iov = iovstack;
466 ssize_t ret; 520 ssize_t ret;
467 int seg; 521 int seg;
468 io_fn_t fn; 522 io_fn_t fn;
@@ -532,39 +586,18 @@ static ssize_t do_readv_writev(int type, struct file *file,
532 fnv = NULL; 586 fnv = NULL;
533 if (type == READ) { 587 if (type == READ) {
534 fn = file->f_op->read; 588 fn = file->f_op->read;
535 fnv = file->f_op->readv; 589 fnv = file->f_op->aio_read;
536 } else { 590 } else {
537 fn = (io_fn_t)file->f_op->write; 591 fn = (io_fn_t)file->f_op->write;
538 fnv = file->f_op->writev; 592 fnv = file->f_op->aio_write;
539 }
540 if (fnv) {
541 ret = fnv(file, iov, nr_segs, pos);
542 goto out;
543 } 593 }
544 594
545 /* Do it by hand, with file-ops */ 595 if (fnv)
546 ret = 0; 596 ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
547 vector = iov; 597 pos, fnv);
548 while (nr_segs > 0) { 598 else
549 void __user * base; 599 ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
550 size_t len;
551 ssize_t nr;
552
553 base = vector->iov_base;
554 len = vector->iov_len;
555 vector++;
556 nr_segs--;
557
558 nr = fn(file, base, len, pos);
559 600
560 if (nr < 0) {
561 if (!ret) ret = nr;
562 break;
563 }
564 ret += nr;
565 if (nr != len)
566 break;
567 }
568out: 601out:
569 if (iov != iovstack) 602 if (iov != iovstack)
570 kfree(iov); 603 kfree(iov);
@@ -585,7 +618,7 @@ ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
585{ 618{
586 if (!(file->f_mode & FMODE_READ)) 619 if (!(file->f_mode & FMODE_READ))
587 return -EBADF; 620 return -EBADF;
588 if (!file->f_op || (!file->f_op->readv && !file->f_op->read)) 621 if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
589 return -EINVAL; 622 return -EINVAL;
590 623
591 return do_readv_writev(READ, file, vec, vlen, pos); 624 return do_readv_writev(READ, file, vec, vlen, pos);
@@ -598,7 +631,7 @@ ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
598{ 631{
599 if (!(file->f_mode & FMODE_WRITE)) 632 if (!(file->f_mode & FMODE_WRITE))
600 return -EBADF; 633 return -EBADF;
601 if (!file->f_op || (!file->f_op->writev && !file->f_op->write)) 634 if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
602 return -EINVAL; 635 return -EINVAL;
603 636
604 return do_readv_writev(WRITE, file, vec, vlen, pos); 637 return do_readv_writev(WRITE, file, vec, vlen, pos);