Newer
Older
return status;
}
static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
{
uint32_t attrlen, bitmap[2] = {0};
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto xdr_error;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto xdr_error;
if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0)
goto xdr_error;
if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0)
goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
dprintk("%s: xdr returned %d!\n", __func__, -status);
return status;
}
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
{
int status;
umode_t fmode = 0;
status = decode_op_hdr(xdr, OP_GETATTR);
if (status < 0)
status = decode_attr_bitmap(xdr, bitmap);
if (status < 0)
status = decode_attr_length(xdr, &attrlen, &savep);
if (status < 0)
status = decode_attr_type(xdr, bitmap, &type);
if (status < 0)

Trond Myklebust
committed
fattr->mode = 0;
if (status != 0) {
fattr->mode |= nfs_type2fmt[type];
fattr->valid |= status;
}
status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_size(xdr, bitmap, &fattr->size);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
struct nfs4_fs_locations,

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_mode(xdr, bitmap, &fmode);
if (status < 0)

Trond Myklebust
committed
if (status != 0) {
fattr->mode |= fmode;
fattr->valid |= status;
}
status = decode_attr_nlink(xdr, bitmap, &fattr->nlink);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
if (status < 0)

Trond Myklebust
committed
if (status != 0 && !(fattr->valid & status)) {
fattr->fileid = fileid;

Trond Myklebust
committed
fattr->valid |= status;
}
status = verify_attr_len(xdr, savep, attrlen);
dprintk("%s: xdr returned %d\n", __func__, -status);
return status;
}
static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
uint32_t attrlen, bitmap[2];
int status;
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto xdr_error;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto xdr_error;
fsinfo->rtmult = fsinfo->wtmult = 512; /* ??? */
if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
goto xdr_error;
if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
goto xdr_error;
if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
goto xdr_error;
fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
goto xdr_error;
fsinfo->wtpref = fsinfo->wtmax;
status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
dprintk("%s: xdr returned %d!\n", __func__, -status);
return status;
}
static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
/* Zero handle first to allow comparisons */
memset(fh, 0, sizeof(*fh));
status = decode_op_hdr(xdr, OP_GETFH);
if (status)
return status;
READ_BUF(4);
READ32(len);
if (len > NFS4_FHSIZE)
return -EIO;
fh->size = len;
READ_BUF(len);
COPYMEM(fh->data, len);
return 0;
}
static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
int status;
status = decode_op_hdr(xdr, OP_LINK);
if (status)
return status;
return decode_change_info(xdr, cinfo);
}
/*
* We create the owner, so we know a proper owner.id length is 4.
*/
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
READ64(offset);
READ64(length);
READ32(type);
if (fl != NULL) {
fl->fl_start = (loff_t)offset;
fl->fl_end = fl->fl_start + (loff_t)length - 1;
if (length == ~(uint64_t)0)
fl->fl_end = OFFSET_MAX;
fl->fl_type = F_WRLCK;
if (type & 1)
fl->fl_type = F_RDLCK;
fl->fl_pid = 0;
}
READ64(clientid);
READ32(namelen);
READ_BUF(namelen);
return -NFS4ERR_DENIED;
}
static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
int status;
status = decode_op_hdr(xdr, OP_LOCK);
if (status == -EIO)
goto out;
READ_BUF(NFS4_STATEID_SIZE);
COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
status = decode_lock_denied(xdr, NULL);
if (res->open_seqid != NULL)
nfs_increment_open_seqid(status, res->open_seqid);
nfs_increment_lock_seqid(status, res->lock_seqid);
out:
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
{
int status;
status = decode_op_hdr(xdr, OP_LOCKT);
if (status == -NFS4ERR_DENIED)
return decode_lock_denied(xdr, res->denied);
static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
int status;
status = decode_op_hdr(xdr, OP_LOCKU);
if (status != -EIO)
nfs_increment_lock_seqid(status, res->seqid);
READ_BUF(NFS4_STATEID_SIZE);
COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
}
return status;
}
static int decode_lookup(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_LOOKUP);
}
/* This is too sick! */
static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
{
uint32_t limit_type, nblocks, blocksize;
READ_BUF(12);
READ32(limit_type);
switch (limit_type) {
case 1:
READ64(*maxsize);
break;
case 2:
READ32(nblocks);
READ32(blocksize);
*maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
}
return 0;
}
static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
READ_BUF(4);
READ32(delegation_type);
if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
res->delegation_type = 0;
return 0;
}
READ_BUF(NFS4_STATEID_SIZE+4);
COPYMEM(res->delegation.data, NFS4_STATEID_SIZE);
case NFS4_OPEN_DELEGATE_READ:
res->delegation_type = FMODE_READ;
break;
case NFS4_OPEN_DELEGATE_WRITE:
res->delegation_type = FMODE_WRITE|FMODE_READ;
if (decode_space_limit(xdr, &res->maxsize) < 0)
return decode_ace(xdr, NULL, res->server->nfs_client);
}
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
uint32_t savewords, bmlen, i;
if (status != -EIO)
nfs_increment_open_seqid(status, res->seqid);
if (status)
return status;
READ_BUF(NFS4_STATEID_SIZE);
COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
READ_BUF(8);
READ32(res->rflags);
READ32(bmlen);
if (bmlen > 10)
goto xdr_error;
savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
for (i = 0; i < savewords; ++i)
READ32(res->attrset[i]);
for (; i < NFS4_BITMAP_SIZE; i++)
res->attrset[i] = 0;
dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
return -EIO;
}
static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
{
status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
if (status != -EIO)
nfs_increment_open_seqid(status, res->seqid);
if (status)
return status;
READ_BUF(NFS4_STATEID_SIZE);
COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
return 0;
}
static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
{
int status;
status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
if (status != -EIO)
nfs_increment_open_seqid(status, res->seqid);
READ_BUF(NFS4_STATEID_SIZE);
COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
return 0;
}
static int decode_putfh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_PUTFH);
}
static int decode_putrootfh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_PUTROOTFH);
}
static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
{
struct kvec *iov = req->rq_rcv_buf.head;
uint32_t count, eof, recvd, hdrlen;
int status;
status = decode_op_hdr(xdr, OP_READ);
if (status)
return status;
READ_BUF(8);
READ32(eof);
READ32(count);
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) {
dprintk("NFS: server cheating in read reply: "
"count %u > recvd %u\n", count, recvd);
count = recvd;
eof = 0;
}
xdr_read_pages(xdr, count);
res->eof = eof;
res->count = count;
return 0;
}
static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct page *page = *rcvbuf->pages;
struct kvec *iov = rcvbuf->head;
size_t hdrlen;
u32 recvd, pglen = rcvbuf->page_len;
unsigned int nr = 0;
int status;
status = decode_op_hdr(xdr, OP_READDIR);
if (status)
return status;
READ_BUF(8);
COPYMEM(readdir->verifier.data, 8);
dprintk("%s: verifier = %08x:%08x\n",
__func__,
((u32 *)readdir->verifier.data)[0],
((u32 *)readdir->verifier.data)[1]);
hdrlen = (char *) p - (char *) iov->iov_base;
recvd = rcvbuf->len - hdrlen;
if (pglen > recvd)
pglen = recvd;
xdr_read_pages(xdr, pglen);
BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
end = p + ((pglen + readdir->pgbase) >> 2);
/* Make sure the packet actually has a value_follows and EOF entry */
if ((entry + 1) > end)
goto short_pkt;
for (; *p++; nr++) {
u32 len, attrlen, xlen;
if (end - p < 3)
dprintk("cookie = %Lu, ", *((unsigned long long *)p));
p += 2; /* cookie */
len = ntohl(*p++); /* filename length */
if (len > NFS4_MAXNAMLEN) {
dprintk("NFS: giant filename in readdir (len 0x%x)\n",
len);
xlen = XDR_QUADLEN(len);
if (end - p < xlen + 1)
dprintk("filename = %*s\n", len, (char *)p);
p += xlen;
if (end - p < len + 1)
p += len;
if (end - p < attrlen + 2)
p += attrlen; /* attributes */
/*
* Apparently some server sends responses that are a valid size, but
* contain no entries, and have value_follows==0 and EOF==0. For
* those, just set the EOF marker.
*/
if (!nr && entry[1] == 0) {
dprintk("NFS: readdir reply truncated!\n");
entry[1] = 1;
}
kunmap_atomic(kaddr, KM_USER0);
return 0;
short_pkt:
/*
* When we get a short packet there are 2 possibilities. We can
* return an error, or fix up the response to look like a valid
* response and return what we have so far. If there are no
* entries and the packet was short, then return -EIO. If there
* are valid entries in the response, return them and pretend that
* the call was successful, but incomplete. The caller can retry the
* readdir starting at the last cookie.
*/
dprintk("%s: short packet at entry %d\n", __func__, nr);
if (nr)
goto out;
err_unmap:
kunmap_atomic(kaddr, KM_USER0);
return -errno_NFSERR_IO;
}
static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head;
size_t hdrlen;
u32 len, recvd;
char *kaddr;
int status;
status = decode_op_hdr(xdr, OP_READLINK);
if (status)
return status;
/* Convert length of symlink */
READ_BUF(4);
READ32(len);
if (len >= rcvbuf->page_len || len <= 0) {
dprintk("nfs: server returned giant symlink!\n");
return -ENAMETOOLONG;
}
hdrlen = (char *) xdr->p - (char *) iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen;
if (recvd < len) {
dprintk("NFS: server cheating in readlink reply: "
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
"count %u > recvd %u\n", len, recvd);
return -EIO;
}
xdr_read_pages(xdr, len);
/*
* The XDR encode routine has set things up so that
* the link text will be copied directly into the
* buffer. We just have to do overflow-checking,
* and and null-terminate the text (the VFS expects
* null-termination).
*/
kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
kaddr[len+rcvbuf->page_base] = '\0';
kunmap_atomic(kaddr, KM_USER0);
return 0;
}
static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
int status;
status = decode_op_hdr(xdr, OP_REMOVE);
if (status)
goto out;
status = decode_change_info(xdr, cinfo);
out:
return status;
}
static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
struct nfs4_change_info *new_cinfo)
{
int status;
status = decode_op_hdr(xdr, OP_RENAME);
if (status)
goto out;
if ((status = decode_change_info(xdr, old_cinfo)))
goto out;
status = decode_change_info(xdr, new_cinfo);
out:
return status;
}
static int decode_renew(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_RENEW);
}
static int
decode_restorefh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_RESTOREFH);
}
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
size_t *acl_len)
{
uint32_t attrlen,
bitmap[2] = {0};
struct kvec *iov = req->rq_rcv_buf.head;
int status;
*acl_len = 0;
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto out;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto out;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto out;
if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
return -EIO;
if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
size_t hdrlen;
u32 recvd;
/* We ignore &savep and don't do consistency checks on
* the attr length. Let userspace figure it out.... */
hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen;
if (attrlen > recvd) {
dprintk("NFS: server cheating in getattr"
" acl reply: attrlen %u > recvd %u\n",
attrlen, recvd);
return -EINVAL;
}
xdr_read_pages(xdr, attrlen);
*acl_len = attrlen;
out:
return status;
}
static int
decode_savefh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_SAVEFH);
}
static int decode_setattr(struct xdr_stream *xdr)
uint32_t bmlen;
int status;
status = decode_op_hdr(xdr, OP_SETATTR);
if (status)
return status;
READ_BUF(4);
READ32(bmlen);
READ_BUF(bmlen << 2);
return 0;
}
static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
uint32_t opnum;
int32_t nfserr;
READ_BUF(8);
READ32(opnum);
if (opnum != OP_SETCLIENTID) {
dprintk("nfs: decode_setclientid: Server returned operation"
return -EIO;
}
READ32(nfserr);
if (nfserr == NFS_OK) {
READ_BUF(8 + NFS4_VERIFIER_SIZE);
COPYMEM(clp->cl_confirm.data, NFS4_VERIFIER_SIZE);
} else if (nfserr == NFSERR_CLID_INUSE) {
uint32_t len;
/* skip netid string */
READ_BUF(4);
READ32(len);
READ_BUF(len);
/* skip uaddr string */
READ_BUF(4);
READ32(len);
READ_BUF(len);
return -NFSERR_CLID_INUSE;
} else
return nfs4_stat_to_errno(nfserr);
return 0;
}
static int decode_setclientid_confirm(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
}
static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
{
int status;
status = decode_op_hdr(xdr, OP_WRITE);
if (status)
return status;
READ_BUF(16);
READ32(res->count);
READ32(res->verf->committed);
COPYMEM(res->verf->verifier, 8);
return 0;
}
static int decode_delegreturn(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_DELEGRETURN);
}
/*
* END OF "GENERIC" DECODE ROUTINES.
*/
static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
status = decode_compound_hdr(&xdr, &hdr);
if (status)
goto out;
status = decode_putfh(&xdr);
if (status)
goto out;
status = decode_open_downgrade(&xdr, res);
if (status != 0)
goto out;
decode_getfattr(&xdr, res->fattr, res->server);
static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
status = decode_putfh(&xdr);
if (status != 0)
goto out;
status = decode_access(&xdr, res);
if (status != 0)
goto out;
decode_getfattr(&xdr, res->fattr, res->server);
out:
return status;
}
/*
* Decode LOOKUP response
*/
static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
if ((status = decode_putfh(&xdr)) != 0)
goto out;
if ((status = decode_lookup(&xdr)) != 0)
goto out;
if ((status = decode_getfh(&xdr, res->fh)) != 0)
goto out;
status = decode_getfattr(&xdr, res->fattr, res->server);
out:
return status;
}
/*
* Decode LOOKUP_ROOT response
*/
static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
if ((status = decode_putrootfh(&xdr)) != 0)
goto out;
if ((status = decode_getfh(&xdr, res->fh)) == 0)
status = decode_getfattr(&xdr, res->fattr, res->server);
out:
return status;
}
/*
* Decode REMOVE response
*/
static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
if ((status = decode_putfh(&xdr)) != 0)
goto out;
if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
goto out;
decode_getfattr(&xdr, &res->dir_attr, res->server);
out:
return status;
}
/*
* Decode RENAME response
*/
static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
if ((status = decode_putfh(&xdr)) != 0)
goto out;
if ((status = decode_savefh(&xdr)) != 0)
goto out;
if ((status = decode_putfh(&xdr)) != 0)
goto out;
if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
goto out;
/* Current FH is target directory */
if (decode_getfattr(&xdr, res->new_fattr, res->server) != 0)
goto out;
if ((status = decode_restorefh(&xdr)) != 0)
goto out;
decode_getfattr(&xdr, res->old_fattr, res->server);
out:
return status;
}
/*
* Decode LINK response
*/
static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
if ((status = decode_putfh(&xdr)) != 0)
goto out;
if ((status = decode_savefh(&xdr)) != 0)
goto out;
if ((status = decode_putfh(&xdr)) != 0)
goto out;
if ((status = decode_link(&xdr, &res->cinfo)) != 0)
goto out;
/*
* Note order: OP_LINK leaves the directory as the current
* filehandle.
*/
if (decode_getfattr(&xdr, res->dir_attr, res->server) != 0)
goto out;
if ((status = decode_restorefh(&xdr)) != 0)
goto out;
decode_getfattr(&xdr, res->fattr, res->server);
out:
return status;
}
/*
* Decode CREATE response
*/
static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
if ((status = decode_putfh(&xdr)) != 0)
goto out;
if ((status = decode_savefh(&xdr)) != 0)
goto out;
if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
goto out;
if ((status = decode_getfh(&xdr, res->fh)) != 0)
goto out;
if (decode_getfattr(&xdr, res->fattr, res->server) != 0)
goto out;
if ((status = decode_restorefh(&xdr)) != 0)
goto out;
decode_getfattr(&xdr, res->dir_fattr, res->server);
out:
return status;
}
/*
* Decode SYMLINK response
*/
static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
{
return nfs4_xdr_dec_create(rqstp, p, res);
}
/*
* Decode GETATTR response
*/
static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
status = decode_compound_hdr(&xdr, &hdr);
if (status)
goto out;
status = decode_putfh(&xdr);
if (status)
goto out;
status = decode_getfattr(&xdr, res->fattr, res->server);
out:
return status;
}
/*
* Encode an SETACL request
*/
static int
nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
struct xdr_stream xdr;
struct compound_hdr hdr = {
};
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
encode_putfh(&xdr, args->fh, &hdr);
status = encode_setacl(&xdr, args, &hdr);
encode_nops(&hdr);
/*
* Decode SETACL response