diff options
author | Jeff Layton <jlayton@redhat.com> | 2007-05-09 05:34:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-09 15:30:54 -0400 |
commit | cd123012d99fde4759500fee611e724e4f3016e3 (patch) | |
tree | a947c5e4210a2a51ea6619b3e127650feaa00421 | |
parent | 669716433598a1498049e75a84a5aaf69c8da173 (diff) |
RPC: add wrapper for svc_reserve to account for checksum
When the kernel calls svc_reserve to downsize the expected size of an RPC
reply, it fails to account for the possibility of a checksum at the end of
the packet. If a client mounts a NFSv2/3 with sec=krb5i/p, and does I/O
then you'll generally see messages similar to this in the server's ring
buffer:
RPC request reserved 164 but used 208
While I was never able to verify it, I suspect that this problem is also
the root cause of some oopses I've seen under these conditions:
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=227726
This is probably also a problem for other sec= types and for NFSv4. The
large reserved size for NFSv4 compound packets seems to generally paper
over the problem, however.
This patch adds a wrapper for svc_reserve that accounts for the possibility
of a checksum. It also fixes up the appropriate callers of svc_reserve to
call the wrapper. For now, it just uses a hardcoded value that I
determined via testing. That value may need to be revised upward as things
change, or we may want to eventually add a new auth_op that attempts to
calculate this somehow.
Unfortunately, there doesn't seem to be a good way to reliably determine
the expected checksum length prior to actually calculating it, particularly
with schemes like spkm3.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Acked-by: Neil Brown <neilb@suse.de>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Acked-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/nfsd/nfs3proc.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfsproc.c | 2 | ||||
-rw-r--r-- | include/linux/sunrpc/svc.h | 19 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 2 |
4 files changed, 22 insertions, 3 deletions
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 7f5bad0393b1..eac82830bfd7 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
@@ -177,7 +177,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, | |||
177 | if (max_blocksize < resp->count) | 177 | if (max_blocksize < resp->count) |
178 | resp->count = max_blocksize; | 178 | resp->count = max_blocksize; |
179 | 179 | ||
180 | svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); | 180 | svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); |
181 | 181 | ||
182 | fh_copy(&resp->fh, &argp->fh); | 182 | fh_copy(&resp->fh, &argp->fh); |
183 | nfserr = nfsd_read(rqstp, &resp->fh, NULL, | 183 | nfserr = nfsd_read(rqstp, &resp->fh, NULL, |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 5cc2eec981b8..b2c7147aa921 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -155,7 +155,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, | |||
155 | argp->count); | 155 | argp->count); |
156 | argp->count = NFSSVC_MAXBLKSIZE_V2; | 156 | argp->count = NFSSVC_MAXBLKSIZE_V2; |
157 | } | 157 | } |
158 | svc_reserve(rqstp, (19<<2) + argp->count + 4); | 158 | svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); |
159 | 159 | ||
160 | resp->count = argp->count; | 160 | resp->count = argp->count; |
161 | nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, | 161 | nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, |
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 35fa4d5aadd0..4a7ae8ab6eb8 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
@@ -396,4 +396,23 @@ char * svc_print_addr(struct svc_rqst *, char *, size_t); | |||
396 | 396 | ||
397 | #define RPC_MAX_ADDRBUFLEN (63U) | 397 | #define RPC_MAX_ADDRBUFLEN (63U) |
398 | 398 | ||
399 | /* | ||
400 | * When we want to reduce the size of the reserved space in the response | ||
401 | * buffer, we need to take into account the size of any checksum data that | ||
402 | * may be at the end of the packet. This is difficult to determine exactly | ||
403 | * for all cases without actually generating the checksum, so we just use a | ||
404 | * static value. | ||
405 | */ | ||
406 | static inline void | ||
407 | svc_reserve_auth(struct svc_rqst *rqstp, int space) | ||
408 | { | ||
409 | int added_space = 0; | ||
410 | |||
411 | switch(rqstp->rq_authop->flavour) { | ||
412 | case RPC_AUTH_GSS: | ||
413 | added_space = RPC_MAX_AUTH_SIZE; | ||
414 | } | ||
415 | return svc_reserve(rqstp, space + added_space); | ||
416 | } | ||
417 | |||
399 | #endif /* SUNRPC_SVC_H */ | 418 | #endif /* SUNRPC_SVC_H */ |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index b7503c103ae8..e673ef993904 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -907,7 +907,7 @@ svc_process(struct svc_rqst *rqstp) | |||
907 | * better idea of reply size | 907 | * better idea of reply size |
908 | */ | 908 | */ |
909 | if (procp->pc_xdrressize) | 909 | if (procp->pc_xdrressize) |
910 | svc_reserve(rqstp, procp->pc_xdrressize<<2); | 910 | svc_reserve_auth(rqstp, procp->pc_xdrressize<<2); |
911 | 911 | ||
912 | /* Call the function that processes the request. */ | 912 | /* Call the function that processes the request. */ |
913 | if (!versp->vs_dispatch) { | 913 | if (!versp->vs_dispatch) { |