aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2014-03-12 21:39:35 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-05-30 17:32:02 -0400
commit47ee52986472dba068e8223cbaf1b65d74238781 (patch)
tree4436adf69861759600318696325b8bb9633d4602 /fs/nfsd
parentdb3f58a95beea6752d90fed03f9f198d282a3913 (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.c11
-rw-r--r--fs/nfsd/nfs4xdr.c24
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
3791void 3783void