diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2007-11-12 12:16:52 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-11-26 16:32:36 -0500 |
commit | c216fd708e1a97431925ecffd6d1896cff61df0a (patch) | |
tree | 3f6e61bb72f5c852773faad9a5baaec00adae39e /fs/nfs/direct.c | |
parent | 19f737879cc623c3aa73e655465faa3bff121768 (diff) |
NFS: Support multiple segment iovecs in the NFS direct I/O path
Allow applications to perform asynchronous scatter-gather direct I/O
to NFS files.
Signed-off-by: Chuck Lever <cel@netapp.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r-- | fs/nfs/direct.c | 67 |
1 files changed, 23 insertions, 44 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index e30d9285a566..88d5d1c7f987 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -272,8 +272,6 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo | |||
272 | int result; | 272 | int result; |
273 | ssize_t started = 0; | 273 | ssize_t started = 0; |
274 | 274 | ||
275 | get_dreq(dreq); | ||
276 | |||
277 | do { | 275 | do { |
278 | struct nfs_read_data *data; | 276 | struct nfs_read_data *data; |
279 | size_t bytes; | 277 | size_t bytes; |
@@ -347,11 +345,8 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo | |||
347 | count -= bytes; | 345 | count -= bytes; |
348 | } while (count != 0); | 346 | } while (count != 0); |
349 | 347 | ||
350 | if (put_dreq(dreq)) | ||
351 | nfs_direct_complete(dreq); | ||
352 | |||
353 | if (started) | 348 | if (started) |
354 | return 0; | 349 | return started; |
355 | return result < 0 ? (ssize_t) result : -EFAULT; | 350 | return result < 0 ? (ssize_t) result : -EFAULT; |
356 | } | 351 | } |
357 | 352 | ||
@@ -390,7 +385,8 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | |||
390 | return -EIO; | 385 | return -EIO; |
391 | } | 386 | } |
392 | 387 | ||
393 | static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos) | 388 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, |
389 | unsigned long nr_segs, loff_t pos) | ||
394 | { | 390 | { |
395 | ssize_t result = 0; | 391 | ssize_t result = 0; |
396 | sigset_t oldset; | 392 | sigset_t oldset; |
@@ -407,9 +403,8 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size | |||
407 | if (!is_sync_kiocb(iocb)) | 403 | if (!is_sync_kiocb(iocb)) |
408 | dreq->iocb = iocb; | 404 | dreq->iocb = iocb; |
409 | 405 | ||
410 | nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count); | ||
411 | rpc_clnt_sigmask(clnt, &oldset); | 406 | rpc_clnt_sigmask(clnt, &oldset); |
412 | result = nfs_direct_read_schedule(dreq, user_addr, count, pos); | 407 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); |
413 | if (!result) | 408 | if (!result) |
414 | result = nfs_direct_wait(dreq); | 409 | result = nfs_direct_wait(dreq); |
415 | rpc_clnt_sigunmask(clnt, &oldset); | 410 | rpc_clnt_sigunmask(clnt, &oldset); |
@@ -645,8 +640,6 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l | |||
645 | int result; | 640 | int result; |
646 | ssize_t started = 0; | 641 | ssize_t started = 0; |
647 | 642 | ||
648 | get_dreq(dreq); | ||
649 | |||
650 | do { | 643 | do { |
651 | struct nfs_write_data *data; | 644 | struct nfs_write_data *data; |
652 | size_t bytes; | 645 | size_t bytes; |
@@ -724,11 +717,8 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l | |||
724 | count -= bytes; | 717 | count -= bytes; |
725 | } while (count != 0); | 718 | } while (count != 0); |
726 | 719 | ||
727 | if (put_dreq(dreq)) | ||
728 | nfs_direct_write_complete(dreq, inode); | ||
729 | |||
730 | if (started) | 720 | if (started) |
731 | return 0; | 721 | return started; |
732 | return result < 0 ? (ssize_t) result : -EFAULT; | 722 | return result < 0 ? (ssize_t) result : -EFAULT; |
733 | } | 723 | } |
734 | 724 | ||
@@ -768,7 +758,9 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | |||
768 | return -EIO; | 758 | return -EIO; |
769 | } | 759 | } |
770 | 760 | ||
771 | static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos) | 761 | static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, |
762 | unsigned long nr_segs, loff_t pos, | ||
763 | size_t count) | ||
772 | { | 764 | { |
773 | ssize_t result = 0; | 765 | ssize_t result = 0; |
774 | sigset_t oldset; | 766 | sigset_t oldset; |
@@ -791,10 +783,8 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz | |||
791 | if (!is_sync_kiocb(iocb)) | 783 | if (!is_sync_kiocb(iocb)) |
792 | dreq->iocb = iocb; | 784 | dreq->iocb = iocb; |
793 | 785 | ||
794 | nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count); | ||
795 | |||
796 | rpc_clnt_sigmask(clnt, &oldset); | 786 | rpc_clnt_sigmask(clnt, &oldset); |
797 | result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync); | 787 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); |
798 | if (!result) | 788 | if (!result) |
799 | result = nfs_direct_wait(dreq); | 789 | result = nfs_direct_wait(dreq); |
800 | rpc_clnt_sigunmask(clnt, &oldset); | 790 | rpc_clnt_sigunmask(clnt, &oldset); |
@@ -830,21 +820,16 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
830 | ssize_t retval = -EINVAL; | 820 | ssize_t retval = -EINVAL; |
831 | struct file *file = iocb->ki_filp; | 821 | struct file *file = iocb->ki_filp; |
832 | struct address_space *mapping = file->f_mapping; | 822 | struct address_space *mapping = file->f_mapping; |
833 | /* XXX: temporary */ | 823 | size_t count; |
834 | const char __user *buf = iov[0].iov_base; | 824 | |
835 | size_t count = iov[0].iov_len; | 825 | count = iov_length(iov, nr_segs); |
826 | nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); | ||
836 | 827 | ||
837 | dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", | 828 | dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n", |
838 | file->f_path.dentry->d_parent->d_name.name, | 829 | file->f_path.dentry->d_parent->d_name.name, |
839 | file->f_path.dentry->d_name.name, | 830 | file->f_path.dentry->d_name.name, |
840 | (unsigned long) count, (long long) pos); | 831 | count, (long long) pos); |
841 | 832 | ||
842 | if (nr_segs != 1) | ||
843 | goto out; | ||
844 | |||
845 | retval = -EFAULT; | ||
846 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
847 | goto out; | ||
848 | retval = 0; | 833 | retval = 0; |
849 | if (!count) | 834 | if (!count) |
850 | goto out; | 835 | goto out; |
@@ -853,7 +838,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
853 | if (retval) | 838 | if (retval) |
854 | goto out; | 839 | goto out; |
855 | 840 | ||
856 | retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos); | 841 | retval = nfs_direct_read(iocb, iov, nr_segs, pos); |
857 | if (retval > 0) | 842 | if (retval > 0) |
858 | iocb->ki_pos = pos + retval; | 843 | iocb->ki_pos = pos + retval; |
859 | 844 | ||
@@ -892,17 +877,15 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
892 | ssize_t retval = -EINVAL; | 877 | ssize_t retval = -EINVAL; |
893 | struct file *file = iocb->ki_filp; | 878 | struct file *file = iocb->ki_filp; |
894 | struct address_space *mapping = file->f_mapping; | 879 | struct address_space *mapping = file->f_mapping; |
895 | /* XXX: temporary */ | 880 | size_t count; |
896 | const char __user *buf = iov[0].iov_base; | ||
897 | size_t count = iov[0].iov_len; | ||
898 | 881 | ||
899 | dprintk("nfs: direct write(%s/%s, %lu@%Ld)\n", | 882 | count = iov_length(iov, nr_segs); |
883 | nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); | ||
884 | |||
885 | dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n", | ||
900 | file->f_path.dentry->d_parent->d_name.name, | 886 | file->f_path.dentry->d_parent->d_name.name, |
901 | file->f_path.dentry->d_name.name, | 887 | file->f_path.dentry->d_name.name, |
902 | (unsigned long) count, (long long) pos); | 888 | count, (long long) pos); |
903 | |||
904 | if (nr_segs != 1) | ||
905 | goto out; | ||
906 | 889 | ||
907 | retval = generic_write_checks(file, &pos, &count, 0); | 890 | retval = generic_write_checks(file, &pos, &count, 0); |
908 | if (retval) | 891 | if (retval) |
@@ -915,15 +898,11 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
915 | if (!count) | 898 | if (!count) |
916 | goto out; | 899 | goto out; |
917 | 900 | ||
918 | retval = -EFAULT; | ||
919 | if (!access_ok(VERIFY_READ, buf, count)) | ||
920 | goto out; | ||
921 | |||
922 | retval = nfs_sync_mapping(mapping); | 901 | retval = nfs_sync_mapping(mapping); |
923 | if (retval) | 902 | if (retval) |
924 | goto out; | 903 | goto out; |
925 | 904 | ||
926 | retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos); | 905 | retval = nfs_direct_write(iocb, iov, nr_segs, pos, count); |
927 | 906 | ||
928 | if (retval > 0) | 907 | if (retval > 0) |
929 | iocb->ki_pos = pos + retval; | 908 | iocb->ki_pos = pos + retval; |