diff options
author | J. Bruce Fields <bfields@redhat.com> | 2014-03-13 05:39:35 +0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-05-31 01:32:02 +0400 |
commit | 47ee52986472dba068e8223cbaf1b65d74238781 (patch) | |
tree | 4436adf69861759600318696325b8bb9633d4602 /fs/nfsd | |
parent | db3f58a95beea6752d90fed03f9f198d282a3913 (diff) | |
download | linux-47ee52986472dba068e8223cbaf1b65d74238781.tar.xz |
nfsd4: adjust buflen to session channel limit
We can simplify session limit enforcement by restricting the xdr buflen
to the session size.
Also fix a preexisting bug: we should really have been taking into
account the auth-required space when comparing against session limits,
which are limits on the size of the entire rpc reply, including any krb5
overhead.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4state.c | 11 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 24 |
2 files changed, 19 insertions, 16 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8e22ea485f99..612b85ac414b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2208,11 +2208,13 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_sequence *seq) { struct nfsd4_compoundres *resp = rqstp->rq_resp; + struct xdr_stream *xdr = &resp->xdr; struct nfsd4_session *session; struct nfs4_client *clp; struct nfsd4_slot *slot; struct nfsd4_conn *conn; __be32 status; + int buflen; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); if (resp->opcnt != 1) @@ -2281,6 +2283,15 @@ nfsd4_sequence(struct svc_rqst *rqstp, if (status) goto out_put_session; + buflen = (seq->cachethis) ? + session->se_fchannel.maxresp_cached : + session->se_fchannel.maxresp_sz; + status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : + nfserr_rep_too_big; + if (xdr_restrict_buflen(xdr, buflen - 2 * RPC_MAX_AUTH_SIZE)) + goto out_put_session; + + status = nfs_ok; /* Success! bump slot seqid */ slot->sl_seqid = seq->seqid; slot->sl_flags |= NFSD4_SLOT_INUSE; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 1278d98a923c..5e7bac4a7e71 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3767,25 +3767,17 @@ static nfsd4_enc nfsd4_enc_ops[] = { __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize) { struct xdr_buf *buf = &resp->rqstp->rq_res; - struct nfsd4_session *session = resp->cstate.session; + struct nfsd4_slot *slot = resp->cstate.slot; - if (nfsd4_has_session(&resp->cstate)) { - struct nfsd4_slot *slot = resp->cstate.slot; - - if (buf->len + respsize > session->se_fchannel.maxresp_sz) - return nfserr_rep_too_big; - - if ((slot->sl_flags & NFSD4_SLOT_CACHETHIS) && - buf->len + respsize > session->se_fchannel.maxresp_cached) - return nfserr_rep_too_big_to_cache; - } - - if (buf->len + respsize > buf->buflen) { - WARN_ON_ONCE(nfsd4_has_session(&resp->cstate)); + if (buf->len + respsize <= buf->buflen) + return nfs_ok; + if (!nfsd4_has_session(&resp->cstate)) return nfserr_resource; + if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) { + WARN_ON_ONCE(1); + return nfserr_rep_too_big_to_cache; } - - return 0; + return nfserr_rep_too_big; } void |