Newer
Older
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", __FUNCTION__, -status);
return status;
}
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
{
uint32_t attrlen,
bitmap[2] = {0},
type;
int status, fmode = 0;
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto xdr_error;
fattr->bitmap[0] = bitmap[0];
fattr->bitmap[1] = bitmap[1];
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto xdr_error;
if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
goto xdr_error;
fattr->type = nfs_type2fmt[type].nfs2type;
fmode = nfs_type2fmt[type].mode;
if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
goto xdr_error;
if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
goto xdr_error;
if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
goto xdr_error;
if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
goto xdr_error;
if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
struct nfs4_fs_locations,
fattr))) != 0)
goto xdr_error;
if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
goto xdr_error;
fattr->mode |= fmode;
if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
goto xdr_error;
if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
goto xdr_error;
if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
goto xdr_error;
if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0)
goto xdr_error;
if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0)
goto xdr_error;
if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0)
goto xdr_error;
if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
goto xdr_error;
if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
goto xdr_error;
if (fattr->fileid == 0 && fileid != 0)
fattr->fileid = fileid;
if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
xdr_error:
dprintk("%s: xdr returned %d\n", __FUNCTION__, -status);
return status;
}
static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
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", __FUNCTION__, -status);
return status;
}
static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
uint32_t len;
int status;
status = decode_op_hdr(xdr, OP_GETFH);
if (status)
return status;
/* Zero handle first to allow comparisons */
memset(fh, 0, sizeof(*fh));
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 == 0) {
READ_BUF(sizeof(res->stateid.data));
COPYMEM(res->stateid.data, sizeof(res->stateid.data));
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 == 0) {
READ_BUF(sizeof(res->stateid.data));
COPYMEM(res->stateid.data, sizeof(res->stateid.data));
}
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)
{
uint32_t delegation_type;
READ_BUF(4);
READ32(delegation_type);
if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
res->delegation_type = 0;
return 0;
}
READ_BUF(20);
COPYMEM(res->delegation.data, sizeof(res->delegation.data));
READ32(res->do_recall);
switch (delegation_type) {
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 -EIO;
}
return decode_ace(xdr, NULL, res->server->nfs_client);
}
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
uint32_t bmlen;
int status;
status = decode_op_hdr(xdr, OP_OPEN);
if (status)
return status;
READ_BUF(sizeof(res->stateid.data));
COPYMEM(res->stateid.data, sizeof(res->stateid.data));
decode_change_info(xdr, &res->cinfo);
READ_BUF(8);
READ32(res->rflags);
READ32(bmlen);
if (bmlen > 10)
goto xdr_error;
READ_BUF(bmlen << 2);
p += bmlen;
return decode_delegation(xdr, res);
xdr_error:
dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen);
return -EIO;
}
static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
{
int status;
status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
if (status)
return status;
READ_BUF(sizeof(res->stateid.data));
COPYMEM(res->stateid.data, sizeof(res->stateid.data));
return 0;
}
static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
{
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
int status;
status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
if (status)
return status;
READ_BUF(sizeof(res->stateid.data));
COPYMEM(res->stateid.data, sizeof(res->stateid.data));
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;
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
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) {
printk(KERN_WARNING "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;
unsigned int nr, pglen = rcvbuf->page_len;
uint32_t len, attrlen, xlen;
int hdrlen, recvd, status;
status = decode_op_hdr(xdr, OP_READDIR);
if (status)
return status;
READ_BUF(8);
COPYMEM(readdir->verifier.data, 8);
dprintk("%s: verifier = 0x%x%x\n",
__FUNCTION__,
((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);
if (end - p < 3)
dprintk("cookie = %Lu, ", *((unsigned long long *)p));
p += 2; /* cookie */
len = ntohl(*p++); /* filename length */
if (len > NFS4_MAXNAMLEN) {
printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
goto err_unmap;
}
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 */
entry = p;
}
if (!nr && (entry[0] != 0 || entry[1] == 0))
goto short_pkt;
out:
kunmap_atomic(kaddr, KM_USER0);
return 0;
short_pkt:
dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr);
entry[0] = entry[1] = 0;
/* truncate listing ? */
if (!nr) {
printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
entry[1] = 1;
}
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;
int hdrlen, len, recvd;
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
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(KERN_WARNING "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) {
printk(KERN_WARNING "NFS: server cheating in readlink reply: "
"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)
{
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
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)) {
int hdrlen, 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) {
printk(KERN_WARNING "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, struct nfs_setattrres *res)
{
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)
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
uint32_t opnum;
int32_t nfserr;
READ_BUF(8);
READ32(opnum);
if (opnum != OP_SETCLIENTID) {
printk(KERN_NOTICE
"nfs4_decode_setclientid: Server returned operation"
" %d\n", opnum);
return -EIO;
}
READ32(nfserr);
if (nfserr == NFS_OK) {
READ_BUF(8 + sizeof(clp->cl_confirm.data));
READ64(clp->cl_clientid);
COPYMEM(clp->cl_confirm.data, sizeof(clp->cl_confirm.data));
} 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)
{
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
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);
}
/*
* Decode OPEN_DOWNGRADE response
*/
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);
out:
return status;
}
/*
* END OF "GENERIC" DECODE ROUTINES.
*/
/*
* Decode ACCESS response
*/
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;
if ((status = decode_putfh(&xdr)) == 0)
status = decode_access(&xdr, res);
out:
return status;
}
/*
* Decode LOOKUP response
*/
static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
{
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 nfs4_remove_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_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 = {
.nops = 2,
};
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh);
if (status)
goto out;
status = encode_setacl(&xdr, args);
out:
return status;
}
/*
* Decode SETACL response
*/
static int
nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *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_setattr(&xdr, res);
out:
return status;
}
/*
* Decode GETACL response
*/
static int
nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
{
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_getacl(&xdr, rqstp, acl_len);
out:
return status;
}
static int nfs4_xdr_dec_close(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_close(&xdr, res);
if (status != 0)
goto out;
/*
* Note: Server may do delete on close for this file
* in which case the getattr call will fail with
* an ESTALE error. Shouldn't be a problem,
* though, since fattr->valid will remain unset.
*/
decode_getfattr(&xdr, res->fattr, res->server);
out:
return status;
}
/*
* Decode OPEN response
*/
static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *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_savefh(&xdr);
if (status)
goto out;
status = decode_open(&xdr, res);
if (status)
goto out;
status = decode_getfh(&xdr, &res->fh);
if (status)
goto out;
if (decode_getfattr(&xdr, res->f_attr, res->server) != 0)
goto out;
if ((status = decode_restorefh(&xdr)) != 0)
goto out;
decode_getfattr(&xdr, res->dir_attr, res->server);
out:
return status;
}
/*
* Decode OPEN_CONFIRM response
*/