Commit d0a381dd authored by J. Bruce Fields's avatar J. Bruce Fields

nfsd4: teach encoders to handle reserve_space failures

We've tried to prevent running out of space with COMPOUND_SLACK_SPACE
and special checking in those operations (getattr) whose result can vary
enormously.

However:
	- COMPOUND_SLACK_SPACE may be difficult to maintain as we add
	  more protocol.
	- BUG_ON or page faulting on failure seems overly fragile.
	- Especially in the 4.1 case, we prefer not to fail compounds
	  just because the returned result came *close* to session
	  limits.  (Though perfect enforcement here may be difficult.)
	- I'd prefer encoding to be uniform for all encoders instead of
	  having special exceptions for encoders containing, for
	  example, attributes.
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 082d4bd7
...@@ -1400,7 +1400,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -1400,7 +1400,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
} }
if (op->status == nfserr_replay_me) { if (op->status == nfserr_replay_me) {
op->replay = &cstate->replay_owner->so_replay; op->replay = &cstate->replay_owner->so_replay;
nfsd4_encode_replay(resp, op); nfsd4_encode_replay(&resp->xdr, op);
status = op->status = op->replay->rp_status; status = op->status = op->replay->rp_status;
} else { } else {
nfsd4_encode_operation(resp, op); nfsd4_encode_operation(resp, op);
......
...@@ -1746,11 +1746,6 @@ static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) ...@@ -1746,11 +1746,6 @@ static void write_cinfo(__be32 **p, struct nfsd4_change_info *c)
} }
} }
#define RESERVE_SPACE(nbytes) do { \
p = xdr_reserve_space(&resp->xdr, nbytes); \
BUG_ON(!p); \
} while (0)
/* Encode as an array of strings the string given with components /* Encode as an array of strings the string given with components
* separated @sep, escaped with esc_enter and esc_exit. * separated @sep, escaped with esc_enter and esc_exit.
*/ */
...@@ -2737,23 +2732,29 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, ...@@ -2737,23 +2732,29 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
return -EINVAL; return -EINVAL;
} }
static void static __be32
nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
{ {
__be32 *p; __be32 *p;
RESERVE_SPACE(sizeof(stateid_t)); p = xdr_reserve_space(xdr, sizeof(stateid_t));
if (!p)
return nfserr_resource;
WRITE32(sid->si_generation); WRITE32(sid->si_generation);
WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
return 0;
} }
static __be32 static __be32
nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
RESERVE_SPACE(8); p = xdr_reserve_space(xdr, 8);
if (!p)
return nfserr_resource;
WRITE32(access->ac_supported); WRITE32(access->ac_supported);
WRITE32(access->ac_resp_access); WRITE32(access->ac_resp_access);
} }
...@@ -2762,10 +2763,13 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ ...@@ -2762,10 +2763,13 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts) static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8); p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8);
if (!p)
return nfserr_resource;
WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
WRITE32(bcts->dir); WRITE32(bcts->dir);
/* Sorry, we do not yet support RDMA over 4.1: */ /* Sorry, we do not yet support RDMA over 4.1: */
...@@ -2777,8 +2781,10 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, ...@@ -2777,8 +2781,10 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp,
static __be32 static __be32
nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
{ {
struct xdr_stream *xdr = &resp->xdr;
if (!nfserr) if (!nfserr)
nfsd4_encode_stateid(resp, &close->cl_stateid); nfserr = nfsd4_encode_stateid(xdr, &close->cl_stateid);
return nfserr; return nfserr;
} }
...@@ -2787,10 +2793,13 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c ...@@ -2787,10 +2793,13 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
static __be32 static __be32
nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
RESERVE_SPACE(NFS4_VERIFIER_SIZE); p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
if (!p)
return nfserr_resource;
WRITEMEM(commit->co_verf.data, NFS4_VERIFIER_SIZE); WRITEMEM(commit->co_verf.data, NFS4_VERIFIER_SIZE);
} }
return nfserr; return nfserr;
...@@ -2799,10 +2808,13 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ ...@@ -2799,10 +2808,13 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
static __be32 static __be32
nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
RESERVE_SPACE(32); p = xdr_reserve_space(xdr, 32);
if (!p)
return nfserr_resource;
write_cinfo(&p, &create->cr_cinfo); write_cinfo(&p, &create->cr_cinfo);
WRITE32(2); WRITE32(2);
WRITE32(create->cr_bmval[0]); WRITE32(create->cr_bmval[0]);
...@@ -2829,13 +2841,16 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 ...@@ -2829,13 +2841,16 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
static __be32 static __be32
nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp) nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp)
{ {
struct xdr_stream *xdr = &resp->xdr;
struct svc_fh *fhp = *fhpp; struct svc_fh *fhp = *fhpp;
unsigned int len; unsigned int len;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
len = fhp->fh_handle.fh_size; len = fhp->fh_handle.fh_size;
RESERVE_SPACE(len + 4); p = xdr_reserve_space(xdr, len + 4);
if (!p)
return nfserr_resource;
WRITE32(len); WRITE32(len);
WRITEMEM(&fhp->fh_handle.fh_base, len); WRITEMEM(&fhp->fh_handle.fh_base, len);
} }
...@@ -2846,13 +2861,15 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh ...@@ -2846,13 +2861,15 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh
* Including all fields other than the name, a LOCK4denied structure requires * Including all fields other than the name, a LOCK4denied structure requires
* 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes. * 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes.
*/ */
static void static __be32
nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld)
{ {
struct xdr_netobj *conf = &ld->ld_owner; struct xdr_netobj *conf = &ld->ld_owner;
__be32 *p; __be32 *p;
RESERVE_SPACE(32 + XDR_LEN(conf->len)); p = xdr_reserve_space(xdr, 32 + XDR_LEN(conf->len));
if (!p)
return nfserr_resource;
WRITE64(ld->ld_start); WRITE64(ld->ld_start);
WRITE64(ld->ld_length); WRITE64(ld->ld_length);
WRITE32(ld->ld_type); WRITE32(ld->ld_type);
...@@ -2865,15 +2882,18 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie ...@@ -2865,15 +2882,18 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie
WRITE64((u64)0); /* clientid */ WRITE64((u64)0); /* clientid */
WRITE32(0); /* length of owner name */ WRITE32(0); /* length of owner name */
} }
return nfserr_denied;
} }
static __be32 static __be32
nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
{ {
struct xdr_stream *xdr = &resp->xdr;
if (!nfserr) if (!nfserr)
nfsd4_encode_stateid(resp, &lock->lk_resp_stateid); nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid);
else if (nfserr == nfserr_denied) else if (nfserr == nfserr_denied)
nfsd4_encode_lock_denied(resp, &lock->lk_denied); nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied);
return nfserr; return nfserr;
} }
...@@ -2881,16 +2901,20 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo ...@@ -2881,16 +2901,20 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
static __be32 static __be32
nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
{ {
struct xdr_stream *xdr = &resp->xdr;
if (nfserr == nfserr_denied) if (nfserr == nfserr_denied)
nfsd4_encode_lock_denied(resp, &lockt->lt_denied); nfsd4_encode_lock_denied(xdr, &lockt->lt_denied);
return nfserr; return nfserr;
} }
static __be32 static __be32
nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
{ {
struct xdr_stream *xdr = &resp->xdr;
if (!nfserr) if (!nfserr)
nfsd4_encode_stateid(resp, &locku->lu_stateid); nfserr = nfsd4_encode_stateid(xdr, &locku->lu_stateid);
return nfserr; return nfserr;
} }
...@@ -2899,10 +2923,13 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l ...@@ -2899,10 +2923,13 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
static __be32 static __be32
nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
RESERVE_SPACE(20); p = xdr_reserve_space(xdr, 20);
if (!p)
return nfserr_resource;
write_cinfo(&p, &link->li_cinfo); write_cinfo(&p, &link->li_cinfo);
} }
return nfserr; return nfserr;
...@@ -2912,13 +2939,18 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li ...@@ -2912,13 +2939,18 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li
static __be32 static __be32
nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (nfserr) if (nfserr)
goto out; goto out;
nfsd4_encode_stateid(resp, &open->op_stateid); nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid);
RESERVE_SPACE(40); if (nfserr)
goto out;
p = xdr_reserve_space(xdr, 40);
if (!p)
return nfserr_resource;
write_cinfo(&p, &open->op_cinfo); write_cinfo(&p, &open->op_cinfo);
WRITE32(open->op_rflags); WRITE32(open->op_rflags);
WRITE32(2); WRITE32(2);
...@@ -2930,8 +2962,12 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op ...@@ -2930,8 +2962,12 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
case NFS4_OPEN_DELEGATE_NONE: case NFS4_OPEN_DELEGATE_NONE:
break; break;
case NFS4_OPEN_DELEGATE_READ: case NFS4_OPEN_DELEGATE_READ:
nfsd4_encode_stateid(resp, &open->op_delegate_stateid); nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid);
RESERVE_SPACE(20); if (nfserr)
return nfserr;
p = xdr_reserve_space(xdr, 20);
if (!p)
return nfserr_resource;
WRITE32(open->op_recall); WRITE32(open->op_recall);
/* /*
...@@ -2943,8 +2979,12 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op ...@@ -2943,8 +2979,12 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
WRITE32(0); /* XXX: is NULL principal ok? */ WRITE32(0); /* XXX: is NULL principal ok? */
break; break;
case NFS4_OPEN_DELEGATE_WRITE: case NFS4_OPEN_DELEGATE_WRITE:
nfsd4_encode_stateid(resp, &open->op_delegate_stateid); nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid);
RESERVE_SPACE(32); if (nfserr)
return nfserr;
p = xdr_reserve_space(xdr, 32);
if (!p)
return nfserr_resource;
WRITE32(0); WRITE32(0);
/* /*
...@@ -2966,12 +3006,16 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op ...@@ -2966,12 +3006,16 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
switch (open->op_why_no_deleg) { switch (open->op_why_no_deleg) {
case WND4_CONTENTION: case WND4_CONTENTION:
case WND4_RESOURCE: case WND4_RESOURCE:
RESERVE_SPACE(8); p = xdr_reserve_space(xdr, 8);
if (!p)
return nfserr_resource;
WRITE32(open->op_why_no_deleg); WRITE32(open->op_why_no_deleg);
WRITE32(0); /* deleg signaling not supported yet */ WRITE32(0); /* deleg signaling not supported yet */
break; break;
default: default:
RESERVE_SPACE(4); p = xdr_reserve_space(xdr, 4);
if (!p)
return nfserr_resource;
WRITE32(open->op_why_no_deleg); WRITE32(open->op_why_no_deleg);
} }
break; break;
...@@ -2986,8 +3030,10 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op ...@@ -2986,8 +3030,10 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
static __be32 static __be32
nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
{ {
struct xdr_stream *xdr = &resp->xdr;
if (!nfserr) if (!nfserr)
nfsd4_encode_stateid(resp, &oc->oc_resp_stateid); nfserr = nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid);
return nfserr; return nfserr;
} }
...@@ -2995,8 +3041,10 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct ...@@ -2995,8 +3041,10 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct
static __be32 static __be32
nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
{ {
struct xdr_stream *xdr = &resp->xdr;
if (!nfserr) if (!nfserr)
nfsd4_encode_stateid(resp, &od->od_stateid); nfserr = nfsd4_encode_stateid(xdr, &od->od_stateid);
return nfserr; return nfserr;
} }
...@@ -3019,7 +3067,9 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3019,7 +3067,9 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
if (resp->xdr.buf->page_len) if (resp->xdr.buf->page_len)
return nfserr_resource; return nfserr_resource;
RESERVE_SPACE(8); /* eof flag and byte count */ p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
if (!p)
return nfserr_resource;
maxcount = svc_max_payload(resp->rqstp); maxcount = svc_max_payload(resp->rqstp);
if (maxcount > read->rd_length) if (maxcount > read->rd_length)
...@@ -3071,7 +3121,9 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3071,7 +3121,9 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
resp->xdr.buf->tail[0].iov_base = p; resp->xdr.buf->tail[0].iov_base = p;
resp->xdr.buf->tail[0].iov_len = 0; resp->xdr.buf->tail[0].iov_len = 0;
if (maxcount&3) { if (maxcount&3) {
RESERVE_SPACE(4); p = xdr_reserve_space(xdr, 4);
if (!p)
return nfserr_resource;
WRITE32(0); WRITE32(0);
resp->xdr.buf->tail[0].iov_base += maxcount&3; resp->xdr.buf->tail[0].iov_base += maxcount&3;
resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3); resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3);
...@@ -3099,7 +3151,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd ...@@ -3099,7 +3151,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
page = page_address(*(resp->rqstp->rq_next_page++)); page = page_address(*(resp->rqstp->rq_next_page++));
maxcount = PAGE_SIZE; maxcount = PAGE_SIZE;
RESERVE_SPACE(4);
p = xdr_reserve_space(xdr, 4);
if (!p)
return nfserr_resource;
/* /*
* XXX: By default, the ->readlink() VFS op will truncate symlinks * XXX: By default, the ->readlink() VFS op will truncate symlinks
...@@ -3126,7 +3181,9 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd ...@@ -3126,7 +3181,9 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
resp->xdr.buf->tail[0].iov_base = p; resp->xdr.buf->tail[0].iov_base = p;
resp->xdr.buf->tail[0].iov_len = 0; resp->xdr.buf->tail[0].iov_len = 0;
if (maxcount&3) { if (maxcount&3) {
RESERVE_SPACE(4); p = xdr_reserve_space(xdr, 4);
if (!p)
return nfserr_resource;
WRITE32(0); WRITE32(0);
resp->xdr.buf->tail[0].iov_base += maxcount&3; resp->xdr.buf->tail[0].iov_base += maxcount&3;
resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3); resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3);
...@@ -3151,7 +3208,9 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 ...@@ -3151,7 +3208,9 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
if (!*resp->rqstp->rq_next_page) if (!*resp->rqstp->rq_next_page)
return nfserr_resource; return nfserr_resource;
RESERVE_SPACE(NFS4_VERIFIER_SIZE); p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
if (!p)
return nfserr_resource;
/* XXX: Following NFSv3, we ignore the READDIR verifier for now. */ /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
WRITE32(0); WRITE32(0);
...@@ -3220,10 +3279,13 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 ...@@ -3220,10 +3279,13 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
static __be32 static __be32
nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
RESERVE_SPACE(20); p = xdr_reserve_space(xdr, 20);
if (!p)
return nfserr_resource;
write_cinfo(&p, &remove->rm_cinfo); write_cinfo(&p, &remove->rm_cinfo);
} }
return nfserr; return nfserr;
...@@ -3232,10 +3294,13 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ ...@@ -3232,10 +3294,13 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
static __be32 static __be32
nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
RESERVE_SPACE(40); p = xdr_reserve_space(xdr, 40);
if (!p)
return nfserr_resource;
write_cinfo(&p, &rename->rn_sinfo); write_cinfo(&p, &rename->rn_sinfo);
write_cinfo(&p, &rename->rn_tinfo); write_cinfo(&p, &rename->rn_tinfo);
} }
...@@ -3243,7 +3308,7 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ ...@@ -3243,7 +3308,7 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
} }
static __be32 static __be32
nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, nfsd4_do_encode_secinfo(struct xdr_stream *xdr,
__be32 nfserr, struct svc_export *exp) __be32 nfserr, struct svc_export *exp)
{ {
u32 i, nflavs, supported; u32 i, nflavs, supported;
...@@ -3254,6 +3319,7 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, ...@@ -3254,6 +3319,7 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
if (nfserr) if (nfserr)
goto out; goto out;
nfserr = nfserr_resource;
if (exp->ex_nflavors) { if (exp->ex_nflavors) {
flavs = exp->ex_flavors; flavs = exp->ex_flavors;
nflavs = exp->ex_nflavors; nflavs = exp->ex_nflavors;
...@@ -3275,7 +3341,9 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, ...@@ -3275,7 +3341,9 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
} }
supported = 0; supported = 0;
RESERVE_SPACE(4); p = xdr_reserve_space(xdr, 4);
if (!p)
goto out;
flavorsp = p++; /* to be backfilled later */ flavorsp = p++; /* to be backfilled later */
for (i = 0; i < nflavs; i++) { for (i = 0; i < nflavs; i++) {
...@@ -3284,7 +3352,10 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, ...@@ -3284,7 +3352,10 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
if (rpcauth_get_gssinfo(pf, &info) == 0) { if (rpcauth_get_gssinfo(pf, &info) == 0) {
supported++; supported++;
RESERVE_SPACE(4 + 4 + XDR_LEN(info.oid.len) + 4 + 4); p = xdr_reserve_space(xdr, 4 + 4 +
XDR_LEN(info.oid.len) + 4 + 4);
if (!p)
goto out;
WRITE32(RPC_AUTH_GSS); WRITE32(RPC_AUTH_GSS);
WRITE32(info.oid.len); WRITE32(info.oid.len);
WRITEMEM(info.oid.data, info.oid.len); WRITEMEM(info.oid.data, info.oid.len);
...@@ -3292,7 +3363,9 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, ...@@ -3292,7 +3363,9 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
WRITE32(info.service); WRITE32(info.service);
} else if (pf < RPC_AUTH_MAXFLAVOR) { } else if (pf < RPC_AUTH_MAXFLAVOR) {
supported++; supported++;
RESERVE_SPACE(4); p = xdr_reserve_space(xdr, 4);
if (!p)
goto out;
WRITE32(pf); WRITE32(pf);
} else { } else {
if (report) if (report)
...@@ -3304,7 +3377,7 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, ...@@ -3304,7 +3377,7 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
if (nflavs != supported) if (nflavs != supported)
report = false; report = false;
*flavorsp = htonl(supported); *flavorsp = htonl(supported);
nfserr = 0;
out: out:
if (exp) if (exp)
exp_put(exp); exp_put(exp);
...@@ -3315,14 +3388,18 @@ static __be32 ...@@ -3315,14 +3388,18 @@ static __be32
nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_secinfo *secinfo) struct nfsd4_secinfo *secinfo)
{ {
return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->si_exp); struct xdr_stream *xdr = &resp->xdr;
return nfsd4_do_encode_secinfo(xdr, nfserr, secinfo->si_exp);
} }
static __be32 static __be32
nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_secinfo_no_name *secinfo) struct nfsd4_secinfo_no_name *secinfo)
{ {
return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->sin_exp); struct xdr_stream *xdr = &resp->xdr;
return nfsd4_do_encode_secinfo(xdr, nfserr, secinfo->sin_exp);
} }
/* /*
...@@ -3332,9 +3409,12 @@ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3332,9 +3409,12 @@ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
static __be32 static __be32
nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
RESERVE_SPACE(16); p = xdr_reserve_space(xdr, 16);
if (!p)
return nfserr_resource;
if (nfserr) { if (nfserr) {
WRITE32(3); WRITE32(3);
WRITE32(0); WRITE32(0);
...@@ -3353,15 +3433,20 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 ...@@ -3353,15 +3433,20 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
static __be32 static __be32
nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
RESERVE_SPACE(8 + NFS4_VERIFIER_SIZE); p = xdr_reserve_space(xdr, 8 + NFS4_VERIFIER_SIZE);
if (!p)
return nfserr_resource;
WRITEMEM(&scd->se_clientid, 8); WRITEMEM(&scd->se_clientid, 8);
WRITEMEM(&scd->se_confirm, NFS4_VERIFIER_SIZE); WRITEMEM(&scd->se_confirm, NFS4_VERIFIER_SIZE);
} }
else if (nfserr == nfserr_clid_inuse) { else if (nfserr == nfserr_clid_inuse) {
RESERVE_SPACE(8); p = xdr_reserve_space(xdr, 8);
if (!p)
return nfserr_resource;
WRITE32(0); WRITE32(0);
WRITE32(0); WRITE32(0);
} }
...@@ -3371,10 +3456,13 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n ...@@ -3371,10 +3456,13 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n
static __be32 static __be32
nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (!nfserr) { if (!nfserr) {
RESERVE_SPACE(16); p = xdr_reserve_space(xdr, 16);
if (!p)
return nfserr_resource;
WRITE32(write->wr_bytes_written); WRITE32(write->wr_bytes_written);
WRITE32(write->wr_how_written); WRITE32(write->wr_how_written);
WRITEMEM(write->wr_verifier.data, NFS4_VERIFIER_SIZE); WRITEMEM(write->wr_verifier.data, NFS4_VERIFIER_SIZE);
...@@ -3394,6 +3482,7 @@ static __be32 ...@@ -3394,6 +3482,7 @@ static __be32
nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_exchange_id *exid) struct nfsd4_exchange_id *exid)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
char *major_id; char *major_id;
char *server_scope; char *server_scope;
...@@ -3409,11 +3498,13 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3409,11 +3498,13 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
server_scope = utsname()->nodename; server_scope = utsname()->nodename;
server_scope_sz = strlen(server_scope); server_scope_sz = strlen(server_scope);
RESERVE_SPACE( p = xdr_reserve_space(xdr,
8 /* eir_clientid */ + 8 /* eir_clientid */ +
4 /* eir_sequenceid */ + 4 /* eir_sequenceid */ +
4 /* eir_flags */ + 4 /* eir_flags */ +
4 /* spr_how */); 4 /* spr_how */);
if (!p)
return nfserr_resource;
WRITEMEM(&exid->clientid, 8); WRITEMEM(&exid->clientid, 8);
WRITE32(exid->seqid); WRITE32(exid->seqid);
...@@ -3426,7 +3517,9 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3426,7 +3517,9 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
break; break;
case SP4_MACH_CRED: case SP4_MACH_CRED:
/* spo_must_enforce, spo_must_allow */ /* spo_must_enforce, spo_must_allow */
RESERVE_SPACE(16); p = xdr_reserve_space(xdr, 16);
if (!p)
return nfserr_resource;
/* spo_must_enforce bitmap: */ /* spo_must_enforce bitmap: */
WRITE32(2); WRITE32(2);
...@@ -3440,13 +3533,15 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3440,13 +3533,15 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
} }
RESERVE_SPACE( p = xdr_reserve_space(xdr,
8 /* so_minor_id */ + 8 /* so_minor_id */ +
4 /* so_major_id.len */ + 4 /* so_major_id.len */ +
(XDR_QUADLEN(major_id_sz) * 4) + (XDR_QUADLEN(major_id_sz) * 4) +
4 /* eir_server_scope.len */ + 4 /* eir_server_scope.len */ +
(XDR_QUADLEN(server_scope_sz) * 4) + (XDR_QUADLEN(server_scope_sz) * 4) +
4 /* eir_server_impl_id.count (0) */); 4 /* eir_server_impl_id.count (0) */);
if (!p)
return nfserr_resource;
/* The server_owner struct */ /* The server_owner struct */
WRITE64(minor_id); /* Minor id */ WRITE64(minor_id); /* Minor id */
...@@ -3467,17 +3562,22 @@ static __be32 ...@@ -3467,17 +3562,22 @@ static __be32
nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_create_session *sess) struct nfsd4_create_session *sess)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (nfserr) if (nfserr)
return nfserr; return nfserr;
RESERVE_SPACE(24); p = xdr_reserve_space(xdr, 24);
if (!p)
return nfserr_resource;
WRITEMEM(sess->sessionid.data, NFS4_MAX_SESSIONID_LEN); WRITEMEM(sess->sessionid.data, NFS4_MAX_SESSIONID_LEN);
WRITE32(sess->seqid); WRITE32(sess->seqid);
WRITE32(sess->flags); WRITE32(sess->flags);
RESERVE_SPACE(28); p = xdr_reserve_space(xdr, 28);
if (!p)
return nfserr_resource;
WRITE32(0); /* headerpadsz */ WRITE32(0); /* headerpadsz */
WRITE32(sess->fore_channel.maxreq_sz); WRITE32(sess->fore_channel.maxreq_sz);
WRITE32(sess->fore_channel.maxresp_sz); WRITE32(sess->fore_channel.maxresp_sz);
...@@ -3487,11 +3587,15 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3487,11 +3587,15 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
WRITE32(sess->fore_channel.nr_rdma_attrs); WRITE32(sess->fore_channel.nr_rdma_attrs);
if (sess->fore_channel.nr_rdma_attrs) { if (sess->fore_channel.nr_rdma_attrs) {
RESERVE_SPACE(4); p = xdr_reserve_space(xdr, 4);
if (!p)
return nfserr_resource;
WRITE32(sess->fore_channel.rdma_attrs); WRITE32(sess->fore_channel.rdma_attrs);
} }
RESERVE_SPACE(28); p = xdr_reserve_space(xdr, 28);
if (!p)
return nfserr_resource;
WRITE32(0); /* headerpadsz */ WRITE32(0); /* headerpadsz */
WRITE32(sess->back_channel.maxreq_sz); WRITE32(sess->back_channel.maxreq_sz);
WRITE32(sess->back_channel.maxresp_sz); WRITE32(sess->back_channel.maxresp_sz);
...@@ -3501,7 +3605,9 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3501,7 +3605,9 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
WRITE32(sess->back_channel.nr_rdma_attrs); WRITE32(sess->back_channel.nr_rdma_attrs);
if (sess->back_channel.nr_rdma_attrs) { if (sess->back_channel.nr_rdma_attrs) {
RESERVE_SPACE(4); p = xdr_reserve_space(xdr, 4);
if (!p)
return nfserr_resource;
WRITE32(sess->back_channel.rdma_attrs); WRITE32(sess->back_channel.rdma_attrs);
} }
return 0; return 0;
...@@ -3511,12 +3617,15 @@ static __be32 ...@@ -3511,12 +3617,15 @@ static __be32
nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_sequence *seq) struct nfsd4_sequence *seq)
{ {
struct xdr_stream *xdr = &resp->xdr;
__be32 *p; __be32 *p;
if (nfserr) if (nfserr)
return nfserr; return nfserr;
RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 20); p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20);
if (!p)
return nfserr_resource;
WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
WRITE32(seq->seqid); WRITE32(seq->seqid);
WRITE32(seq->slotid); WRITE32(seq->slotid);
...@@ -3533,13 +3642,16 @@ static __be32 ...@@ -3533,13 +3642,16 @@ static __be32
nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_test_stateid *test_stateid) struct nfsd4_test_stateid *test_stateid)
{ {
struct xdr_stream *xdr = &resp->xdr;
struct nfsd4_test_stateid_id *stateid, *next; struct nfsd4_test_stateid_id *stateid, *next;
__be32 *p; __be32 *p;
if (nfserr) if (nfserr)
return nfserr; return nfserr;
RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids)); p = xdr_reserve_space(xdr, 4 + (4 * test_stateid->ts_num_ids));
if (!p)
return nfserr_resource;
*p++ = htonl(test_stateid->ts_num_ids); *p++ = htonl(test_stateid->ts_num_ids);
list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) { list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) {
...@@ -3678,7 +3790,11 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) ...@@ -3678,7 +3790,11 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
nfsd4_enc encoder; nfsd4_enc encoder;
__be32 *p; __be32 *p;
RESERVE_SPACE(8); p = xdr_reserve_space(xdr, 8);
if (!p) {
WARN_ON_ONCE(1);
return;
}
WRITE32(op->opnum); WRITE32(op->opnum);
post_err_offset = xdr->buf->len; post_err_offset = xdr->buf->len;
...@@ -3730,18 +3846,21 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) ...@@ -3730,18 +3846,21 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
* called with nfs4_lock_state() held * called with nfs4_lock_state() held
*/ */
void void
nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op)
{ {
__be32 *p; __be32 *p;
struct nfs4_replay *rp = op->replay; struct nfs4_replay *rp = op->replay;
BUG_ON(!rp); BUG_ON(!rp);
RESERVE_SPACE(8); p = xdr_reserve_space(xdr, 8 + rp->rp_buflen);
if (!p) {
WARN_ON_ONCE(1);
return;
}
WRITE32(op->opnum); WRITE32(op->opnum);
*p++ = rp->rp_status; /* already xdr'ed */ *p++ = rp->rp_status; /* already xdr'ed */
RESERVE_SPACE(rp->rp_buflen);
WRITEMEM(rp->rp_buf, rp->rp_buflen); WRITEMEM(rp->rp_buf, rp->rp_buflen);
} }
......
...@@ -563,7 +563,7 @@ int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, ...@@ -563,7 +563,7 @@ int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
struct nfsd4_compoundres *); struct nfsd4_compoundres *);
__be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32);
void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); void nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op);
__be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words, __be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words,
struct svc_fh *fhp, struct svc_export *exp, struct svc_fh *fhp, struct svc_export *exp,
struct dentry *dentry, struct dentry *dentry,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment