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>
This commit is contained in:
parent
6697164335
commit
cd123012d9
|
@ -177,7 +177,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
|
||||||
if (max_blocksize < resp->count)
|
if (max_blocksize < resp->count)
|
||||||
resp->count = max_blocksize;
|
resp->count = max_blocksize;
|
||||||
|
|
||||||
svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
|
svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
|
||||||
|
|
||||||
fh_copy(&resp->fh, &argp->fh);
|
fh_copy(&resp->fh, &argp->fh);
|
||||||
nfserr = nfsd_read(rqstp, &resp->fh, NULL,
|
nfserr = nfsd_read(rqstp, &resp->fh, NULL,
|
||||||
|
|
|
@ -155,7 +155,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
|
||||||
argp->count);
|
argp->count);
|
||||||
argp->count = NFSSVC_MAXBLKSIZE_V2;
|
argp->count = NFSSVC_MAXBLKSIZE_V2;
|
||||||
}
|
}
|
||||||
svc_reserve(rqstp, (19<<2) + argp->count + 4);
|
svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
|
||||||
|
|
||||||
resp->count = argp->count;
|
resp->count = argp->count;
|
||||||
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
|
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
|
||||||
|
|
|
@ -396,4 +396,23 @@ char * svc_print_addr(struct svc_rqst *, char *, size_t);
|
||||||
|
|
||||||
#define RPC_MAX_ADDRBUFLEN (63U)
|
#define RPC_MAX_ADDRBUFLEN (63U)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When we want to reduce the size of the reserved space in the response
|
||||||
|
* buffer, we need to take into account the size of any checksum data that
|
||||||
|
* may be at the end of the packet. This is difficult to determine exactly
|
||||||
|
* for all cases without actually generating the checksum, so we just use a
|
||||||
|
* static value.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
svc_reserve_auth(struct svc_rqst *rqstp, int space)
|
||||||
|
{
|
||||||
|
int added_space = 0;
|
||||||
|
|
||||||
|
switch(rqstp->rq_authop->flavour) {
|
||||||
|
case RPC_AUTH_GSS:
|
||||||
|
added_space = RPC_MAX_AUTH_SIZE;
|
||||||
|
}
|
||||||
|
return svc_reserve(rqstp, space + added_space);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SUNRPC_SVC_H */
|
#endif /* SUNRPC_SVC_H */
|
||||||
|
|
|
@ -907,7 +907,7 @@ svc_process(struct svc_rqst *rqstp)
|
||||||
* better idea of reply size
|
* better idea of reply size
|
||||||
*/
|
*/
|
||||||
if (procp->pc_xdrressize)
|
if (procp->pc_xdrressize)
|
||||||
svc_reserve(rqstp, procp->pc_xdrressize<<2);
|
svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
|
||||||
|
|
||||||
/* Call the function that processes the request. */
|
/* Call the function that processes the request. */
|
||||||
if (!versp->vs_dispatch) {
|
if (!versp->vs_dispatch) {
|
||||||
|
|
Loading…
Reference in a new issue