diff options
author | J. Bruce Fields <bfields@redhat.com> | 2014-03-12 21:39:35 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-05-30 17:32:02 -0400 |
commit | 47ee52986472dba068e8223cbaf1b65d74238781 (patch) | |
tree | 4436adf69861759600318696325b8bb9633d4602 /fs/nfsd | |
parent | db3f58a95beea6752d90fed03f9f198d282a3913 (diff) |
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, | |||
2208 | struct nfsd4_sequence *seq) | 2208 | struct nfsd4_sequence *seq) |
2209 | { | 2209 | { |
2210 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 2210 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
2211 | struct xdr_stream *xdr = &resp->xdr; | ||
2211 | struct nfsd4_session *session; | 2212 | struct nfsd4_session *session; |
2212 | struct nfs4_client *clp; | 2213 | struct nfs4_client *clp; |
2213 | struct nfsd4_slot *slot; | 2214 | struct nfsd4_slot *slot; |
2214 | struct nfsd4_conn *conn; | 2215 | struct nfsd4_conn *conn; |
2215 | __be32 status; | 2216 | __be32 status; |
2217 | int buflen; | ||
2216 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 2218 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
2217 | 2219 | ||
2218 | if (resp->opcnt != 1) | 2220 | if (resp->opcnt != 1) |
@@ -2281,6 +2283,15 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2281 | if (status) | 2283 | if (status) |
2282 | goto out_put_session; | 2284 | goto out_put_session; |
2283 | 2285 | ||
2286 | buflen = (seq->cachethis) ? | ||
2287 | session->se_fchannel.maxresp_cached : | ||
2288 | session->se_fchannel.maxresp_sz; | ||
2289 | status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : | ||
2290 | nfserr_rep_too_big; | ||
2291 | if (xdr_restrict_buflen(xdr, buflen - 2 * RPC_MAX_AUTH_SIZE)) | ||
2292 | goto out_put_session; | ||
2293 | |||
2294 | status = nfs_ok; | ||
2284 | /* Success! bump slot seqid */ | 2295 | /* Success! bump slot seqid */ |
2285 | slot->sl_seqid = seq->seqid; | 2296 | slot->sl_seqid = seq->seqid; |
2286 | slot->sl_flags |= NFSD4_SLOT_INUSE; | 2297 | 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[] = { | |||
3767 | __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize) | 3767 | __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize) |
3768 | { | 3768 | { |
3769 | struct xdr_buf *buf = &resp->rqstp->rq_res; | 3769 | struct xdr_buf *buf = &resp->rqstp->rq_res; |
3770 | struct nfsd4_session *session = resp->cstate.session; | 3770 | struct nfsd4_slot *slot = resp->cstate.slot; |
3771 | 3771 | ||
3772 | if (nfsd4_has_session(&resp->cstate)) { | 3772 | if (buf->len + respsize <= buf->buflen) |
3773 | struct nfsd4_slot *slot = resp->cstate.slot; | 3773 | return nfs_ok; |
3774 | 3774 | if (!nfsd4_has_session(&resp->cstate)) | |
3775 | if (buf->len + respsize > session->se_fchannel.maxresp_sz) | ||
3776 | return nfserr_rep_too_big; | ||
3777 | |||
3778 | if ((slot->sl_flags & NFSD4_SLOT_CACHETHIS) && | ||
3779 | buf->len + respsize > session->se_fchannel.maxresp_cached) | ||
3780 | return nfserr_rep_too_big_to_cache; | ||
3781 | } | ||
3782 | |||
3783 | if (buf->len + respsize > buf->buflen) { | ||
3784 | WARN_ON_ONCE(nfsd4_has_session(&resp->cstate)); | ||
3785 | return nfserr_resource; | 3775 | return nfserr_resource; |
3776 | if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) { | ||
3777 | WARN_ON_ONCE(1); | ||
3778 | return nfserr_rep_too_big_to_cache; | ||
3786 | } | 3779 | } |
3787 | 3780 | return nfserr_rep_too_big; | |
3788 | return 0; | ||
3789 | } | 3781 | } |
3790 | 3782 | ||
3791 | void | 3783 | void |