Commit cd123012d99fde4759500fee611e724e4f3016e3

Authored by Jeff Layton
Committed by Linus Torvalds
1 parent 6697164335

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

... ... @@ -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,
... ... @@ -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 */
... ... @@ -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) {