aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/nfs/nfs41-server.txt4
-rw-r--r--fs/nfsd/nfs4proc.c24
-rw-r--r--fs/nfsd/nfs4xdr.c20
-rw-r--r--fs/nfsd/xdr4.h1
4 files changed, 25 insertions, 24 deletions
diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt
index 392ef637e101..01c2db769791 100644
--- a/Documentation/filesystems/nfs/nfs41-server.txt
+++ b/Documentation/filesystems/nfs/nfs41-server.txt
@@ -190,7 +190,7 @@ Nonstandard compound limitations:
190 ca_maxrequestsize request and a ca_maxresponsesize reply, so we may 190 ca_maxrequestsize request and a ca_maxresponsesize reply, so we may
191 fail to live up to the promise we made in CREATE_SESSION fore channel 191 fail to live up to the promise we made in CREATE_SESSION fore channel
192 negotiation. 192 negotiation.
193* No more than one IO operation (read, write, readdir) allowed per 193* No more than one read-like operation allowed per compound; encoding
194 compound. 194 replies that cross page boundaries (except for read data) not handled.
195 195
196See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues. 196See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues.
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 1d2396b79574..87d24e5f3ca4 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -881,6 +881,24 @@ out:
881 return status; 881 return status;
882} 882}
883 883
884static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
885{
886 int i = 1;
887 int buflen = write->wr_buflen;
888
889 vec[0].iov_base = write->wr_head.iov_base;
890 vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len);
891 buflen -= vec[0].iov_len;
892
893 while (buflen) {
894 vec[i].iov_base = page_address(write->wr_pagelist[i - 1]);
895 vec[i].iov_len = min_t(int, PAGE_SIZE, buflen);
896 buflen -= vec[i].iov_len;
897 i++;
898 }
899 return i;
900}
901
884static __be32 902static __be32
885nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 903nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
886 struct nfsd4_write *write) 904 struct nfsd4_write *write)
@@ -889,6 +907,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
889 struct file *filp = NULL; 907 struct file *filp = NULL;
890 __be32 status = nfs_ok; 908 __be32 status = nfs_ok;
891 unsigned long cnt; 909 unsigned long cnt;
910 int nvecs;
892 911
893 /* no need to check permission - this will be done in nfsd_write() */ 912 /* no need to check permission - this will be done in nfsd_write() */
894 913
@@ -911,8 +930,11 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
911 write->wr_how_written = write->wr_stable_how; 930 write->wr_how_written = write->wr_stable_how;
912 gen_boot_verifier(&write->wr_verifier); 931 gen_boot_verifier(&write->wr_verifier);
913 932
933 nvecs = fill_in_write_vector(rqstp->rq_vec, write);
934 WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));
935
914 status = nfsd_write(rqstp, &cstate->current_fh, filp, 936 status = nfsd_write(rqstp, &cstate->current_fh, filp,
915 write->wr_offset, rqstp->rq_vec, write->wr_vlen, 937 write->wr_offset, rqstp->rq_vec, nvecs,
916 &cnt, &write->wr_how_written); 938 &cnt, &write->wr_how_written);
917 if (filp) 939 if (filp)
918 fput(filp); 940 fput(filp);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index cb9f9017af8f..09204f590355 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1139,24 +1139,6 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
1139 DECODE_TAIL; 1139 DECODE_TAIL;
1140} 1140}
1141 1141
1142static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
1143{
1144 int i = 1;
1145 int buflen = write->wr_buflen;
1146
1147 vec[0].iov_base = write->wr_head.iov_base;
1148 vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len);
1149 buflen -= vec[0].iov_len;
1150
1151 while (buflen) {
1152 vec[i].iov_base = page_address(write->wr_pagelist[i - 1]);
1153 vec[i].iov_len = min_t(int, PAGE_SIZE, buflen);
1154 buflen -= vec[i].iov_len;
1155 i++;
1156 }
1157 return i;
1158}
1159
1160static __be32 1142static __be32
1161nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) 1143nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
1162{ 1144{
@@ -1204,8 +1186,6 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
1204 argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); 1186 argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE);
1205 } 1187 }
1206 argp->p += XDR_QUADLEN(len); 1188 argp->p += XDR_QUADLEN(len);
1207 write->wr_vlen = fill_in_write_vector(argp->rqstp->rq_vec, write);
1208 WARN_ON_ONCE(write->wr_vlen > ARRAY_SIZE(argp->rqstp->rq_vec));
1209 1189
1210 DECODE_TAIL; 1190 DECODE_TAIL;
1211} 1191}
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 152867b8125d..331f8a3277ab 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -385,7 +385,6 @@ struct nfsd4_write {
385 u64 wr_offset; /* request */ 385 u64 wr_offset; /* request */
386 u32 wr_stable_how; /* request */ 386 u32 wr_stable_how; /* request */
387 u32 wr_buflen; /* request */ 387 u32 wr_buflen; /* request */
388 int wr_vlen;
389 struct kvec wr_head; 388 struct kvec wr_head;
390 struct page ** wr_pagelist; /* request */ 389 struct page ** wr_pagelist; /* request */
391 390