Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> --- fs/nfsd/nfs4xdr.c | 121 +++++++++++++++++++++++++++++++++------------ include/uapi/linux/nfs4.h | 1 2 files changed, 91 insertions(+), 31 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c621a38e7874..35329e3d1339 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -484,6 +484,32 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, DECODE_TAIL; } +static __be32 nfsd4_decode_clientid4(struct nfsd4_compoundargs *argp, + clientid_t *clientid) +{ + __be32 *p; + + p = xdr_inline_decode(argp->xdr, NFS4_CLIENTID_SIZE); + if (!p) + goto xdr_error; + memcpy(clientid, p, sizeof(*clientid)); + return nfs_ok; +xdr_error: + return nfserr_bad_xdr; +} + +static __be32 nfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp, + clientid_t *clientid, + struct xdr_netobj *owner) +{ + __be32 status; + + status = nfsd4_decode_clientid4(argp, clientid); + if (status) + return status; + return nfsd4_decode_opaque(argp, owner); +} + static __be32 nfsd4_decode_stateid4(struct nfsd4_compoundargs *argp, stateid_t *sid) { @@ -706,44 +732,77 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) return nfsd4_decode_component4(argp, &link->li_name, &link->li_namelen); } +static __be32 +nfsd4_decode_open_to_lock_owner4(struct nfsd4_compoundargs *argp, + struct nfsd4_lock *lock) +{ + __be32 status; + + lock->lk_is_new = 1; + + if (xdr_stream_decode_u32(argp->xdr, &lock->lk_new_open_seqid) < 0) + goto xdr_error; + status = nfsd4_decode_stateid4(argp, &lock->lk_new_open_stateid); + if (status) + goto out; + if (xdr_stream_decode_u32(argp->xdr, &lock->lk_new_lock_seqid) < 0) + goto xdr_error; + status = nfsd4_decode_state_owner4(argp, &lock->lk_new_clientid, + &lock->lk_new_owner); + +out: + return status; +xdr_error: + return nfserr_bad_xdr; +} + +static __be32 +nfsd4_decode_exist_lock_owner4(struct nfsd4_compoundargs *argp, + struct nfsd4_lock *lock) +{ + __be32 status; + + lock->lk_is_new = 0; + + status = nfsd4_decode_stateid4(argp, &lock->lk_old_lock_stateid); + if (status) + goto out; + if (xdr_stream_decode_u32(argp->xdr, &lock->lk_old_lock_seqid) < 0) + goto xdr_error; + + status = nfs_ok; +out: + return status; +xdr_error: + return nfserr_bad_xdr; +} + static __be32 nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) { - DECODE_HEAD; + __be32 *p; - /* - * type, reclaim(boolean), offset, length, new_lock_owner(boolean) - */ - READ_BUF(28); - lock->lk_type = be32_to_cpup(p++); + if (xdr_stream_decode_u32(argp->xdr, &lock->lk_type) < 0) + goto xdr_error; if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT)) goto xdr_error; - lock->lk_reclaim = be32_to_cpup(p++); - p = xdr_decode_hyper(p, &lock->lk_offset); - p = xdr_decode_hyper(p, &lock->lk_length); - lock->lk_is_new = be32_to_cpup(p++); - - if (lock->lk_is_new) { - READ_BUF(4); - lock->lk_new_open_seqid = be32_to_cpup(p++); - status = nfsd4_decode_stateid4(argp, &lock->lk_new_open_stateid); - if (status) - return status; - READ_BUF(8 + sizeof(clientid_t)); - lock->lk_new_lock_seqid = be32_to_cpup(p++); - COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t)); - lock->lk_new_owner.len = be32_to_cpup(p++); - READ_BUF(lock->lk_new_owner.len); - READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len); - } else { - status = nfsd4_decode_stateid4(argp, &lock->lk_old_lock_stateid); - if (status) - return status; - READ_BUF(4); - lock->lk_old_lock_seqid = be32_to_cpup(p++); - } + p = xdr_inline_decode(argp->xdr, sizeof(__be32)); + if (!p) + goto xdr_error; + lock->lk_reclaim = (*p == xdr_zero) ? 0 : 1; + if (xdr_stream_decode_u64(argp->xdr, &lock->lk_offset) < 0) + goto xdr_error; + if (xdr_stream_decode_u64(argp->xdr, &lock->lk_length) < 0) + goto xdr_error; + p = xdr_inline_decode(argp->xdr, sizeof(__be32)); + if (!p) + goto xdr_error; + if (*p != xdr_zero) + return nfsd4_decode_open_to_lock_owner4(argp, lock); + return nfsd4_decode_exist_lock_owner4(argp, lock); - DECODE_TAIL; +xdr_error: + return nfserr_bad_xdr; } static __be32 diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h index ed5415e0f1c1..31072a653436 100644 --- a/include/uapi/linux/nfs4.h +++ b/include/uapi/linux/nfs4.h @@ -21,6 +21,7 @@ #define NFS4_STATEID_SEQID_SIZE 4 #define NFS4_STATEID_OTHER_SIZE 12 #define NFS4_STATEID_SIZE (NFS4_STATEID_SEQID_SIZE + NFS4_STATEID_OTHER_SIZE) +#define NFS4_CLIENTID_SIZE 8 #define NFS4_FHSIZE 128 #define NFS4_MAXPATHLEN PATH_MAX #define NFS4_MAXNAMLEN NAME_MAX