Commit dccb90df authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[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.
parent 241c59e2
...@@ -65,11 +65,6 @@ nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops, ...@@ -65,11 +65,6 @@ nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
memset(cp, 0, sizeof(*cp)); memset(cp, 0, sizeof(*cp));
cp->ops = ops; cp->ops = ops;
cp->server = server; cp->server = server;
#if NFS4_DEBUG
cp->taglen = strlen(tag);
cp->tag = tag;
#endif
} }
static void static void
...@@ -373,6 +368,7 @@ nfs4_setup_open(struct nfs4_compound *cp, int flags, struct qstr *name, ...@@ -373,6 +368,7 @@ nfs4_setup_open(struct nfs4_compound *cp, int flags, struct qstr *name,
BUG_ON(cp->flags); BUG_ON(cp->flags);
open->op_client_state = cp->server->nfs4_state;
open->op_share_access = flags & 3; open->op_share_access = flags & 3;
open->op_opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE; open->op_opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE;
open->op_createmode = NFS4_CREATE_UNCHECKED; open->op_createmode = NFS4_CREATE_UNCHECKED;
...@@ -527,6 +523,10 @@ nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new, ...@@ -527,6 +523,10 @@ nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new,
static void static void
nfs4_setup_renew(struct nfs4_compound *cp) 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; OPNUM(cp) = OP_RENEW;
cp->req_nops++; cp->req_nops++;
cp->renew_index = 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 ...@@ -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); sprintf(setclientid->sc_uaddr, "%s.%d.%d", server->ip_addr, port >> 8, port & 255);
setclientid->sc_prog = program; setclientid->sc_prog = program;
setclientid->sc_cb_ident = 0; setclientid->sc_cb_ident = 0;
setclientid->sc_state = server->nfs4_state;
OPNUM(cp) = OP_SETCLIENTID; OPNUM(cp) = OP_SETCLIENTID;
cp->req_nops++; cp->req_nops++;
...@@ -583,6 +584,10 @@ nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short por ...@@ -583,6 +584,10 @@ nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short por
static void static void
nfs4_setup_setclientid_confirm(struct nfs4_compound *cp) 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; OPNUM(cp) = OP_SETCLIENTID_CONFIRM;
cp->req_nops++; cp->req_nops++;
cp->renew_index = cp->req_nops; cp->renew_index = cp->req_nops;
......
...@@ -57,8 +57,6 @@ ...@@ -57,8 +57,6 @@
*/ */
#define COOKIE_MAX 0x7fffffff #define COOKIE_MAX 0x7fffffff
#define NFS4_CLIENTID(server) ((server)->nfs4_state->cl_clientid)
#define NFSDBG_FACILITY NFSDBG_XDR #define NFSDBG_FACILITY NFSDBG_XDR
/* Mapping from NFS error code to "errno" error code. */ /* Mapping from NFS error code to "errno" error code. */
...@@ -95,25 +93,22 @@ static struct { ...@@ -95,25 +93,22 @@ static struct {
* task to translate them into Linux-specific versions which are more * task to translate them into Linux-specific versions which are more
* consistent with the style used in NFSv2/v3... * 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 WRITE32(n) *p++ = htonl(n)
#define WRITE64(n) do { \ #define WRITE64(n) do { \
*p++ = htonl((u32)((n) >> 32)); \ *p++ = htonl((uint32_t)((n) >> 32)); \
*p++ = htonl((u32)(n)); \ *p++ = htonl((uint32_t)(n)); \
} while (0) } while (0)
#define WRITEMEM(ptr,nbytes) do { \ #define WRITEMEM(ptr,nbytes) do { \
p = xdr_writemem(p, ptr, nbytes); \ p = xdr_writemem(p, ptr, nbytes); \
} while (0) } while (0)
#define RESERVE_SPACE(nbytes) do { BUG_ON(cp->p + XDR_QUADLEN(nbytes) > cp->end); p = cp->p; } while (0) #define RESERVE_SPACE(nbytes) do { \
#define ADJUST_ARGS() cp->p = p p = xdr_reserve_space(xdr, nbytes); \
BUG_ON(!p); \
} while (0)
static inline 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); int tmp = XDR_QUADLEN(nbytes);
if (!tmp) if (!tmp)
...@@ -146,18 +141,18 @@ encode_gid(char *p, gid_t gid) ...@@ -146,18 +141,18 @@ encode_gid(char *p, gid_t gid)
} }
static int 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_name[256];
char owner_group[256]; char owner_group[256];
int owner_namelen = 0; int owner_namelen = 0;
int owner_grouplen = 0; int owner_grouplen = 0;
u32 *q; uint32_t *p;
uint32_t *q;
int len; int len;
u32 bmval0 = 0; uint32_t bmval0 = 0;
u32 bmval1 = 0; uint32_t bmval1 = 0;
int status; int status;
ENCODE_HEAD;
/* /*
* We reserve enough space to write the entire attribute buffer at once. * 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) ...@@ -240,8 +235,6 @@ encode_attrs(struct nfs4_compound *cp, struct iattr *iap)
WRITE32(NFS4_SET_TO_SERVER_TIME); WRITE32(NFS4_SET_TO_SERVER_TIME);
} }
ADJUST_ARGS();
/* /*
* Now we backfill the bitmap and the attribute buffer length. * Now we backfill the bitmap and the attribute buffer length.
*/ */
...@@ -256,69 +249,63 @@ encode_attrs(struct nfs4_compound *cp, struct iattr *iap) ...@@ -256,69 +249,63 @@ encode_attrs(struct nfs4_compound *cp, struct iattr *iap)
} }
static int 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); RESERVE_SPACE(8);
WRITE32(OP_ACCESS); WRITE32(OP_ACCESS);
WRITE32(access->ac_req_access); WRITE32(access->ac_req_access);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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); RESERVE_SPACE(20);
WRITE32(OP_CLOSE); WRITE32(OP_CLOSE);
WRITE32(close->cl_seqid); WRITE32(close->cl_seqid);
WRITEMEM(close->cl_stateid, sizeof(nfs4_stateid)); WRITEMEM(close->cl_stateid, sizeof(nfs4_stateid));
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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); RESERVE_SPACE(16);
WRITE32(OP_COMMIT); WRITE32(OP_COMMIT);
WRITE64(commit->co_start); WRITE64(commit->co_start);
WRITE32(commit->co_len); WRITE32(commit->co_len);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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); RESERVE_SPACE(8);
WRITE32(OP_CREATE); WRITE32(OP_CREATE);
WRITE32(create->cr_ftype); WRITE32(create->cr_ftype);
ADJUST_ARGS();
switch (create->cr_ftype) { switch (create->cr_ftype) {
case NF4LNK: case NF4LNK:
RESERVE_SPACE(4 + create->cr_textlen); RESERVE_SPACE(4 + create->cr_textlen);
WRITE32(create->cr_textlen); WRITE32(create->cr_textlen);
WRITEMEM(create->cr_text, create->cr_textlen); WRITEMEM(create->cr_text, create->cr_textlen);
ADJUST_ARGS();
break; break;
case NF4BLK: case NF4CHR: case NF4BLK: case NF4CHR:
RESERVE_SPACE(8); RESERVE_SPACE(8);
WRITE32(create->cr_specdata1); WRITE32(create->cr_specdata1);
WRITE32(create->cr_specdata2); WRITE32(create->cr_specdata2);
ADJUST_ARGS();
break; break;
default: default:
...@@ -328,74 +315,69 @@ encode_create(struct nfs4_compound *cp, struct nfs4_create *create) ...@@ -328,74 +315,69 @@ encode_create(struct nfs4_compound *cp, struct nfs4_create *create)
RESERVE_SPACE(4 + create->cr_namelen); RESERVE_SPACE(4 + create->cr_namelen);
WRITE32(create->cr_namelen); WRITE32(create->cr_namelen);
WRITEMEM(create->cr_name, 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 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); RESERVE_SPACE(16);
WRITE32(OP_GETATTR); WRITE32(OP_GETATTR);
WRITE32(2); WRITE32(2);
WRITE32(getattr->gt_bmval[0]); WRITE32(getattr->gt_bmval[0]);
WRITE32(getattr->gt_bmval[1]); WRITE32(getattr->gt_bmval[1]);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int static int
encode_getfh(struct nfs4_compound *cp) encode_getfh(struct xdr_stream *xdr)
{ {
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(4); RESERVE_SPACE(4);
WRITE32(OP_GETFH); WRITE32(OP_GETFH);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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); RESERVE_SPACE(8 + link->ln_namelen);
WRITE32(OP_LINK); WRITE32(OP_LINK);
WRITE32(link->ln_namelen); WRITE32(link->ln_namelen);
WRITEMEM(link->ln_name, link->ln_namelen); WRITEMEM(link->ln_name, link->ln_namelen);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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; int len = lookup->lo_name->len;
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(8 + len); RESERVE_SPACE(8 + len);
WRITE32(OP_LOOKUP); WRITE32(OP_LOOKUP);
WRITE32(len); WRITE32(len);
WRITEMEM(lookup->lo_name->name, len); WRITEMEM(lookup->lo_name->name, len);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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; static int global_id = 0;
int id = global_id++; int id = global_id++;
int status; int status;
ENCODE_HEAD; uint32_t *p;
/* seqid, share_access, share_deny, clientid, ownerlen, owner, opentype */ /* seqid, share_access, share_deny, clientid, ownerlen, owner, opentype */
RESERVE_SPACE(52); RESERVE_SPACE(52);
...@@ -403,24 +385,21 @@ encode_open(struct nfs4_compound *cp, struct nfs4_open *open) ...@@ -403,24 +385,21 @@ encode_open(struct nfs4_compound *cp, struct nfs4_open *open)
WRITE32(0); /* seqid */ WRITE32(0); /* seqid */
WRITE32(open->op_share_access); WRITE32(open->op_share_access);
WRITE32(0); /* for us, share_deny== 0 always */ WRITE32(0); /* for us, share_deny== 0 always */
WRITE64(NFS4_CLIENTID(cp->server)); WRITE64(open->op_client_state->cl_clientid);
WRITE32(4); WRITE32(4);
WRITE32(id); WRITE32(id);
WRITE32(open->op_opentype); WRITE32(open->op_opentype);
ADJUST_ARGS();
if (open->op_opentype == NFS4_OPEN_CREATE) { if (open->op_opentype == NFS4_OPEN_CREATE) {
if (open->op_createmode == NFS4_CREATE_EXCLUSIVE) { if (open->op_createmode == NFS4_CREATE_EXCLUSIVE) {
RESERVE_SPACE(12); RESERVE_SPACE(12);
WRITE32(open->op_createmode); WRITE32(open->op_createmode);
WRITEMEM(open->op_verifier, sizeof(nfs4_verifier)); WRITEMEM(open->op_verifier, sizeof(nfs4_verifier));
ADJUST_ARGS();
} }
else if (open->op_attrs) { else if (open->op_attrs) {
RESERVE_SPACE(4); RESERVE_SPACE(4);
WRITE32(open->op_createmode); WRITE32(open->op_createmode);
ADJUST_ARGS(); if ((status = encode_attrs(xdr, open->op_attrs)))
if ((status = encode_attrs(cp, open->op_attrs)))
return status; return status;
} }
else { else {
...@@ -428,7 +407,6 @@ encode_open(struct nfs4_compound *cp, struct nfs4_open *open) ...@@ -428,7 +407,6 @@ encode_open(struct nfs4_compound *cp, struct nfs4_open *open)
WRITE32(open->op_createmode); WRITE32(open->op_createmode);
WRITE32(0); WRITE32(0);
WRITE32(0); WRITE32(0);
ADJUST_ARGS();
} }
} }
...@@ -436,15 +414,14 @@ encode_open(struct nfs4_compound *cp, struct nfs4_open *open) ...@@ -436,15 +414,14 @@ encode_open(struct nfs4_compound *cp, struct nfs4_open *open)
WRITE32(NFS4_OPEN_CLAIM_NULL); WRITE32(NFS4_OPEN_CLAIM_NULL);
WRITE32(open->op_name->len); WRITE32(open->op_name->len);
WRITEMEM(open->op_name->name, open->op_name->len); WRITEMEM(open->op_name->name, open->op_name->len);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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 * 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 ...@@ -454,44 +431,41 @@ encode_open_confirm(struct nfs4_compound *cp, struct nfs4_open_confirm *open_con
WRITE32(OP_OPEN_CONFIRM); WRITE32(OP_OPEN_CONFIRM);
WRITEMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid)); WRITEMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid));
WRITE32(1); WRITE32(1);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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; int len = putfh->pf_fhandle->size;
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(8 + len); RESERVE_SPACE(8 + len);
WRITE32(OP_PUTFH); WRITE32(OP_PUTFH);
WRITE32(len); WRITE32(len);
WRITEMEM(putfh->pf_fhandle->data, len); WRITEMEM(putfh->pf_fhandle->data, len);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int static int
encode_putrootfh(struct nfs4_compound *cp) encode_putrootfh(struct xdr_stream *xdr)
{ {
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(4); RESERVE_SPACE(4);
WRITE32(OP_PUTROOTFH); WRITE32(OP_PUTROOTFH);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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; struct rpc_auth *auth = req->rq_task->tk_auth;
int replen; int replen;
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(32); RESERVE_SPACE(32);
WRITE32(OP_READ); WRITE32(OP_READ);
...@@ -501,26 +475,24 @@ encode_read(struct nfs4_compound *cp, struct nfs4_read *read, struct rpc_rqst *r ...@@ -501,26 +475,24 @@ encode_read(struct nfs4_compound *cp, struct nfs4_read *read, struct rpc_rqst *r
WRITE32(0); WRITE32(0);
WRITE64(read->rd_offset); WRITE64(read->rd_offset);
WRITE32(read->rd_length); WRITE32(read->rd_length);
ADJUST_ARGS();
/* set up reply iovec /* set up reply iovec
* toplevel status + taglen + rescount + OP_PUTFH + status * toplevel status + taglen + rescount + OP_PUTFH + status
* + OP_READ + status + eof + datalen = 9 * + OP_READ + status + eof + datalen = 9
*/ */
replen = (RPC_REPHDRSIZE + auth->au_rslack + 9 + XDR_QUADLEN(cp->taglen)) << 2; replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
xdr_inline_pages(&req->rq_rcv_buf, replen, xdr_inline_pages(&req->rq_rcv_buf, replen,
read->rd_pages, read->rd_pgbase, read->rd_length); read->rd_pages, read->rd_pgbase, read->rd_length);
ENCODE_TAIL; return 0;
} }
static int 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; struct rpc_auth *auth = req->rq_task->tk_auth;
int replen; int replen;
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(40); RESERVE_SPACE(40);
WRITE32(OP_READDIR); WRITE32(OP_READDIR);
...@@ -531,135 +503,124 @@ encode_readdir(struct nfs4_compound *cp, struct nfs4_readdir *readdir, struct rp ...@@ -531,135 +503,124 @@ encode_readdir(struct nfs4_compound *cp, struct nfs4_readdir *readdir, struct rp
WRITE32(2); WRITE32(2);
WRITE32(readdir->rd_bmval[0]); WRITE32(readdir->rd_bmval[0]);
WRITE32(readdir->rd_bmval[1]); WRITE32(readdir->rd_bmval[1]);
ADJUST_ARGS();
/* set up reply iovec /* set up reply iovec
* toplevel_status + taglen + rescount + OP_PUTFH + status * toplevel_status + taglen + rescount + OP_PUTFH + status
* + OP_READDIR + status + verifer(2) = 9 * + OP_READDIR + status + verifer(2) = 9
*/ */
replen = (RPC_REPHDRSIZE + auth->au_rslack + 9 + XDR_QUADLEN(cp->taglen)) << 2; replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->rd_pages, xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->rd_pages,
readdir->rd_pgbase, readdir->rd_count); readdir->rd_pgbase, readdir->rd_count);
ENCODE_TAIL; return 0;
} }
static int 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; struct rpc_auth *auth = req->rq_task->tk_auth;
int replen; int replen;
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(4); RESERVE_SPACE(4);
WRITE32(OP_READLINK); WRITE32(OP_READLINK);
ADJUST_ARGS();
/* set up reply iovec /* set up reply iovec
* toplevel_status + taglen + rescount + OP_PUTFH + status * toplevel_status + taglen + rescount + OP_PUTFH + status
* + OP_READLINK + status = 7 * + OP_READLINK + status = 7
*/ */
replen = (RPC_REPHDRSIZE + auth->au_rslack + 7 + XDR_QUADLEN(cp->taglen)) << 2; replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count); xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count);
ENCODE_TAIL; return 0;
} }
static int 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); RESERVE_SPACE(8 + remove->rm_namelen);
WRITE32(OP_REMOVE); WRITE32(OP_REMOVE);
WRITE32(remove->rm_namelen); WRITE32(remove->rm_namelen);
WRITEMEM(remove->rm_name, remove->rm_namelen); WRITEMEM(remove->rm_name, remove->rm_namelen);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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); RESERVE_SPACE(8 + rename->rn_oldnamelen);
WRITE32(OP_RENAME); WRITE32(OP_RENAME);
WRITE32(rename->rn_oldnamelen); WRITE32(rename->rn_oldnamelen);
WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen); WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen);
ADJUST_ARGS();
RESERVE_SPACE(8 + rename->rn_newnamelen); RESERVE_SPACE(8 + rename->rn_newnamelen);
WRITE32(rename->rn_newnamelen); WRITE32(rename->rn_newnamelen);
WRITEMEM(rename->rn_newname, rename->rn_newnamelen); WRITEMEM(rename->rn_newname, rename->rn_newnamelen);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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); RESERVE_SPACE(12);
WRITE32(OP_RENEW); WRITE32(OP_RENEW);
WRITE64(NFS4_CLIENTID(cp->server)); WRITE64(client_stateid->cl_clientid);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int static int
encode_restorefh(struct nfs4_compound *cp) encode_restorefh(struct xdr_stream *xdr)
{ {
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(4); RESERVE_SPACE(4);
WRITE32(OP_RESTOREFH); WRITE32(OP_RESTOREFH);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int static int
encode_savefh(struct nfs4_compound *cp) encode_savefh(struct xdr_stream *xdr)
{ {
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(4); RESERVE_SPACE(4);
WRITE32(OP_SAVEFH); WRITE32(OP_SAVEFH);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int static int
encode_setattr(struct nfs4_compound *cp, struct nfs4_setattr *setattr) encode_setattr(struct xdr_stream *xdr, struct nfs4_setattr *setattr)
{ {
int status; int status;
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(20); RESERVE_SPACE(20);
WRITE32(OP_SETATTR); WRITE32(OP_SETATTR);
WRITEMEM(setattr->st_stateid, sizeof(nfs4_stateid)); 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; return status;
ENCODE_TAIL; return 0;
} }
static int 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; uint32_t total_len;
u32 len1, len2, len3; uint32_t len1, len2, len3;
ENCODE_HEAD; uint32_t *p;
len1 = strlen(setclientid->sc_name); len1 = strlen(setclientid->sc_name);
len2 = strlen(setclientid->sc_netid); len2 = strlen(setclientid->sc_netid);
...@@ -678,30 +639,28 @@ encode_setclientid(struct nfs4_compound *cp, struct nfs4_setclientid *setclienti ...@@ -678,30 +639,28 @@ encode_setclientid(struct nfs4_compound *cp, struct nfs4_setclientid *setclienti
WRITE32(len3); WRITE32(len3);
WRITEMEM(setclientid->sc_uaddr, len3); WRITEMEM(setclientid->sc_uaddr, len3);
WRITE32(setclientid->sc_cb_ident); WRITE32(setclientid->sc_cb_ident);
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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)); RESERVE_SPACE(12 + sizeof(nfs4_verifier));
WRITE32(OP_SETCLIENTID_CONFIRM); WRITE32(OP_SETCLIENTID_CONFIRM);
WRITE64(cp->server->nfs4_state->cl_clientid); WRITE64(client_state->cl_clientid);
WRITEMEM(cp->server->nfs4_state->cl_confirm,sizeof(nfs4_verifier)); WRITEMEM(client_state->cl_confirm,sizeof(nfs4_verifier));
ADJUST_ARGS();
ENCODE_TAIL; return 0;
} }
static int 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; struct xdr_buf *sndbuf = &req->rq_snd_buf;
ENCODE_HEAD; uint32_t *p;
RESERVE_SPACE(36); RESERVE_SPACE(36);
WRITE32(OP_WRITE); WRITE32(OP_WRITE);
...@@ -712,20 +671,18 @@ encode_write(struct nfs4_compound *cp, struct nfs4_write *write, struct rpc_rqst ...@@ -712,20 +671,18 @@ encode_write(struct nfs4_compound *cp, struct nfs4_write *write, struct rpc_rqst
WRITE64(write->wr_offset); WRITE64(write->wr_offset);
WRITE32(write->wr_stable_how); WRITE32(write->wr_stable_how);
WRITE32(write->wr_len); 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); xdr_encode_pages(sndbuf, write->wr_pages, write->wr_pgbase, write->wr_len);
ENCODE_TAIL; return 0;
} }
/* FIXME: this sucks */ /* FIXME: this sucks */
static int 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; int i, status = 0;
ENCODE_HEAD; uint32_t *p;
dprintk("encode_compound: tag=%.*s\n", (int)cp->taglen, cp->tag); 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) ...@@ -734,81 +691,80 @@ encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
WRITEMEM(cp->tag, cp->taglen); WRITEMEM(cp->tag, cp->taglen);
WRITE32(NFS4_MINOR_VERSION); WRITE32(NFS4_MINOR_VERSION);
WRITE32(cp->req_nops); WRITE32(cp->req_nops);
ADJUST_ARGS();
for (i = 0; i < cp->req_nops; i++) { for (i = 0; i < cp->req_nops; i++) {
switch (cp->ops[i].opnum) { switch (cp->ops[i].opnum) {
case OP_ACCESS: case OP_ACCESS:
status = encode_access(cp, &cp->ops[i].u.access); status = encode_access(xdr, &cp->ops[i].u.access);
break; break;
case OP_CLOSE: case OP_CLOSE:
status = encode_close(cp, &cp->ops[i].u.close); status = encode_close(xdr, &cp->ops[i].u.close);
break; break;
case OP_COMMIT: case OP_COMMIT:
status = encode_commit(cp, &cp->ops[i].u.commit); status = encode_commit(xdr, &cp->ops[i].u.commit);
break; break;
case OP_CREATE: case OP_CREATE:
status = encode_create(cp, &cp->ops[i].u.create); status = encode_create(xdr, &cp->ops[i].u.create);
break; break;
case OP_GETATTR: case OP_GETATTR:
status = encode_getattr(cp, &cp->ops[i].u.getattr); status = encode_getattr(xdr, &cp->ops[i].u.getattr);
break; break;
case OP_GETFH: case OP_GETFH:
status = encode_getfh(cp); status = encode_getfh(xdr);
break; break;
case OP_LINK: case OP_LINK:
status = encode_link(cp, &cp->ops[i].u.link); status = encode_link(xdr, &cp->ops[i].u.link);
break; break;
case OP_LOOKUP: case OP_LOOKUP:
status = encode_lookup(cp, &cp->ops[i].u.lookup); status = encode_lookup(xdr, &cp->ops[i].u.lookup);
break; break;
case OP_OPEN: case OP_OPEN:
status = encode_open(cp, &cp->ops[i].u.open); status = encode_open(xdr, &cp->ops[i].u.open);
break; break;
case OP_OPEN_CONFIRM: 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; break;
case OP_PUTFH: case OP_PUTFH:
status = encode_putfh(cp, &cp->ops[i].u.putfh); status = encode_putfh(xdr, &cp->ops[i].u.putfh);
break; break;
case OP_PUTROOTFH: case OP_PUTROOTFH:
status = encode_putrootfh(cp); status = encode_putrootfh(xdr);
break; break;
case OP_READ: case OP_READ:
status = encode_read(cp, &cp->ops[i].u.read, req); status = encode_read(xdr, &cp->ops[i].u.read, req);
break; break;
case OP_READDIR: case OP_READDIR:
status = encode_readdir(cp, &cp->ops[i].u.readdir, req); status = encode_readdir(xdr, &cp->ops[i].u.readdir, req);
break; break;
case OP_READLINK: case OP_READLINK:
status = encode_readlink(cp, &cp->ops[i].u.readlink, req); status = encode_readlink(xdr, &cp->ops[i].u.readlink, req);
break; break;
case OP_REMOVE: case OP_REMOVE:
status = encode_remove(cp, &cp->ops[i].u.remove); status = encode_remove(xdr, &cp->ops[i].u.remove);
break; break;
case OP_RENAME: case OP_RENAME:
status = encode_rename(cp, &cp->ops[i].u.rename); status = encode_rename(xdr, &cp->ops[i].u.rename);
break; break;
case OP_RENEW: case OP_RENEW:
status = encode_renew(cp); status = encode_renew(xdr, cp->ops[i].u.renew);
break; break;
case OP_RESTOREFH: case OP_RESTOREFH:
status = encode_restorefh(cp); status = encode_restorefh(xdr);
break; break;
case OP_SAVEFH: case OP_SAVEFH:
status = encode_savefh(cp); status = encode_savefh(xdr);
break; break;
case OP_SETATTR: case OP_SETATTR:
status = encode_setattr(cp, &cp->ops[i].u.setattr); status = encode_setattr(xdr, &cp->ops[i].u.setattr);
break; break;
case OP_SETCLIENTID: case OP_SETCLIENTID:
status = encode_setclientid(cp, &cp->ops[i].u.setclientid); status = encode_setclientid(xdr, &cp->ops[i].u.setclientid);
break; break;
case OP_SETCLIENTID_CONFIRM: case OP_SETCLIENTID_CONFIRM:
status = encode_setclientid_confirm(cp); status = encode_setclientid_confirm(xdr, cp->ops[i].u.setclientid_confirm);
break; break;
case OP_WRITE: case OP_WRITE:
status = encode_write(cp, &cp->ops[i].u.write, req); status = encode_write(xdr, &cp->ops[i].u.write, req);
break; break;
default: default:
BUG(); BUG();
...@@ -817,7 +773,7 @@ encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) ...@@ -817,7 +773,7 @@ encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
return status; return status;
} }
ENCODE_TAIL; return 0;
} }
/* /*
* END OF "GENERIC" ENCODE ROUTINES. * END OF "GENERIC" ENCODE ROUTINES.
...@@ -828,18 +784,14 @@ encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) ...@@ -828,18 +784,14 @@ encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
* Encode COMPOUND argument * Encode COMPOUND argument
*/ */
static int 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; int status;
struct xdr_buf *sndbuf = &req->rq_snd_buf;
cp->p = p; xdr_init_encode(&xdr, &req->rq_snd_buf, p);
cp->end = (u32 *) ((char *)req->rq_svec[0].iov_base + req->rq_svec[0].iov_len); status = encode_compound(&xdr, cp, req);
status = encode_compound(cp, req);
cp->timestamp = jiffies; cp->timestamp = jiffies;
if (!status && !sndbuf->page_len)
req->rq_slen = xdr_adjust_iovec(sndbuf->head, cp->p);
return status; return status;
} }
...@@ -854,9 +806,6 @@ nfs4_xdr_enc_compound(struct rpc_rqst *req, u32 *p, struct nfs4_compound *cp) ...@@ -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 * task to translate them into Linux-specific versions which are more
* consistent with the style used in NFSv2/v3... * consistent with the style used in NFSv2/v3...
*/ */
#define DECODE_HEAD \
u32 *p; \
int status
#define DECODE_TAIL \ #define DECODE_TAIL \
status = 0; \ status = 0; \
out: \ out: \
...@@ -882,10 +831,12 @@ xdr_error: \ ...@@ -882,10 +831,12 @@ xdr_error: \
} while (0) } while (0)
#define READ_BUF(nbytes) do { \ #define READ_BUF(nbytes) do { \
if (nbytes > (u32)((char *)cp->end - (char *)cp->p)) \ p = xdr_inline_decode(xdr, nbytes); \
goto xdr_error; \ if (!p) { \
p = cp->p; \ printk(KERN_WARNING "%s: reply buffer overflowed in line %d.", \
cp->p += XDR_QUADLEN(nbytes); \ __FUNCTION__, __LINE__); \
return -EIO; \
} \
} while (0) } while (0)
/* /*
...@@ -893,7 +844,7 @@ xdr_error: \ ...@@ -893,7 +844,7 @@ xdr_error: \
* upcall gets in... * upcall gets in...
*/ */
static int static int
decode_uid(char *p, u32 len, uid_t *uid) decode_uid(char *p, uint32_t len, uid_t *uid)
{ {
*uid = -2; *uid = -2;
return 0; return 0;
...@@ -904,82 +855,78 @@ decode_uid(char *p, u32 len, uid_t *uid) ...@@ -904,82 +855,78 @@ decode_uid(char *p, u32 len, uid_t *uid)
* upcall gets in... * upcall gets in...
*/ */
static int static int
decode_gid(char *p, u32 len, gid_t *gid) decode_gid(char *p, uint32_t len, gid_t *gid)
{ {
*gid = -2; *gid = -2;
return 0; return 0;
} }
static int 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); READ_BUF(20);
READ32(cinfo->atomic); READ32(cinfo->atomic);
READ64(cinfo->before); READ64(cinfo->before);
READ64(cinfo->after); READ64(cinfo->after);
return 0;
DECODE_TAIL;
} }
static int 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; uint32_t *p;
DECODE_HEAD; uint32_t supp, acc;
if (!nfserr) { if (!nfserr) {
READ_BUF(8); READ_BUF(8);
READ32(supp); READ32(supp);
READ32(acc); READ32(acc);
status = -EIO;
if ((supp & ~access->ac_req_access) || (acc & ~supp)) { if ((supp & ~access->ac_req_access) || (acc & ~supp)) {
printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n"); printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n");
goto out; return -EIO;
} }
*access->ac_resp_supported = supp; *access->ac_resp_supported = supp;
*access->ac_resp_access = acc; *access->ac_resp_access = acc;
} }
return 0;
DECODE_TAIL;
} }
static int 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) { if (!nfserr) {
READ_BUF(sizeof(nfs4_stateid)); READ_BUF(sizeof(nfs4_stateid));
COPYMEM(close->cl_stateid, sizeof(nfs4_stateid)); COPYMEM(close->cl_stateid, sizeof(nfs4_stateid));
} }
return 0;
DECODE_TAIL;
} }
static int 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) { if (!nfserr) {
READ_BUF(8); READ_BUF(8);
COPYMEM(commit->co_verifier->verifier, 8); COPYMEM(commit->co_verifier->verifier, 8);
} }
return 0;
DECODE_TAIL;
} }
static int 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; uint32_t *p;
DECODE_HEAD; uint32_t bmlen;
int status;
if (!nfserr) { if (!nfserr) {
if ((status = decode_change_info(cp, create->cr_cinfo))) if ((status = decode_change_info(xdr, create->cr_cinfo)))
goto out; goto out;
READ_BUF(4); READ_BUF(4);
READ32(bmlen); READ32(bmlen);
...@@ -991,27 +938,28 @@ decode_create(struct nfs4_compound *cp, int nfserr, struct nfs4_create *create) ...@@ -991,27 +938,28 @@ decode_create(struct nfs4_compound *cp, int nfserr, struct nfs4_create *create)
DECODE_TAIL; DECODE_TAIL;
} }
extern u32 nfs4_fattr_bitmap[2]; extern uint32_t nfs4_fattr_bitmap[2];
extern u32 nfs4_fsinfo_bitmap[2]; extern uint32_t nfs4_fsinfo_bitmap[2];
extern u32 nfs4_fsstat_bitmap[2]; extern uint32_t nfs4_fsstat_bitmap[2];
extern u32 nfs4_pathconf_bitmap[2]; extern uint32_t nfs4_pathconf_bitmap[2];
static int 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_fattr *nfp = getattr->gt_attrs;
struct nfs_fsstat *fsstat = getattr->gt_fsstat; struct nfs_fsstat *fsstat = getattr->gt_fsstat;
struct nfs_fsinfo *fsinfo = getattr->gt_fsinfo; struct nfs_fsinfo *fsinfo = getattr->gt_fsinfo;
struct nfs_pathconf *pathconf = getattr->gt_pathconf; struct nfs_pathconf *pathconf = getattr->gt_pathconf;
u32 bmlen; uint32_t *p;
u32 bmval0 = 0; uint32_t bmlen;
u32 bmval1 = 0; uint32_t bmval0 = 0;
u32 attrlen; uint32_t bmval1 = 0;
u32 dummy32; uint32_t attrlen;
u32 len = 0; uint32_t dummy32;
uint32_t len = 0;
unsigned int type; unsigned int type;
int fmode = 0; int fmode = 0;
DECODE_HEAD; int status;
if (nfserr) if (nfserr)
goto success; goto success;
...@@ -1060,7 +1008,7 @@ decode_getattr(struct nfs4_compound *cp, int nfserr, struct nfs4_getattr *getatt ...@@ -1060,7 +1008,7 @@ decode_getattr(struct nfs4_compound *cp, int nfserr, struct nfs4_getattr *getatt
} }
nfp->type = nfs_type2fmt[type].nfs2type; nfp->type = nfs_type2fmt[type].nfs2type;
fmode = nfs_type2fmt[type].mode; 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) { if (bmval0 & FATTR4_WORD0_CHANGE) {
READ_BUF(8); READ_BUF(8);
...@@ -1250,11 +1198,12 @@ decode_getattr(struct nfs4_compound *cp, int nfserr, struct nfs4_getattr *getatt ...@@ -1250,11 +1198,12 @@ decode_getattr(struct nfs4_compound *cp, int nfserr, struct nfs4_getattr *getatt
} }
static int 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; struct nfs_fh *fh = getfh->gf_fhandle;
int len; uint32_t *p;
DECODE_HEAD; uint32_t len;
int status;
/* Zero handle first to allow comparisons */ /* Zero handle first to allow comparisons */
memset(fh, 0, sizeof(*fh)); memset(fh, 0, sizeof(*fh));
...@@ -1273,26 +1222,27 @@ decode_getfh(struct nfs4_compound *cp, int nfserr, struct nfs4_getfh *getfh) ...@@ -1273,26 +1222,27 @@ decode_getfh(struct nfs4_compound *cp, int nfserr, struct nfs4_getfh *getfh)
} }
static int 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; int status = 0;
if (!nfserr) if (!nfserr)
status = decode_change_info(cp, link->ln_cinfo); status = decode_change_info(xdr, link->ln_cinfo);
return status; return status;
} }
static int 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; uint32_t *p;
DECODE_HEAD; uint32_t bmlen, delegation_type;
int status;
if (!nfserr) { if (!nfserr) {
READ_BUF(sizeof(nfs4_stateid)); READ_BUF(sizeof(nfs4_stateid));
COPYMEM(open->op_stateid, 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); READ_BUF(8);
READ32(*open->op_rflags); READ32(*open->op_rflags);
...@@ -1311,23 +1261,23 @@ decode_open(struct nfs4_compound *cp, int nfserr, struct nfs4_open *open) ...@@ -1311,23 +1261,23 @@ decode_open(struct nfs4_compound *cp, int nfserr, struct nfs4_open *open)
} }
static int 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) { if (!nfserr) {
READ_BUF(sizeof(nfs4_stateid)); READ_BUF(sizeof(nfs4_stateid));
COPYMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid)); COPYMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid));
} }
return 0;
DECODE_TAIL;
} }
static int 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; uint32_t throwaway;
DECODE_HEAD; uint32_t *p;
int status;
if (!nfserr) { if (!nfserr) {
READ_BUF(8); READ_BUF(8);
...@@ -1344,23 +1294,22 @@ decode_read(struct nfs4_compound *cp, int nfserr, struct nfs4_read *read) ...@@ -1344,23 +1294,22 @@ decode_read(struct nfs4_compound *cp, int nfserr, struct nfs4_read *read)
} }
static int 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 xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct page *page = *rcvbuf->pages; struct page *page = *rcvbuf->pages;
unsigned int pglen = rcvbuf->page_len; unsigned int pglen = rcvbuf->page_len;
u32 *end, *entry; uint32_t *end, *entry, *p;
u32 len, attrlen, word; uint32_t len, attrlen, word;
int i; int i;
DECODE_HEAD;
if (!nfserr) { if (!nfserr) {
READ_BUF(8); READ_BUF(8);
COPYMEM(readdir->rd_resp_verifier, 8); COPYMEM(readdir->rd_resp_verifier, 8);
BUG_ON(pglen > PAGE_CACHE_SIZE); BUG_ON(pglen > PAGE_CACHE_SIZE);
p = (u32 *) kmap(page); p = (uint32_t *) kmap(page);
end = (u32 *) ((char *)p + pglen + readdir->rd_pgbase); end = (uint32_t *) ((char *)p + pglen + readdir->rd_pgbase);
while (*p++) { while (*p++) {
entry = p - 1; entry = p - 1;
...@@ -1406,7 +1355,7 @@ decode_readdir(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struc ...@@ -1406,7 +1355,7 @@ decode_readdir(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struc
kunmap(page); kunmap(page);
} }
DECODE_TAIL; return 0;
short_pkt: short_pkt:
printk(KERN_NOTICE "NFS: short packet in readdir reply!\n"); printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
/* truncate listing */ /* truncate listing */
...@@ -1419,11 +1368,11 @@ decode_readdir(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struc ...@@ -1419,11 +1368,11 @@ decode_readdir(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struc
} }
static int 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; struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
u32 *strlen; uint32_t *strlen;
u32 len; uint32_t len;
char *string; char *string;
if (!nfserr) { if (!nfserr) {
...@@ -1434,7 +1383,7 @@ decode_readlink(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, stru ...@@ -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 * and and null-terminate the text (the VFS expects
* null-termination). * null-termination).
*/ */
strlen = (u32 *) kmap(rcvbuf->pages[0]); strlen = (uint32_t *) kmap(rcvbuf->pages[0]);
len = ntohl(*strlen); len = ntohl(*strlen);
if (len > PAGE_CACHE_SIZE - 5) { if (len > PAGE_CACHE_SIZE - 5) {
printk(KERN_WARNING "nfs: server returned giant symlink!\n"); 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 ...@@ -1451,25 +1400,25 @@ decode_readlink(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, stru
} }
static int 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; int status;
status = 0; status = 0;
if (!nfserr) if (!nfserr)
status = decode_change_info(cp, remove->rm_cinfo); status = decode_change_info(xdr, remove->rm_cinfo);
return status; return status;
} }
static int 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; int status = 0;
if (!nfserr) { if (!nfserr) {
if ((status = decode_change_info(cp, rename->rn_src_cinfo))) if ((status = decode_change_info(xdr, rename->rn_src_cinfo)))
goto out; goto out;
if ((status = decode_change_info(cp, rename->rn_dst_cinfo))) if ((status = decode_change_info(xdr, rename->rn_dst_cinfo)))
goto out; goto out;
} }
out: out:
...@@ -1477,10 +1426,11 @@ decode_rename(struct nfs4_compound *cp, int nfserr, struct nfs4_rename *rename) ...@@ -1477,10 +1426,11 @@ decode_rename(struct nfs4_compound *cp, int nfserr, struct nfs4_rename *rename)
} }
static int static int
decode_setattr(struct nfs4_compound *cp) decode_setattr(struct xdr_stream *xdr)
{ {
u32 bmlen; uint32_t *p;
DECODE_HEAD; uint32_t bmlen;
int status;
READ_BUF(4); READ_BUF(4);
READ32(bmlen); READ32(bmlen);
...@@ -1492,17 +1442,17 @@ decode_setattr(struct nfs4_compound *cp) ...@@ -1492,17 +1442,17 @@ decode_setattr(struct nfs4_compound *cp)
} }
static int 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) { if (!nfserr) {
READ_BUF(8 + sizeof(nfs4_verifier)); READ_BUF(8 + sizeof(nfs4_verifier));
READ64(cp->server->nfs4_state->cl_clientid); READ64(setclientid->sc_state->cl_clientid);
COPYMEM(cp->server->nfs4_state->cl_confirm, sizeof(nfs4_verifier)); COPYMEM(setclientid->sc_state->cl_confirm, sizeof(nfs4_verifier));
} }
else if (nfserr == NFSERR_CLID_INUSE) { else if (nfserr == NFSERR_CLID_INUSE) {
u32 len; uint32_t len;
/* skip netid string */ /* skip netid string */
READ_BUF(4); READ_BUF(4);
...@@ -1515,13 +1465,14 @@ decode_setclientid(struct nfs4_compound *cp, int nfserr) ...@@ -1515,13 +1465,14 @@ decode_setclientid(struct nfs4_compound *cp, int nfserr)
READ_BUF(len); READ_BUF(len);
} }
DECODE_TAIL; return 0;
} }
static int 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) { if (!nfserr) {
READ_BUF(16); READ_BUF(16);
...@@ -1537,11 +1488,12 @@ decode_write(struct nfs4_compound *cp, int nfserr, struct nfs4_write *write) ...@@ -1537,11 +1488,12 @@ decode_write(struct nfs4_compound *cp, int nfserr, struct nfs4_write *write)
/* FIXME: this sucks */ /* FIXME: this sucks */
static int 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; uint32_t *p;
u32 opnum, nfserr; uint32_t taglen;
DECODE_HEAD; uint32_t opnum, nfserr;
int status;
READ_BUF(8); READ_BUF(8);
READ32(cp->toplevel_status); READ32(cp->toplevel_status);
...@@ -1584,34 +1536,34 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) ...@@ -1584,34 +1536,34 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
switch (opnum) { switch (opnum) {
case OP_ACCESS: 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; break;
case OP_CLOSE: 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; break;
case OP_COMMIT: 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; break;
case OP_CREATE: 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; break;
case OP_GETATTR: 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; break;
case OP_GETFH: 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; break;
case OP_LINK: 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; break;
case OP_LOOKUP: case OP_LOOKUP:
status = 0; status = 0;
break; break;
case OP_OPEN: 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; break;
case OP_OPEN_CONFIRM: 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; break;
case OP_PUTFH: case OP_PUTFH:
status = 0; status = 0;
...@@ -1620,22 +1572,22 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) ...@@ -1620,22 +1572,22 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
status = 0; status = 0;
break; break;
case OP_READ: 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; break;
case OP_READDIR: 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; break;
case OP_READLINK: 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; break;
case OP_RESTOREFH: case OP_RESTOREFH:
status = 0; status = 0;
break; break;
case OP_REMOVE: 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; break;
case OP_RENAME: 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; break;
case OP_RENEW: case OP_RENEW:
status = 0; status = 0;
...@@ -1644,16 +1596,16 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) ...@@ -1644,16 +1596,16 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
status = 0; status = 0;
break; break;
case OP_SETATTR: case OP_SETATTR:
status = decode_setattr(cp); status = decode_setattr(xdr);
break; break;
case OP_SETCLIENTID: case OP_SETCLIENTID:
status = decode_setclientid(cp, nfserr); status = decode_setclientid(xdr, nfserr, &cp->ops[cp->nops].u.setclientid);
break; break;
case OP_SETCLIENTID_CONFIRM: case OP_SETCLIENTID_CONFIRM:
status = 0; status = 0;
break; break;
case OP_WRITE: 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; break;
default: default:
BUG(); BUG();
...@@ -1673,14 +1625,13 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req) ...@@ -1673,14 +1625,13 @@ decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
* Decode COMPOUND response * Decode COMPOUND response
*/ */
static int 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; int status;
cp->p = p; xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
cp->end = (u32 *) ((u8 *) rqstp->rq_rvec->iov_base + rqstp->rq_rvec->iov_len); if ((status = decode_compound(&xdr, cp, rqstp)))
if ((status = decode_compound(cp, rqstp)))
goto out; goto out;
status = 0; status = 0;
...@@ -1691,10 +1642,10 @@ nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, u32 *p, struct nfs4_compound *cp) ...@@ -1691,10 +1642,10 @@ nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, u32 *p, struct nfs4_compound *cp)
return status; return status;
} }
u32 * uint32_t *
nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
{ {
u32 len; uint32_t len;
if (!*p++) { if (!*p++) {
if (!*p) if (!*p)
......
...@@ -398,6 +398,7 @@ struct nfs4_lookup { ...@@ -398,6 +398,7 @@ struct nfs4_lookup {
}; };
struct nfs4_open { struct nfs4_open {
struct nfs4_client * op_client_state; /* request */
u32 op_share_access; /* request */ u32 op_share_access; /* request */
u32 op_opentype; /* request */ u32 op_opentype; /* request */
u32 op_createmode; /* request */ u32 op_createmode; /* request */
...@@ -472,6 +473,7 @@ struct nfs4_setclientid { ...@@ -472,6 +473,7 @@ struct nfs4_setclientid {
char sc_netid[4]; /* request */ char sc_netid[4]; /* request */
char sc_uaddr[24]; /* request */ char sc_uaddr[24]; /* request */
u32 sc_cb_ident; /* request */ u32 sc_cb_ident; /* request */
struct nfs4_client * sc_state; /* response */
}; };
struct nfs4_write { struct nfs4_write {
...@@ -504,8 +506,10 @@ struct nfs4_op { ...@@ -504,8 +506,10 @@ struct nfs4_op {
struct nfs4_readlink readlink; struct nfs4_readlink readlink;
struct nfs4_remove remove; struct nfs4_remove remove;
struct nfs4_rename rename; struct nfs4_rename rename;
struct nfs4_client * renew;
struct nfs4_setattr setattr; struct nfs4_setattr setattr;
struct nfs4_setclientid setclientid; struct nfs4_setclientid setclientid;
struct nfs4_client * setclientid_confirm;
struct nfs4_write write; struct nfs4_write write;
} u; } u;
}; };
......
...@@ -155,6 +155,93 @@ typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); ...@@ -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, extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,
skb_reader_t *, skb_read_actor_t); 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 /* __KERNEL__ */
#endif /* _SUNRPC_XDR_H_ */ #endif /* _SUNRPC_XDR_H_ */
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