Commit cd123012d99fde4759500fee611e724e4f3016e3
Committed by
Linus Torvalds
1 parent
6697164335
Exists in
master
and in
7 other branches
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>
Showing 4 changed files with 22 additions and 3 deletions Side-by-side Diff
fs/nfsd/nfs3proc.c
... | ... | @@ -177,7 +177,7 @@ |
177 | 177 | if (max_blocksize < resp->count) |
178 | 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 | 182 | fh_copy(&resp->fh, &argp->fh); |
183 | 183 | nfserr = nfsd_read(rqstp, &resp->fh, NULL, |
fs/nfsd/nfsproc.c
... | ... | @@ -155,7 +155,7 @@ |
155 | 155 | argp->count); |
156 | 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 | 160 | resp->count = argp->count; |
161 | 161 | nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, |
include/linux/sunrpc/svc.h
... | ... | @@ -396,5 +396,24 @@ |
396 | 396 | |
397 | 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 | 418 | #endif /* SUNRPC_SVC_H */ |
net/sunrpc/svc.c
... | ... | @@ -907,7 +907,7 @@ |
907 | 907 | * better idea of reply size |
908 | 908 | */ |
909 | 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 | 912 | /* Call the function that processes the request. */ |
913 | 913 | if (!versp->vs_dispatch) { |