diff options
| author | Trond Myklebust <trond.myklebust@fys.uio.no> | 2002-11-21 19:08:38 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@penguin.transmeta.com> | 2002-11-21 19:08:38 -0800 |
| commit | dccb90df2d3fa9e4ac08b7e91f9e900273bbedef (patch) | |
| tree | 2941db9fd968de0e628c0972cb885441851b3930 | |
| parent | 241c59e257d3b1b04f281773d06e2cc94a9d78f5 (diff) | |
[PATCH] Split buffer overflow checking out of struct nfs4_compound
Here is the a pre-patch in the attempt to get rid of 'struct
nfs4_compound', and the associated horrible union in 'struct
nfs4_op'.
It splits out the fields that are meant to do buffer overflow checking
and iovec adjusting on the XDR received/sent data. It moves support
for that nto the dedicated structure 'xdr_stream', and the associated
functions 'xdr_reserve_space()', 'xdr_inline_decode()'.
The patch also expands out the all macros ENCODE_HEAD, ENCODE_TAIL,
ADJUST_ARGS and DECODE_HEAD, as well as most of the DECODE_TAILs.
| -rw-r--r-- | fs/nfs/nfs4proc.c | 15 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 537 | ||||
| -rw-r--r-- | include/linux/nfs_xdr.h | 4 | ||||
| -rw-r--r-- | include/linux/sunrpc/xdr.h | 87 |
4 files changed, 345 insertions, 298 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b17c138681eb..e563bdc7e315 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -65,11 +65,6 @@ nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops, memset(cp, 0, sizeof(*cp)); cp->ops = ops; cp->server = server; - -#if NFS4_DEBUG - cp->taglen = strlen(tag); - cp->tag = tag; -#endif } static void @@ -373,6 +368,7 @@ nfs4_setup_open(struct nfs4_compound *cp, int flags, struct qstr *name, BUG_ON(cp->flags); + open->op_client_state = cp->server->nfs4_state; open->op_share_access = flags & 3; open->op_opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE; open->op_createmode = NFS4_CREATE_UNCHECKED; @@ -527,6 +523,10 @@ nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new, static void nfs4_setup_renew(struct nfs4_compound *cp) { + struct nfs4_client **client_state = GET_OP(cp, renew); + + *client_state = cp->server->nfs4_state; + OPNUM(cp) = OP_RENEW; cp->req_nops++; cp->renew_index = cp->req_nops; @@ -575,6 +575,7 @@ nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short por sprintf(setclientid->sc_uaddr, "%s.%d.%d", server->ip_addr, port >> 8, port & 255); setclientid->sc_prog = program; setclientid->sc_cb_ident = 0; + setclientid->sc_state = server->nfs4_state; OPNUM(cp) = OP_SETCLIENTID; cp->req_nops++; @@ -583,6 +584,10 @@ nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short por static void nfs4_setup_setclientid_confirm(struct nfs4_compound *cp) { + struct nfs4_client **client_state = GET_OP(cp, setclientid_confirm); + + *client_state = cp->server->nfs4_state; + OPNUM(cp) = OP_SETCLIENTID_CONFIRM; cp->req_nops++; cp->renew_index = cp->req_nops; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 7b6c503e4cc7..3847a6bf0874 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -57,8 +57,6 @@ */ #define COOKIE_MAX 0x7fffffff -#define NFS4_CLIENTID(server) ((server)->nfs4_state->cl_clientid) - #define NFSDBG_FACILITY NFSDBG_XDR /* Mapping from NFS error code to "errno" error code. */ @@ -95,25 +93,22 @@ static struct { * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define ENCODE_HEAD \ - u32 *p; -#define ENCODE_TAIL \ - return 0 - #define WRITE32(n) *p++ = htonl(n) #define WRITE64(n) do { \ - *p++ = htonl((u32)((n) >> 32)); \ - *p++ = htonl((u32)(n)); \ + *p++ = htonl((uint32_t)((n) >> 32)); \ + *p++ = htonl((uint32_t)(n)); \ } while (0) #define WRITEMEM(ptr,nbytes) do { \ p = xdr_writemem(p, ptr, nbytes); \ } while (0) -#define RESERVE_SPACE(nbytes) do { BUG_ON(cp->p + XDR_QUADLEN(nbytes) > cp->end); p = cp->p; } while (0) -#define ADJUST_ARGS() cp->p = p +#define RESERVE_SPACE(nbytes) do { \ + p = xdr_reserve_space(xdr, nbytes); \ + BUG_ON(!p); \ +} while (0) static inline -u32 *xdr_writemem(u32 *p, const void *ptr, int nbytes) +uint32_t *xdr_writemem(uint32_t *p, const void *ptr, int nbytes) { int tmp = XDR_QUADLEN(nbytes); if (!tmp) @@ -146,18 +141,18 @@ encode_gid(char *p, gid_t gid) } static int -encode_attrs(struct nfs4_compound *cp, struct iattr *iap) +encode_attrs(struct xdr_stream *xdr, struct iattr *iap) { char owner_name[256]; char owner_group[256]; int owner_namelen = 0; int owner_grouplen = 0; - u32 *q; + uint32_t *p; + uint32_t *q; int len; - u32 bmval0 = 0; - u32 bmval1 = 0; + uint32_t bmval0 = 0; + uint32_t bmval1 = 0; int status; - ENCODE_HEAD; /* * We reserve enough space to write the entire attribute buffer at once. @@ -240,8 +235,6 @@ encode_attrs(struct nfs4_compound *cp, struct iattr *iap) WRITE32(NFS4_SET_TO_SERVER_TIME); } - ADJUST_ARGS(); - /* * Now we backfill the bitmap and the attribute buffer length. */ @@ -256,69 +249,63 @@ out: } static int -encode_access(struct nfs4_compound *cp, struct nfs4_access *access) +encode_access(struct xdr_stream *xdr, struct nfs4_access *access) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(8); WRITE32(OP_ACCESS); WRITE32(access->ac_req_access); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_close(struct nfs4_compound *cp, struct nfs4_close *close) +encode_close(struct xdr_stream *xdr, struct nfs4_close *close) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(20); WRITE32(OP_CLOSE); WRITE32(close->cl_seqid); WRITEMEM(close->cl_stateid, sizeof(nfs4_stateid)); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_commit(struct nfs4_compound *cp, struct nfs4_commit *commit) +encode_commit(struct xdr_stream *xdr, struct nfs4_commit *commit) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(16); WRITE32(OP_COMMIT); WRITE64(commit->co_start); WRITE32(commit->co_len); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_create(struct nfs4_compound *cp, struct nfs4_create *create) +encode_create(struct xdr_stream *xdr, struct nfs4_create *create) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(8); WRITE32(OP_CREATE); WRITE32(create->cr_ftype); - ADJUST_ARGS(); switch (create->cr_ftype) { case NF4LNK: RESERVE_SPACE(4 + create->cr_textlen); WRITE32(create->cr_textlen); WRITEMEM(create->cr_text, create->cr_textlen); - ADJUST_ARGS(); break; case NF4BLK: case NF4CHR: RESERVE_SPACE(8); WRITE32(create->cr_specdata1); WRITE32(create->cr_specdata2); - ADJUST_ARGS(); break; default: @@ -328,74 +315,69 @@ encode_create(struct nfs4_compound *cp, struct nfs4_create *create) RESERVE_SPACE(4 + create->cr_namelen); WRITE32(create->cr_namelen); WRITEMEM(create->cr_name, create->cr_namelen); - ADJUST_ARGS(); - return encode_attrs(cp, create->cr_attrs); + return encode_attrs(xdr, create->cr_attrs); } static int -encode_getattr(struct nfs4_compound *cp, struct nfs4_getattr *getattr) +encode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(16); WRITE32(OP_GETATTR); WRITE32(2); WRITE32(getattr->gt_bmval[0]); WRITE32(getattr->gt_bmval[1]); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_getfh(struct nfs4_compound *cp) +encode_getfh(struct xdr_stream *xdr) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(4); WRITE32(OP_GETFH); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_link(struct nfs4_compound *cp, struct nfs4_link *link) +encode_link(struct xdr_stream *xdr, struct nfs4_link *link) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(8 + link->ln_namelen); WRITE32(OP_LINK); WRITE32(link->ln_namelen); WRITEMEM(link->ln_name, link->ln_namelen); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_lookup(struct nfs4_compound *cp, struct nfs4_lookup *lookup) +encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup) { int len = lookup->lo_name->len; - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(8 + len); WRITE32(OP_LOOKUP); WRITE32(len); WRITEMEM(lookup->lo_name->name, len); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_open(struct nfs4_compound *cp, struct nfs4_open *open) +encode_open(struct xdr_stream *xdr, struct nfs4_open *open) { static int global_id = 0; int id = global_id++; int status; - ENCODE_HEAD; + uint32_t *p; /* seqid, share_access, share_deny, clientid, ownerlen, owner, opentype */ RESERVE_SPACE(52); @@ -403,24 +385,21 @@ encode_open(struct nfs4_compound *cp, struct nfs4_open *open) WRITE32(0); /* seqid */ WRITE32(open->op_share_access); WRITE32(0); /* for us, share_deny== 0 always */ - WRITE64(NFS4_CLIENTID(cp->server)); + WRITE64(open->op_client_state->cl_clientid); WRITE32(4); WRITE32(id); WRITE32(open->op_opentype); - ADJUST_ARGS(); if (open->op_opentype == NFS4_OPEN_CREATE) { if (open->op_createmode == NFS4_CREATE_EXCLUSIVE) { RESERVE_SPACE(12); WRITE32(open->op_createmode); WRITEMEM(open->op_verifier, sizeof(nfs4_verifier)); - ADJUST_ARGS(); } else if (open->op_attrs) { RESERVE_SPACE(4); WRITE32(open->op_createmode); - ADJUST_ARGS(); - if ((status = encode_attrs(cp, open->op_attrs))) + if ((status = encode_attrs(xdr, open->op_attrs))) return status; } else { @@ -428,7 +407,6 @@ encode_open(struct nfs4_compound *cp, struct nfs4_open *open) WRITE32(open->op_createmode); WRITE32(0); WRITE32(0); - ADJUST_ARGS(); } } @@ -436,15 +414,14 @@ encode_open(struct nfs4_compound *cp, struct nfs4_open *open) WRITE32(NFS4_OPEN_CLAIM_NULL); WRITE32(open->op_name->len); WRITEMEM(open->op_name->name, open->op_name->len); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_open_confirm(struct nfs4_compound *cp, struct nfs4_open_confirm *open_confirm) +encode_open_confirm(struct xdr_stream *xdr, struct nfs4_open_confirm *open_confirm) { - ENCODE_HEAD; + uint32_t *p; /* * Note: In this "stateless" implementation, the OPEN_CONFIRM @@ -454,44 +431,41 @@ encode_open_confirm(struct nfs4_compound *cp, struct nfs4_open_confirm *open_con WRITE32(OP_OPEN_CONFIRM); WRITEMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid)); WRITE32(1); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_putfh(struct nfs4_compound *cp, struct nfs4_putfh *putfh) +encode_putfh(struct xdr_stream *xdr, struct nfs4_putfh *putfh) { int len = putfh->pf_fhandle->size; - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(8 + len); WRITE32(OP_PUTFH); WRITE32(len); WRITEMEM(putfh->pf_fhandle->data, len); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_putrootfh(struct nfs4_compound *cp) +encode_putrootfh(struct xdr_stream *xdr) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(4); WRITE32(OP_PUTROOTFH); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_read(struct nfs4_compound *cp, struct nfs4_read *read, struct rpc_rqst *req) +encode_read(struct xdr_stream *xdr, struct nfs4_read *read, struct rpc_rqst *req) { struct rpc_auth *auth = req->rq_task->tk_auth; int replen; - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(32); WRITE32(OP_READ); @@ -501,26 +475,24 @@ encode_read(struct nfs4_compound *cp, struct nfs4_read *read, struct rpc_rqst *r WRITE32(0); WRITE64(read->rd_offset); WRITE32(read->rd_length); - ADJUST_ARGS(); /* set up reply iovec * toplevel status + taglen + rescount + OP_PUTFH + status * + OP_READ + status + eof + datalen = 9 */ - replen = (RPC_REPHDRSIZE + auth->au_rslack + 9 + XDR_QUADLEN(cp->taglen)) << 2; - req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, read->rd_pages, read->rd_pgbase, read->rd_length); - ENCODE_TAIL; + return 0; } static int -encode_readdir(struct nfs4_compound *cp, struct nfs4_readdir *readdir, struct rpc_rqst *req) +encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir *readdir, struct rpc_rqst *req) { struct rpc_auth *auth = req->rq_task->tk_auth; int replen; - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(40); WRITE32(OP_READDIR); @@ -531,135 +503,124 @@ encode_readdir(struct nfs4_compound *cp, struct nfs4_readdir *readdir, struct rp WRITE32(2); WRITE32(readdir->rd_bmval[0]); WRITE32(readdir->rd_bmval[1]); - ADJUST_ARGS(); /* set up reply iovec * toplevel_status + taglen + rescount + OP_PUTFH + status * + OP_READDIR + status + verifer(2) = 9 */ - replen = (RPC_REPHDRSIZE + auth->au_rslack + 9 + XDR_QUADLEN(cp->taglen)) << 2; - req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->rd_pages, readdir->rd_pgbase, readdir->rd_count); - ENCODE_TAIL; + return 0; } static int -encode_readlink(struct nfs4_compound *cp, struct nfs4_readlink *readlink, struct rpc_rqst *req) +encode_readlink(struct xdr_stream *xdr, struct nfs4_readlink *readlink, struct rpc_rqst *req) { struct rpc_auth *auth = req->rq_task->tk_auth; int replen; - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(4); WRITE32(OP_READLINK); - ADJUST_ARGS(); /* set up reply iovec * toplevel_status + taglen + rescount + OP_PUTFH + status * + OP_READLINK + status = 7 */ - replen = (RPC_REPHDRSIZE + auth->au_rslack + 7 + XDR_QUADLEN(cp->taglen)) << 2; - req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count); - ENCODE_TAIL; + return 0; } static int -encode_remove(struct nfs4_compound *cp, struct nfs4_remove *remove) +encode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(8 + remove->rm_namelen); WRITE32(OP_REMOVE); WRITE32(remove->rm_namelen); WRITEMEM(remove->rm_name, remove->rm_namelen); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_rename(struct nfs4_compound *cp, struct nfs4_rename *rename) +encode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(8 + rename->rn_oldnamelen); WRITE32(OP_RENAME); WRITE32(rename->rn_oldnamelen); WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen); - ADJUST_ARGS(); RESERVE_SPACE(8 + rename->rn_newnamelen); WRITE32(rename->rn_newnamelen); WRITEMEM(rename->rn_newname, rename->rn_newnamelen); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_renew(struct nfs4_compound *cp) +encode_renew(struct xdr_stream *xdr, struct nfs4_client *client_stateid) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(12); WRITE32(OP_RENEW); - WRITE64(NFS4_CLIENTID(cp->server)); - ADJUST_ARGS(); + WRITE64(client_stateid->cl_clientid); - ENCODE_TAIL; + return 0; } static int -encode_restorefh(struct nfs4_compound *cp) +encode_restorefh(struct xdr_stream *xdr) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(4); WRITE32(OP_RESTOREFH); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_savefh(struct nfs4_compound *cp) +encode_savefh(struct xdr_stream *xdr) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(4); WRITE32(OP_SAVEFH); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_setattr(struct nfs4_compound *cp, struct nfs4_setattr *setattr) +encode_setattr(struct xdr_stream *xdr, struct nfs4_setattr *setattr) { int status; - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(20); WRITE32(OP_SETATTR); WRITEMEM(setattr->st_stateid, sizeof(nfs4_stateid)); - ADJUST_ARGS(); - if ((status = encode_attrs(cp, setattr->st_iap))) + if ((status = encode_attrs(xdr, setattr->st_iap))) return status; - ENCODE_TAIL; + return 0; } static int -encode_setclientid(struct nfs4_compound *cp, struct nfs4_setclientid *setclientid) +encode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid *setclientid) { - u32 total_len; - u32 len1, len2, len3; - ENCODE_HEAD; + uint32_t total_len; + uint32_t len1, len2, len3; + uint32_t *p; len1 = strlen(setclientid->sc_name); len2 = strlen(setclientid->sc_netid); @@ -678,30 +639,28 @@ encode_setclientid(struct nfs4_compound *cp, struct nfs4_setclientid *setclienti WRITE32(len3); WRITEMEM(setclientid->sc_uaddr, len3); WRITE32(setclientid->sc_cb_ident); - ADJUST_ARGS(); - ENCODE_TAIL; + return 0; } static int -encode_setclientid_confirm(struct nfs4_compound *cp) +encode_setclientid_confirm(struct xdr_stream *xdr, struct nfs4_client *client_state) { - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(12 + sizeof(nfs4_verifier)); WRITE32(OP_SETCLIENTID_CONFIRM); - WRITE64(cp->server->nfs4_state->cl_clientid); - WRITEMEM(cp->server->nfs4_state->cl_confirm,sizeof(nfs4_verifier)); - ADJUST_ARGS(); + WRITE64(client_state->cl_clientid); + WRITEMEM(client_state->cl_confirm,sizeof(nfs4_verifier)); - ENCODE_TAIL; + return 0; } static int -encode_write(struct nfs4_compound *cp, struct nfs4_write *write, struct rpc_rqst *req) +encode_write(struct xdr_stream *xdr, struct nfs4_write *write, struct rpc_rqst *req) { struct xdr_buf *sndbuf = &req->rq_snd_buf; - ENCODE_HEAD; + uint32_t *p; RESERVE_SPACE(36); WRITE32(OP_WRITE); @@ -712,20 +671,18 @@ encode_write(struct nfs4_compound *cp, struct nfs4_write *write, struct rpc_rqst WRITE64(write->wr_offset); WRITE32(write->wr_stable_how); WRITE32(write->wr_len); - ADJUST_ARGS(); - sndbuf->len = xdr_adjust_iovec(sndbuf->head, p); xdr_encode_pages(sndbuf, write->wr_pages, write->wr_pgbase, write->wr_len); - ENCODE_TAIL; + return 0; } /* FIXME: this sucks */ static int -encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) +encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req) { int i, status = 0; - ENCODE_HEAD; + uint32_t *p; dprintk("encode_compound: tag=%.*s\n", (int)cp->taglen, cp->tag); @@ -734,81 +691,80 @@ encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) WRITEMEM(cp->tag, cp->taglen); WRITE32(NFS4_MINOR_VERSION); WRITE32(cp->req_nops); - ADJUST_ARGS(); for (i = 0; i < cp->req_nops; i++) { switch (cp->ops[i].opnum) { case OP_ACCESS: - status = encode_access(cp, &cp->ops[i].u.access); + status = encode_access(xdr, &cp->ops[i].u.access); break; case OP_CLOSE: - status = encode_close(cp, &cp->ops[i].u.close); + status = encode_close(xdr, &cp->ops[i].u.close); break; case OP_COMMIT: - status = encode_commit(cp, &cp->ops[i].u.commit); + status = encode_commit(xdr, &cp->ops[i].u.commit); break; case OP_CREATE: - status = encode_create(cp, &cp->ops[i].u.create); + status = encode_create(xdr, &cp->ops[i].u.create); break; case OP_GETATTR: - status = encode_getattr(cp, &cp->ops[i].u.getattr); + status = encode_getattr(xdr, &cp->ops[i].u.getattr); break; case OP_GETFH: - status = encode_getfh(cp); + status = encode_getfh(xdr); break; case OP_LINK: - status = encode_link(cp, &cp->ops[i].u.link); + status = encode_link(xdr, &cp->ops[i].u.link); break; case OP_LOOKUP: - status = encode_lookup(cp, &cp->ops[i].u.lookup); + status = encode_lookup(xdr, &cp->ops[i].u.lookup); break; case OP_OPEN: - status = encode_open(cp, &cp->ops[i].u.open); + status = encode_open(xdr, &cp->ops[i].u.open); break; case OP_OPEN_CONFIRM: - status = encode_open_confirm(cp, &cp->ops[i].u.open_confirm); + status = encode_open_confirm(xdr, &cp->ops[i].u.open_confirm); break; case OP_PUTFH: - status = encode_putfh(cp, &cp->ops[i].u.putfh); + status = encode_putfh(xdr, &cp->ops[i].u.putfh); break; case OP_PUTROOTFH: - status = encode_putrootfh(cp); + status = encode_putrootfh(xdr); break; case OP_READ: - status = encode_read(cp, &cp->ops[i].u.read, req); + status = encode_read(xdr, &cp->ops[i].u.read, req); break; case OP_READDIR: - status = encode_readdir(cp, &cp->ops[i].u.readdir, req); + status = encode_readdir(xdr, &cp->ops[i].u.readdir, req); break; case OP_READLINK: - status = encode_readlink(cp, &cp->ops[i].u.readlink, req); + status = encode_readlink(xdr, &cp->ops[i].u.readlink, req); break; case OP_REMOVE: - status = encode_remove(cp, &cp->ops[i].u.remove); + status = encode_remove(xdr, &cp->ops[i].u.remove); break; case OP_RENAME: - status = encode_rename(cp, &cp->ops[i].u.rename); + status = encode_rename(xdr, &cp->ops[i].u.rename); break; case OP_RENEW: - status = encode_renew(cp); + status = encode_renew(xdr, cp->ops[i].u.renew); break; case OP_RESTOREFH: - status = encode_restorefh(cp); + status = encode_restorefh(xdr); break; case OP_SAVEFH: - status = encode_savefh(cp); + status = encode_savefh(xdr); break; case OP_SETATTR: - status = encode_setattr(cp, &cp->ops[i].u.setattr); + status = encode_setattr(xdr, &cp->ops[i].u.setattr); break; case OP_SETCLIENTID: - status = encode_setclientid(cp, &cp->ops[i].u.setclientid); + status = encode_setclientid(xdr, &cp->ops[i].u.setclientid); break; case OP_SETCLIENTID_CONFIRM: - status = encode_setclientid_confirm(cp); + status = encode_setclientid_confirm(xdr, cp->ops[i].u.setclientid_confirm); break; case OP_WRITE: - status = encode_write(cp, &cp->ops[i].u.write, req); + status = encode_write(xdr, &cp->ops[i].u.write, req); break; default: BUG(); @@ -817,7 +773,7 @@ encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) return status; } - ENCODE_TAIL; + return 0; } /* * END OF "GENERIC" ENCODE ROUTINES. @@ -828,18 +784,14 @@ encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) * Encode COMPOUND argument */ static int -nfs4_xdr_enc_compound(struct rpc_rqst *req, u32 *p, struct nfs4_compound *cp) +nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *cp) { + struct xdr_stream xdr; int status; - struct xdr_buf *sndbuf = &req->rq_snd_buf; - cp->p = p; - cp->end = (u32 *) ((char *)req->rq_svec[0].iov_base + req->rq_svec[0].iov_len); - status = encode_compound(cp, req); + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + status = encode_compound(&xdr, cp, req); cp->timestamp = jiffies; - - if (!status && !sndbuf->page_len) - req->rq_slen = xdr_adjust_iovec(sndbuf->head, cp->p); return status; } @@ -854,9 +806,6 @@ nfs4_xdr_enc_compound(struct rpc_rqst *req, u32 *p, struct nfs4_compound *cp) * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define DECODE_HEAD \ - u32 *p; \ - int status #define DECODE_TAIL \ status = 0; \ out: \ @@ -881,11 +830,13 @@ xdr_error: \ p += XDR_QUADLEN(nbytes); \ } while (0) -#define READ_BUF(nbytes) do { \ - if (nbytes > (u32)((char *)cp->end - (char *)cp->p)) \ - goto xdr_error; \ - p = cp->p; \ - cp->p += XDR_QUADLEN(nbytes); \ +#define READ_BUF(nbytes) do { \ + p = xdr_inline_decode(xdr, nbytes); \ + if (!p) { \ + printk(KERN_WARNING "%s: reply buffer overflowed in line %d.", \ + __FUNCTION__, __LINE__); \ + return -EIO; \ + } \ } while (0) /* @@ -893,7 +844,7 @@ xdr_error: \ * upcall gets in... */ static int -decode_uid(char *p, u32 len, uid_t *uid) +decode_uid(char *p, uint32_t len, uid_t *uid) { *uid = -2; return 0; @@ -904,82 +855,78 @@ decode_uid(char *p, u32 len, uid_t *uid) * upcall gets in... */ static int -decode_gid(char *p, u32 len, gid_t *gid) +decode_gid(char *p, uint32_t len, gid_t *gid) { *gid = -2; return 0; } static int -decode_change_info(struct nfs4_compound *cp, struct nfs4_change_info *cinfo) +decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { - DECODE_HEAD; + uint32_t *p; READ_BUF(20); READ32(cinfo->atomic); READ64(cinfo->before); READ64(cinfo->after); - - DECODE_TAIL; + return 0; } static int -decode_access(struct nfs4_compound *cp, int nfserr, struct nfs4_access *access) +decode_access(struct xdr_stream *xdr, int nfserr, struct nfs4_access *access) { - u32 supp, acc; - DECODE_HEAD; + uint32_t *p; + uint32_t supp, acc; if (!nfserr) { READ_BUF(8); READ32(supp); READ32(acc); - status = -EIO; if ((supp & ~access->ac_req_access) || (acc & ~supp)) { printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n"); - goto out; + return -EIO; } *access->ac_resp_supported = supp; *access->ac_resp_access = acc; } - - DECODE_TAIL; + return 0; } static int -decode_close(struct nfs4_compound *cp, int nfserr, struct nfs4_close *close) +decode_close(struct xdr_stream *xdr, int nfserr, struct nfs4_close *close) { - DECODE_HEAD; + uint32_t *p; if (!nfserr) { READ_BUF(sizeof(nfs4_stateid)); COPYMEM(close->cl_stateid, sizeof(nfs4_stateid)); } - - DECODE_TAIL; + return 0; } static int -decode_commit(struct nfs4_compound *cp, int nfserr, struct nfs4_commit *commit) +decode_commit(struct xdr_stream *xdr, int nfserr, struct nfs4_commit *commit) { - DECODE_HEAD; + uint32_t *p; if (!nfserr) { READ_BUF(8); COPYMEM(commit->co_verifier->verifier, 8); } - - DECODE_TAIL; + return 0; } static int -decode_create(struct nfs4_compound *cp, int nfserr, struct nfs4_create *create) +decode_create(struct xdr_stream *xdr, int nfserr, struct nfs4_create *create) { - u32 bmlen; - DECODE_HEAD; + uint32_t *p; + uint32_t bmlen; + int status; if (!nfserr) { - if ((status = decode_change_info(cp, create->cr_cinfo))) + if ((status = decode_change_info(xdr, create->cr_cinfo))) goto out; READ_BUF(4); READ32(bmlen); @@ -991,27 +938,28 @@ decode_create(struct nfs4_compound *cp, int nfserr, struct nfs4_create *create) DECODE_TAIL; } -extern u32 nfs4_fattr_bitmap[2]; -extern u32 nfs4_fsinfo_bitmap[2]; -extern u32 nfs4_fsstat_bitmap[2]; -extern u32 nfs4_pathconf_bitmap[2]; +extern uint32_t nfs4_fattr_bitmap[2]; +extern uint32_t nfs4_fsinfo_bitmap[2]; +extern uint32_t nfs4_fsstat_bitmap[2]; +extern uint32_t nfs4_pathconf_bitmap[2]; static int -decode_getattr(struct nfs4_compound *cp, int nfserr, struct nfs4_getattr *getattr) +decode_getattr(struct xdr_stream *xdr, int nfserr, struct nfs4_getattr *getattr) { struct nfs_fattr *nfp = getattr->gt_attrs; struct nfs_fsstat *fsstat = getattr->gt_fsstat; struct nfs_fsinfo *fsinfo = getattr->gt_fsinfo; struct nfs_pathconf *pathconf = getattr->gt_pathconf; - u32 bmlen; - u32 bmval0 = 0; - u32 bmval1 = 0; - u32 attrlen; - u32 dummy32; - u32 len = 0; + uint32_t *p; + uint32_t bmlen; + uint32_t bmval0 = 0; + uint32_t bmval1 = 0; + uint32_t attrlen; + uint32_t dummy32; + uint32_t len = 0; unsigned int type; int fmode = 0; - DECODE_HEAD; + int status; if (nfserr) goto success; @@ -1060,7 +1008,7 @@ decode_getattr(struct nfs4_compound *cp, int nfserr, struct nfs4_getattr *getatt } nfp->type = nfs_type2fmt[type].nfs2type; fmode = nfs_type2fmt[type].mode; - dprintk("read_attrs: type=%d\n", (u32)nfp->type); + dprintk("read_attrs: type=%d\n", (uint32_t)nfp->type); } if (bmval0 & FATTR4_WORD0_CHANGE) { READ_BUF(8); @@ -1250,11 +1198,12 @@ success: } static int -decode_getfh(struct nfs4_compound *cp, int nfserr, struct nfs4_getfh *getfh) +decode_getfh(struct xdr_stream *xdr, int nfserr, struct nfs4_getfh *getfh) { struct nfs_fh *fh = getfh->gf_fhandle; - int len; - DECODE_HEAD; + uint32_t *p; + uint32_t len; + int status; /* Zero handle first to allow comparisons */ memset(fh, 0, sizeof(*fh)); @@ -1273,26 +1222,27 @@ decode_getfh(struct nfs4_compound *cp, int nfserr, struct nfs4_getfh *getfh) } static int -decode_link(struct nfs4_compound *cp, int nfserr, struct nfs4_link *link) +decode_link(struct xdr_stream *xdr, int nfserr, struct nfs4_link *link) { int status = 0; if (!nfserr) - status = decode_change_info(cp, link->ln_cinfo); + status = decode_change_info(xdr, link->ln_cinfo); return status; } static int -decode_open(struct nfs4_compound *cp, int nfserr, struct nfs4_open *open) +decode_open(struct xdr_stream *xdr, int nfserr, struct nfs4_open *open) { - u32 bmlen, delegation_type; - DECODE_HEAD; + uint32_t *p; + uint32_t bmlen, delegation_type; + int status; if (!nfserr) { READ_BUF(sizeof(nfs4_stateid)); COPYMEM(open->op_stateid, sizeof(nfs4_stateid)); - decode_change_info(cp, open->op_cinfo); + decode_change_info(xdr, open->op_cinfo); READ_BUF(8); READ32(*open->op_rflags); @@ -1311,23 +1261,23 @@ decode_open(struct nfs4_compound *cp, int nfserr, struct nfs4_open *open) } static int -decode_open_confirm(struct nfs4_compound *cp, int nfserr, struct nfs4_open_confirm *open_confirm) +decode_open_confirm(struct xdr_stream *xdr, int nfserr, struct nfs4_open_confirm *open_confirm) { - DECODE_HEAD; + uint32_t *p; if (!nfserr) { READ_BUF(sizeof(nfs4_stateid)); COPYMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid)); } - - DECODE_TAIL; + return 0; } static int -decode_read(struct nfs4_compound *cp, int nfserr, struct nfs4_read *read) +decode_read(struct xdr_stream *xdr, int nfserr, struct nfs4_read *read) { - u32 throwaway; - DECODE_HEAD; + uint32_t throwaway; + uint32_t *p; + int status; if (!nfserr) { READ_BUF(8); @@ -1344,23 +1294,22 @@ decode_read(struct nfs4_compound *cp, int nfserr, struct nfs4_read *read) } static int -decode_readdir(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struct nfs4_readdir *readdir) +decode_readdir(struct xdr_stream *xdr, int nfserr, struct rpc_rqst *req, struct nfs4_readdir *readdir) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct page *page = *rcvbuf->pages; unsigned int pglen = rcvbuf->page_len; - u32 *end, *entry; - u32 len, attrlen, word; - int i; - DECODE_HEAD; + uint32_t *end, *entry, *p; + uint32_t len, attrlen, word; + int i; if (!nfserr) { READ_BUF(8); COPYMEM(readdir->rd_resp_verifier, 8); BUG_ON(pglen > PAGE_CACHE_SIZE); - p = (u32 *) kmap(page); - end = (u32 *) ((char *)p + pglen + readdir->rd_pgbase); + p = (uint32_t *) kmap(page); + end = (uint32_t *) ((char *)p + pglen + readdir->rd_pgbase); while (*p++) { entry = p - 1; @@ -1406,7 +1355,7 @@ decode_readdir(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struc kunmap(page); } - DECODE_TAIL; + return 0; short_pkt: printk(KERN_NOTICE "NFS: short packet in readdir reply!\n"); /* truncate listing */ @@ -1419,11 +1368,11 @@ err_unmap: } static int -decode_readlink(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struct nfs4_readlink *readlink) +decode_readlink(struct xdr_stream *xdr, int nfserr, struct rpc_rqst *req, struct nfs4_readlink *readlink) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; - u32 *strlen; - u32 len; + uint32_t *strlen; + uint32_t len; char *string; if (!nfserr) { @@ -1434,7 +1383,7 @@ decode_readlink(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, stru * and and null-terminate the text (the VFS expects * null-termination). */ - strlen = (u32 *) kmap(rcvbuf->pages[0]); + strlen = (uint32_t *) kmap(rcvbuf->pages[0]); len = ntohl(*strlen); if (len > PAGE_CACHE_SIZE - 5) { printk(KERN_WARNING "nfs: server returned giant symlink!\n"); @@ -1451,25 +1400,25 @@ decode_readlink(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, stru } static int -decode_remove(struct nfs4_compound *cp, int nfserr, struct nfs4_remove *remove) +decode_remove(struct xdr_stream *xdr, int nfserr, struct nfs4_remove *remove) { int status; status = 0; if (!nfserr) - status = decode_change_info(cp, remove->rm_cinfo); + status = decode_change_info(xdr, remove->rm_cinfo); return status; } static int -decode_rename(struct nfs4_compound *cp, int nfserr, struct nfs4_rename *rename) +decode_rename(struct xdr_stream *xdr, int nfserr, struct nfs4_rename *rename) { int status = 0; if (!nfserr) { - if ((status = decode_change_info(cp, rename->rn_src_cinfo))) + if ((status = decode_change_info(xdr, rename->rn_src_cinfo))) goto out; - if ((status = decode_change_info(cp, rename->rn_dst_cinfo))) + if ((status = decode_change_info(xdr, rename->rn_dst_cinfo))) goto out; } out: @@ -1477,10 +1426,11 @@ out: } static int -decode_setattr(struct nfs4_compound *cp) +decode_setattr(struct xdr_stream *xdr) { - u32 bmlen; - DECODE_HEAD; + uint32_t *p; + uint32_t bmlen; + int status; READ_BUF(4); READ32(bmlen); @@ -1492,17 +1442,17 @@ decode_setattr(struct nfs4_compound *cp) } static int -decode_setclientid(struct nfs4_compound *cp, int nfserr) +decode_setclientid(struct xdr_stream *xdr, int nfserr, struct nfs4_setclientid *setclientid) { - DECODE_HEAD; + uint32_t *p; if (!nfserr) { READ_BUF(8 + sizeof(nfs4_verifier)); - READ64(cp->server->nfs4_state->cl_clientid); - COPYMEM(cp->server->nfs4_state->cl_confirm, sizeof(nfs4_verifier)); + READ64(setclientid->sc_state->cl_clientid); + COPYMEM(setclientid->sc_state->cl_confirm, sizeof(nfs4_verifier)); } else if (nfserr == NFSERR_CLID_INUSE) { - u32 len; + uint32_t len; /* skip netid string */ READ_BUF(4); @@ -1515,13 +1465,14 @@ decode_setclientid(struct nfs4_compound *cp, int nfserr) READ_BUF(len); } - DECODE_TAIL; + return 0; } static int -decode_write(struct nfs4_compound *cp, int nfserr, struct nfs4_write *write) +decode_write(struct xdr_stream *xdr, int nfserr, struct nfs4_write *write) { - DECODE_HEAD; + uint32_t *p; + int status; if (!nfserr) { READ_BUF(16); @@ -1537,11 +1488,12 @@ decode_write(struct nfs4_compound *cp, int nfserr, struct nfs4_write *write) /* FIXME: this sucks */ static int -decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) +decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req) { - u32 taglen; - u32 opnum, nfserr; - DECODE_HEAD; + uint32_t *p; + uint32_t taglen; + uint32_t opnum, nfserr; + int status; READ_BUF(8); READ32(cp->toplevel_status); @@ -1584,34 +1536,34 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) switch (opnum) { case OP_ACCESS: - status = decode_access(cp, nfserr, &cp->ops[cp->nops].u.access); + status = decode_access(xdr, nfserr, &cp->ops[cp->nops].u.access); break; case OP_CLOSE: - status = decode_close(cp, nfserr, &cp->ops[cp->nops].u.close); + status = decode_close(xdr, nfserr, &cp->ops[cp->nops].u.close); break; case OP_COMMIT: - status = decode_commit(cp, nfserr, &cp->ops[cp->nops].u.commit); + status = decode_commit(xdr, nfserr, &cp->ops[cp->nops].u.commit); break; case OP_CREATE: - status = decode_create(cp, nfserr, &cp->ops[cp->nops].u.create); + status = decode_create(xdr, nfserr, &cp->ops[cp->nops].u.create); break; case OP_GETATTR: - status = decode_getattr(cp, nfserr, &cp->ops[cp->nops].u.getattr); + status = decode_getattr(xdr, nfserr, &cp->ops[cp->nops].u.getattr); break; case OP_GETFH: - status = decode_getfh(cp, nfserr, &cp->ops[cp->nops].u.getfh); + status = decode_getfh(xdr, nfserr, &cp->ops[cp->nops].u.getfh); break; case OP_LINK: - status = decode_link(cp, nfserr, &cp->ops[cp->nops].u.link); + status = decode_link(xdr, nfserr, &cp->ops[cp->nops].u.link); break; case OP_LOOKUP: status = 0; break; case OP_OPEN: - status = decode_open(cp, nfserr, &cp->ops[cp->nops].u.open); + status = decode_open(xdr, nfserr, &cp->ops[cp->nops].u.open); break; case OP_OPEN_CONFIRM: - status = decode_open_confirm(cp, nfserr, &cp->ops[cp->nops].u.open_confirm); + status = decode_open_confirm(xdr, nfserr, &cp->ops[cp->nops].u.open_confirm); break; case OP_PUTFH: status = 0; @@ -1620,22 +1572,22 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) status = 0; break; case OP_READ: - status = decode_read(cp, nfserr, &cp->ops[cp->nops].u.read); + status = decode_read(xdr, nfserr, &cp->ops[cp->nops].u.read); break; case OP_READDIR: - status = decode_readdir(cp, nfserr, req, &cp->ops[cp->nops].u.readdir); + status = decode_readdir(xdr, nfserr, req, &cp->ops[cp->nops].u.readdir); break; case OP_READLINK: - status = decode_readlink(cp, nfserr, req, &cp->ops[cp->nops].u.readlink); + status = decode_readlink(xdr, nfserr, req, &cp->ops[cp->nops].u.readlink); break; case OP_RESTOREFH: status = 0; break; case OP_REMOVE: - status = decode_remove(cp, nfserr, &cp->ops[cp->nops].u.remove); + status = decode_remove(xdr, nfserr, &cp->ops[cp->nops].u.remove); break; case OP_RENAME: - status = decode_rename(cp, nfserr, &cp->ops[cp->nops].u.rename); + status = decode_rename(xdr, nfserr, &cp->ops[cp->nops].u.rename); break; case OP_RENEW: status = 0; @@ -1644,16 +1596,16 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) status = 0; break; case OP_SETATTR: - status = decode_setattr(cp); + status = decode_setattr(xdr); break; case OP_SETCLIENTID: - status = decode_setclientid(cp, nfserr); + status = decode_setclientid(xdr, nfserr, &cp->ops[cp->nops].u.setclientid); break; case OP_SETCLIENTID_CONFIRM: status = 0; break; case OP_WRITE: - status = decode_write(cp, nfserr, &cp->ops[cp->nops].u.write); + status = decode_write(xdr, nfserr, &cp->ops[cp->nops].u.write); break; default: BUG(); @@ -1673,14 +1625,13 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) * Decode COMPOUND response */ static int -nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, u32 *p, struct nfs4_compound *cp) +nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_compound *cp) { + struct xdr_stream xdr; int status; - cp->p = p; - cp->end = (u32 *) ((u8 *) rqstp->rq_rvec->iov_base + rqstp->rq_rvec->iov_len); - - if ((status = decode_compound(cp, rqstp))) + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + if ((status = decode_compound(&xdr, cp, rqstp))) goto out; status = 0; @@ -1691,10 +1642,10 @@ out: return status; } -u32 * -nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) +uint32_t * +nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) { - u32 len; + uint32_t len; if (!*p++) { if (!*p) diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 6c82048e2acf..970ffa785f78 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -398,6 +398,7 @@ struct nfs4_lookup { }; struct nfs4_open { + struct nfs4_client * op_client_state; /* request */ u32 op_share_access; /* request */ u32 op_opentype; /* request */ u32 op_createmode; /* request */ @@ -472,6 +473,7 @@ struct nfs4_setclientid { char sc_netid[4]; /* request */ char sc_uaddr[24]; /* request */ u32 sc_cb_ident; /* request */ + struct nfs4_client * sc_state; /* response */ }; struct nfs4_write { @@ -504,8 +506,10 @@ struct nfs4_op { struct nfs4_readlink readlink; struct nfs4_remove remove; struct nfs4_rename rename; + struct nfs4_client * renew; struct nfs4_setattr setattr; struct nfs4_setclientid setclientid; + struct nfs4_client * setclientid_confirm; struct nfs4_write write; } u; }; diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 0233988f40b4..74c5260b2343 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -155,6 +155,93 @@ typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, skb_reader_t *, skb_read_actor_t); +/* + * Provide some simple tools for XDR buffer overflow-checking etc. + */ +struct xdr_stream { + uint32_t *p; /* start of available buffer */ + struct xdr_buf *buf; /* XDR buffer to read/write */ + + uint32_t *end; /* end of available buffer space */ + struct iovec *iov; /* pointer to the current iovec */ +}; + +/* + * Initialize an xdr_stream for encoding data. + * + * Note: at the moment the RPC client only passes the length of our + * scratch buffer in the xdr_buf's header iovec. Previously this + * meant we needed to call xdr_adjust_iovec() after encoding the + * data. With the new scheme, the xdr_stream manages the details + * of the buffer length, and takes care of adjusting the iovec + * length for us. + */ +static inline void +xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) +{ + struct iovec *iov = buf->head; + + xdr->buf = buf; + xdr->iov = iov; + xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); + buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base; + xdr->p = p; +} + +/* + * Check that we have enough buffer space to encode 'nbytes' more + * bytes of data. If so, update the total xdr_buf length, and + * adjust the length of the current iovec. + */ +static inline uint32_t * +xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) +{ + uint32_t *p = xdr->p; + uint32_t *q; + + /* align nbytes on the next 32-bit boundary */ + nbytes += 3; + nbytes &= ~3; + q = p + (nbytes >> 2); + if (unlikely(q > xdr->end || q < p)) + return NULL; + xdr->p = q; + xdr->iov->iov_len += nbytes; + xdr->buf->len += nbytes; + return p; +} + +/* + * Initialize an xdr_stream for decoding data. + */ +static inline void +xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) +{ + struct iovec *iov = buf->head; + xdr->buf = buf; + xdr->iov = iov; + xdr->p = p; + xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); +} + +/* + * Check if the input buffer is long enough to enable us to decode + * 'nbytes' more bytes of data starting at the current position. + * If so return the current pointer, then update the current + * position. + */ +static inline uint32_t * +xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) +{ + uint32_t *p = xdr->p; + uint32_t *q = p + XDR_QUADLEN(nbytes); + + if (unlikely(q > xdr->end || q < p)) + return NULL; + xdr->p = q; + return p; +} + #endif /* __KERNEL__ */ #endif /* _SUNRPC_XDR_H_ */ |
