aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/direct.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r--fs/nfs/direct.c142
1 files changed, 99 insertions, 43 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index afcab007a22b..5e8d82f6666b 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -263,17 +263,19 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
263 * handled automatically by nfs_direct_read_result(). Otherwise, if 263 * handled automatically by nfs_direct_read_result(). Otherwise, if
264 * no requests have been sent, just return an error. 264 * no requests have been sent, just return an error.
265 */ 265 */
266static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos) 266static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq,
267 const struct iovec *iov,
268 loff_t pos)
267{ 269{
268 struct nfs_open_context *ctx = dreq->ctx; 270 struct nfs_open_context *ctx = dreq->ctx;
269 struct inode *inode = ctx->path.dentry->d_inode; 271 struct inode *inode = ctx->path.dentry->d_inode;
272 unsigned long user_addr = (unsigned long)iov->iov_base;
273 size_t count = iov->iov_len;
270 size_t rsize = NFS_SERVER(inode)->rsize; 274 size_t rsize = NFS_SERVER(inode)->rsize;
271 unsigned int pgbase; 275 unsigned int pgbase;
272 int result; 276 int result;
273 ssize_t started = 0; 277 ssize_t started = 0;
274 278
275 get_dreq(dreq);
276
277 do { 279 do {
278 struct nfs_read_data *data; 280 struct nfs_read_data *data;
279 size_t bytes; 281 size_t bytes;
@@ -347,15 +349,46 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
347 count -= bytes; 349 count -= bytes;
348 } while (count != 0); 350 } while (count != 0);
349 351
352 if (started)
353 return started;
354 return result < 0 ? (ssize_t) result : -EFAULT;
355}
356
357static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
358 const struct iovec *iov,
359 unsigned long nr_segs,
360 loff_t pos)
361{
362 ssize_t result = -EINVAL;
363 size_t requested_bytes = 0;
364 unsigned long seg;
365
366 get_dreq(dreq);
367
368 for (seg = 0; seg < nr_segs; seg++) {
369 const struct iovec *vec = &iov[seg];
370 result = nfs_direct_read_schedule_segment(dreq, vec, pos);
371 if (result < 0)
372 break;
373 requested_bytes += result;
374 if ((size_t)result < vec->iov_len)
375 break;
376 pos += vec->iov_len;
377 }
378
350 if (put_dreq(dreq)) 379 if (put_dreq(dreq))
351 nfs_direct_complete(dreq); 380 nfs_direct_complete(dreq);
352 381
353 if (started) 382 if (requested_bytes != 0)
354 return 0; 383 return 0;
355 return result < 0 ? (ssize_t) result : -EFAULT; 384
385 if (result < 0)
386 return result;
387 return -EIO;
356} 388}
357 389
358static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos) 390static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
391 unsigned long nr_segs, loff_t pos)
359{ 392{
360 ssize_t result = 0; 393 ssize_t result = 0;
361 sigset_t oldset; 394 sigset_t oldset;
@@ -372,9 +405,8 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
372 if (!is_sync_kiocb(iocb)) 405 if (!is_sync_kiocb(iocb))
373 dreq->iocb = iocb; 406 dreq->iocb = iocb;
374 407
375 nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count);
376 rpc_clnt_sigmask(clnt, &oldset); 408 rpc_clnt_sigmask(clnt, &oldset);
377 result = nfs_direct_read_schedule(dreq, user_addr, count, pos); 409 result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos);
378 if (!result) 410 if (!result)
379 result = nfs_direct_wait(dreq); 411 result = nfs_direct_wait(dreq);
380 rpc_clnt_sigunmask(clnt, &oldset); 412 rpc_clnt_sigunmask(clnt, &oldset);
@@ -601,17 +633,19 @@ static const struct rpc_call_ops nfs_write_direct_ops = {
601 * handled automatically by nfs_direct_write_result(). Otherwise, if 633 * handled automatically by nfs_direct_write_result(). Otherwise, if
602 * no requests have been sent, just return an error. 634 * no requests have been sent, just return an error.
603 */ 635 */
604static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync) 636static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq,
637 const struct iovec *iov,
638 loff_t pos, int sync)
605{ 639{
606 struct nfs_open_context *ctx = dreq->ctx; 640 struct nfs_open_context *ctx = dreq->ctx;
607 struct inode *inode = ctx->path.dentry->d_inode; 641 struct inode *inode = ctx->path.dentry->d_inode;
642 unsigned long user_addr = (unsigned long)iov->iov_base;
643 size_t count = iov->iov_len;
608 size_t wsize = NFS_SERVER(inode)->wsize; 644 size_t wsize = NFS_SERVER(inode)->wsize;
609 unsigned int pgbase; 645 unsigned int pgbase;
610 int result; 646 int result;
611 ssize_t started = 0; 647 ssize_t started = 0;
612 648
613 get_dreq(dreq);
614
615 do { 649 do {
616 struct nfs_write_data *data; 650 struct nfs_write_data *data;
617 size_t bytes; 651 size_t bytes;
@@ -689,15 +723,48 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
689 count -= bytes; 723 count -= bytes;
690 } while (count != 0); 724 } while (count != 0);
691 725
726 if (started)
727 return started;
728 return result < 0 ? (ssize_t) result : -EFAULT;
729}
730
731static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
732 const struct iovec *iov,
733 unsigned long nr_segs,
734 loff_t pos, int sync)
735{
736 ssize_t result = 0;
737 size_t requested_bytes = 0;
738 unsigned long seg;
739
740 get_dreq(dreq);
741
742 for (seg = 0; seg < nr_segs; seg++) {
743 const struct iovec *vec = &iov[seg];
744 result = nfs_direct_write_schedule_segment(dreq, vec,
745 pos, sync);
746 if (result < 0)
747 break;
748 requested_bytes += result;
749 if ((size_t)result < vec->iov_len)
750 break;
751 pos += vec->iov_len;
752 }
753
692 if (put_dreq(dreq)) 754 if (put_dreq(dreq))
693 nfs_direct_write_complete(dreq, inode); 755 nfs_direct_write_complete(dreq, dreq->inode);
694 756
695 if (started) 757 if (requested_bytes != 0)
696 return 0; 758 return 0;
697 return result < 0 ? (ssize_t) result : -EFAULT; 759
760 if (result < 0)
761 return result;
762 return -EIO;
698} 763}
699 764
700static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos) 765static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
766 unsigned long nr_segs, loff_t pos,
767 size_t count)
701{ 768{
702 ssize_t result = 0; 769 ssize_t result = 0;
703 sigset_t oldset; 770 sigset_t oldset;
@@ -720,10 +787,8 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
720 if (!is_sync_kiocb(iocb)) 787 if (!is_sync_kiocb(iocb))
721 dreq->iocb = iocb; 788 dreq->iocb = iocb;
722 789
723 nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count);
724
725 rpc_clnt_sigmask(clnt, &oldset); 790 rpc_clnt_sigmask(clnt, &oldset);
726 result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync); 791 result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync);
727 if (!result) 792 if (!result)
728 result = nfs_direct_wait(dreq); 793 result = nfs_direct_wait(dreq);
729 rpc_clnt_sigunmask(clnt, &oldset); 794 rpc_clnt_sigunmask(clnt, &oldset);
@@ -759,21 +824,16 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
759 ssize_t retval = -EINVAL; 824 ssize_t retval = -EINVAL;
760 struct file *file = iocb->ki_filp; 825 struct file *file = iocb->ki_filp;
761 struct address_space *mapping = file->f_mapping; 826 struct address_space *mapping = file->f_mapping;
762 /* XXX: temporary */ 827 size_t count;
763 const char __user *buf = iov[0].iov_base; 828
764 size_t count = iov[0].iov_len; 829 count = iov_length(iov, nr_segs);
830 nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
765 831
766 dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", 832 dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n",
767 file->f_path.dentry->d_parent->d_name.name, 833 file->f_path.dentry->d_parent->d_name.name,
768 file->f_path.dentry->d_name.name, 834 file->f_path.dentry->d_name.name,
769 (unsigned long) count, (long long) pos); 835 count, (long long) pos);
770
771 if (nr_segs != 1)
772 goto out;
773 836
774 retval = -EFAULT;
775 if (!access_ok(VERIFY_WRITE, buf, count))
776 goto out;
777 retval = 0; 837 retval = 0;
778 if (!count) 838 if (!count)
779 goto out; 839 goto out;
@@ -782,7 +842,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
782 if (retval) 842 if (retval)
783 goto out; 843 goto out;
784 844
785 retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos); 845 retval = nfs_direct_read(iocb, iov, nr_segs, pos);
786 if (retval > 0) 846 if (retval > 0)
787 iocb->ki_pos = pos + retval; 847 iocb->ki_pos = pos + retval;
788 848
@@ -821,21 +881,21 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
821 ssize_t retval = -EINVAL; 881 ssize_t retval = -EINVAL;
822 struct file *file = iocb->ki_filp; 882 struct file *file = iocb->ki_filp;
823 struct address_space *mapping = file->f_mapping; 883 struct address_space *mapping = file->f_mapping;
824 /* XXX: temporary */ 884 size_t count;
825 const char __user *buf = iov[0].iov_base; 885
826 size_t count = iov[0].iov_len; 886 count = iov_length(iov, nr_segs);
887 nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);
827 888
828 dprintk("nfs: direct write(%s/%s, %lu@%Ld)\n", 889 dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n",
829 file->f_path.dentry->d_parent->d_name.name, 890 file->f_path.dentry->d_parent->d_name.name,
830 file->f_path.dentry->d_name.name, 891 file->f_path.dentry->d_name.name,
831 (unsigned long) count, (long long) pos); 892 count, (long long) pos);
832
833 if (nr_segs != 1)
834 goto out;
835 893
836 retval = generic_write_checks(file, &pos, &count, 0); 894 retval = generic_write_checks(file, &pos, &count, 0);
837 if (retval) 895 if (retval)
838 goto out; 896 goto out;
897 if (!count)
898 goto out; /* return 0 */
839 899
840 retval = -EINVAL; 900 retval = -EINVAL;
841 if ((ssize_t) count < 0) 901 if ((ssize_t) count < 0)
@@ -844,15 +904,11 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
844 if (!count) 904 if (!count)
845 goto out; 905 goto out;
846 906
847 retval = -EFAULT;
848 if (!access_ok(VERIFY_READ, buf, count))
849 goto out;
850
851 retval = nfs_sync_mapping(mapping); 907 retval = nfs_sync_mapping(mapping);
852 if (retval) 908 if (retval)
853 goto out; 909 goto out;
854 910
855 retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos); 911 retval = nfs_direct_write(iocb, iov, nr_segs, pos, count);
856 912
857 if (retval > 0) 913 if (retval > 0)
858 iocb->ki_pos = pos + retval; 914 iocb->ki_pos = pos + retval;