Newer
Older
}
static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
{
int status = 0;
time->tv_sec = 0;
time->tv_nsec = 0;
if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U)))
return -EIO;
if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
status = decode_attr_time(xdr, time);

Trond Myklebust
committed
if (status == 0)
status = NFS_ATTR_FATTR_ATIME;
dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
return status;
}
static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
{
int status = 0;
time->tv_sec = 0;
time->tv_nsec = 0;
if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
return -EIO;
if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
status = decode_attr_time(xdr, time);

Trond Myklebust
committed
if (status == 0)
status = NFS_ATTR_FATTR_CTIME;
dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
struct timespec *time)
{
int status = 0;
time->tv_sec = 0;
time->tv_nsec = 0;
if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_DELTA - 1U)))
return -EIO;
if (likely(bitmap[1] & FATTR4_WORD1_TIME_DELTA)) {
status = decode_attr_time(xdr, time);
bitmap[1] &= ~FATTR4_WORD1_TIME_DELTA;
}
dprintk("%s: time_delta=%ld %ld\n", __func__, (long)time->tv_sec,
(long)time->tv_nsec);
return status;
}
static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
{
int status = 0;
time->tv_sec = 0;
time->tv_nsec = 0;
if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
return -EIO;
if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
status = decode_attr_time(xdr, time);

Trond Myklebust
committed
if (status == 0)
status = NFS_ATTR_FATTR_MTIME;
dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
{
unsigned int attrwords = XDR_QUADLEN(attrlen);
unsigned int nwords = (xdr_stream_pos(xdr) - savep) >> 2;
dprintk("%s: server returned incorrect attribute length: "
"%u %c %u\n",
attrwords << 2,
(attrwords < nwords) ? '<' : '>',
nwords << 2);
return -EIO;
}
return 0;
}
static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
p = xdr_inline_decode(xdr, 20);
if (unlikely(!p))
goto out_overflow;
p = xdr_decode_hyper(p, &cinfo->before);
xdr_decode_hyper(p, &cinfo->after);
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
static int decode_access(struct xdr_stream *xdr, u32 *supported, u32 *access)
uint32_t supp, acc;
int status;
status = decode_op_hdr(xdr, OP_ACCESS);
if (status)
return status;
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;
*supported = supp;
*access = acc;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
p = xdr_inline_decode(xdr, len);
if (likely(p)) {
memcpy(buf, p, len);
return 0;
}
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
{
return decode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE);
}
static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
{
int status;
status = decode_op_hdr(xdr, OP_CLOSE);
if (status != -EIO)
nfs_increment_open_seqid(status, res->seqid);
if (!status)
status = decode_stateid(xdr, &res->stateid);
return status;
static int decode_verifier(struct xdr_stream *xdr, void *verifier)
{
return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE);
static int decode_write_verifier(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
{
return decode_opaque_fixed(xdr, verifier->data, NFS4_VERIFIER_SIZE);
}
static int decode_commit(struct xdr_stream *xdr, struct nfs_commitres *res)
{
int status;
status = decode_op_hdr(xdr, OP_COMMIT);
status = decode_write_verifier(xdr, &res->verf->verifier);
}
static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
uint32_t bmlen;
int status;
status = decode_op_hdr(xdr, OP_CREATE);
if (status)
return status;
if ((status = decode_change_info(xdr, cinfo)))
return status;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
p = xdr_inline_decode(xdr, bmlen << 2);
if (likely(p))
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
unsigned int savep;
uint32_t attrlen, bitmap[3] = {0};
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;
if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
goto xdr_error;
if ((status = decode_attr_fh_expire_type(xdr, bitmap,
&res->fh_expire_type)) != 0)
goto xdr_error;
if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
goto xdr_error;
if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
goto xdr_error;
if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
dprintk("%s: xdr returned %d!\n", __func__, -status);
static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
{
unsigned int savep;
uint32_t attrlen, bitmap[3] = {0};
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
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_files_avail(xdr, bitmap, &fsstat->afiles)) != 0)
goto xdr_error;
if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0)
goto xdr_error;
if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
goto xdr_error;
if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
goto xdr_error;
if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
goto xdr_error;
if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 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_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
{
unsigned int savep;
uint32_t attrlen, bitmap[3] = {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);
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
static int decode_threshold_hint(struct xdr_stream *xdr,
uint32_t *bitmap,
uint64_t *res,
uint32_t hint_bit)
{
__be32 *p;
*res = 0;
if (likely(bitmap[0] & hint_bit)) {
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;
xdr_decode_hyper(p, res);
}
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_first_threshold_item4(struct xdr_stream *xdr,
struct nfs4_threshold *res)
{
__be32 *p;
unsigned int savep;
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
uint32_t bitmap[3] = {0,}, attrlen;
int status;
/* layout type */
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) {
print_overflow_msg(__func__, xdr);
return -EIO;
}
res->l_type = be32_to_cpup(p);
/* thi_hintset bitmap */
status = decode_attr_bitmap(xdr, bitmap);
if (status < 0)
goto xdr_error;
/* thi_hintlist length */
status = decode_attr_length(xdr, &attrlen, &savep);
if (status < 0)
goto xdr_error;
/* thi_hintlist */
status = decode_threshold_hint(xdr, bitmap, &res->rd_sz, THRESHOLD_RD);
if (status < 0)
goto xdr_error;
status = decode_threshold_hint(xdr, bitmap, &res->wr_sz, THRESHOLD_WR);
if (status < 0)
goto xdr_error;
status = decode_threshold_hint(xdr, bitmap, &res->rd_io_sz,
THRESHOLD_RD_IO);
if (status < 0)
goto xdr_error;
status = decode_threshold_hint(xdr, bitmap, &res->wr_io_sz,
THRESHOLD_WR_IO);
if (status < 0)
goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
res->bm = bitmap[0];
dprintk("%s bm=0x%x rd_sz=%llu wr_sz=%llu rd_io=%llu wr_io=%llu\n",
__func__, res->bm, res->rd_sz, res->wr_sz, res->rd_io_sz,
res->wr_io_sz);
xdr_error:
dprintk("%s ret=%d!\n", __func__, status);
return status;
}
/*
* Thresholds on pNFS direct I/O vrs MDS I/O
*/
static int decode_attr_mdsthreshold(struct xdr_stream *xdr,
uint32_t *bitmap,
struct nfs4_threshold *res)
{
__be32 *p;
int status = 0;
uint32_t num;
if (unlikely(bitmap[2] & (FATTR4_WORD2_MDSTHRESHOLD - 1U)))
return -EIO;
if (bitmap[2] & FATTR4_WORD2_MDSTHRESHOLD) {
/* Did the server return an unrequested attribute? */
if (unlikely(res == NULL))
return -EREMOTEIO;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
num = be32_to_cpup(p);
if (num == 0)
return 0;
if (num > 1)
printk(KERN_INFO "%s: Warning: Multiple pNFS layout "
"drivers per filesystem not supported\n",
__func__);
status = decode_first_threshold_item4(xdr, res);
bitmap[2] &= ~FATTR4_WORD2_MDSTHRESHOLD;
}
return status;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
struct nfs_fattr *fattr, struct nfs_fh *fh,
struct nfs4_fs_locations *fs_loc,
const struct nfs_server *server)
int status;
umode_t fmode = 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;
err = 0;
status = decode_attr_error(xdr, bitmap, &err);
if (status < 0)
goto xdr_error;
status = decode_attr_filehandle(xdr, bitmap, fh);
if (status < 0)
goto xdr_error;
status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_fs_locations(xdr, bitmap, fs_loc);

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, &fattr->uid, fattr->owner_name);

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

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, &fattr->mounted_on_fileid);
fattr->valid |= status;
status = decode_attr_mdsthreshold(xdr, bitmap, fattr->mdsthreshold);
if (status < 0)
goto xdr_error;
xdr_error:
dprintk("%s: xdr returned %d\n", __func__, -status);
return status;
}
static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
const struct nfs_server *server)
unsigned int savep;
int status;
status = decode_op_hdr(xdr, OP_GETATTR);
if (status < 0)
goto xdr_error;
status = decode_attr_bitmap(xdr, bitmap);
if (status < 0)
goto xdr_error;
status = decode_attr_length(xdr, &attrlen, &savep);
if (status < 0)
goto xdr_error;
status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server);
if (status < 0)
goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
dprintk("%s: xdr returned %d\n", __func__, -status);
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
const struct nfs_server *server)
return decode_getfattr_generic(xdr, fattr, NULL, NULL, server);
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
/*
* Decode potentially multiple layout types. Currently we only support
* one layout driver per file system.
*/
static int decode_first_pnfs_layout_type(struct xdr_stream *xdr,
uint32_t *layouttype)
{
uint32_t *p;
int num;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
num = be32_to_cpup(p);
/* pNFS is not supported by the underlying file system */
if (num == 0) {
*layouttype = 0;
return 0;
}
if (num > 1)
printk(KERN_INFO "NFS: %s: Warning: Multiple pNFS layout "
"drivers per filesystem not supported\n", __func__);
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
/* Decode and set first layout type, move xdr->p past unused types */
p = xdr_inline_decode(xdr, num * 4);
if (unlikely(!p))
goto out_overflow;
*layouttype = be32_to_cpup(p);
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
/*
* The type of file system exported.
* Note we must ensure that layouttype is set in any non-error case.
*/
static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
uint32_t *layouttype)
{
int status = 0;
dprintk("%s: bitmap is %x\n", __func__, bitmap[1]);
if (unlikely(bitmap[1] & (FATTR4_WORD1_FS_LAYOUT_TYPES - 1U)))
return -EIO;
if (bitmap[1] & FATTR4_WORD1_FS_LAYOUT_TYPES) {
status = decode_first_pnfs_layout_type(xdr, layouttype);
bitmap[1] &= ~FATTR4_WORD1_FS_LAYOUT_TYPES;
} else
*layouttype = 0;
return status;
}
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
/*
* The prefered block size for layout directed io
*/
static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
uint32_t *res)
{
__be32 *p;
dprintk("%s: bitmap is %x\n", __func__, bitmap[2]);
*res = 0;
if (bitmap[2] & FATTR4_WORD2_LAYOUT_BLKSIZE) {
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) {
print_overflow_msg(__func__, xdr);
return -EIO;
}
*res = be32_to_cpup(p);
bitmap[2] &= ~FATTR4_WORD2_LAYOUT_BLKSIZE;
}
return 0;
}
static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
unsigned int savep;
uint32_t attrlen, bitmap[3];
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
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 = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta);
if (status != 0)
goto xdr_error;
status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype);
if (status != 0)
goto xdr_error;
status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize);
if (status)
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_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;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
if (len > NFS4_FHSIZE)
return -EIO;
fh->size = len;
p = xdr_inline_decode(xdr, len);
if (unlikely(!p))
goto out_overflow;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
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)
p = xdr_inline_decode(xdr, 32); /* read 32 bytes */
if (unlikely(!p))
goto out_overflow;
p = xdr_decode_hyper(p, &offset); /* read 2 8-byte long words */
type = be32_to_cpup(p++); /* 4 byte read */
if (fl != NULL) { /* manipulate file lock */
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;
}
p = xdr_decode_hyper(p, &clientid); /* read 8 bytes */
namelen = be32_to_cpup(p); /* read 4 bytes */ /* have read all 32 bytes now */
p = xdr_inline_decode(xdr, namelen); /* variable size field */
if (likely(p))
return -NFS4ERR_DENIED;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
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;
status = decode_stateid(xdr, &res->stateid);
if (unlikely(status))
goto out;
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);
if (status == 0)
status = decode_stateid(xdr, &res->stateid);
static int decode_release_lockowner(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_RELEASE_LOCKOWNER);
}
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)
{
p = xdr_inline_decode(xdr, 12);
if (unlikely(!p))
goto out_overflow;
*maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
int status;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
delegation_type = be32_to_cpup(p);
if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
res->delegation_type = 0;
return 0;
}
status = decode_stateid(xdr, &res->delegation);
if (unlikely(status))
return status;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
res->do_recall = be32_to_cpup(p);
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);
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
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)
status = decode_stateid(xdr, &res->stateid);
if (unlikely(status))
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;
p = xdr_inline_decode(xdr, bmlen << 2);
if (unlikely(!p))
goto out_overflow;
savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
for (i = 0; i < savewords; ++i)
for (; i < NFS4_BITMAP_SIZE; i++)
res->attrset[i] = 0;
dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
out_overflow:
print_overflow_msg(__func__, xdr);
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 != -EIO)
nfs_increment_open_seqid(status, res->seqid);
if (!status)
status = decode_stateid(xdr, &res->stateid);
return status;
}
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);
if (!status)
status = decode_stateid(xdr, &res->stateid);
return status;
}
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)
{
uint32_t count, eof, recvd;
int status;
status = decode_op_hdr(xdr, OP_READ);
if (status)
return status;
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;
recvd = xdr_read_pages(xdr, count);
dprintk("NFS: server cheating in read reply: "
"count %u > recvd %u\n", count, recvd);
count = recvd;
eof = 0;
}
res->eof = eof;
res->count = count;
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
{
int status;
if (!status)
status = decode_verifier(xdr, readdir->verifier.data);
if (unlikely(status))
memcpy(verf, readdir->verifier.data, sizeof(verf));
dprintk("%s: verifier = %08x:%08x\n",
return xdr_read_pages(xdr, xdr->buf->page_len);
}
static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
u32 len, recvd;
int status;
status = decode_op_hdr(xdr, OP_READLINK);
if (status)
return status;
/* Convert length of symlink */
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
dprintk("nfs: server returned giant symlink!\n");
recvd = xdr_read_pages(xdr, len);
dprintk("NFS: server cheating in readlink reply: "
"count %u > recvd %u\n", len, recvd);
return -EIO;