11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/nfs/nfs3xdr.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * XDR functions to encode/decode NFSv3 RPC arguments and results. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1996, 1997 Olaf Kirch 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/param.h> 101da177e4SLinus Torvalds #include <linux/time.h> 111da177e4SLinus Torvalds #include <linux/mm.h> 121da177e4SLinus Torvalds #include <linux/errno.h> 131da177e4SLinus Torvalds #include <linux/string.h> 141da177e4SLinus Torvalds #include <linux/in.h> 151da177e4SLinus Torvalds #include <linux/pagemap.h> 161da177e4SLinus Torvalds #include <linux/proc_fs.h> 171da177e4SLinus Torvalds #include <linux/kdev_t.h> 181da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 191da177e4SLinus Torvalds #include <linux/nfs.h> 201da177e4SLinus Torvalds #include <linux/nfs3.h> 211da177e4SLinus Torvalds #include <linux/nfs_fs.h> 22b7fa0554SAndreas Gruenbacher #include <linux/nfsacl.h> 23f7b422b1SDavid Howells #include "internal.h" 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #define NFSDBG_FACILITY NFSDBG_XDR 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */ 281da177e4SLinus Torvalds #define errno_NFSERR_IO EIO 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* 311da177e4SLinus Torvalds * Declare the space requirements for NFS arguments and replies as 321da177e4SLinus Torvalds * number of 32bit-words 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds #define NFS3_fhandle_sz (1+16) 351da177e4SLinus Torvalds #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */ 361da177e4SLinus Torvalds #define NFS3_sattr_sz (15) 371da177e4SLinus Torvalds #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2)) 381da177e4SLinus Torvalds #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2)) 391da177e4SLinus Torvalds #define NFS3_fattr_sz (21) 40d9c407b1SChuck Lever #define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2) 411da177e4SLinus Torvalds #define NFS3_wcc_attr_sz (6) 421da177e4SLinus Torvalds #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz) 431da177e4SLinus Torvalds #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz) 441da177e4SLinus Torvalds #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz) 451da177e4SLinus Torvalds #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz) 46ad96b5b5SChuck Lever 47ad96b5b5SChuck Lever #define NFS3_getattrargs_sz (NFS3_fh_sz) 48ad96b5b5SChuck Lever #define NFS3_setattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3) 49ad96b5b5SChuck Lever #define NFS3_lookupargs_sz (NFS3_fh_sz+NFS3_filename_sz) 501da177e4SLinus Torvalds #define NFS3_accessargs_sz (NFS3_fh_sz+1) 511da177e4SLinus Torvalds #define NFS3_readlinkargs_sz (NFS3_fh_sz) 521da177e4SLinus Torvalds #define NFS3_readargs_sz (NFS3_fh_sz+3) 531da177e4SLinus Torvalds #define NFS3_writeargs_sz (NFS3_fh_sz+5) 541da177e4SLinus Torvalds #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 551da177e4SLinus Torvalds #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 5694a6d753SChuck Lever #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz) 571da177e4SLinus Torvalds #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) 58ad96b5b5SChuck Lever #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz) 591da177e4SLinus Torvalds #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) 601da177e4SLinus Torvalds #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) 61d9c407b1SChuck Lever #define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3) 62d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4) 631da177e4SLinus Torvalds #define NFS3_commitargs_sz (NFS3_fh_sz+3) 641da177e4SLinus Torvalds 65f5fc3c50SChuck Lever #define NFS3_getattrres_sz (1+NFS3_fattr_sz) 66f5fc3c50SChuck Lever #define NFS3_setattrres_sz (1+NFS3_wcc_data_sz) 67f5fc3c50SChuck Lever #define NFS3_removeres_sz (NFS3_setattrres_sz) 681da177e4SLinus Torvalds #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) 691da177e4SLinus Torvalds #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) 701da177e4SLinus Torvalds #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1) 711da177e4SLinus Torvalds #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3) 721da177e4SLinus Torvalds #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4) 731da177e4SLinus Torvalds #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 741da177e4SLinus Torvalds #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz)) 751da177e4SLinus Torvalds #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 761da177e4SLinus Torvalds #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2) 771da177e4SLinus Torvalds #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13) 781da177e4SLinus Torvalds #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12) 791da177e4SLinus Torvalds #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) 801da177e4SLinus Torvalds #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) 811da177e4SLinus Torvalds 82b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz (NFS3_fh_sz+1) 83ae46141fSTrond Myklebust #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \ 84ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 85ae46141fSTrond Myklebust #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \ 86ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 87b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) 88b7fa0554SAndreas Gruenbacher 891da177e4SLinus Torvalds /* 901da177e4SLinus Torvalds * Map file type to S_IFMT bits 911da177e4SLinus Torvalds */ 92bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = { 93bca79478STrond Myklebust [NF3BAD] = 0, 94bca79478STrond Myklebust [NF3REG] = S_IFREG, 95bca79478STrond Myklebust [NF3DIR] = S_IFDIR, 96bca79478STrond Myklebust [NF3BLK] = S_IFBLK, 97bca79478STrond Myklebust [NF3CHR] = S_IFCHR, 98bca79478STrond Myklebust [NF3LNK] = S_IFLNK, 99bca79478STrond Myklebust [NF3SOCK] = S_IFSOCK, 100bca79478STrond Myklebust [NF3FIFO] = S_IFIFO, 1011da177e4SLinus Torvalds }; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /* 104d9c407b1SChuck Lever * While encoding arguments, set up the reply buffer in advance to 105d9c407b1SChuck Lever * receive reply data directly into the page cache. 106d9c407b1SChuck Lever */ 107d9c407b1SChuck Lever static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages, 108d9c407b1SChuck Lever unsigned int base, unsigned int len, 109d9c407b1SChuck Lever unsigned int bufsize) 110d9c407b1SChuck Lever { 111d9c407b1SChuck Lever struct rpc_auth *auth = req->rq_cred->cr_auth; 112d9c407b1SChuck Lever unsigned int replen; 113d9c407b1SChuck Lever 114d9c407b1SChuck Lever replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize; 115d9c407b1SChuck Lever xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len); 116d9c407b1SChuck Lever } 117d9c407b1SChuck Lever 118e4f93234SChuck Lever /* 119e4f93234SChuck Lever * Handle decode buffer overflows out-of-line. 120e4f93234SChuck Lever */ 121e4f93234SChuck Lever static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 122e4f93234SChuck Lever { 123e4f93234SChuck Lever dprintk("NFS: %s prematurely hit the end of our receive buffer. " 124e4f93234SChuck Lever "Remaining buffer length is %tu words.\n", 125e4f93234SChuck Lever func, xdr->end - xdr->p); 126e4f93234SChuck Lever } 127e4f93234SChuck Lever 128d9c407b1SChuck Lever 129d9c407b1SChuck Lever /* 1301da177e4SLinus Torvalds * Common NFS XDR functions as inlines 1311da177e4SLinus Torvalds */ 132d61005a6SAl Viro static inline __be32 * 133d61005a6SAl Viro xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) { 1361da177e4SLinus Torvalds memcpy(fh->data, p, fh->size); 1371da177e4SLinus Torvalds return p + XDR_QUADLEN(fh->size); 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds return NULL; 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds 142babddc72SBryan Schumaker static inline __be32 * 143babddc72SBryan Schumaker xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh) 144babddc72SBryan Schumaker { 145babddc72SBryan Schumaker __be32 *p; 146babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 147babddc72SBryan Schumaker if (unlikely(!p)) 148babddc72SBryan Schumaker goto out_overflow; 149babddc72SBryan Schumaker fh->size = ntohl(*p++); 150babddc72SBryan Schumaker 151babddc72SBryan Schumaker if (fh->size <= NFS3_FHSIZE) { 152babddc72SBryan Schumaker p = xdr_inline_decode(xdr, fh->size); 153babddc72SBryan Schumaker if (unlikely(!p)) 154babddc72SBryan Schumaker goto out_overflow; 155babddc72SBryan Schumaker memcpy(fh->data, p, fh->size); 156babddc72SBryan Schumaker return p + XDR_QUADLEN(fh->size); 157babddc72SBryan Schumaker } 158babddc72SBryan Schumaker return NULL; 159babddc72SBryan Schumaker 160babddc72SBryan Schumaker out_overflow: 161babddc72SBryan Schumaker print_overflow_msg(__func__, xdr); 162babddc72SBryan Schumaker return ERR_PTR(-EIO); 163babddc72SBryan Schumaker } 164babddc72SBryan Schumaker 1651da177e4SLinus Torvalds /* 1661da177e4SLinus Torvalds * Encode/decode time. 1671da177e4SLinus Torvalds */ 168d61005a6SAl Viro static inline __be32 * 169d61005a6SAl Viro xdr_decode_time3(__be32 *p, struct timespec *timep) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds timep->tv_sec = ntohl(*p++); 1721da177e4SLinus Torvalds timep->tv_nsec = ntohl(*p++); 1731da177e4SLinus Torvalds return p; 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 176d61005a6SAl Viro static __be32 * 177d61005a6SAl Viro xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) 1781da177e4SLinus Torvalds { 1791da177e4SLinus Torvalds unsigned int type, major, minor; 180bca79478STrond Myklebust umode_t fmode; 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds type = ntohl(*p++); 183bca79478STrond Myklebust if (type > NF3FIFO) 184bca79478STrond Myklebust type = NF3NON; 185bca79478STrond Myklebust fmode = nfs_type2fmt[type]; 1861da177e4SLinus Torvalds fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode; 1871da177e4SLinus Torvalds fattr->nlink = ntohl(*p++); 1881da177e4SLinus Torvalds fattr->uid = ntohl(*p++); 1891da177e4SLinus Torvalds fattr->gid = ntohl(*p++); 1901da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->size); 1911da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->du.nfs3.used); 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds /* Turn remote device info into Linux-specific dev_t */ 1941da177e4SLinus Torvalds major = ntohl(*p++); 1951da177e4SLinus Torvalds minor = ntohl(*p++); 1961da177e4SLinus Torvalds fattr->rdev = MKDEV(major, minor); 1971da177e4SLinus Torvalds if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor) 1981da177e4SLinus Torvalds fattr->rdev = 0; 1991da177e4SLinus Torvalds 2008b4bdcf8STrond Myklebust p = xdr_decode_hyper(p, &fattr->fsid.major); 2018b4bdcf8STrond Myklebust fattr->fsid.minor = 0; 2021da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->fileid); 2031da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->atime); 2041da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->mtime); 2051da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->ctime); 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* Update the mode bits */ 2089e6e70f8STrond Myklebust fattr->valid |= NFS_ATTR_FATTR_V3; 2091da177e4SLinus Torvalds return p; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 212d61005a6SAl Viro static inline __be32 * 213d61005a6SAl Viro xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr) 2141da177e4SLinus Torvalds { 2151da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->pre_size); 2161da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->pre_mtime); 2171da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->pre_ctime); 2189e6e70f8STrond Myklebust fattr->valid |= NFS_ATTR_FATTR_PRESIZE 2199e6e70f8STrond Myklebust | NFS_ATTR_FATTR_PREMTIME 2209e6e70f8STrond Myklebust | NFS_ATTR_FATTR_PRECTIME; 2211da177e4SLinus Torvalds return p; 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds 224d61005a6SAl Viro static inline __be32 * 225d61005a6SAl Viro xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr) 2261da177e4SLinus Torvalds { 2271da177e4SLinus Torvalds if (*p++) 2281da177e4SLinus Torvalds p = xdr_decode_fattr(p, fattr); 2291da177e4SLinus Torvalds return p; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 232d61005a6SAl Viro static inline __be32 * 233babddc72SBryan Schumaker xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr) 234babddc72SBryan Schumaker { 235babddc72SBryan Schumaker __be32 *p; 236babddc72SBryan Schumaker 237babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 238babddc72SBryan Schumaker if (unlikely(!p)) 239babddc72SBryan Schumaker goto out_overflow; 240babddc72SBryan Schumaker if (ntohl(*p++)) { 241babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 84); 242babddc72SBryan Schumaker if (unlikely(!p)) 243babddc72SBryan Schumaker goto out_overflow; 244babddc72SBryan Schumaker p = xdr_decode_fattr(p, fattr); 245babddc72SBryan Schumaker } 246babddc72SBryan Schumaker return p; 247babddc72SBryan Schumaker out_overflow: 248babddc72SBryan Schumaker print_overflow_msg(__func__, xdr); 249babddc72SBryan Schumaker return ERR_PTR(-EIO); 250babddc72SBryan Schumaker } 251babddc72SBryan Schumaker 252babddc72SBryan Schumaker static inline __be32 * 253d61005a6SAl Viro xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr) 2541da177e4SLinus Torvalds { 2551da177e4SLinus Torvalds if (*p++) 2561da177e4SLinus Torvalds return xdr_decode_wcc_attr(p, fattr); 2571da177e4SLinus Torvalds return p; 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds 261d61005a6SAl Viro static inline __be32 * 262d61005a6SAl Viro xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr) 2631da177e4SLinus Torvalds { 2641da177e4SLinus Torvalds p = xdr_decode_pre_op_attr(p, fattr); 2651da177e4SLinus Torvalds return xdr_decode_post_op_attr(p, fattr); 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds 268d9c407b1SChuck Lever 269d9c407b1SChuck Lever /* 270d9c407b1SChuck Lever * Encode/decode NFSv3 basic data types 271d9c407b1SChuck Lever * 272d9c407b1SChuck Lever * Basic NFSv3 data types are defined in section 2.5 of RFC 1813: 273d9c407b1SChuck Lever * "NFS Version 3 Protocol Specification". 274d9c407b1SChuck Lever * 275d9c407b1SChuck Lever * Not all basic data types have their own encoding and decoding 276d9c407b1SChuck Lever * functions. For run-time efficiency, some data types are encoded 277d9c407b1SChuck Lever * or decoded inline. 278d9c407b1SChuck Lever */ 279d9c407b1SChuck Lever 280d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value) 281d9c407b1SChuck Lever { 282d9c407b1SChuck Lever __be32 *p = xdr_reserve_space(xdr, 4); 283d9c407b1SChuck Lever *p = cpu_to_be32(value); 284d9c407b1SChuck Lever } 285d9c407b1SChuck Lever 286e4f93234SChuck Lever static int decode_uint32(struct xdr_stream *xdr, u32 *value) 287e4f93234SChuck Lever { 288e4f93234SChuck Lever __be32 *p; 289e4f93234SChuck Lever 290e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 291e4f93234SChuck Lever if (unlikely(p == NULL)) 292e4f93234SChuck Lever goto out_overflow; 293e4f93234SChuck Lever *value = be32_to_cpup(p); 294e4f93234SChuck Lever return 0; 295e4f93234SChuck Lever out_overflow: 296e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 297e4f93234SChuck Lever return -EIO; 298e4f93234SChuck Lever } 299e4f93234SChuck Lever 300e4f93234SChuck Lever static int decode_uint64(struct xdr_stream *xdr, u64 *value) 301e4f93234SChuck Lever { 302e4f93234SChuck Lever __be32 *p; 303e4f93234SChuck Lever 304e4f93234SChuck Lever p = xdr_inline_decode(xdr, 8); 305e4f93234SChuck Lever if (unlikely(p == NULL)) 306e4f93234SChuck Lever goto out_overflow; 307e4f93234SChuck Lever xdr_decode_hyper(p, value); 308e4f93234SChuck Lever return 0; 309e4f93234SChuck Lever out_overflow: 310e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 311e4f93234SChuck Lever return -EIO; 312e4f93234SChuck Lever } 313e4f93234SChuck Lever 314e4f93234SChuck Lever /* 315e4f93234SChuck Lever * fileid3 316e4f93234SChuck Lever * 317e4f93234SChuck Lever * typedef uint64 fileid3; 318e4f93234SChuck Lever */ 319e4f93234SChuck Lever static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid) 320e4f93234SChuck Lever { 321e4f93234SChuck Lever return decode_uint64(xdr, fileid); 322e4f93234SChuck Lever } 323e4f93234SChuck Lever 324d9c407b1SChuck Lever /* 325d9c407b1SChuck Lever * filename3 326d9c407b1SChuck Lever * 327d9c407b1SChuck Lever * typedef string filename3<>; 328d9c407b1SChuck Lever */ 329d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr, 330d9c407b1SChuck Lever const char *name, u32 length) 331d9c407b1SChuck Lever { 332d9c407b1SChuck Lever __be32 *p; 333d9c407b1SChuck Lever 334d9c407b1SChuck Lever BUG_ON(length > NFS3_MAXNAMLEN); 335d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + length); 336d9c407b1SChuck Lever xdr_encode_opaque(p, name, length); 337d9c407b1SChuck Lever } 338d9c407b1SChuck Lever 339e4f93234SChuck Lever static int decode_inline_filename3(struct xdr_stream *xdr, 340e4f93234SChuck Lever const char **name, u32 *length) 341e4f93234SChuck Lever { 342e4f93234SChuck Lever __be32 *p; 343e4f93234SChuck Lever u32 count; 344e4f93234SChuck Lever 345e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 346e4f93234SChuck Lever if (unlikely(p == NULL)) 347e4f93234SChuck Lever goto out_overflow; 348e4f93234SChuck Lever count = be32_to_cpup(p); 349e4f93234SChuck Lever if (count > NFS3_MAXNAMLEN) 350e4f93234SChuck Lever goto out_nametoolong; 351e4f93234SChuck Lever p = xdr_inline_decode(xdr, count); 352e4f93234SChuck Lever if (unlikely(p == NULL)) 353e4f93234SChuck Lever goto out_overflow; 354e4f93234SChuck Lever *name = (const char *)p; 355e4f93234SChuck Lever *length = count; 356e4f93234SChuck Lever return 0; 357e4f93234SChuck Lever 358e4f93234SChuck Lever out_nametoolong: 359e4f93234SChuck Lever dprintk("NFS: returned filename too long: %u\n", count); 360e4f93234SChuck Lever return -ENAMETOOLONG; 361e4f93234SChuck Lever out_overflow: 362e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 363e4f93234SChuck Lever return -EIO; 364e4f93234SChuck Lever } 365e4f93234SChuck Lever 366d9c407b1SChuck Lever /* 367d9c407b1SChuck Lever * nfspath3 368d9c407b1SChuck Lever * 369d9c407b1SChuck Lever * typedef string nfspath3<>; 370d9c407b1SChuck Lever */ 371d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages, 372d9c407b1SChuck Lever const u32 length) 373d9c407b1SChuck Lever { 374d9c407b1SChuck Lever BUG_ON(length > NFS3_MAXPATHLEN); 375d9c407b1SChuck Lever encode_uint32(xdr, length); 376d9c407b1SChuck Lever xdr_write_pages(xdr, pages, 0, length); 377d9c407b1SChuck Lever } 378d9c407b1SChuck Lever 379e4f93234SChuck Lever static int decode_nfspath3(struct xdr_stream *xdr) 380e4f93234SChuck Lever { 381e4f93234SChuck Lever u32 recvd, count; 382e4f93234SChuck Lever size_t hdrlen; 383e4f93234SChuck Lever __be32 *p; 384e4f93234SChuck Lever 385e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 386e4f93234SChuck Lever if (unlikely(p == NULL)) 387e4f93234SChuck Lever goto out_overflow; 388e4f93234SChuck Lever count = be32_to_cpup(p); 389e4f93234SChuck Lever if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN)) 390e4f93234SChuck Lever goto out_nametoolong; 391e4f93234SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 392e4f93234SChuck Lever recvd = xdr->buf->len - hdrlen; 393e4f93234SChuck Lever if (unlikely(count > recvd)) 394e4f93234SChuck Lever goto out_cheating; 395e4f93234SChuck Lever 396e4f93234SChuck Lever xdr_read_pages(xdr, count); 397e4f93234SChuck Lever xdr_terminate_string(xdr->buf, count); 398e4f93234SChuck Lever return 0; 399e4f93234SChuck Lever 400e4f93234SChuck Lever out_nametoolong: 401e4f93234SChuck Lever dprintk("NFS: returned pathname too long: %u\n", count); 402e4f93234SChuck Lever return -ENAMETOOLONG; 403e4f93234SChuck Lever out_cheating: 404e4f93234SChuck Lever dprintk("NFS: server cheating in pathname result: " 405e4f93234SChuck Lever "count %u > recvd %u\n", count, recvd); 406e4f93234SChuck Lever return -EIO; 407e4f93234SChuck Lever out_overflow: 408e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 409e4f93234SChuck Lever return -EIO; 410e4f93234SChuck Lever } 411e4f93234SChuck Lever 412d9c407b1SChuck Lever /* 413d9c407b1SChuck Lever * cookie3 414d9c407b1SChuck Lever * 415d9c407b1SChuck Lever * typedef uint64 cookie3 416d9c407b1SChuck Lever */ 417d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie) 418d9c407b1SChuck Lever { 419d9c407b1SChuck Lever return xdr_encode_hyper(p, cookie); 420d9c407b1SChuck Lever } 421d9c407b1SChuck Lever 422e4f93234SChuck Lever static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie) 423e4f93234SChuck Lever { 424e4f93234SChuck Lever return decode_uint64(xdr, cookie); 425e4f93234SChuck Lever } 426e4f93234SChuck Lever 427d9c407b1SChuck Lever /* 428d9c407b1SChuck Lever * cookieverf3 429d9c407b1SChuck Lever * 430d9c407b1SChuck Lever * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; 431d9c407b1SChuck Lever */ 432d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier) 433d9c407b1SChuck Lever { 434d9c407b1SChuck Lever memcpy(p, verifier, NFS3_COOKIEVERFSIZE); 435d9c407b1SChuck Lever return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE); 436d9c407b1SChuck Lever } 437d9c407b1SChuck Lever 438e4f93234SChuck Lever static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier) 439e4f93234SChuck Lever { 440e4f93234SChuck Lever __be32 *p; 441e4f93234SChuck Lever 442e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); 443e4f93234SChuck Lever if (unlikely(p == NULL)) 444e4f93234SChuck Lever goto out_overflow; 445e4f93234SChuck Lever memcpy(verifier, p, NFS3_COOKIEVERFSIZE); 446e4f93234SChuck Lever return 0; 447e4f93234SChuck Lever out_overflow: 448e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 449e4f93234SChuck Lever return -EIO; 450e4f93234SChuck Lever } 451e4f93234SChuck Lever 452d9c407b1SChuck Lever /* 453d9c407b1SChuck Lever * createverf3 454d9c407b1SChuck Lever * 455d9c407b1SChuck Lever * typedef opaque createverf3[NFS3_CREATEVERFSIZE]; 456d9c407b1SChuck Lever */ 457d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier) 458d9c407b1SChuck Lever { 459d9c407b1SChuck Lever __be32 *p; 460d9c407b1SChuck Lever 461d9c407b1SChuck Lever p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE); 462d9c407b1SChuck Lever memcpy(p, verifier, NFS3_CREATEVERFSIZE); 463d9c407b1SChuck Lever } 464d9c407b1SChuck Lever 465e4f93234SChuck Lever static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier) 466e4f93234SChuck Lever { 467e4f93234SChuck Lever __be32 *p; 468e4f93234SChuck Lever 469e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE); 470e4f93234SChuck Lever if (unlikely(p == NULL)) 471e4f93234SChuck Lever goto out_overflow; 472e4f93234SChuck Lever memcpy(verifier, p, NFS3_WRITEVERFSIZE); 473e4f93234SChuck Lever return 0; 474e4f93234SChuck Lever out_overflow: 475e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 476e4f93234SChuck Lever return -EIO; 477e4f93234SChuck Lever } 478e4f93234SChuck Lever 479e4f93234SChuck Lever /* 480e4f93234SChuck Lever * size3 481e4f93234SChuck Lever * 482e4f93234SChuck Lever * typedef uint64 size3; 483e4f93234SChuck Lever */ 484e4f93234SChuck Lever static __be32 *xdr_decode_size3(__be32 *p, u64 *size) 485e4f93234SChuck Lever { 486e4f93234SChuck Lever return xdr_decode_hyper(p, size); 487e4f93234SChuck Lever } 488e4f93234SChuck Lever 489e4f93234SChuck Lever /* 490e4f93234SChuck Lever * nfsstat3 491e4f93234SChuck Lever * 492e4f93234SChuck Lever * enum nfsstat3 { 493e4f93234SChuck Lever * NFS3_OK = 0, 494e4f93234SChuck Lever * ... 495e4f93234SChuck Lever * } 496e4f93234SChuck Lever */ 497e4f93234SChuck Lever #define NFS3_OK NFS_OK 498e4f93234SChuck Lever 499e4f93234SChuck Lever static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status) 500e4f93234SChuck Lever { 501e4f93234SChuck Lever __be32 *p; 502e4f93234SChuck Lever 503e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 504e4f93234SChuck Lever if (unlikely(p == NULL)) 505e4f93234SChuck Lever goto out_overflow; 506e4f93234SChuck Lever *status = be32_to_cpup(p); 507e4f93234SChuck Lever return 0; 508e4f93234SChuck Lever out_overflow: 509e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 510e4f93234SChuck Lever return -EIO; 511e4f93234SChuck Lever } 512e4f93234SChuck Lever 513d9c407b1SChuck Lever /* 514d9c407b1SChuck Lever * ftype3 515d9c407b1SChuck Lever * 516d9c407b1SChuck Lever * enum ftype3 { 517d9c407b1SChuck Lever * NF3REG = 1, 518d9c407b1SChuck Lever * NF3DIR = 2, 519d9c407b1SChuck Lever * NF3BLK = 3, 520d9c407b1SChuck Lever * NF3CHR = 4, 521d9c407b1SChuck Lever * NF3LNK = 5, 522d9c407b1SChuck Lever * NF3SOCK = 6, 523d9c407b1SChuck Lever * NF3FIFO = 7 524d9c407b1SChuck Lever * }; 525d9c407b1SChuck Lever */ 526d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type) 527d9c407b1SChuck Lever { 528d9c407b1SChuck Lever BUG_ON(type > NF3FIFO); 529d9c407b1SChuck Lever encode_uint32(xdr, type); 530d9c407b1SChuck Lever } 531d9c407b1SChuck Lever 532d9c407b1SChuck Lever /* 533d9c407b1SChuck Lever * specdata3 534d9c407b1SChuck Lever * 535d9c407b1SChuck Lever * struct specdata3 { 536d9c407b1SChuck Lever * uint32 specdata1; 537d9c407b1SChuck Lever * uint32 specdata2; 538d9c407b1SChuck Lever * }; 539d9c407b1SChuck Lever */ 540d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev) 541d9c407b1SChuck Lever { 542d9c407b1SChuck Lever __be32 *p; 543d9c407b1SChuck Lever 544d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8); 545d9c407b1SChuck Lever *p++ = cpu_to_be32(MAJOR(rdev)); 546d9c407b1SChuck Lever *p = cpu_to_be32(MINOR(rdev)); 547d9c407b1SChuck Lever } 548d9c407b1SChuck Lever 549d9c407b1SChuck Lever /* 550d9c407b1SChuck Lever * nfs_fh3 551d9c407b1SChuck Lever * 552d9c407b1SChuck Lever * struct nfs_fh3 { 553d9c407b1SChuck Lever * opaque data<NFS3_FHSIZE>; 554d9c407b1SChuck Lever * }; 555d9c407b1SChuck Lever */ 556d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh) 557d9c407b1SChuck Lever { 558d9c407b1SChuck Lever __be32 *p; 559d9c407b1SChuck Lever 560d9c407b1SChuck Lever BUG_ON(fh->size > NFS3_FHSIZE); 561d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + fh->size); 562d9c407b1SChuck Lever xdr_encode_opaque(p, fh->data, fh->size); 563d9c407b1SChuck Lever } 564d9c407b1SChuck Lever 565e4f93234SChuck Lever static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) 566e4f93234SChuck Lever { 567e4f93234SChuck Lever u32 length; 568e4f93234SChuck Lever __be32 *p; 569e4f93234SChuck Lever 570e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 571e4f93234SChuck Lever if (unlikely(p == NULL)) 572e4f93234SChuck Lever goto out_overflow; 573e4f93234SChuck Lever length = be32_to_cpup(p++); 574e4f93234SChuck Lever if (unlikely(length > NFS3_FHSIZE)) 575e4f93234SChuck Lever goto out_toobig; 576e4f93234SChuck Lever p = xdr_inline_decode(xdr, length); 577e4f93234SChuck Lever if (unlikely(p == NULL)) 578e4f93234SChuck Lever goto out_overflow; 579e4f93234SChuck Lever fh->size = length; 580e4f93234SChuck Lever memcpy(fh->data, p, length); 581e4f93234SChuck Lever return 0; 582e4f93234SChuck Lever out_toobig: 583e4f93234SChuck Lever dprintk("NFS: file handle size (%u) too big\n", length); 584e4f93234SChuck Lever return -E2BIG; 585e4f93234SChuck Lever out_overflow: 586e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 587e4f93234SChuck Lever return -EIO; 588e4f93234SChuck Lever } 589e4f93234SChuck Lever 590e4f93234SChuck Lever static void zero_nfs_fh3(struct nfs_fh *fh) 591e4f93234SChuck Lever { 592e4f93234SChuck Lever memset(fh, 0, sizeof(*fh)); 593e4f93234SChuck Lever } 594e4f93234SChuck Lever 595d9c407b1SChuck Lever /* 5969d5a6434SChuck Lever * nfstime3 5979d5a6434SChuck Lever * 5989d5a6434SChuck Lever * struct nfstime3 { 5999d5a6434SChuck Lever * uint32 seconds; 6009d5a6434SChuck Lever * uint32 nseconds; 6019d5a6434SChuck Lever * }; 6029d5a6434SChuck Lever */ 6039d5a6434SChuck Lever static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep) 6049d5a6434SChuck Lever { 6059d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_sec); 6069d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_nsec); 6079d5a6434SChuck Lever return p; 6089d5a6434SChuck Lever } 6099d5a6434SChuck Lever 6109d5a6434SChuck Lever /* 611d9c407b1SChuck Lever * sattr3 612d9c407b1SChuck Lever * 613d9c407b1SChuck Lever * enum time_how { 614d9c407b1SChuck Lever * DONT_CHANGE = 0, 615d9c407b1SChuck Lever * SET_TO_SERVER_TIME = 1, 616d9c407b1SChuck Lever * SET_TO_CLIENT_TIME = 2 617d9c407b1SChuck Lever * }; 618d9c407b1SChuck Lever * 619d9c407b1SChuck Lever * union set_mode3 switch (bool set_it) { 620d9c407b1SChuck Lever * case TRUE: 621d9c407b1SChuck Lever * mode3 mode; 622d9c407b1SChuck Lever * default: 623d9c407b1SChuck Lever * void; 624d9c407b1SChuck Lever * }; 625d9c407b1SChuck Lever * 626d9c407b1SChuck Lever * union set_uid3 switch (bool set_it) { 627d9c407b1SChuck Lever * case TRUE: 628d9c407b1SChuck Lever * uid3 uid; 629d9c407b1SChuck Lever * default: 630d9c407b1SChuck Lever * void; 631d9c407b1SChuck Lever * }; 632d9c407b1SChuck Lever * 633d9c407b1SChuck Lever * union set_gid3 switch (bool set_it) { 634d9c407b1SChuck Lever * case TRUE: 635d9c407b1SChuck Lever * gid3 gid; 636d9c407b1SChuck Lever * default: 637d9c407b1SChuck Lever * void; 638d9c407b1SChuck Lever * }; 639d9c407b1SChuck Lever * 640d9c407b1SChuck Lever * union set_size3 switch (bool set_it) { 641d9c407b1SChuck Lever * case TRUE: 642d9c407b1SChuck Lever * size3 size; 643d9c407b1SChuck Lever * default: 644d9c407b1SChuck Lever * void; 645d9c407b1SChuck Lever * }; 646d9c407b1SChuck Lever * 647d9c407b1SChuck Lever * union set_atime switch (time_how set_it) { 648d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 649d9c407b1SChuck Lever * nfstime3 atime; 650d9c407b1SChuck Lever * default: 651d9c407b1SChuck Lever * void; 652d9c407b1SChuck Lever * }; 653d9c407b1SChuck Lever * 654d9c407b1SChuck Lever * union set_mtime switch (time_how set_it) { 655d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 656d9c407b1SChuck Lever * nfstime3 mtime; 657d9c407b1SChuck Lever * default: 658d9c407b1SChuck Lever * void; 659d9c407b1SChuck Lever * }; 660d9c407b1SChuck Lever * 661d9c407b1SChuck Lever * struct sattr3 { 662d9c407b1SChuck Lever * set_mode3 mode; 663d9c407b1SChuck Lever * set_uid3 uid; 664d9c407b1SChuck Lever * set_gid3 gid; 665d9c407b1SChuck Lever * set_size3 size; 666d9c407b1SChuck Lever * set_atime atime; 667d9c407b1SChuck Lever * set_mtime mtime; 668d9c407b1SChuck Lever * }; 669d9c407b1SChuck Lever */ 670d9c407b1SChuck Lever static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr) 671d9c407b1SChuck Lever { 672d9c407b1SChuck Lever u32 nbytes; 673d9c407b1SChuck Lever __be32 *p; 674d9c407b1SChuck Lever 675d9c407b1SChuck Lever /* 676d9c407b1SChuck Lever * In order to make only a single xdr_reserve_space() call, 677d9c407b1SChuck Lever * pre-compute the total number of bytes to be reserved. 678d9c407b1SChuck Lever * Six boolean values, one for each set_foo field, are always 679d9c407b1SChuck Lever * present in the encoded result, so start there. 680d9c407b1SChuck Lever */ 681d9c407b1SChuck Lever nbytes = 6 * 4; 682d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MODE) 683d9c407b1SChuck Lever nbytes += 4; 684d9c407b1SChuck Lever if (attr->ia_valid & ATTR_UID) 685d9c407b1SChuck Lever nbytes += 4; 686d9c407b1SChuck Lever if (attr->ia_valid & ATTR_GID) 687d9c407b1SChuck Lever nbytes += 4; 688d9c407b1SChuck Lever if (attr->ia_valid & ATTR_SIZE) 689d9c407b1SChuck Lever nbytes += 8; 690d9c407b1SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) 691d9c407b1SChuck Lever nbytes += 8; 692d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) 693d9c407b1SChuck Lever nbytes += 8; 694d9c407b1SChuck Lever p = xdr_reserve_space(xdr, nbytes); 695d9c407b1SChuck Lever 6969d5a6434SChuck Lever if (attr->ia_valid & ATTR_MODE) { 6979d5a6434SChuck Lever *p++ = xdr_one; 6989d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO); 6999d5a6434SChuck Lever } else 7009d5a6434SChuck Lever *p++ = xdr_zero; 7019d5a6434SChuck Lever 7029d5a6434SChuck Lever if (attr->ia_valid & ATTR_UID) { 7039d5a6434SChuck Lever *p++ = xdr_one; 7049d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_uid); 7059d5a6434SChuck Lever } else 7069d5a6434SChuck Lever *p++ = xdr_zero; 7079d5a6434SChuck Lever 7089d5a6434SChuck Lever if (attr->ia_valid & ATTR_GID) { 7099d5a6434SChuck Lever *p++ = xdr_one; 7109d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_gid); 7119d5a6434SChuck Lever } else 7129d5a6434SChuck Lever *p++ = xdr_zero; 7139d5a6434SChuck Lever 7149d5a6434SChuck Lever if (attr->ia_valid & ATTR_SIZE) { 7159d5a6434SChuck Lever *p++ = xdr_one; 7169d5a6434SChuck Lever p = xdr_encode_hyper(p, (u64)attr->ia_size); 7179d5a6434SChuck Lever } else 7189d5a6434SChuck Lever *p++ = xdr_zero; 7199d5a6434SChuck Lever 7209d5a6434SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) { 7219d5a6434SChuck Lever *p++ = xdr_two; 7229d5a6434SChuck Lever p = xdr_encode_nfstime3(p, &attr->ia_atime); 7239d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_ATIME) { 7249d5a6434SChuck Lever *p++ = xdr_one; 7259d5a6434SChuck Lever } else 7269d5a6434SChuck Lever *p++ = xdr_zero; 7279d5a6434SChuck Lever 7289d5a6434SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) { 7299d5a6434SChuck Lever *p++ = xdr_two; 7309d5a6434SChuck Lever xdr_encode_nfstime3(p, &attr->ia_mtime); 7319d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_MTIME) { 7329d5a6434SChuck Lever *p = xdr_one; 7339d5a6434SChuck Lever } else 7349d5a6434SChuck Lever *p = xdr_zero; 735d9c407b1SChuck Lever } 736d9c407b1SChuck Lever 737d9c407b1SChuck Lever /* 738e4f93234SChuck Lever * fattr3 739e4f93234SChuck Lever * 740e4f93234SChuck Lever * struct fattr3 { 741e4f93234SChuck Lever * ftype3 type; 742e4f93234SChuck Lever * mode3 mode; 743e4f93234SChuck Lever * uint32 nlink; 744e4f93234SChuck Lever * uid3 uid; 745e4f93234SChuck Lever * gid3 gid; 746e4f93234SChuck Lever * size3 size; 747e4f93234SChuck Lever * size3 used; 748e4f93234SChuck Lever * specdata3 rdev; 749e4f93234SChuck Lever * uint64 fsid; 750e4f93234SChuck Lever * fileid3 fileid; 751e4f93234SChuck Lever * nfstime3 atime; 752e4f93234SChuck Lever * nfstime3 mtime; 753e4f93234SChuck Lever * nfstime3 ctime; 754e4f93234SChuck Lever * }; 755e4f93234SChuck Lever */ 756e4f93234SChuck Lever static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr) 757e4f93234SChuck Lever { 758e4f93234SChuck Lever __be32 *p; 759e4f93234SChuck Lever 760e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2); 761e4f93234SChuck Lever if (unlikely(p == NULL)) 762e4f93234SChuck Lever goto out_overflow; 763e4f93234SChuck Lever xdr_decode_fattr(p, fattr); 764e4f93234SChuck Lever return 0; 765e4f93234SChuck Lever out_overflow: 766e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 767e4f93234SChuck Lever return -EIO; 768e4f93234SChuck Lever } 769e4f93234SChuck Lever 770e4f93234SChuck Lever /* 771e4f93234SChuck Lever * post_op_attr 772e4f93234SChuck Lever * 773e4f93234SChuck Lever * union post_op_attr switch (bool attributes_follow) { 774e4f93234SChuck Lever * case TRUE: 775e4f93234SChuck Lever * fattr3 attributes; 776e4f93234SChuck Lever * case FALSE: 777e4f93234SChuck Lever * void; 778e4f93234SChuck Lever * }; 779e4f93234SChuck Lever */ 780e4f93234SChuck Lever static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 781e4f93234SChuck Lever { 782e4f93234SChuck Lever __be32 *p; 783e4f93234SChuck Lever 784e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 785e4f93234SChuck Lever if (unlikely(p == NULL)) 786e4f93234SChuck Lever goto out_overflow; 787e4f93234SChuck Lever if (*p != xdr_zero) 788e4f93234SChuck Lever return decode_fattr3(xdr, fattr); 789e4f93234SChuck Lever return 0; 790e4f93234SChuck Lever out_overflow: 791e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 792e4f93234SChuck Lever return -EIO; 793e4f93234SChuck Lever } 794e4f93234SChuck Lever 795e4f93234SChuck Lever /* 796e4f93234SChuck Lever * wcc_attr 797e4f93234SChuck Lever * struct wcc_attr { 798e4f93234SChuck Lever * size3 size; 799e4f93234SChuck Lever * nfstime3 mtime; 800e4f93234SChuck Lever * nfstime3 ctime; 801e4f93234SChuck Lever * }; 802e4f93234SChuck Lever */ 803e4f93234SChuck Lever static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 804e4f93234SChuck Lever { 805e4f93234SChuck Lever __be32 *p; 806e4f93234SChuck Lever 807e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2); 808e4f93234SChuck Lever if (unlikely(p == NULL)) 809e4f93234SChuck Lever goto out_overflow; 810e4f93234SChuck Lever xdr_decode_wcc_attr(p, fattr); 811e4f93234SChuck Lever return 0; 812e4f93234SChuck Lever out_overflow: 813e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 814e4f93234SChuck Lever return -EIO; 815e4f93234SChuck Lever } 816e4f93234SChuck Lever 817e4f93234SChuck Lever /* 818e4f93234SChuck Lever * pre_op_attr 819e4f93234SChuck Lever * union pre_op_attr switch (bool attributes_follow) { 820e4f93234SChuck Lever * case TRUE: 821e4f93234SChuck Lever * wcc_attr attributes; 822e4f93234SChuck Lever * case FALSE: 823e4f93234SChuck Lever * void; 824e4f93234SChuck Lever * }; 825e4f93234SChuck Lever * 826e4f93234SChuck Lever * wcc_data 827e4f93234SChuck Lever * 828e4f93234SChuck Lever * struct wcc_data { 829e4f93234SChuck Lever * pre_op_attr before; 830e4f93234SChuck Lever * post_op_attr after; 831e4f93234SChuck Lever * }; 832e4f93234SChuck Lever */ 833e4f93234SChuck Lever static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 834e4f93234SChuck Lever { 835e4f93234SChuck Lever __be32 *p; 836e4f93234SChuck Lever 837e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 838e4f93234SChuck Lever if (unlikely(p == NULL)) 839e4f93234SChuck Lever goto out_overflow; 840e4f93234SChuck Lever if (*p != xdr_zero) 841e4f93234SChuck Lever return decode_wcc_attr(xdr, fattr); 842e4f93234SChuck Lever return 0; 843e4f93234SChuck Lever out_overflow: 844e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 845e4f93234SChuck Lever return -EIO; 846e4f93234SChuck Lever } 847e4f93234SChuck Lever 848e4f93234SChuck Lever static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr) 849e4f93234SChuck Lever { 850e4f93234SChuck Lever int error; 851e4f93234SChuck Lever 852e4f93234SChuck Lever error = decode_pre_op_attr(xdr, fattr); 853e4f93234SChuck Lever if (unlikely(error)) 854e4f93234SChuck Lever goto out; 855e4f93234SChuck Lever error = decode_post_op_attr(xdr, fattr); 856e4f93234SChuck Lever out: 857e4f93234SChuck Lever return error; 858e4f93234SChuck Lever } 859e4f93234SChuck Lever 860e4f93234SChuck Lever /* 861e4f93234SChuck Lever * post_op_fh3 862e4f93234SChuck Lever * 863e4f93234SChuck Lever * union post_op_fh3 switch (bool handle_follows) { 864e4f93234SChuck Lever * case TRUE: 865e4f93234SChuck Lever * nfs_fh3 handle; 866e4f93234SChuck Lever * case FALSE: 867e4f93234SChuck Lever * void; 868e4f93234SChuck Lever * }; 869e4f93234SChuck Lever */ 870e4f93234SChuck Lever static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) 871e4f93234SChuck Lever { 872e4f93234SChuck Lever __be32 *p = xdr_inline_decode(xdr, 4); 873e4f93234SChuck Lever if (unlikely(p == NULL)) 874e4f93234SChuck Lever goto out_overflow; 875e4f93234SChuck Lever if (*p != xdr_zero) 876e4f93234SChuck Lever return decode_nfs_fh3(xdr, fh); 877e4f93234SChuck Lever zero_nfs_fh3(fh); 878e4f93234SChuck Lever return 0; 879e4f93234SChuck Lever out_overflow: 880e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 881e4f93234SChuck Lever return -EIO; 882e4f93234SChuck Lever } 883e4f93234SChuck Lever 884e4f93234SChuck Lever /* 885d9c407b1SChuck Lever * diropargs3 886d9c407b1SChuck Lever * 887d9c407b1SChuck Lever * struct diropargs3 { 888d9c407b1SChuck Lever * nfs_fh3 dir; 889d9c407b1SChuck Lever * filename3 name; 890d9c407b1SChuck Lever * }; 891d9c407b1SChuck Lever */ 892d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh, 893d9c407b1SChuck Lever const char *name, u32 length) 894d9c407b1SChuck Lever { 895d9c407b1SChuck Lever encode_nfs_fh3(xdr, fh); 896d9c407b1SChuck Lever encode_filename3(xdr, name, length); 897d9c407b1SChuck Lever } 898d9c407b1SChuck Lever 899d9c407b1SChuck Lever 9001da177e4SLinus Torvalds /* 901499ff710SChuck Lever * NFSv3 XDR encode functions 902499ff710SChuck Lever * 903499ff710SChuck Lever * NFSv3 argument types are defined in section 3.3 of RFC 1813: 904499ff710SChuck Lever * "NFS Version 3 Protocol Specification". 9051da177e4SLinus Torvalds */ 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds /* 908d9c407b1SChuck Lever * 3.3.1 GETATTR3args 909d9c407b1SChuck Lever * 910d9c407b1SChuck Lever * struct GETATTR3args { 911d9c407b1SChuck Lever * nfs_fh3 object; 912d9c407b1SChuck Lever * }; 913d9c407b1SChuck Lever */ 914d9c407b1SChuck Lever static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p, 915d9c407b1SChuck Lever const struct nfs_fh *fh) 916d9c407b1SChuck Lever { 917d9c407b1SChuck Lever struct xdr_stream xdr; 918d9c407b1SChuck Lever 919d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 920d9c407b1SChuck Lever encode_nfs_fh3(&xdr, fh); 921d9c407b1SChuck Lever return 0; 922d9c407b1SChuck Lever } 923d9c407b1SChuck Lever 924d9c407b1SChuck Lever /* 925d9c407b1SChuck Lever * 3.3.2 SETATTR3args 926d9c407b1SChuck Lever * 927d9c407b1SChuck Lever * union sattrguard3 switch (bool check) { 928d9c407b1SChuck Lever * case TRUE: 929d9c407b1SChuck Lever * nfstime3 obj_ctime; 930d9c407b1SChuck Lever * case FALSE: 931d9c407b1SChuck Lever * void; 932d9c407b1SChuck Lever * }; 933d9c407b1SChuck Lever * 934d9c407b1SChuck Lever * struct SETATTR3args { 935d9c407b1SChuck Lever * nfs_fh3 object; 936d9c407b1SChuck Lever * sattr3 new_attributes; 937d9c407b1SChuck Lever * sattrguard3 guard; 938d9c407b1SChuck Lever * }; 939d9c407b1SChuck Lever */ 940d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr, 941d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 942d9c407b1SChuck Lever { 943d9c407b1SChuck Lever __be32 *p; 944d9c407b1SChuck Lever 945d9c407b1SChuck Lever if (args->guard) { 946d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + 8); 947d9c407b1SChuck Lever *p++ = xdr_one; 9489d5a6434SChuck Lever xdr_encode_nfstime3(p, &args->guardtime); 949d9c407b1SChuck Lever } else { 950d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4); 951d9c407b1SChuck Lever *p = xdr_zero; 952d9c407b1SChuck Lever } 953d9c407b1SChuck Lever } 954d9c407b1SChuck Lever 955d9c407b1SChuck Lever static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p, 956d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 957d9c407b1SChuck Lever { 958d9c407b1SChuck Lever struct xdr_stream xdr; 959d9c407b1SChuck Lever 960d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 961d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fh); 962d9c407b1SChuck Lever encode_sattr3(&xdr, args->sattr); 963d9c407b1SChuck Lever encode_sattrguard3(&xdr, args); 964d9c407b1SChuck Lever return 0; 965d9c407b1SChuck Lever } 966d9c407b1SChuck Lever 967d9c407b1SChuck Lever /* 968d9c407b1SChuck Lever * 3.3.3 LOOKUP3args 969d9c407b1SChuck Lever * 970d9c407b1SChuck Lever * struct LOOKUP3args { 971d9c407b1SChuck Lever * diropargs3 what; 972d9c407b1SChuck Lever * }; 973d9c407b1SChuck Lever */ 974d9c407b1SChuck Lever static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p, 975d9c407b1SChuck Lever const struct nfs3_diropargs *args) 976d9c407b1SChuck Lever { 977d9c407b1SChuck Lever struct xdr_stream xdr; 978d9c407b1SChuck Lever 979d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 980d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 981d9c407b1SChuck Lever return 0; 982d9c407b1SChuck Lever } 983d9c407b1SChuck Lever 984d9c407b1SChuck Lever /* 985d9c407b1SChuck Lever * 3.3.4 ACCESS3args 986d9c407b1SChuck Lever * 987d9c407b1SChuck Lever * struct ACCESS3args { 988d9c407b1SChuck Lever * nfs_fh3 object; 989d9c407b1SChuck Lever * uint32 access; 990d9c407b1SChuck Lever * }; 991d9c407b1SChuck Lever */ 992d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr, 993d9c407b1SChuck Lever const struct nfs3_accessargs *args) 994d9c407b1SChuck Lever { 995d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 996d9c407b1SChuck Lever encode_uint32(xdr, args->access); 997d9c407b1SChuck Lever } 998d9c407b1SChuck Lever 999d9c407b1SChuck Lever static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p, 1000d9c407b1SChuck Lever const struct nfs3_accessargs *args) 1001d9c407b1SChuck Lever { 1002d9c407b1SChuck Lever struct xdr_stream xdr; 1003d9c407b1SChuck Lever 1004d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1005d9c407b1SChuck Lever encode_access3args(&xdr, args); 1006d9c407b1SChuck Lever return 0; 1007d9c407b1SChuck Lever } 1008d9c407b1SChuck Lever 1009d9c407b1SChuck Lever /* 1010d9c407b1SChuck Lever * 3.3.5 READLINK3args 1011d9c407b1SChuck Lever * 1012d9c407b1SChuck Lever * struct READLINK3args { 1013d9c407b1SChuck Lever * nfs_fh3 symlink; 1014d9c407b1SChuck Lever * }; 1015d9c407b1SChuck Lever */ 1016d9c407b1SChuck Lever static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p, 1017d9c407b1SChuck Lever const struct nfs3_readlinkargs *args) 1018d9c407b1SChuck Lever { 1019d9c407b1SChuck Lever struct xdr_stream xdr; 1020d9c407b1SChuck Lever 1021d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1022d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fh); 1023d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 1024d9c407b1SChuck Lever args->pglen, NFS3_readlinkres_sz); 1025d9c407b1SChuck Lever return 0; 1026d9c407b1SChuck Lever } 1027d9c407b1SChuck Lever 1028d9c407b1SChuck Lever /* 1029d9c407b1SChuck Lever * 3.3.6 READ3args 1030d9c407b1SChuck Lever * 1031d9c407b1SChuck Lever * struct READ3args { 1032d9c407b1SChuck Lever * nfs_fh3 file; 1033d9c407b1SChuck Lever * offset3 offset; 1034d9c407b1SChuck Lever * count3 count; 1035d9c407b1SChuck Lever * }; 1036d9c407b1SChuck Lever */ 1037d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr, 1038d9c407b1SChuck Lever const struct nfs_readargs *args) 1039d9c407b1SChuck Lever { 1040d9c407b1SChuck Lever __be32 *p; 1041d9c407b1SChuck Lever 1042d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1043d9c407b1SChuck Lever 1044d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 1045d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 1046d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1047d9c407b1SChuck Lever } 1048d9c407b1SChuck Lever 1049d9c407b1SChuck Lever static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p, 1050d9c407b1SChuck Lever const struct nfs_readargs *args) 1051d9c407b1SChuck Lever { 1052d9c407b1SChuck Lever struct xdr_stream xdr; 1053d9c407b1SChuck Lever 1054d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1055d9c407b1SChuck Lever encode_read3args(&xdr, args); 1056d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 1057d9c407b1SChuck Lever args->count, NFS3_readres_sz); 1058d9c407b1SChuck Lever req->rq_rcv_buf.flags |= XDRBUF_READ; 1059d9c407b1SChuck Lever return 0; 1060d9c407b1SChuck Lever } 1061d9c407b1SChuck Lever 1062d9c407b1SChuck Lever /* 1063d9c407b1SChuck Lever * 3.3.7 WRITE3args 1064d9c407b1SChuck Lever * 1065d9c407b1SChuck Lever * enum stable_how { 1066d9c407b1SChuck Lever * UNSTABLE = 0, 1067d9c407b1SChuck Lever * DATA_SYNC = 1, 1068d9c407b1SChuck Lever * FILE_SYNC = 2 1069d9c407b1SChuck Lever * }; 1070d9c407b1SChuck Lever * 1071d9c407b1SChuck Lever * struct WRITE3args { 1072d9c407b1SChuck Lever * nfs_fh3 file; 1073d9c407b1SChuck Lever * offset3 offset; 1074d9c407b1SChuck Lever * count3 count; 1075d9c407b1SChuck Lever * stable_how stable; 1076d9c407b1SChuck Lever * opaque data<>; 1077d9c407b1SChuck Lever * }; 1078d9c407b1SChuck Lever */ 1079d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr, 1080d9c407b1SChuck Lever const struct nfs_writeargs *args) 1081d9c407b1SChuck Lever { 1082d9c407b1SChuck Lever __be32 *p; 1083d9c407b1SChuck Lever 1084d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1085d9c407b1SChuck Lever 1086d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4); 1087d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 1088d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count); 1089d9c407b1SChuck Lever 1090d9c407b1SChuck Lever BUG_ON(args->stable > NFS_FILE_SYNC); 1091d9c407b1SChuck Lever *p++ = cpu_to_be32(args->stable); 1092d9c407b1SChuck Lever 1093d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1094d9c407b1SChuck Lever xdr_write_pages(xdr, args->pages, args->pgbase, args->count); 1095d9c407b1SChuck Lever } 1096d9c407b1SChuck Lever 1097d9c407b1SChuck Lever static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p, 1098d9c407b1SChuck Lever const struct nfs_writeargs *args) 1099d9c407b1SChuck Lever { 1100d9c407b1SChuck Lever struct xdr_stream xdr; 1101d9c407b1SChuck Lever 1102d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1103d9c407b1SChuck Lever encode_write3args(&xdr, args); 1104d9c407b1SChuck Lever xdr.buf->flags |= XDRBUF_WRITE; 1105d9c407b1SChuck Lever return 0; 1106d9c407b1SChuck Lever } 1107d9c407b1SChuck Lever 1108d9c407b1SChuck Lever /* 1109d9c407b1SChuck Lever * 3.3.8 CREATE3args 1110d9c407b1SChuck Lever * 1111d9c407b1SChuck Lever * enum createmode3 { 1112d9c407b1SChuck Lever * UNCHECKED = 0, 1113d9c407b1SChuck Lever * GUARDED = 1, 1114d9c407b1SChuck Lever * EXCLUSIVE = 2 1115d9c407b1SChuck Lever * }; 1116d9c407b1SChuck Lever * 1117d9c407b1SChuck Lever * union createhow3 switch (createmode3 mode) { 1118d9c407b1SChuck Lever * case UNCHECKED: 1119d9c407b1SChuck Lever * case GUARDED: 1120d9c407b1SChuck Lever * sattr3 obj_attributes; 1121d9c407b1SChuck Lever * case EXCLUSIVE: 1122d9c407b1SChuck Lever * createverf3 verf; 1123d9c407b1SChuck Lever * }; 1124d9c407b1SChuck Lever * 1125d9c407b1SChuck Lever * struct CREATE3args { 1126d9c407b1SChuck Lever * diropargs3 where; 1127d9c407b1SChuck Lever * createhow3 how; 1128d9c407b1SChuck Lever * }; 1129d9c407b1SChuck Lever */ 1130d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr, 1131d9c407b1SChuck Lever const struct nfs3_createargs *args) 1132d9c407b1SChuck Lever { 1133d9c407b1SChuck Lever encode_uint32(xdr, args->createmode); 1134d9c407b1SChuck Lever switch (args->createmode) { 1135d9c407b1SChuck Lever case NFS3_CREATE_UNCHECKED: 1136d9c407b1SChuck Lever case NFS3_CREATE_GUARDED: 1137d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1138d9c407b1SChuck Lever break; 1139d9c407b1SChuck Lever case NFS3_CREATE_EXCLUSIVE: 1140d9c407b1SChuck Lever encode_createverf3(xdr, args->verifier); 1141d9c407b1SChuck Lever break; 1142d9c407b1SChuck Lever default: 1143d9c407b1SChuck Lever BUG(); 1144d9c407b1SChuck Lever } 1145d9c407b1SChuck Lever } 1146d9c407b1SChuck Lever 1147d9c407b1SChuck Lever static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p, 1148d9c407b1SChuck Lever const struct nfs3_createargs *args) 1149d9c407b1SChuck Lever { 1150d9c407b1SChuck Lever struct xdr_stream xdr; 1151d9c407b1SChuck Lever 1152d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1153d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 1154d9c407b1SChuck Lever encode_createhow3(&xdr, args); 1155d9c407b1SChuck Lever return 0; 1156d9c407b1SChuck Lever } 1157d9c407b1SChuck Lever 1158d9c407b1SChuck Lever /* 1159d9c407b1SChuck Lever * 3.3.9 MKDIR3args 1160d9c407b1SChuck Lever * 1161d9c407b1SChuck Lever * struct MKDIR3args { 1162d9c407b1SChuck Lever * diropargs3 where; 1163d9c407b1SChuck Lever * sattr3 attributes; 1164d9c407b1SChuck Lever * }; 1165d9c407b1SChuck Lever */ 1166d9c407b1SChuck Lever static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p, 1167d9c407b1SChuck Lever const struct nfs3_mkdirargs *args) 1168d9c407b1SChuck Lever { 1169d9c407b1SChuck Lever struct xdr_stream xdr; 1170d9c407b1SChuck Lever 1171d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1172d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 1173d9c407b1SChuck Lever encode_sattr3(&xdr, args->sattr); 1174d9c407b1SChuck Lever return 0; 1175d9c407b1SChuck Lever } 1176d9c407b1SChuck Lever 1177d9c407b1SChuck Lever /* 1178d9c407b1SChuck Lever * 3.3.10 SYMLINK3args 1179d9c407b1SChuck Lever * 1180d9c407b1SChuck Lever * struct symlinkdata3 { 1181d9c407b1SChuck Lever * sattr3 symlink_attributes; 1182d9c407b1SChuck Lever * nfspath3 symlink_data; 1183d9c407b1SChuck Lever * }; 1184d9c407b1SChuck Lever * 1185d9c407b1SChuck Lever * struct SYMLINK3args { 1186d9c407b1SChuck Lever * diropargs3 where; 1187d9c407b1SChuck Lever * symlinkdata3 symlink; 1188d9c407b1SChuck Lever * }; 1189d9c407b1SChuck Lever */ 1190d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr, 1191d9c407b1SChuck Lever const struct nfs3_symlinkargs *args) 1192d9c407b1SChuck Lever { 1193d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1194d9c407b1SChuck Lever encode_nfspath3(xdr, args->pages, args->pathlen); 1195d9c407b1SChuck Lever } 1196d9c407b1SChuck Lever 1197d9c407b1SChuck Lever static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p, 1198d9c407b1SChuck Lever const struct nfs3_symlinkargs *args) 1199d9c407b1SChuck Lever { 1200d9c407b1SChuck Lever struct xdr_stream xdr; 1201d9c407b1SChuck Lever 1202d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1203d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen); 1204d9c407b1SChuck Lever encode_symlinkdata3(&xdr, args); 1205d9c407b1SChuck Lever return 0; 1206d9c407b1SChuck Lever } 1207d9c407b1SChuck Lever 1208d9c407b1SChuck Lever /* 1209d9c407b1SChuck Lever * 3.3.11 MKNOD3args 1210d9c407b1SChuck Lever * 1211d9c407b1SChuck Lever * struct devicedata3 { 1212d9c407b1SChuck Lever * sattr3 dev_attributes; 1213d9c407b1SChuck Lever * specdata3 spec; 1214d9c407b1SChuck Lever * }; 1215d9c407b1SChuck Lever * 1216d9c407b1SChuck Lever * union mknoddata3 switch (ftype3 type) { 1217d9c407b1SChuck Lever * case NF3CHR: 1218d9c407b1SChuck Lever * case NF3BLK: 1219d9c407b1SChuck Lever * devicedata3 device; 1220d9c407b1SChuck Lever * case NF3SOCK: 1221d9c407b1SChuck Lever * case NF3FIFO: 1222d9c407b1SChuck Lever * sattr3 pipe_attributes; 1223d9c407b1SChuck Lever * default: 1224d9c407b1SChuck Lever * void; 1225d9c407b1SChuck Lever * }; 1226d9c407b1SChuck Lever * 1227d9c407b1SChuck Lever * struct MKNOD3args { 1228d9c407b1SChuck Lever * diropargs3 where; 1229d9c407b1SChuck Lever * mknoddata3 what; 1230d9c407b1SChuck Lever * }; 1231d9c407b1SChuck Lever */ 1232d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr, 1233d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1234d9c407b1SChuck Lever { 1235d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1236d9c407b1SChuck Lever encode_specdata3(xdr, args->rdev); 1237d9c407b1SChuck Lever } 1238d9c407b1SChuck Lever 1239d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr, 1240d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1241d9c407b1SChuck Lever { 1242d9c407b1SChuck Lever encode_ftype3(xdr, args->type); 1243d9c407b1SChuck Lever switch (args->type) { 1244d9c407b1SChuck Lever case NF3CHR: 1245d9c407b1SChuck Lever case NF3BLK: 1246d9c407b1SChuck Lever encode_devicedata3(xdr, args); 1247d9c407b1SChuck Lever break; 1248d9c407b1SChuck Lever case NF3SOCK: 1249d9c407b1SChuck Lever case NF3FIFO: 1250d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1251d9c407b1SChuck Lever break; 1252d9c407b1SChuck Lever case NF3REG: 1253d9c407b1SChuck Lever case NF3DIR: 1254d9c407b1SChuck Lever break; 1255d9c407b1SChuck Lever default: 1256d9c407b1SChuck Lever BUG(); 1257d9c407b1SChuck Lever } 1258d9c407b1SChuck Lever } 1259d9c407b1SChuck Lever 1260d9c407b1SChuck Lever static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p, 1261d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1262d9c407b1SChuck Lever { 1263d9c407b1SChuck Lever struct xdr_stream xdr; 1264d9c407b1SChuck Lever 1265d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1266d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 1267d9c407b1SChuck Lever encode_mknoddata3(&xdr, args); 1268d9c407b1SChuck Lever return 0; 1269d9c407b1SChuck Lever } 1270d9c407b1SChuck Lever 1271d9c407b1SChuck Lever /* 1272d9c407b1SChuck Lever * 3.3.12 REMOVE3args 1273d9c407b1SChuck Lever * 1274d9c407b1SChuck Lever * struct REMOVE3args { 1275d9c407b1SChuck Lever * diropargs3 object; 1276d9c407b1SChuck Lever * }; 1277d9c407b1SChuck Lever */ 1278d9c407b1SChuck Lever static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p, 1279d9c407b1SChuck Lever const struct nfs_removeargs *args) 1280d9c407b1SChuck Lever { 1281d9c407b1SChuck Lever struct xdr_stream xdr; 1282d9c407b1SChuck Lever 1283d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1284d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len); 1285d9c407b1SChuck Lever return 0; 1286d9c407b1SChuck Lever } 1287d9c407b1SChuck Lever 1288d9c407b1SChuck Lever /* 1289d9c407b1SChuck Lever * 3.3.14 RENAME3args 1290d9c407b1SChuck Lever * 1291d9c407b1SChuck Lever * struct RENAME3args { 1292d9c407b1SChuck Lever * diropargs3 from; 1293d9c407b1SChuck Lever * diropargs3 to; 1294d9c407b1SChuck Lever * }; 1295d9c407b1SChuck Lever */ 1296d9c407b1SChuck Lever static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p, 1297d9c407b1SChuck Lever const struct nfs_renameargs *args) 1298d9c407b1SChuck Lever { 1299d9c407b1SChuck Lever const struct qstr *old = args->old_name; 1300d9c407b1SChuck Lever const struct qstr *new = args->new_name; 1301d9c407b1SChuck Lever struct xdr_stream xdr; 1302d9c407b1SChuck Lever 1303d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1304d9c407b1SChuck Lever encode_diropargs3(&xdr, args->old_dir, old->name, old->len); 1305d9c407b1SChuck Lever encode_diropargs3(&xdr, args->new_dir, new->name, new->len); 1306d9c407b1SChuck Lever return 0; 1307d9c407b1SChuck Lever } 1308d9c407b1SChuck Lever 1309d9c407b1SChuck Lever /* 1310d9c407b1SChuck Lever * 3.3.15 LINK3args 1311d9c407b1SChuck Lever * 1312d9c407b1SChuck Lever * struct LINK3args { 1313d9c407b1SChuck Lever * nfs_fh3 file; 1314d9c407b1SChuck Lever * diropargs3 link; 1315d9c407b1SChuck Lever * }; 1316d9c407b1SChuck Lever */ 1317d9c407b1SChuck Lever static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p, 1318d9c407b1SChuck Lever const struct nfs3_linkargs *args) 1319d9c407b1SChuck Lever { 1320d9c407b1SChuck Lever struct xdr_stream xdr; 1321d9c407b1SChuck Lever 1322d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1323d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fromfh); 1324d9c407b1SChuck Lever encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen); 1325d9c407b1SChuck Lever return 0; 1326d9c407b1SChuck Lever } 1327d9c407b1SChuck Lever 1328d9c407b1SChuck Lever /* 1329d9c407b1SChuck Lever * 3.3.16 READDIR3args 1330d9c407b1SChuck Lever * 1331d9c407b1SChuck Lever * struct READDIR3args { 1332d9c407b1SChuck Lever * nfs_fh3 dir; 1333d9c407b1SChuck Lever * cookie3 cookie; 1334d9c407b1SChuck Lever * cookieverf3 cookieverf; 1335d9c407b1SChuck Lever * count3 count; 1336d9c407b1SChuck Lever * }; 1337d9c407b1SChuck Lever */ 1338d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr, 1339d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1340d9c407b1SChuck Lever { 1341d9c407b1SChuck Lever __be32 *p; 1342d9c407b1SChuck Lever 1343d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1344d9c407b1SChuck Lever 1345d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4); 1346d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1347d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1348d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1349d9c407b1SChuck Lever } 1350d9c407b1SChuck Lever 1351d9c407b1SChuck Lever static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p, 1352d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1353d9c407b1SChuck Lever { 1354d9c407b1SChuck Lever struct xdr_stream xdr; 1355d9c407b1SChuck Lever 1356d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1357d9c407b1SChuck Lever encode_readdir3args(&xdr, args); 1358d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1359d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1360d9c407b1SChuck Lever return 0; 1361d9c407b1SChuck Lever } 1362d9c407b1SChuck Lever 1363d9c407b1SChuck Lever /* 1364d9c407b1SChuck Lever * 3.3.17 READDIRPLUS3args 1365d9c407b1SChuck Lever * 1366d9c407b1SChuck Lever * struct READDIRPLUS3args { 1367d9c407b1SChuck Lever * nfs_fh3 dir; 1368d9c407b1SChuck Lever * cookie3 cookie; 1369d9c407b1SChuck Lever * cookieverf3 cookieverf; 1370d9c407b1SChuck Lever * count3 dircount; 1371d9c407b1SChuck Lever * count3 maxcount; 1372d9c407b1SChuck Lever * }; 1373d9c407b1SChuck Lever */ 1374d9c407b1SChuck Lever static void encode_readdirplus3args(struct xdr_stream *xdr, 1375d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1376d9c407b1SChuck Lever { 1377d9c407b1SChuck Lever __be32 *p; 1378d9c407b1SChuck Lever 1379d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1380d9c407b1SChuck Lever 1381d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4); 1382d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1383d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1384d9c407b1SChuck Lever 1385d9c407b1SChuck Lever /* 1386d9c407b1SChuck Lever * readdirplus: need dircount + buffer size. 1387d9c407b1SChuck Lever * We just make sure we make dircount big enough 1388d9c407b1SChuck Lever */ 1389d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count >> 3); 1390d9c407b1SChuck Lever 1391d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1392d9c407b1SChuck Lever } 1393d9c407b1SChuck Lever 1394d9c407b1SChuck Lever static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p, 1395d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1396d9c407b1SChuck Lever { 1397d9c407b1SChuck Lever struct xdr_stream xdr; 1398d9c407b1SChuck Lever 1399d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1400d9c407b1SChuck Lever encode_readdirplus3args(&xdr, args); 1401d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1402d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1403d9c407b1SChuck Lever return 0; 1404d9c407b1SChuck Lever } 1405d9c407b1SChuck Lever 1406d9c407b1SChuck Lever /* 14071da177e4SLinus Torvalds * Decode the result of a readdir call. 14081da177e4SLinus Torvalds * We just check for syntactical correctness. 14091da177e4SLinus Torvalds */ 14101da177e4SLinus Torvalds static int 1411d61005a6SAl Viro nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res) 14121da177e4SLinus Torvalds { 14131da177e4SLinus Torvalds struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 14141da177e4SLinus Torvalds struct kvec *iov = rcvbuf->head; 14151da177e4SLinus Torvalds struct page **page; 1416c957c526SChuck Lever size_t hdrlen; 1417afa8ccc9SBryan Schumaker u32 recvd, pglen; 1418ac396128STrond Myklebust int status; 14191da177e4SLinus Torvalds 14201da177e4SLinus Torvalds status = ntohl(*p++); 14211da177e4SLinus Torvalds /* Decode post_op_attrs */ 14221da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->dir_attr); 14231da177e4SLinus Torvalds if (status) 1424856dff3dSBenny Halevy return nfs_stat_to_errno(status); 14251da177e4SLinus Torvalds /* Decode verifier cookie */ 14261da177e4SLinus Torvalds if (res->verf) { 14271da177e4SLinus Torvalds res->verf[0] = *p++; 14281da177e4SLinus Torvalds res->verf[1] = *p++; 14291da177e4SLinus Torvalds } else { 14301da177e4SLinus Torvalds p += 2; 14311da177e4SLinus Torvalds } 14321da177e4SLinus Torvalds 14331da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 14341da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1435fe82a183SChuck Lever dprintk("NFS: READDIR reply header overflowed:" 1436c957c526SChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 14371da177e4SLinus Torvalds return -errno_NFSERR_IO; 14381da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 14391da177e4SLinus Torvalds dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); 14401da177e4SLinus Torvalds xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds pglen = rcvbuf->page_len; 14441da177e4SLinus Torvalds recvd = rcvbuf->len - hdrlen; 14451da177e4SLinus Torvalds if (pglen > recvd) 14461da177e4SLinus Torvalds pglen = recvd; 14471da177e4SLinus Torvalds page = rcvbuf->pages; 1448643f8111SJeff Layton 1449ac396128STrond Myklebust return pglen; 14501da177e4SLinus Torvalds } 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds /* 1453d9c407b1SChuck Lever * 3.3.21 COMMIT3args 1454d9c407b1SChuck Lever * 1455d9c407b1SChuck Lever * struct COMMIT3args { 1456d9c407b1SChuck Lever * nfs_fh3 file; 1457d9c407b1SChuck Lever * offset3 offset; 1458d9c407b1SChuck Lever * count3 count; 1459d9c407b1SChuck Lever * }; 1460d9c407b1SChuck Lever */ 1461d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr, 1462d9c407b1SChuck Lever const struct nfs_writeargs *args) 1463d9c407b1SChuck Lever { 1464d9c407b1SChuck Lever __be32 *p; 1465d9c407b1SChuck Lever 1466d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1467d9c407b1SChuck Lever 1468d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 1469d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 1470d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1471d9c407b1SChuck Lever } 1472d9c407b1SChuck Lever 1473d9c407b1SChuck Lever static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p, 1474d9c407b1SChuck Lever const struct nfs_writeargs *args) 1475d9c407b1SChuck Lever { 1476d9c407b1SChuck Lever struct xdr_stream xdr; 1477d9c407b1SChuck Lever 1478d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1479d9c407b1SChuck Lever encode_commit3args(&xdr, args); 1480d9c407b1SChuck Lever return 0; 1481d9c407b1SChuck Lever } 1482d9c407b1SChuck Lever 1483b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 1484b7fa0554SAndreas Gruenbacher 1485d9c407b1SChuck Lever static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p, 1486d9c407b1SChuck Lever const struct nfs3_getaclargs *args) 1487d9c407b1SChuck Lever { 1488d9c407b1SChuck Lever struct xdr_stream xdr; 1489d9c407b1SChuck Lever 1490d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1491d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fh); 1492d9c407b1SChuck Lever encode_uint32(&xdr, args->mask); 1493d9c407b1SChuck Lever if (args->mask & (NFS_ACL | NFS_DFACL)) 1494d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1495d9c407b1SChuck Lever NFSACL_MAXPAGES << PAGE_SHIFT, 1496d9c407b1SChuck Lever ACL3_getaclres_sz); 1497d9c407b1SChuck Lever return 0; 1498d9c407b1SChuck Lever } 1499d9c407b1SChuck Lever 1500d9c407b1SChuck Lever static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p, 1501d9c407b1SChuck Lever const struct nfs3_setaclargs *args) 1502d9c407b1SChuck Lever { 1503d9c407b1SChuck Lever struct xdr_stream xdr; 1504d9c407b1SChuck Lever unsigned int base; 1505d9c407b1SChuck Lever int error; 1506d9c407b1SChuck Lever 1507d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1508d9c407b1SChuck Lever encode_nfs_fh3(&xdr, NFS_FH(args->inode)); 1509d9c407b1SChuck Lever encode_uint32(&xdr, args->mask); 1510d9c407b1SChuck Lever if (args->npages != 0) 1511d9c407b1SChuck Lever xdr_write_pages(&xdr, args->pages, 0, args->len); 1512d9c407b1SChuck Lever 1513d9c407b1SChuck Lever base = req->rq_slen; 1514d9c407b1SChuck Lever error = nfsacl_encode(xdr.buf, base, args->inode, 1515d9c407b1SChuck Lever (args->mask & NFS_ACL) ? 1516d9c407b1SChuck Lever args->acl_access : NULL, 1, 0); 1517d9c407b1SChuck Lever BUG_ON(error < 0); 1518d9c407b1SChuck Lever error = nfsacl_encode(xdr.buf, base + error, args->inode, 1519d9c407b1SChuck Lever (args->mask & NFS_DFACL) ? 1520d9c407b1SChuck Lever args->acl_default : NULL, 1, 1521d9c407b1SChuck Lever NFS_ACL_DEFAULT); 1522d9c407b1SChuck Lever BUG_ON(error < 0); 1523d9c407b1SChuck Lever return 0; 1524d9c407b1SChuck Lever } 1525d9c407b1SChuck Lever 1526b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 1527b7fa0554SAndreas Gruenbacher 15281da177e4SLinus Torvalds /* 15291da177e4SLinus Torvalds * NFS XDR decode functions 15301da177e4SLinus Torvalds */ 15311da177e4SLinus Torvalds 15321da177e4SLinus Torvalds /* 15331da177e4SLinus Torvalds * Decode attrstat reply. 15341da177e4SLinus Torvalds */ 15351da177e4SLinus Torvalds static int 1536d61005a6SAl Viro nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 15371da177e4SLinus Torvalds { 15381da177e4SLinus Torvalds int status; 15391da177e4SLinus Torvalds 15401da177e4SLinus Torvalds if ((status = ntohl(*p++))) 1541856dff3dSBenny Halevy return nfs_stat_to_errno(status); 15421da177e4SLinus Torvalds xdr_decode_fattr(p, fattr); 15431da177e4SLinus Torvalds return 0; 15441da177e4SLinus Torvalds } 15451da177e4SLinus Torvalds 15461da177e4SLinus Torvalds /* 1547e4f93234SChuck Lever * 3.3.1 GETATTR3res 1548e4f93234SChuck Lever * 1549e4f93234SChuck Lever * struct GETATTR3resok { 1550e4f93234SChuck Lever * fattr3 obj_attributes; 1551e4f93234SChuck Lever * }; 1552e4f93234SChuck Lever * 1553e4f93234SChuck Lever * union GETATTR3res switch (nfsstat3 status) { 1554e4f93234SChuck Lever * case NFS3_OK: 1555e4f93234SChuck Lever * GETATTR3resok resok; 1556e4f93234SChuck Lever * default: 1557e4f93234SChuck Lever * void; 1558e4f93234SChuck Lever * }; 1559e4f93234SChuck Lever */ 1560e4f93234SChuck Lever static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req, __be32 *p, 1561e4f93234SChuck Lever struct nfs_fattr *result) 1562e4f93234SChuck Lever { 1563e4f93234SChuck Lever struct xdr_stream xdr; 1564e4f93234SChuck Lever enum nfs_stat status; 1565e4f93234SChuck Lever int error; 1566e4f93234SChuck Lever 1567e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1568e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 1569e4f93234SChuck Lever if (unlikely(error)) 1570e4f93234SChuck Lever goto out; 1571e4f93234SChuck Lever if (status != NFS3_OK) 1572e4f93234SChuck Lever goto out_default; 1573e4f93234SChuck Lever error = decode_fattr3(&xdr, result); 1574e4f93234SChuck Lever out: 1575e4f93234SChuck Lever return error; 1576e4f93234SChuck Lever out_default: 1577e4f93234SChuck Lever return nfs_stat_to_errno(status); 1578e4f93234SChuck Lever } 1579e4f93234SChuck Lever 1580e4f93234SChuck Lever /* 15811da177e4SLinus Torvalds * Decode status+wcc_data reply 15821da177e4SLinus Torvalds * SATTR, REMOVE, RMDIR 15831da177e4SLinus Torvalds */ 15841da177e4SLinus Torvalds static int 1585d61005a6SAl Viro nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 15861da177e4SLinus Torvalds { 15871da177e4SLinus Torvalds int status; 15881da177e4SLinus Torvalds 15891da177e4SLinus Torvalds if ((status = ntohl(*p++))) 1590856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 15911da177e4SLinus Torvalds xdr_decode_wcc_data(p, fattr); 15921da177e4SLinus Torvalds return status; 15931da177e4SLinus Torvalds } 15941da177e4SLinus Torvalds 1595e4f93234SChuck Lever /* 1596e4f93234SChuck Lever * 3.3.2 SETATTR3res 1597e4f93234SChuck Lever * 1598e4f93234SChuck Lever * struct SETATTR3resok { 1599e4f93234SChuck Lever * wcc_data obj_wcc; 1600e4f93234SChuck Lever * }; 1601e4f93234SChuck Lever * 1602e4f93234SChuck Lever * struct SETATTR3resfail { 1603e4f93234SChuck Lever * wcc_data obj_wcc; 1604e4f93234SChuck Lever * }; 1605e4f93234SChuck Lever * 1606e4f93234SChuck Lever * union SETATTR3res switch (nfsstat3 status) { 1607e4f93234SChuck Lever * case NFS3_OK: 1608e4f93234SChuck Lever * SETATTR3resok resok; 1609e4f93234SChuck Lever * default: 1610e4f93234SChuck Lever * SETATTR3resfail resfail; 1611e4f93234SChuck Lever * }; 1612e4f93234SChuck Lever */ 1613e4f93234SChuck Lever static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req, __be32 *p, 1614e4f93234SChuck Lever struct nfs_fattr *result) 1615e4f93234SChuck Lever { 1616e4f93234SChuck Lever struct xdr_stream xdr; 1617e4f93234SChuck Lever enum nfs_stat status; 1618e4f93234SChuck Lever int error; 1619e4f93234SChuck Lever 1620e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1621e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 1622e4f93234SChuck Lever if (unlikely(error)) 1623e4f93234SChuck Lever goto out; 1624e4f93234SChuck Lever error = decode_wcc_data(&xdr, result); 1625e4f93234SChuck Lever if (unlikely(error)) 1626e4f93234SChuck Lever goto out; 1627e4f93234SChuck Lever if (status != NFS3_OK) 1628e4f93234SChuck Lever goto out_status; 1629e4f93234SChuck Lever out: 1630e4f93234SChuck Lever return error; 1631e4f93234SChuck Lever out_status: 1632e4f93234SChuck Lever return nfs_stat_to_errno(status); 1633e4f93234SChuck Lever } 1634e4f93234SChuck Lever 16354fdc17b2STrond Myklebust static int 16364fdc17b2STrond Myklebust nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res) 16374fdc17b2STrond Myklebust { 1638d346890bSTrond Myklebust return nfs3_xdr_wccstat(req, p, res->dir_attr); 16394fdc17b2STrond Myklebust } 16404fdc17b2STrond Myklebust 16411da177e4SLinus Torvalds /* 16421da177e4SLinus Torvalds * Decode LOOKUP reply 16431da177e4SLinus Torvalds */ 16441da177e4SLinus Torvalds static int 1645d61005a6SAl Viro nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) 16461da177e4SLinus Torvalds { 16471da177e4SLinus Torvalds int status; 16481da177e4SLinus Torvalds 16491da177e4SLinus Torvalds if ((status = ntohl(*p++))) { 1650856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 16511da177e4SLinus Torvalds } else { 16521da177e4SLinus Torvalds if (!(p = xdr_decode_fhandle(p, res->fh))) 16531da177e4SLinus Torvalds return -errno_NFSERR_IO; 16541da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 16551da177e4SLinus Torvalds } 16561da177e4SLinus Torvalds xdr_decode_post_op_attr(p, res->dir_attr); 16571da177e4SLinus Torvalds return status; 16581da177e4SLinus Torvalds } 16591da177e4SLinus Torvalds 16601da177e4SLinus Torvalds /* 1661e4f93234SChuck Lever * 3.3.3 LOOKUP3res 1662e4f93234SChuck Lever * 1663e4f93234SChuck Lever * struct LOOKUP3resok { 1664e4f93234SChuck Lever * nfs_fh3 object; 1665e4f93234SChuck Lever * post_op_attr obj_attributes; 1666e4f93234SChuck Lever * post_op_attr dir_attributes; 1667e4f93234SChuck Lever * }; 1668e4f93234SChuck Lever * 1669e4f93234SChuck Lever * struct LOOKUP3resfail { 1670e4f93234SChuck Lever * post_op_attr dir_attributes; 1671e4f93234SChuck Lever * }; 1672e4f93234SChuck Lever * 1673e4f93234SChuck Lever * union LOOKUP3res switch (nfsstat3 status) { 1674e4f93234SChuck Lever * case NFS3_OK: 1675e4f93234SChuck Lever * LOOKUP3resok resok; 1676e4f93234SChuck Lever * default: 1677e4f93234SChuck Lever * LOOKUP3resfail resfail; 1678e4f93234SChuck Lever * }; 1679e4f93234SChuck Lever */ 1680e4f93234SChuck Lever static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req, __be32 *p, 1681e4f93234SChuck Lever struct nfs3_diropres *result) 1682e4f93234SChuck Lever { 1683e4f93234SChuck Lever struct xdr_stream xdr; 1684e4f93234SChuck Lever enum nfs_stat status; 1685e4f93234SChuck Lever int error; 1686e4f93234SChuck Lever 1687e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1688e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 1689e4f93234SChuck Lever if (unlikely(error)) 1690e4f93234SChuck Lever goto out; 1691e4f93234SChuck Lever if (status != NFS3_OK) 1692e4f93234SChuck Lever goto out_default; 1693e4f93234SChuck Lever error = decode_nfs_fh3(&xdr, result->fh); 1694e4f93234SChuck Lever if (unlikely(error)) 1695e4f93234SChuck Lever goto out; 1696e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->fattr); 1697e4f93234SChuck Lever if (unlikely(error)) 1698e4f93234SChuck Lever goto out; 1699e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->dir_attr); 1700e4f93234SChuck Lever out: 1701e4f93234SChuck Lever return error; 1702e4f93234SChuck Lever out_default: 1703e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->dir_attr); 1704e4f93234SChuck Lever if (unlikely(error)) 1705e4f93234SChuck Lever goto out; 1706e4f93234SChuck Lever return nfs_stat_to_errno(status); 1707e4f93234SChuck Lever } 1708e4f93234SChuck Lever 1709e4f93234SChuck Lever /* 17101da177e4SLinus Torvalds * Decode ACCESS reply 17111da177e4SLinus Torvalds */ 17121da177e4SLinus Torvalds static int 1713d61005a6SAl Viro nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) 17141da177e4SLinus Torvalds { 17151da177e4SLinus Torvalds int status = ntohl(*p++); 17161da177e4SLinus Torvalds 17171da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 17181da177e4SLinus Torvalds if (status) 1719856dff3dSBenny Halevy return nfs_stat_to_errno(status); 17201da177e4SLinus Torvalds res->access = ntohl(*p++); 17211da177e4SLinus Torvalds return 0; 17221da177e4SLinus Torvalds } 17231da177e4SLinus Torvalds 17241da177e4SLinus Torvalds /* 1725e4f93234SChuck Lever * 3.3.4 ACCESS3res 1726e4f93234SChuck Lever * 1727e4f93234SChuck Lever * struct ACCESS3resok { 1728e4f93234SChuck Lever * post_op_attr obj_attributes; 1729e4f93234SChuck Lever * uint32 access; 1730e4f93234SChuck Lever * }; 1731e4f93234SChuck Lever * 1732e4f93234SChuck Lever * struct ACCESS3resfail { 1733e4f93234SChuck Lever * post_op_attr obj_attributes; 1734e4f93234SChuck Lever * }; 1735e4f93234SChuck Lever * 1736e4f93234SChuck Lever * union ACCESS3res switch (nfsstat3 status) { 1737e4f93234SChuck Lever * case NFS3_OK: 1738e4f93234SChuck Lever * ACCESS3resok resok; 1739e4f93234SChuck Lever * default: 1740e4f93234SChuck Lever * ACCESS3resfail resfail; 1741e4f93234SChuck Lever * }; 1742e4f93234SChuck Lever */ 1743e4f93234SChuck Lever static int nfs3_xdr_dec_access3res(struct rpc_rqst *req, __be32 *p, 1744e4f93234SChuck Lever struct nfs3_accessres *result) 1745e4f93234SChuck Lever { 1746e4f93234SChuck Lever struct xdr_stream xdr; 1747e4f93234SChuck Lever enum nfs_stat status; 1748e4f93234SChuck Lever int error; 1749e4f93234SChuck Lever 1750e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1751e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 1752e4f93234SChuck Lever if (unlikely(error)) 1753e4f93234SChuck Lever goto out; 1754e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->fattr); 1755e4f93234SChuck Lever if (unlikely(error)) 1756e4f93234SChuck Lever goto out; 1757e4f93234SChuck Lever if (status != NFS3_OK) 1758e4f93234SChuck Lever goto out_default; 1759e4f93234SChuck Lever error = decode_uint32(&xdr, &result->access); 1760e4f93234SChuck Lever out: 1761e4f93234SChuck Lever return error; 1762e4f93234SChuck Lever out_default: 1763e4f93234SChuck Lever return nfs_stat_to_errno(status); 1764e4f93234SChuck Lever } 1765e4f93234SChuck Lever 1766e4f93234SChuck Lever /* 17671da177e4SLinus Torvalds * Decode READLINK reply 17681da177e4SLinus Torvalds */ 17691da177e4SLinus Torvalds static int 1770d61005a6SAl Viro nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 17711da177e4SLinus Torvalds { 17721da177e4SLinus Torvalds struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 17731da177e4SLinus Torvalds struct kvec *iov = rcvbuf->head; 1774c957c526SChuck Lever size_t hdrlen; 1775c957c526SChuck Lever u32 len, recvd; 17761da177e4SLinus Torvalds int status; 17771da177e4SLinus Torvalds 17781da177e4SLinus Torvalds status = ntohl(*p++); 17791da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, fattr); 17801da177e4SLinus Torvalds 17811da177e4SLinus Torvalds if (status != 0) 1782856dff3dSBenny Halevy return nfs_stat_to_errno(status); 17831da177e4SLinus Torvalds 17841da177e4SLinus Torvalds /* Convert length of symlink */ 17851da177e4SLinus Torvalds len = ntohl(*p++); 1786c957c526SChuck Lever if (len >= rcvbuf->page_len) { 1787fe82a183SChuck Lever dprintk("nfs: server returned giant symlink!\n"); 17881da177e4SLinus Torvalds return -ENAMETOOLONG; 17891da177e4SLinus Torvalds } 17901da177e4SLinus Torvalds 17911da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 17921da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1793fe82a183SChuck Lever dprintk("NFS: READLINK reply header overflowed:" 1794c957c526SChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 17951da177e4SLinus Torvalds return -errno_NFSERR_IO; 17961da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 1797fe82a183SChuck Lever dprintk("NFS: READLINK header is short. " 1798fe82a183SChuck Lever "iovec will be shifted.\n"); 17991da177e4SLinus Torvalds xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 18001da177e4SLinus Torvalds } 18011da177e4SLinus Torvalds recvd = req->rq_rcv_buf.len - hdrlen; 18021da177e4SLinus Torvalds if (recvd < len) { 1803fe82a183SChuck Lever dprintk("NFS: server cheating in readlink reply: " 18041da177e4SLinus Torvalds "count %u > recvd %u\n", len, recvd); 18051da177e4SLinus Torvalds return -EIO; 18061da177e4SLinus Torvalds } 18071da177e4SLinus Torvalds 1808b4687da7SChuck Lever xdr_terminate_string(rcvbuf, len); 18091da177e4SLinus Torvalds return 0; 18101da177e4SLinus Torvalds } 18111da177e4SLinus Torvalds 18121da177e4SLinus Torvalds /* 1813e4f93234SChuck Lever * 3.3.5 READLINK3res 1814e4f93234SChuck Lever * 1815e4f93234SChuck Lever * struct READLINK3resok { 1816e4f93234SChuck Lever * post_op_attr symlink_attributes; 1817e4f93234SChuck Lever * nfspath3 data; 1818e4f93234SChuck Lever * }; 1819e4f93234SChuck Lever * 1820e4f93234SChuck Lever * struct READLINK3resfail { 1821e4f93234SChuck Lever * post_op_attr symlink_attributes; 1822e4f93234SChuck Lever * }; 1823e4f93234SChuck Lever * 1824e4f93234SChuck Lever * union READLINK3res switch (nfsstat3 status) { 1825e4f93234SChuck Lever * case NFS3_OK: 1826e4f93234SChuck Lever * READLINK3resok resok; 1827e4f93234SChuck Lever * default: 1828e4f93234SChuck Lever * READLINK3resfail resfail; 1829e4f93234SChuck Lever * }; 1830e4f93234SChuck Lever */ 1831e4f93234SChuck Lever static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req, __be32 *p, 1832e4f93234SChuck Lever struct nfs_fattr *result) 1833e4f93234SChuck Lever { 1834e4f93234SChuck Lever struct xdr_stream xdr; 1835e4f93234SChuck Lever enum nfs_stat status; 1836e4f93234SChuck Lever int error; 1837e4f93234SChuck Lever 1838e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1839e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 1840e4f93234SChuck Lever if (unlikely(error)) 1841e4f93234SChuck Lever goto out; 1842e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result); 1843e4f93234SChuck Lever if (unlikely(error)) 1844e4f93234SChuck Lever goto out; 1845e4f93234SChuck Lever if (status != NFS3_OK) 1846e4f93234SChuck Lever goto out_default; 1847e4f93234SChuck Lever error = decode_nfspath3(&xdr); 1848e4f93234SChuck Lever out: 1849e4f93234SChuck Lever return error; 1850e4f93234SChuck Lever out_default: 1851e4f93234SChuck Lever return nfs_stat_to_errno(status); 1852e4f93234SChuck Lever } 1853e4f93234SChuck Lever 1854e4f93234SChuck Lever /* 18551da177e4SLinus Torvalds * Decode READ reply 18561da177e4SLinus Torvalds */ 18571da177e4SLinus Torvalds static int 1858d61005a6SAl Viro nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) 18591da177e4SLinus Torvalds { 18601da177e4SLinus Torvalds struct kvec *iov = req->rq_rcv_buf.head; 1861c957c526SChuck Lever size_t hdrlen; 1862c957c526SChuck Lever u32 count, ocount, recvd; 1863c957c526SChuck Lever int status; 18641da177e4SLinus Torvalds 18651da177e4SLinus Torvalds status = ntohl(*p++); 18661da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 18671da177e4SLinus Torvalds 18681da177e4SLinus Torvalds if (status != 0) 1869856dff3dSBenny Halevy return nfs_stat_to_errno(status); 18701da177e4SLinus Torvalds 1871c957c526SChuck Lever /* Decode reply count and EOF flag. NFSv3 is somewhat redundant 18721da177e4SLinus Torvalds * in that it puts the count both in the res struct and in the 18731da177e4SLinus Torvalds * opaque data count. */ 18741da177e4SLinus Torvalds count = ntohl(*p++); 18751da177e4SLinus Torvalds res->eof = ntohl(*p++); 18761da177e4SLinus Torvalds ocount = ntohl(*p++); 18771da177e4SLinus Torvalds 18781da177e4SLinus Torvalds if (ocount != count) { 1879fe82a183SChuck Lever dprintk("NFS: READ count doesn't match RPC opaque count.\n"); 18801da177e4SLinus Torvalds return -errno_NFSERR_IO; 18811da177e4SLinus Torvalds } 18821da177e4SLinus Torvalds 18831da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 18841da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1885fe82a183SChuck Lever dprintk("NFS: READ reply header overflowed:" 1886c957c526SChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 18871da177e4SLinus Torvalds return -errno_NFSERR_IO; 18881da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 18891da177e4SLinus Torvalds dprintk("NFS: READ header is short. iovec will be shifted.\n"); 18901da177e4SLinus Torvalds xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); 18911da177e4SLinus Torvalds } 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds recvd = req->rq_rcv_buf.len - hdrlen; 18941da177e4SLinus Torvalds if (count > recvd) { 1895fe82a183SChuck Lever dprintk("NFS: server cheating in read reply: " 1896c957c526SChuck Lever "count %u > recvd %u\n", count, recvd); 18971da177e4SLinus Torvalds count = recvd; 18981da177e4SLinus Torvalds res->eof = 0; 18991da177e4SLinus Torvalds } 19001da177e4SLinus Torvalds 19011da177e4SLinus Torvalds if (count < res->count) 19021da177e4SLinus Torvalds res->count = count; 19031da177e4SLinus Torvalds 19041da177e4SLinus Torvalds return count; 19051da177e4SLinus Torvalds } 19061da177e4SLinus Torvalds 19071da177e4SLinus Torvalds /* 1908e4f93234SChuck Lever * 3.3.6 READ3res 1909e4f93234SChuck Lever * 1910e4f93234SChuck Lever * struct READ3resok { 1911e4f93234SChuck Lever * post_op_attr file_attributes; 1912e4f93234SChuck Lever * count3 count; 1913e4f93234SChuck Lever * bool eof; 1914e4f93234SChuck Lever * opaque data<>; 1915e4f93234SChuck Lever * }; 1916e4f93234SChuck Lever * 1917e4f93234SChuck Lever * struct READ3resfail { 1918e4f93234SChuck Lever * post_op_attr file_attributes; 1919e4f93234SChuck Lever * }; 1920e4f93234SChuck Lever * 1921e4f93234SChuck Lever * union READ3res switch (nfsstat3 status) { 1922e4f93234SChuck Lever * case NFS3_OK: 1923e4f93234SChuck Lever * READ3resok resok; 1924e4f93234SChuck Lever * default: 1925e4f93234SChuck Lever * READ3resfail resfail; 1926e4f93234SChuck Lever * }; 1927e4f93234SChuck Lever */ 1928e4f93234SChuck Lever static int decode_read3resok(struct xdr_stream *xdr, 1929e4f93234SChuck Lever struct nfs_readres *result) 1930e4f93234SChuck Lever { 1931e4f93234SChuck Lever u32 eof, count, ocount, recvd; 1932e4f93234SChuck Lever size_t hdrlen; 1933e4f93234SChuck Lever __be32 *p; 1934e4f93234SChuck Lever 1935e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 + 4 + 4); 1936e4f93234SChuck Lever if (unlikely(p == NULL)) 1937e4f93234SChuck Lever goto out_overflow; 1938e4f93234SChuck Lever count = be32_to_cpup(p++); 1939e4f93234SChuck Lever eof = be32_to_cpup(p++); 1940e4f93234SChuck Lever ocount = be32_to_cpup(p++); 1941e4f93234SChuck Lever if (unlikely(ocount != count)) 1942e4f93234SChuck Lever goto out_mismatch; 1943e4f93234SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 1944e4f93234SChuck Lever recvd = xdr->buf->len - hdrlen; 1945e4f93234SChuck Lever if (unlikely(count > recvd)) 1946e4f93234SChuck Lever goto out_cheating; 1947e4f93234SChuck Lever 1948e4f93234SChuck Lever out: 1949e4f93234SChuck Lever xdr_read_pages(xdr, count); 1950e4f93234SChuck Lever result->eof = eof; 1951e4f93234SChuck Lever result->count = count; 1952e4f93234SChuck Lever return count; 1953e4f93234SChuck Lever out_mismatch: 1954e4f93234SChuck Lever dprintk("NFS: READ count doesn't match length of opaque: " 1955e4f93234SChuck Lever "count %u != ocount %u\n", count, ocount); 1956e4f93234SChuck Lever return -EIO; 1957e4f93234SChuck Lever out_cheating: 1958e4f93234SChuck Lever dprintk("NFS: server cheating in read result: " 1959e4f93234SChuck Lever "count %u > recvd %u\n", count, recvd); 1960e4f93234SChuck Lever count = recvd; 1961e4f93234SChuck Lever eof = 0; 1962e4f93234SChuck Lever goto out; 1963e4f93234SChuck Lever out_overflow: 1964e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 1965e4f93234SChuck Lever return -EIO; 1966e4f93234SChuck Lever } 1967e4f93234SChuck Lever 1968e4f93234SChuck Lever static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, __be32 *p, 1969e4f93234SChuck Lever struct nfs_readres *result) 1970e4f93234SChuck Lever { 1971e4f93234SChuck Lever struct xdr_stream xdr; 1972e4f93234SChuck Lever enum nfs_stat status; 1973e4f93234SChuck Lever int error; 1974e4f93234SChuck Lever 1975e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1976e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 1977e4f93234SChuck Lever if (unlikely(error)) 1978e4f93234SChuck Lever goto out; 1979e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->fattr); 1980e4f93234SChuck Lever if (unlikely(error)) 1981e4f93234SChuck Lever goto out; 1982e4f93234SChuck Lever if (status != NFS3_OK) 1983e4f93234SChuck Lever goto out_status; 1984e4f93234SChuck Lever error = decode_read3resok(&xdr, result); 1985e4f93234SChuck Lever out: 1986e4f93234SChuck Lever return error; 1987e4f93234SChuck Lever out_status: 1988e4f93234SChuck Lever return nfs_stat_to_errno(status); 1989e4f93234SChuck Lever } 1990e4f93234SChuck Lever 1991e4f93234SChuck Lever /* 19921da177e4SLinus Torvalds * Decode WRITE response 19931da177e4SLinus Torvalds */ 19941da177e4SLinus Torvalds static int 1995d61005a6SAl Viro nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) 19961da177e4SLinus Torvalds { 19971da177e4SLinus Torvalds int status; 19981da177e4SLinus Torvalds 19991da177e4SLinus Torvalds status = ntohl(*p++); 20001da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->fattr); 20011da177e4SLinus Torvalds 20021da177e4SLinus Torvalds if (status != 0) 2003856dff3dSBenny Halevy return nfs_stat_to_errno(status); 20041da177e4SLinus Torvalds 20051da177e4SLinus Torvalds res->count = ntohl(*p++); 20061da177e4SLinus Torvalds res->verf->committed = (enum nfs3_stable_how)ntohl(*p++); 20071da177e4SLinus Torvalds res->verf->verifier[0] = *p++; 20081da177e4SLinus Torvalds res->verf->verifier[1] = *p++; 20091da177e4SLinus Torvalds 20101da177e4SLinus Torvalds return res->count; 20111da177e4SLinus Torvalds } 20121da177e4SLinus Torvalds 20131da177e4SLinus Torvalds /* 2014e4f93234SChuck Lever * 3.3.7 WRITE3res 2015e4f93234SChuck Lever * 2016e4f93234SChuck Lever * enum stable_how { 2017e4f93234SChuck Lever * UNSTABLE = 0, 2018e4f93234SChuck Lever * DATA_SYNC = 1, 2019e4f93234SChuck Lever * FILE_SYNC = 2 2020e4f93234SChuck Lever * }; 2021e4f93234SChuck Lever * 2022e4f93234SChuck Lever * struct WRITE3resok { 2023e4f93234SChuck Lever * wcc_data file_wcc; 2024e4f93234SChuck Lever * count3 count; 2025e4f93234SChuck Lever * stable_how committed; 2026e4f93234SChuck Lever * writeverf3 verf; 2027e4f93234SChuck Lever * }; 2028e4f93234SChuck Lever * 2029e4f93234SChuck Lever * struct WRITE3resfail { 2030e4f93234SChuck Lever * wcc_data file_wcc; 2031e4f93234SChuck Lever * }; 2032e4f93234SChuck Lever * 2033e4f93234SChuck Lever * union WRITE3res switch (nfsstat3 status) { 2034e4f93234SChuck Lever * case NFS3_OK: 2035e4f93234SChuck Lever * WRITE3resok resok; 2036e4f93234SChuck Lever * default: 2037e4f93234SChuck Lever * WRITE3resfail resfail; 2038e4f93234SChuck Lever * }; 2039e4f93234SChuck Lever */ 2040e4f93234SChuck Lever static int decode_write3resok(struct xdr_stream *xdr, 2041e4f93234SChuck Lever struct nfs_writeres *result) 2042e4f93234SChuck Lever { 2043e4f93234SChuck Lever __be32 *p; 2044e4f93234SChuck Lever 2045e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE); 2046e4f93234SChuck Lever if (unlikely(p == NULL)) 2047e4f93234SChuck Lever goto out_overflow; 2048e4f93234SChuck Lever result->count = be32_to_cpup(p++); 2049e4f93234SChuck Lever result->verf->committed = be32_to_cpup(p++); 2050e4f93234SChuck Lever if (unlikely(result->verf->committed > NFS_FILE_SYNC)) 2051e4f93234SChuck Lever goto out_badvalue; 2052e4f93234SChuck Lever memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE); 2053e4f93234SChuck Lever return result->count; 2054e4f93234SChuck Lever out_badvalue: 2055e4f93234SChuck Lever dprintk("NFS: bad stable_how value: %u\n", result->verf->committed); 2056e4f93234SChuck Lever return -EIO; 2057e4f93234SChuck Lever out_overflow: 2058e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2059e4f93234SChuck Lever return -EIO; 2060e4f93234SChuck Lever } 2061e4f93234SChuck Lever 2062e4f93234SChuck Lever static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, __be32 *p, 2063e4f93234SChuck Lever struct nfs_writeres *result) 2064e4f93234SChuck Lever { 2065e4f93234SChuck Lever struct xdr_stream xdr; 2066e4f93234SChuck Lever enum nfs_stat status; 2067e4f93234SChuck Lever int error; 2068e4f93234SChuck Lever 2069e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2070e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2071e4f93234SChuck Lever if (unlikely(error)) 2072e4f93234SChuck Lever goto out; 2073e4f93234SChuck Lever error = decode_wcc_data(&xdr, result->fattr); 2074e4f93234SChuck Lever if (unlikely(error)) 2075e4f93234SChuck Lever goto out; 2076e4f93234SChuck Lever if (status != NFS3_OK) 2077e4f93234SChuck Lever goto out_status; 2078e4f93234SChuck Lever error = decode_write3resok(&xdr, result); 2079e4f93234SChuck Lever out: 2080e4f93234SChuck Lever return error; 2081e4f93234SChuck Lever out_status: 2082e4f93234SChuck Lever return nfs_stat_to_errno(status); 2083e4f93234SChuck Lever } 2084e4f93234SChuck Lever 2085e4f93234SChuck Lever /* 20861da177e4SLinus Torvalds * Decode a CREATE response 20871da177e4SLinus Torvalds */ 20881da177e4SLinus Torvalds static int 2089d61005a6SAl Viro nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) 20901da177e4SLinus Torvalds { 20911da177e4SLinus Torvalds int status; 20921da177e4SLinus Torvalds 20931da177e4SLinus Torvalds status = ntohl(*p++); 20941da177e4SLinus Torvalds if (status == 0) { 20951da177e4SLinus Torvalds if (*p++) { 20961da177e4SLinus Torvalds if (!(p = xdr_decode_fhandle(p, res->fh))) 20971da177e4SLinus Torvalds return -errno_NFSERR_IO; 20981da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 20991da177e4SLinus Torvalds } else { 21001da177e4SLinus Torvalds memset(res->fh, 0, sizeof(*res->fh)); 21011da177e4SLinus Torvalds /* Do decode post_op_attr but set it to NULL */ 21021da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 21031da177e4SLinus Torvalds res->fattr->valid = 0; 21041da177e4SLinus Torvalds } 21051da177e4SLinus Torvalds } else { 2106856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 21071da177e4SLinus Torvalds } 21081da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->dir_attr); 21091da177e4SLinus Torvalds return status; 21101da177e4SLinus Torvalds } 21111da177e4SLinus Torvalds 21121da177e4SLinus Torvalds /* 2113e4f93234SChuck Lever * 3.3.8 CREATE3res 2114e4f93234SChuck Lever * 2115e4f93234SChuck Lever * struct CREATE3resok { 2116e4f93234SChuck Lever * post_op_fh3 obj; 2117e4f93234SChuck Lever * post_op_attr obj_attributes; 2118e4f93234SChuck Lever * wcc_data dir_wcc; 2119e4f93234SChuck Lever * }; 2120e4f93234SChuck Lever * 2121e4f93234SChuck Lever * struct CREATE3resfail { 2122e4f93234SChuck Lever * wcc_data dir_wcc; 2123e4f93234SChuck Lever * }; 2124e4f93234SChuck Lever * 2125e4f93234SChuck Lever * union CREATE3res switch (nfsstat3 status) { 2126e4f93234SChuck Lever * case NFS3_OK: 2127e4f93234SChuck Lever * CREATE3resok resok; 2128e4f93234SChuck Lever * default: 2129e4f93234SChuck Lever * CREATE3resfail resfail; 2130e4f93234SChuck Lever * }; 2131e4f93234SChuck Lever */ 2132e4f93234SChuck Lever static int decode_create3resok(struct xdr_stream *xdr, 2133e4f93234SChuck Lever struct nfs3_diropres *result) 2134e4f93234SChuck Lever { 2135e4f93234SChuck Lever int error; 2136e4f93234SChuck Lever 2137e4f93234SChuck Lever error = decode_post_op_fh3(xdr, result->fh); 2138e4f93234SChuck Lever if (unlikely(error)) 2139e4f93234SChuck Lever goto out; 2140e4f93234SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2141e4f93234SChuck Lever if (unlikely(error)) 2142e4f93234SChuck Lever goto out; 2143e4f93234SChuck Lever /* The server isn't required to return a file handle. 2144e4f93234SChuck Lever * If it didn't, force the client to perform a LOOKUP 2145e4f93234SChuck Lever * to determine the correct file handle and attribute 2146e4f93234SChuck Lever * values for the new object. */ 2147e4f93234SChuck Lever if (result->fh->size == 0) 2148e4f93234SChuck Lever result->fattr->valid = 0; 2149e4f93234SChuck Lever error = decode_wcc_data(xdr, result->dir_attr); 2150e4f93234SChuck Lever out: 2151e4f93234SChuck Lever return error; 2152e4f93234SChuck Lever } 2153e4f93234SChuck Lever 2154e4f93234SChuck Lever static int nfs3_xdr_dec_create3res(struct rpc_rqst *req, __be32 *p, 2155e4f93234SChuck Lever struct nfs3_diropres *result) 2156e4f93234SChuck Lever { 2157e4f93234SChuck Lever struct xdr_stream xdr; 2158e4f93234SChuck Lever enum nfs_stat status; 2159e4f93234SChuck Lever int error; 2160e4f93234SChuck Lever 2161e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2162e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2163e4f93234SChuck Lever if (unlikely(error)) 2164e4f93234SChuck Lever goto out; 2165e4f93234SChuck Lever if (status != NFS3_OK) 2166e4f93234SChuck Lever goto out_default; 2167e4f93234SChuck Lever error = decode_create3resok(&xdr, result); 2168e4f93234SChuck Lever out: 2169e4f93234SChuck Lever return error; 2170e4f93234SChuck Lever out_default: 2171e4f93234SChuck Lever error = decode_wcc_data(&xdr, result->dir_attr); 2172e4f93234SChuck Lever if (unlikely(error)) 2173e4f93234SChuck Lever goto out; 2174e4f93234SChuck Lever return nfs_stat_to_errno(status); 2175e4f93234SChuck Lever } 2176e4f93234SChuck Lever 2177e4f93234SChuck Lever /* 2178e4f93234SChuck Lever * 3.3.12 REMOVE3res 2179e4f93234SChuck Lever * 2180e4f93234SChuck Lever * struct REMOVE3resok { 2181e4f93234SChuck Lever * wcc_data dir_wcc; 2182e4f93234SChuck Lever * }; 2183e4f93234SChuck Lever * 2184e4f93234SChuck Lever * struct REMOVE3resfail { 2185e4f93234SChuck Lever * wcc_data dir_wcc; 2186e4f93234SChuck Lever * }; 2187e4f93234SChuck Lever * 2188e4f93234SChuck Lever * union REMOVE3res switch (nfsstat3 status) { 2189e4f93234SChuck Lever * case NFS3_OK: 2190e4f93234SChuck Lever * REMOVE3resok resok; 2191e4f93234SChuck Lever * default: 2192e4f93234SChuck Lever * REMOVE3resfail resfail; 2193e4f93234SChuck Lever * }; 2194e4f93234SChuck Lever */ 2195e4f93234SChuck Lever static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req, __be32 *p, 2196e4f93234SChuck Lever struct nfs_removeres *result) 2197e4f93234SChuck Lever { 2198e4f93234SChuck Lever struct xdr_stream xdr; 2199e4f93234SChuck Lever enum nfs_stat status; 2200e4f93234SChuck Lever int error; 2201e4f93234SChuck Lever 2202e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2203e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2204e4f93234SChuck Lever if (unlikely(error)) 2205e4f93234SChuck Lever goto out; 2206e4f93234SChuck Lever error = decode_wcc_data(&xdr, result->dir_attr); 2207e4f93234SChuck Lever if (unlikely(error)) 2208e4f93234SChuck Lever goto out; 2209e4f93234SChuck Lever if (status != NFS3_OK) 2210e4f93234SChuck Lever goto out_status; 2211e4f93234SChuck Lever out: 2212e4f93234SChuck Lever return error; 2213e4f93234SChuck Lever out_status: 2214e4f93234SChuck Lever return nfs_stat_to_errno(status); 2215e4f93234SChuck Lever } 2216e4f93234SChuck Lever 2217e4f93234SChuck Lever /* 22181da177e4SLinus Torvalds * Decode RENAME reply 22191da177e4SLinus Torvalds */ 22201da177e4SLinus Torvalds static int 2221e8582a8bSJeff Layton nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res) 22221da177e4SLinus Torvalds { 22231da177e4SLinus Torvalds int status; 22241da177e4SLinus Torvalds 22251da177e4SLinus Torvalds if ((status = ntohl(*p++)) != 0) 2226856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 2227e8582a8bSJeff Layton p = xdr_decode_wcc_data(p, res->old_fattr); 2228e8582a8bSJeff Layton p = xdr_decode_wcc_data(p, res->new_fattr); 22291da177e4SLinus Torvalds return status; 22301da177e4SLinus Torvalds } 22311da177e4SLinus Torvalds 22321da177e4SLinus Torvalds /* 2233e4f93234SChuck Lever * 3.3.14 RENAME3res 2234e4f93234SChuck Lever * 2235e4f93234SChuck Lever * struct RENAME3resok { 2236e4f93234SChuck Lever * wcc_data fromdir_wcc; 2237e4f93234SChuck Lever * wcc_data todir_wcc; 2238e4f93234SChuck Lever * }; 2239e4f93234SChuck Lever * 2240e4f93234SChuck Lever * struct RENAME3resfail { 2241e4f93234SChuck Lever * wcc_data fromdir_wcc; 2242e4f93234SChuck Lever * wcc_data todir_wcc; 2243e4f93234SChuck Lever * }; 2244e4f93234SChuck Lever * 2245e4f93234SChuck Lever * union RENAME3res switch (nfsstat3 status) { 2246e4f93234SChuck Lever * case NFS3_OK: 2247e4f93234SChuck Lever * RENAME3resok resok; 2248e4f93234SChuck Lever * default: 2249e4f93234SChuck Lever * RENAME3resfail resfail; 2250e4f93234SChuck Lever * }; 2251e4f93234SChuck Lever */ 2252e4f93234SChuck Lever static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req, __be32 *p, 2253e4f93234SChuck Lever struct nfs_renameres *result) 2254e4f93234SChuck Lever { 2255e4f93234SChuck Lever struct xdr_stream xdr; 2256e4f93234SChuck Lever enum nfs_stat status; 2257e4f93234SChuck Lever int error; 2258e4f93234SChuck Lever 2259e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2260e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2261e4f93234SChuck Lever if (unlikely(error)) 2262e4f93234SChuck Lever goto out; 2263e4f93234SChuck Lever error = decode_wcc_data(&xdr, result->old_fattr); 2264e4f93234SChuck Lever if (unlikely(error)) 2265e4f93234SChuck Lever goto out; 2266e4f93234SChuck Lever error = decode_wcc_data(&xdr, result->new_fattr); 2267e4f93234SChuck Lever if (unlikely(error)) 2268e4f93234SChuck Lever goto out; 2269e4f93234SChuck Lever if (status != NFS3_OK) 2270e4f93234SChuck Lever goto out_status; 2271e4f93234SChuck Lever out: 2272e4f93234SChuck Lever return error; 2273e4f93234SChuck Lever out_status: 2274e4f93234SChuck Lever return nfs_stat_to_errno(status); 2275e4f93234SChuck Lever } 2276e4f93234SChuck Lever 2277e4f93234SChuck Lever /* 22781da177e4SLinus Torvalds * Decode LINK reply 22791da177e4SLinus Torvalds */ 22801da177e4SLinus Torvalds static int 2281d61005a6SAl Viro nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res) 22821da177e4SLinus Torvalds { 22831da177e4SLinus Torvalds int status; 22841da177e4SLinus Torvalds 22851da177e4SLinus Torvalds if ((status = ntohl(*p++)) != 0) 2286856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 22871da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 22881da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->dir_attr); 22891da177e4SLinus Torvalds return status; 22901da177e4SLinus Torvalds } 22911da177e4SLinus Torvalds 22921da177e4SLinus Torvalds /* 2293e4f93234SChuck Lever * 3.3.15 LINK3res 2294e4f93234SChuck Lever * 2295e4f93234SChuck Lever * struct LINK3resok { 2296e4f93234SChuck Lever * post_op_attr file_attributes; 2297e4f93234SChuck Lever * wcc_data linkdir_wcc; 2298e4f93234SChuck Lever * }; 2299e4f93234SChuck Lever * 2300e4f93234SChuck Lever * struct LINK3resfail { 2301e4f93234SChuck Lever * post_op_attr file_attributes; 2302e4f93234SChuck Lever * wcc_data linkdir_wcc; 2303e4f93234SChuck Lever * }; 2304e4f93234SChuck Lever * 2305e4f93234SChuck Lever * union LINK3res switch (nfsstat3 status) { 2306e4f93234SChuck Lever * case NFS3_OK: 2307e4f93234SChuck Lever * LINK3resok resok; 2308e4f93234SChuck Lever * default: 2309e4f93234SChuck Lever * LINK3resfail resfail; 2310e4f93234SChuck Lever * }; 2311e4f93234SChuck Lever */ 2312e4f93234SChuck Lever static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, __be32 *p, 2313e4f93234SChuck Lever struct nfs3_linkres *result) 2314e4f93234SChuck Lever { 2315e4f93234SChuck Lever struct xdr_stream xdr; 2316e4f93234SChuck Lever enum nfs_stat status; 2317e4f93234SChuck Lever int error; 2318e4f93234SChuck Lever 2319e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2320e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2321e4f93234SChuck Lever if (unlikely(error)) 2322e4f93234SChuck Lever goto out; 2323e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->fattr); 2324e4f93234SChuck Lever if (unlikely(error)) 2325e4f93234SChuck Lever goto out; 2326e4f93234SChuck Lever error = decode_wcc_data(&xdr, result->dir_attr); 2327e4f93234SChuck Lever if (unlikely(error)) 2328e4f93234SChuck Lever goto out; 2329e4f93234SChuck Lever if (status != NFS3_OK) 2330e4f93234SChuck Lever goto out_status; 2331e4f93234SChuck Lever out: 2332e4f93234SChuck Lever return error; 2333e4f93234SChuck Lever out_status: 2334e4f93234SChuck Lever return nfs_stat_to_errno(status); 2335e4f93234SChuck Lever } 2336e4f93234SChuck Lever 2337e4f93234SChuck Lever /** 2338e4f93234SChuck Lever * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in 2339e4f93234SChuck Lever * the local page cache 2340e4f93234SChuck Lever * @xdr: XDR stream where entry resides 2341e4f93234SChuck Lever * @entry: buffer to fill in with entry data 2342e4f93234SChuck Lever * @server: nfs_server data for this directory 2343e4f93234SChuck Lever * @plus: boolean indicating whether this should be a readdirplus entry 2344e4f93234SChuck Lever * 2345e4f93234SChuck Lever * Returns the position of the next item in the buffer, or an ERR_PTR. 2346e4f93234SChuck Lever * 2347e4f93234SChuck Lever * This function is not invoked during READDIR reply decoding, but 2348e4f93234SChuck Lever * rather whenever an application invokes the getdents(2) system call 2349e4f93234SChuck Lever * on a directory already in our cache. 2350e4f93234SChuck Lever * 2351e4f93234SChuck Lever * 3.3.16 entry3 2352e4f93234SChuck Lever * 2353e4f93234SChuck Lever * struct entry3 { 2354e4f93234SChuck Lever * fileid3 fileid; 2355e4f93234SChuck Lever * filename3 name; 2356e4f93234SChuck Lever * cookie3 cookie; 2357e4f93234SChuck Lever * fhandle3 filehandle; 2358e4f93234SChuck Lever * post_op_attr3 attributes; 2359e4f93234SChuck Lever * entry3 *nextentry; 2360e4f93234SChuck Lever * }; 2361e4f93234SChuck Lever * 2362e4f93234SChuck Lever * 3.3.17 entryplus3 2363e4f93234SChuck Lever * struct entryplus3 { 2364e4f93234SChuck Lever * fileid3 fileid; 2365e4f93234SChuck Lever * filename3 name; 2366e4f93234SChuck Lever * cookie3 cookie; 2367e4f93234SChuck Lever * post_op_attr name_attributes; 2368e4f93234SChuck Lever * post_op_fh3 name_handle; 2369e4f93234SChuck Lever * entryplus3 *nextentry; 2370e4f93234SChuck Lever * }; 2371e4f93234SChuck Lever */ 2372e4f93234SChuck Lever __be32 *nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, 2373e4f93234SChuck Lever struct nfs_server *server, int plus) 2374e4f93234SChuck Lever { 2375e4f93234SChuck Lever struct nfs_entry old = *entry; 2376e4f93234SChuck Lever __be32 *p; 2377e4f93234SChuck Lever int error; 2378e4f93234SChuck Lever 2379e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 2380e4f93234SChuck Lever if (unlikely(p == NULL)) 2381e4f93234SChuck Lever goto out_overflow; 2382e4f93234SChuck Lever if (*p == xdr_zero) { 2383e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 2384e4f93234SChuck Lever if (unlikely(p == NULL)) 2385e4f93234SChuck Lever goto out_overflow; 2386e4f93234SChuck Lever if (*p == xdr_zero) 2387e4f93234SChuck Lever return ERR_PTR(-EAGAIN); 2388e4f93234SChuck Lever entry->eof = 1; 2389e4f93234SChuck Lever return ERR_PTR(-EBADCOOKIE); 2390e4f93234SChuck Lever } 2391e4f93234SChuck Lever 2392e4f93234SChuck Lever error = decode_fileid3(xdr, &entry->ino); 2393e4f93234SChuck Lever if (unlikely(error)) 2394e4f93234SChuck Lever return ERR_PTR(error); 2395e4f93234SChuck Lever 2396e4f93234SChuck Lever error = decode_inline_filename3(xdr, &entry->name, &entry->len); 2397e4f93234SChuck Lever if (unlikely(error)) 2398e4f93234SChuck Lever return ERR_PTR(error); 2399e4f93234SChuck Lever 2400e4f93234SChuck Lever entry->prev_cookie = entry->cookie; 2401e4f93234SChuck Lever error = decode_cookie3(xdr, &entry->cookie); 2402e4f93234SChuck Lever if (unlikely(error)) 2403e4f93234SChuck Lever return ERR_PTR(error); 2404e4f93234SChuck Lever 2405e4f93234SChuck Lever entry->d_type = DT_UNKNOWN; 2406e4f93234SChuck Lever 2407e4f93234SChuck Lever if (plus) { 2408e4f93234SChuck Lever entry->fattr->valid = 0; 2409e4f93234SChuck Lever error = decode_post_op_attr(xdr, entry->fattr); 2410e4f93234SChuck Lever if (unlikely(error)) 2411e4f93234SChuck Lever return ERR_PTR(error); 2412e4f93234SChuck Lever if (entry->fattr->valid & NFS_ATTR_FATTR_V3) 2413e4f93234SChuck Lever entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); 2414e4f93234SChuck Lever 2415e4f93234SChuck Lever /* In fact, a post_op_fh3: */ 2416e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 2417e4f93234SChuck Lever if (unlikely(p == NULL)) 2418e4f93234SChuck Lever goto out_overflow; 2419e4f93234SChuck Lever if (*p != xdr_zero) { 2420e4f93234SChuck Lever error = decode_nfs_fh3(xdr, entry->fh); 2421e4f93234SChuck Lever if (unlikely(error)) { 2422e4f93234SChuck Lever if (error == -E2BIG) 2423e4f93234SChuck Lever goto out_truncated; 2424e4f93234SChuck Lever return ERR_PTR(error); 2425e4f93234SChuck Lever } 2426e4f93234SChuck Lever } else 2427e4f93234SChuck Lever zero_nfs_fh3(entry->fh); 2428e4f93234SChuck Lever } 2429e4f93234SChuck Lever 2430e4f93234SChuck Lever /* Peek at the next entry to see if we're at EOD */ 2431e4f93234SChuck Lever p = xdr_inline_peek(xdr, 4 + 4); 2432e4f93234SChuck Lever entry->eof = 0; 2433e4f93234SChuck Lever if (p != NULL) 2434e4f93234SChuck Lever entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero); 2435e4f93234SChuck Lever return p; 2436e4f93234SChuck Lever 2437e4f93234SChuck Lever out_overflow: 2438e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2439e4f93234SChuck Lever return ERR_PTR(-EAGAIN); 2440e4f93234SChuck Lever out_truncated: 2441e4f93234SChuck Lever dprintk("NFS: directory entry contains invalid file handle\n"); 2442e4f93234SChuck Lever *entry = old; 2443e4f93234SChuck Lever return ERR_PTR(-EAGAIN); 2444e4f93234SChuck Lever } 2445e4f93234SChuck Lever 2446e4f93234SChuck Lever /* 2447e4f93234SChuck Lever * 3.3.16 READDIR3res 2448e4f93234SChuck Lever * 2449e4f93234SChuck Lever * struct dirlist3 { 2450e4f93234SChuck Lever * entry3 *entries; 2451e4f93234SChuck Lever * bool eof; 2452e4f93234SChuck Lever * }; 2453e4f93234SChuck Lever * 2454e4f93234SChuck Lever * struct READDIR3resok { 2455e4f93234SChuck Lever * post_op_attr dir_attributes; 2456e4f93234SChuck Lever * cookieverf3 cookieverf; 2457e4f93234SChuck Lever * dirlist3 reply; 2458e4f93234SChuck Lever * }; 2459e4f93234SChuck Lever * 2460e4f93234SChuck Lever * struct READDIR3resfail { 2461e4f93234SChuck Lever * post_op_attr dir_attributes; 2462e4f93234SChuck Lever * }; 2463e4f93234SChuck Lever * 2464e4f93234SChuck Lever * union READDIR3res switch (nfsstat3 status) { 2465e4f93234SChuck Lever * case NFS3_OK: 2466e4f93234SChuck Lever * READDIR3resok resok; 2467e4f93234SChuck Lever * default: 2468e4f93234SChuck Lever * READDIR3resfail resfail; 2469e4f93234SChuck Lever * }; 2470e4f93234SChuck Lever * 2471e4f93234SChuck Lever * Read the directory contents into the page cache, but otherwise 2472e4f93234SChuck Lever * don't touch them. The actual decoding is done by nfs3_decode_entry() 2473e4f93234SChuck Lever * during subsequent nfs_readdir() calls. 2474e4f93234SChuck Lever */ 2475e4f93234SChuck Lever static int decode_dirlist3(struct xdr_stream *xdr) 2476e4f93234SChuck Lever { 2477e4f93234SChuck Lever u32 recvd, pglen; 2478e4f93234SChuck Lever size_t hdrlen; 2479e4f93234SChuck Lever 2480e4f93234SChuck Lever pglen = xdr->buf->page_len; 2481e4f93234SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 2482e4f93234SChuck Lever recvd = xdr->buf->len - hdrlen; 2483e4f93234SChuck Lever if (unlikely(pglen > recvd)) 2484e4f93234SChuck Lever goto out_cheating; 2485e4f93234SChuck Lever out: 2486e4f93234SChuck Lever xdr_read_pages(xdr, pglen); 2487e4f93234SChuck Lever return pglen; 2488e4f93234SChuck Lever out_cheating: 2489e4f93234SChuck Lever dprintk("NFS: server cheating in readdir result: " 2490e4f93234SChuck Lever "pglen %u > recvd %u\n", pglen, recvd); 2491e4f93234SChuck Lever pglen = recvd; 2492e4f93234SChuck Lever goto out; 2493e4f93234SChuck Lever } 2494e4f93234SChuck Lever 2495e4f93234SChuck Lever static int decode_readdir3resok(struct xdr_stream *xdr, 2496e4f93234SChuck Lever struct nfs3_readdirres *result) 2497e4f93234SChuck Lever { 2498e4f93234SChuck Lever int error; 2499e4f93234SChuck Lever 2500e4f93234SChuck Lever error = decode_post_op_attr(xdr, result->dir_attr); 2501e4f93234SChuck Lever if (unlikely(error)) 2502e4f93234SChuck Lever goto out; 2503e4f93234SChuck Lever /* XXX: do we need to check if result->verf != NULL ? */ 2504e4f93234SChuck Lever error = decode_cookieverf3(xdr, result->verf); 2505e4f93234SChuck Lever if (unlikely(error)) 2506e4f93234SChuck Lever goto out; 2507e4f93234SChuck Lever error = decode_dirlist3(xdr); 2508e4f93234SChuck Lever out: 2509e4f93234SChuck Lever return error; 2510e4f93234SChuck Lever } 2511e4f93234SChuck Lever 2512e4f93234SChuck Lever static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req, __be32 *p, 2513e4f93234SChuck Lever struct nfs3_readdirres *result) 2514e4f93234SChuck Lever { 2515e4f93234SChuck Lever struct xdr_stream xdr; 2516e4f93234SChuck Lever enum nfs_stat status; 2517e4f93234SChuck Lever int error; 2518e4f93234SChuck Lever 2519e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2520e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2521e4f93234SChuck Lever if (unlikely(error)) 2522e4f93234SChuck Lever goto out; 2523e4f93234SChuck Lever if (status != NFS3_OK) 2524e4f93234SChuck Lever goto out_default; 2525e4f93234SChuck Lever error = decode_readdir3resok(&xdr, result); 2526e4f93234SChuck Lever out: 2527e4f93234SChuck Lever return error; 2528e4f93234SChuck Lever out_default: 2529e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->dir_attr); 2530e4f93234SChuck Lever if (unlikely(error)) 2531e4f93234SChuck Lever goto out; 2532e4f93234SChuck Lever return nfs_stat_to_errno(status); 2533e4f93234SChuck Lever } 2534e4f93234SChuck Lever 2535e4f93234SChuck Lever /* 25361da177e4SLinus Torvalds * Decode FSSTAT reply 25371da177e4SLinus Torvalds */ 25381da177e4SLinus Torvalds static int 2539d61005a6SAl Viro nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res) 25401da177e4SLinus Torvalds { 25411da177e4SLinus Torvalds int status; 25421da177e4SLinus Torvalds 25431da177e4SLinus Torvalds status = ntohl(*p++); 25441da177e4SLinus Torvalds 25451da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 25461da177e4SLinus Torvalds if (status != 0) 2547856dff3dSBenny Halevy return nfs_stat_to_errno(status); 25481da177e4SLinus Torvalds 25491da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->tbytes); 25501da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->fbytes); 25511da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->abytes); 25521da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->tfiles); 25531da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->ffiles); 25541da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->afiles); 25551da177e4SLinus Torvalds 25561da177e4SLinus Torvalds /* ignore invarsec */ 25571da177e4SLinus Torvalds return 0; 25581da177e4SLinus Torvalds } 25591da177e4SLinus Torvalds 25601da177e4SLinus Torvalds /* 2561e4f93234SChuck Lever * 3.3.18 FSSTAT3res 2562e4f93234SChuck Lever * 2563e4f93234SChuck Lever * struct FSSTAT3resok { 2564e4f93234SChuck Lever * post_op_attr obj_attributes; 2565e4f93234SChuck Lever * size3 tbytes; 2566e4f93234SChuck Lever * size3 fbytes; 2567e4f93234SChuck Lever * size3 abytes; 2568e4f93234SChuck Lever * size3 tfiles; 2569e4f93234SChuck Lever * size3 ffiles; 2570e4f93234SChuck Lever * size3 afiles; 2571e4f93234SChuck Lever * uint32 invarsec; 2572e4f93234SChuck Lever * }; 2573e4f93234SChuck Lever * 2574e4f93234SChuck Lever * struct FSSTAT3resfail { 2575e4f93234SChuck Lever * post_op_attr obj_attributes; 2576e4f93234SChuck Lever * }; 2577e4f93234SChuck Lever * 2578e4f93234SChuck Lever * union FSSTAT3res switch (nfsstat3 status) { 2579e4f93234SChuck Lever * case NFS3_OK: 2580e4f93234SChuck Lever * FSSTAT3resok resok; 2581e4f93234SChuck Lever * default: 2582e4f93234SChuck Lever * FSSTAT3resfail resfail; 2583e4f93234SChuck Lever * }; 2584e4f93234SChuck Lever */ 2585e4f93234SChuck Lever static int decode_fsstat3resok(struct xdr_stream *xdr, 2586e4f93234SChuck Lever struct nfs_fsstat *result) 2587e4f93234SChuck Lever { 2588e4f93234SChuck Lever __be32 *p; 2589e4f93234SChuck Lever 2590e4f93234SChuck Lever p = xdr_inline_decode(xdr, 8 * 6 + 4); 2591e4f93234SChuck Lever if (unlikely(p == NULL)) 2592e4f93234SChuck Lever goto out_overflow; 2593e4f93234SChuck Lever p = xdr_decode_size3(p, &result->tbytes); 2594e4f93234SChuck Lever p = xdr_decode_size3(p, &result->fbytes); 2595e4f93234SChuck Lever p = xdr_decode_size3(p, &result->abytes); 2596e4f93234SChuck Lever p = xdr_decode_size3(p, &result->tfiles); 2597e4f93234SChuck Lever p = xdr_decode_size3(p, &result->ffiles); 2598e4f93234SChuck Lever xdr_decode_size3(p, &result->afiles); 2599e4f93234SChuck Lever /* ignore invarsec */ 2600e4f93234SChuck Lever return 0; 2601e4f93234SChuck Lever out_overflow: 2602e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2603e4f93234SChuck Lever return -EIO; 2604e4f93234SChuck Lever } 2605e4f93234SChuck Lever 2606e4f93234SChuck Lever static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req, __be32 *p, 2607e4f93234SChuck Lever struct nfs_fsstat *result) 2608e4f93234SChuck Lever { 2609e4f93234SChuck Lever struct xdr_stream xdr; 2610e4f93234SChuck Lever enum nfs_stat status; 2611e4f93234SChuck Lever int error; 2612e4f93234SChuck Lever 2613e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2614e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2615e4f93234SChuck Lever if (unlikely(error)) 2616e4f93234SChuck Lever goto out; 2617e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->fattr); 2618e4f93234SChuck Lever if (unlikely(error)) 2619e4f93234SChuck Lever goto out; 2620e4f93234SChuck Lever if (status != NFS3_OK) 2621e4f93234SChuck Lever goto out_status; 2622e4f93234SChuck Lever error = decode_fsstat3resok(&xdr, result); 2623e4f93234SChuck Lever out: 2624e4f93234SChuck Lever return error; 2625e4f93234SChuck Lever out_status: 2626e4f93234SChuck Lever return nfs_stat_to_errno(status); 2627e4f93234SChuck Lever } 2628e4f93234SChuck Lever 2629e4f93234SChuck Lever /* 26301da177e4SLinus Torvalds * Decode FSINFO reply 26311da177e4SLinus Torvalds */ 26321da177e4SLinus Torvalds static int 2633d61005a6SAl Viro nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res) 26341da177e4SLinus Torvalds { 26351da177e4SLinus Torvalds int status; 26361da177e4SLinus Torvalds 26371da177e4SLinus Torvalds status = ntohl(*p++); 26381da177e4SLinus Torvalds 26391da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 26401da177e4SLinus Torvalds if (status != 0) 2641856dff3dSBenny Halevy return nfs_stat_to_errno(status); 26421da177e4SLinus Torvalds 26431da177e4SLinus Torvalds res->rtmax = ntohl(*p++); 26441da177e4SLinus Torvalds res->rtpref = ntohl(*p++); 26451da177e4SLinus Torvalds res->rtmult = ntohl(*p++); 26461da177e4SLinus Torvalds res->wtmax = ntohl(*p++); 26471da177e4SLinus Torvalds res->wtpref = ntohl(*p++); 26481da177e4SLinus Torvalds res->wtmult = ntohl(*p++); 26491da177e4SLinus Torvalds res->dtpref = ntohl(*p++); 26501da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->maxfilesize); 26516b96724eSRicardo Labiaga p = xdr_decode_time3(p, &res->time_delta); 26521da177e4SLinus Torvalds 26536b96724eSRicardo Labiaga /* ignore properties */ 26541da177e4SLinus Torvalds res->lease_time = 0; 26551da177e4SLinus Torvalds return 0; 26561da177e4SLinus Torvalds } 26571da177e4SLinus Torvalds 26581da177e4SLinus Torvalds /* 2659e4f93234SChuck Lever * 3.3.19 FSINFO3res 2660e4f93234SChuck Lever * 2661e4f93234SChuck Lever * struct FSINFO3resok { 2662e4f93234SChuck Lever * post_op_attr obj_attributes; 2663e4f93234SChuck Lever * uint32 rtmax; 2664e4f93234SChuck Lever * uint32 rtpref; 2665e4f93234SChuck Lever * uint32 rtmult; 2666e4f93234SChuck Lever * uint32 wtmax; 2667e4f93234SChuck Lever * uint32 wtpref; 2668e4f93234SChuck Lever * uint32 wtmult; 2669e4f93234SChuck Lever * uint32 dtpref; 2670e4f93234SChuck Lever * size3 maxfilesize; 2671e4f93234SChuck Lever * nfstime3 time_delta; 2672e4f93234SChuck Lever * uint32 properties; 2673e4f93234SChuck Lever * }; 2674e4f93234SChuck Lever * 2675e4f93234SChuck Lever * struct FSINFO3resfail { 2676e4f93234SChuck Lever * post_op_attr obj_attributes; 2677e4f93234SChuck Lever * }; 2678e4f93234SChuck Lever * 2679e4f93234SChuck Lever * union FSINFO3res switch (nfsstat3 status) { 2680e4f93234SChuck Lever * case NFS3_OK: 2681e4f93234SChuck Lever * FSINFO3resok resok; 2682e4f93234SChuck Lever * default: 2683e4f93234SChuck Lever * FSINFO3resfail resfail; 2684e4f93234SChuck Lever * }; 2685e4f93234SChuck Lever */ 2686e4f93234SChuck Lever static int decode_fsinfo3resok(struct xdr_stream *xdr, 2687e4f93234SChuck Lever struct nfs_fsinfo *result) 2688e4f93234SChuck Lever { 2689e4f93234SChuck Lever __be32 *p; 2690e4f93234SChuck Lever 2691e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4); 2692e4f93234SChuck Lever if (unlikely(p == NULL)) 2693e4f93234SChuck Lever goto out_overflow; 2694e4f93234SChuck Lever result->rtmax = be32_to_cpup(p++); 2695e4f93234SChuck Lever result->rtpref = be32_to_cpup(p++); 2696e4f93234SChuck Lever result->rtmult = be32_to_cpup(p++); 2697e4f93234SChuck Lever result->wtmax = be32_to_cpup(p++); 2698e4f93234SChuck Lever result->wtpref = be32_to_cpup(p++); 2699e4f93234SChuck Lever result->wtmult = be32_to_cpup(p++); 2700e4f93234SChuck Lever result->dtpref = be32_to_cpup(p++); 2701e4f93234SChuck Lever p = xdr_decode_size3(p, &result->maxfilesize); 2702e4f93234SChuck Lever xdr_decode_time3(p, &result->time_delta); 2703e4f93234SChuck Lever 2704e4f93234SChuck Lever /* ignore properties */ 2705e4f93234SChuck Lever result->lease_time = 0; 2706e4f93234SChuck Lever return 0; 2707e4f93234SChuck Lever out_overflow: 2708e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2709e4f93234SChuck Lever return -EIO; 2710e4f93234SChuck Lever } 2711e4f93234SChuck Lever 2712e4f93234SChuck Lever static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req, __be32 *p, 2713e4f93234SChuck Lever struct nfs_fsinfo *result) 2714e4f93234SChuck Lever { 2715e4f93234SChuck Lever struct xdr_stream xdr; 2716e4f93234SChuck Lever enum nfs_stat status; 2717e4f93234SChuck Lever int error; 2718e4f93234SChuck Lever 2719e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2720e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2721e4f93234SChuck Lever if (unlikely(error)) 2722e4f93234SChuck Lever goto out; 2723e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->fattr); 2724e4f93234SChuck Lever if (unlikely(error)) 2725e4f93234SChuck Lever goto out; 2726e4f93234SChuck Lever if (status != NFS3_OK) 2727e4f93234SChuck Lever goto out_status; 2728e4f93234SChuck Lever error = decode_fsinfo3resok(&xdr, result); 2729e4f93234SChuck Lever out: 2730e4f93234SChuck Lever return error; 2731e4f93234SChuck Lever out_status: 2732e4f93234SChuck Lever return nfs_stat_to_errno(status); 2733e4f93234SChuck Lever } 2734e4f93234SChuck Lever 2735e4f93234SChuck Lever /* 27361da177e4SLinus Torvalds * Decode PATHCONF reply 27371da177e4SLinus Torvalds */ 27381da177e4SLinus Torvalds static int 2739d61005a6SAl Viro nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res) 27401da177e4SLinus Torvalds { 27411da177e4SLinus Torvalds int status; 27421da177e4SLinus Torvalds 27431da177e4SLinus Torvalds status = ntohl(*p++); 27441da177e4SLinus Torvalds 27451da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 27461da177e4SLinus Torvalds if (status != 0) 2747856dff3dSBenny Halevy return nfs_stat_to_errno(status); 27481da177e4SLinus Torvalds res->max_link = ntohl(*p++); 27491da177e4SLinus Torvalds res->max_namelen = ntohl(*p++); 27501da177e4SLinus Torvalds 27511da177e4SLinus Torvalds /* ignore remaining fields */ 27521da177e4SLinus Torvalds return 0; 27531da177e4SLinus Torvalds } 27541da177e4SLinus Torvalds 27551da177e4SLinus Torvalds /* 2756e4f93234SChuck Lever * 3.3.20 PATHCONF3res 2757e4f93234SChuck Lever * 2758e4f93234SChuck Lever * struct PATHCONF3resok { 2759e4f93234SChuck Lever * post_op_attr obj_attributes; 2760e4f93234SChuck Lever * uint32 linkmax; 2761e4f93234SChuck Lever * uint32 name_max; 2762e4f93234SChuck Lever * bool no_trunc; 2763e4f93234SChuck Lever * bool chown_restricted; 2764e4f93234SChuck Lever * bool case_insensitive; 2765e4f93234SChuck Lever * bool case_preserving; 2766e4f93234SChuck Lever * }; 2767e4f93234SChuck Lever * 2768e4f93234SChuck Lever * struct PATHCONF3resfail { 2769e4f93234SChuck Lever * post_op_attr obj_attributes; 2770e4f93234SChuck Lever * }; 2771e4f93234SChuck Lever * 2772e4f93234SChuck Lever * union PATHCONF3res switch (nfsstat3 status) { 2773e4f93234SChuck Lever * case NFS3_OK: 2774e4f93234SChuck Lever * PATHCONF3resok resok; 2775e4f93234SChuck Lever * default: 2776e4f93234SChuck Lever * PATHCONF3resfail resfail; 2777e4f93234SChuck Lever * }; 2778e4f93234SChuck Lever */ 2779e4f93234SChuck Lever static int decode_pathconf3resok(struct xdr_stream *xdr, 2780e4f93234SChuck Lever struct nfs_pathconf *result) 2781e4f93234SChuck Lever { 2782e4f93234SChuck Lever __be32 *p; 2783e4f93234SChuck Lever 2784e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 * 6); 2785e4f93234SChuck Lever if (unlikely(p == NULL)) 2786e4f93234SChuck Lever goto out_overflow; 2787e4f93234SChuck Lever result->max_link = be32_to_cpup(p++); 2788e4f93234SChuck Lever result->max_namelen = be32_to_cpup(p); 2789e4f93234SChuck Lever /* ignore remaining fields */ 2790e4f93234SChuck Lever return 0; 2791e4f93234SChuck Lever out_overflow: 2792e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2793e4f93234SChuck Lever return -EIO; 2794e4f93234SChuck Lever } 2795e4f93234SChuck Lever 2796e4f93234SChuck Lever static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req, __be32 *p, 2797e4f93234SChuck Lever struct nfs_pathconf *result) 2798e4f93234SChuck Lever { 2799e4f93234SChuck Lever struct xdr_stream xdr; 2800e4f93234SChuck Lever enum nfs_stat status; 2801e4f93234SChuck Lever int error; 2802e4f93234SChuck Lever 2803e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2804e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2805e4f93234SChuck Lever if (unlikely(error)) 2806e4f93234SChuck Lever goto out; 2807e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result->fattr); 2808e4f93234SChuck Lever if (unlikely(error)) 2809e4f93234SChuck Lever goto out; 2810e4f93234SChuck Lever if (status != NFS3_OK) 2811e4f93234SChuck Lever goto out_status; 2812e4f93234SChuck Lever error = decode_pathconf3resok(&xdr, result); 2813e4f93234SChuck Lever out: 2814e4f93234SChuck Lever return error; 2815e4f93234SChuck Lever out_status: 2816e4f93234SChuck Lever return nfs_stat_to_errno(status); 2817e4f93234SChuck Lever } 2818e4f93234SChuck Lever 2819e4f93234SChuck Lever /* 28201da177e4SLinus Torvalds * Decode COMMIT reply 28211da177e4SLinus Torvalds */ 28221da177e4SLinus Torvalds static int 2823d61005a6SAl Viro nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) 28241da177e4SLinus Torvalds { 28251da177e4SLinus Torvalds int status; 28261da177e4SLinus Torvalds 28271da177e4SLinus Torvalds status = ntohl(*p++); 28281da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->fattr); 28291da177e4SLinus Torvalds if (status != 0) 2830856dff3dSBenny Halevy return nfs_stat_to_errno(status); 28311da177e4SLinus Torvalds 28321da177e4SLinus Torvalds res->verf->verifier[0] = *p++; 28331da177e4SLinus Torvalds res->verf->verifier[1] = *p++; 28341da177e4SLinus Torvalds return 0; 28351da177e4SLinus Torvalds } 28361da177e4SLinus Torvalds 2837e4f93234SChuck Lever /* 2838e4f93234SChuck Lever * 3.3.21 COMMIT3res 2839e4f93234SChuck Lever * 2840e4f93234SChuck Lever * struct COMMIT3resok { 2841e4f93234SChuck Lever * wcc_data file_wcc; 2842e4f93234SChuck Lever * writeverf3 verf; 2843e4f93234SChuck Lever * }; 2844e4f93234SChuck Lever * 2845e4f93234SChuck Lever * struct COMMIT3resfail { 2846e4f93234SChuck Lever * wcc_data file_wcc; 2847e4f93234SChuck Lever * }; 2848e4f93234SChuck Lever * 2849e4f93234SChuck Lever * union COMMIT3res switch (nfsstat3 status) { 2850e4f93234SChuck Lever * case NFS3_OK: 2851e4f93234SChuck Lever * COMMIT3resok resok; 2852e4f93234SChuck Lever * default: 2853e4f93234SChuck Lever * COMMIT3resfail resfail; 2854e4f93234SChuck Lever * }; 2855e4f93234SChuck Lever */ 2856e4f93234SChuck Lever static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, __be32 *p, 2857e4f93234SChuck Lever struct nfs_writeres *result) 2858e4f93234SChuck Lever { 2859e4f93234SChuck Lever struct xdr_stream xdr; 2860e4f93234SChuck Lever enum nfs_stat status; 2861e4f93234SChuck Lever int error; 2862e4f93234SChuck Lever 2863e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2864e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2865e4f93234SChuck Lever if (unlikely(error)) 2866e4f93234SChuck Lever goto out; 2867e4f93234SChuck Lever error = decode_wcc_data(&xdr, result->fattr); 2868e4f93234SChuck Lever if (unlikely(error)) 2869e4f93234SChuck Lever goto out; 2870e4f93234SChuck Lever if (status != NFS3_OK) 2871e4f93234SChuck Lever goto out_status; 2872e4f93234SChuck Lever error = decode_writeverf3(&xdr, result->verf->verifier); 2873e4f93234SChuck Lever out: 2874e4f93234SChuck Lever return error; 2875e4f93234SChuck Lever out_status: 2876e4f93234SChuck Lever return nfs_stat_to_errno(status); 2877e4f93234SChuck Lever } 2878e4f93234SChuck Lever 2879b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 2880b7fa0554SAndreas Gruenbacher /* 2881b7fa0554SAndreas Gruenbacher * Decode GETACL reply 2882b7fa0554SAndreas Gruenbacher */ 2883b7fa0554SAndreas Gruenbacher static int 2884d61005a6SAl Viro nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p, 2885b7fa0554SAndreas Gruenbacher struct nfs3_getaclres *res) 2886b7fa0554SAndreas Gruenbacher { 2887b7fa0554SAndreas Gruenbacher struct xdr_buf *buf = &req->rq_rcv_buf; 2888b7fa0554SAndreas Gruenbacher int status = ntohl(*p++); 2889b7fa0554SAndreas Gruenbacher struct posix_acl **acl; 2890b7fa0554SAndreas Gruenbacher unsigned int *aclcnt; 2891b7fa0554SAndreas Gruenbacher int err, base; 2892b7fa0554SAndreas Gruenbacher 2893b7fa0554SAndreas Gruenbacher if (status != 0) 2894856dff3dSBenny Halevy return nfs_stat_to_errno(status); 2895b7fa0554SAndreas Gruenbacher p = xdr_decode_post_op_attr(p, res->fattr); 2896b7fa0554SAndreas Gruenbacher res->mask = ntohl(*p++); 2897b7fa0554SAndreas Gruenbacher if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 2898b7fa0554SAndreas Gruenbacher return -EINVAL; 2899b7fa0554SAndreas Gruenbacher base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base; 2900b7fa0554SAndreas Gruenbacher 2901b7fa0554SAndreas Gruenbacher acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL; 2902b7fa0554SAndreas Gruenbacher aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL; 2903b7fa0554SAndreas Gruenbacher err = nfsacl_decode(buf, base, aclcnt, acl); 2904b7fa0554SAndreas Gruenbacher 2905b7fa0554SAndreas Gruenbacher acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL; 2906b7fa0554SAndreas Gruenbacher aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL; 2907b7fa0554SAndreas Gruenbacher if (err > 0) 2908b7fa0554SAndreas Gruenbacher err = nfsacl_decode(buf, base + err, aclcnt, acl); 2909b7fa0554SAndreas Gruenbacher return (err > 0) ? 0 : err; 2910b7fa0554SAndreas Gruenbacher } 2911b7fa0554SAndreas Gruenbacher 2912e4f93234SChuck Lever static inline int decode_getacl3resok(struct xdr_stream *xdr, 2913e4f93234SChuck Lever struct nfs3_getaclres *result) 2914e4f93234SChuck Lever { 2915e4f93234SChuck Lever struct posix_acl **acl; 2916e4f93234SChuck Lever unsigned int *aclcnt; 2917e4f93234SChuck Lever size_t hdrlen; 2918e4f93234SChuck Lever int error; 2919e4f93234SChuck Lever 2920e4f93234SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2921e4f93234SChuck Lever if (unlikely(error)) 2922e4f93234SChuck Lever goto out; 2923e4f93234SChuck Lever error = decode_uint32(xdr, &result->mask); 2924e4f93234SChuck Lever if (unlikely(error)) 2925e4f93234SChuck Lever goto out; 2926e4f93234SChuck Lever error = -EINVAL; 2927e4f93234SChuck Lever if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 2928e4f93234SChuck Lever goto out; 2929e4f93234SChuck Lever 2930e4f93234SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 2931e4f93234SChuck Lever 2932e4f93234SChuck Lever acl = NULL; 2933e4f93234SChuck Lever if (result->mask & NFS_ACL) 2934e4f93234SChuck Lever acl = &result->acl_access; 2935e4f93234SChuck Lever aclcnt = NULL; 2936e4f93234SChuck Lever if (result->mask & NFS_ACLCNT) 2937e4f93234SChuck Lever aclcnt = &result->acl_access_count; 2938e4f93234SChuck Lever error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl); 2939e4f93234SChuck Lever if (unlikely(error <= 0)) 2940e4f93234SChuck Lever goto out; 2941e4f93234SChuck Lever 2942e4f93234SChuck Lever acl = NULL; 2943e4f93234SChuck Lever if (result->mask & NFS_DFACL) 2944e4f93234SChuck Lever acl = &result->acl_default; 2945e4f93234SChuck Lever aclcnt = NULL; 2946e4f93234SChuck Lever if (result->mask & NFS_DFACLCNT) 2947e4f93234SChuck Lever aclcnt = &result->acl_default_count; 2948e4f93234SChuck Lever error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl); 2949e4f93234SChuck Lever if (unlikely(error <= 0)) 2950e4f93234SChuck Lever return error; 2951e4f93234SChuck Lever error = 0; 2952e4f93234SChuck Lever out: 2953e4f93234SChuck Lever return error; 2954e4f93234SChuck Lever } 2955e4f93234SChuck Lever 2956e4f93234SChuck Lever static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req, __be32 *p, 2957e4f93234SChuck Lever struct nfs3_getaclres *result) 2958e4f93234SChuck Lever { 2959e4f93234SChuck Lever struct xdr_stream xdr; 2960e4f93234SChuck Lever enum nfs_stat status; 2961e4f93234SChuck Lever int error; 2962e4f93234SChuck Lever 2963e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2964e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2965e4f93234SChuck Lever if (unlikely(error)) 2966e4f93234SChuck Lever goto out; 2967e4f93234SChuck Lever if (status != NFS3_OK) 2968e4f93234SChuck Lever goto out_default; 2969e4f93234SChuck Lever error = decode_getacl3resok(&xdr, result); 2970e4f93234SChuck Lever out: 2971e4f93234SChuck Lever return error; 2972e4f93234SChuck Lever out_default: 2973e4f93234SChuck Lever return nfs_stat_to_errno(status); 2974e4f93234SChuck Lever } 2975e4f93234SChuck Lever 2976b7fa0554SAndreas Gruenbacher /* 2977b7fa0554SAndreas Gruenbacher * Decode setacl reply. 2978b7fa0554SAndreas Gruenbacher */ 2979b7fa0554SAndreas Gruenbacher static int 2980d61005a6SAl Viro nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 2981b7fa0554SAndreas Gruenbacher { 2982b7fa0554SAndreas Gruenbacher int status = ntohl(*p++); 2983b7fa0554SAndreas Gruenbacher 2984b7fa0554SAndreas Gruenbacher if (status) 2985856dff3dSBenny Halevy return nfs_stat_to_errno(status); 2986b7fa0554SAndreas Gruenbacher xdr_decode_post_op_attr(p, fattr); 2987b7fa0554SAndreas Gruenbacher return 0; 2988b7fa0554SAndreas Gruenbacher } 2989e4f93234SChuck Lever 2990e4f93234SChuck Lever static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req, __be32 *p, 2991e4f93234SChuck Lever struct nfs_fattr *result) 2992e4f93234SChuck Lever { 2993e4f93234SChuck Lever struct xdr_stream xdr; 2994e4f93234SChuck Lever enum nfs_stat status; 2995e4f93234SChuck Lever int error; 2996e4f93234SChuck Lever 2997e4f93234SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 2998e4f93234SChuck Lever error = decode_nfsstat3(&xdr, &status); 2999e4f93234SChuck Lever if (unlikely(error)) 3000e4f93234SChuck Lever goto out; 3001e4f93234SChuck Lever if (status != NFS3_OK) 3002e4f93234SChuck Lever goto out_default; 3003e4f93234SChuck Lever error = decode_post_op_attr(&xdr, result); 3004e4f93234SChuck Lever out: 3005e4f93234SChuck Lever return error; 3006e4f93234SChuck Lever out_default: 3007e4f93234SChuck Lever return nfs_stat_to_errno(status); 3008e4f93234SChuck Lever } 3009e4f93234SChuck Lever 3010b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 3011b7fa0554SAndreas Gruenbacher 30121da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer) \ 30131da177e4SLinus Torvalds [NFS3PROC_##proc] = { \ 30141da177e4SLinus Torvalds .p_proc = NFS3PROC_##proc, \ 3015ad96b5b5SChuck Lever .p_encode = (kxdrproc_t)nfs3_xdr_enc_##argtype##3args, \ 3016f5fc3c50SChuck Lever .p_decode = (kxdrproc_t)nfs3_xdr_dec_##restype##3res, \ 3017ad96b5b5SChuck Lever .p_arglen = NFS3_##argtype##args_sz, \ 3018f5fc3c50SChuck Lever .p_replen = NFS3_##restype##res_sz, \ 3019cc0175c1SChuck Lever .p_timer = timer, \ 3020cc0175c1SChuck Lever .p_statidx = NFS3PROC_##proc, \ 3021cc0175c1SChuck Lever .p_name = #proc, \ 30221da177e4SLinus Torvalds } 30231da177e4SLinus Torvalds 30241da177e4SLinus Torvalds struct rpc_procinfo nfs3_procedures[] = { 3025f5fc3c50SChuck Lever PROC(GETATTR, getattr, getattr, 1), 3026f5fc3c50SChuck Lever PROC(SETATTR, setattr, setattr, 0), 3027f5fc3c50SChuck Lever PROC(LOOKUP, lookup, lookup, 2), 3028f5fc3c50SChuck Lever PROC(ACCESS, access, access, 1), 3029f5fc3c50SChuck Lever PROC(READLINK, readlink, readlink, 3), 3030f5fc3c50SChuck Lever PROC(READ, read, read, 3), 3031f5fc3c50SChuck Lever PROC(WRITE, write, write, 4), 3032f5fc3c50SChuck Lever PROC(CREATE, create, create, 0), 3033f5fc3c50SChuck Lever PROC(MKDIR, mkdir, create, 0), 3034f5fc3c50SChuck Lever PROC(SYMLINK, symlink, create, 0), 3035f5fc3c50SChuck Lever PROC(MKNOD, mknod, create, 0), 3036f5fc3c50SChuck Lever PROC(REMOVE, remove, remove, 0), 3037f5fc3c50SChuck Lever PROC(RMDIR, lookup, setattr, 0), 3038f5fc3c50SChuck Lever PROC(RENAME, rename, rename, 0), 3039f5fc3c50SChuck Lever PROC(LINK, link, link, 0), 3040f5fc3c50SChuck Lever PROC(READDIR, readdir, readdir, 3), 3041f5fc3c50SChuck Lever PROC(READDIRPLUS, readdirplus, readdir, 3), 3042f5fc3c50SChuck Lever PROC(FSSTAT, getattr, fsstat, 0), 3043f5fc3c50SChuck Lever PROC(FSINFO, getattr, fsinfo, 0), 3044f5fc3c50SChuck Lever PROC(PATHCONF, getattr, pathconf, 0), 3045f5fc3c50SChuck Lever PROC(COMMIT, commit, commit, 5), 30461da177e4SLinus Torvalds }; 30471da177e4SLinus Torvalds 30481da177e4SLinus Torvalds struct rpc_version nfs_version3 = { 30491da177e4SLinus Torvalds .number = 3, 3050e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nfs3_procedures), 30511da177e4SLinus Torvalds .procs = nfs3_procedures 30521da177e4SLinus Torvalds }; 30531da177e4SLinus Torvalds 3054b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 3055b7fa0554SAndreas Gruenbacher static struct rpc_procinfo nfs3_acl_procedures[] = { 3056b7fa0554SAndreas Gruenbacher [ACLPROC3_GETACL] = { 3057b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_GETACL, 3058ad96b5b5SChuck Lever .p_encode = (kxdrproc_t)nfs3_xdr_enc_getacl3args, 3059f5fc3c50SChuck Lever .p_decode = (kxdrproc_t)nfs3_xdr_dec_getacl3res, 30602bea90d4SChuck Lever .p_arglen = ACL3_getaclargs_sz, 30612bea90d4SChuck Lever .p_replen = ACL3_getaclres_sz, 3062b7fa0554SAndreas Gruenbacher .p_timer = 1, 3063cc0175c1SChuck Lever .p_name = "GETACL", 3064b7fa0554SAndreas Gruenbacher }, 3065b7fa0554SAndreas Gruenbacher [ACLPROC3_SETACL] = { 3066b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_SETACL, 3067ad96b5b5SChuck Lever .p_encode = (kxdrproc_t)nfs3_xdr_enc_setacl3args, 3068f5fc3c50SChuck Lever .p_decode = (kxdrproc_t)nfs3_xdr_dec_setacl3res, 30692bea90d4SChuck Lever .p_arglen = ACL3_setaclargs_sz, 30702bea90d4SChuck Lever .p_replen = ACL3_setaclres_sz, 3071b7fa0554SAndreas Gruenbacher .p_timer = 0, 3072cc0175c1SChuck Lever .p_name = "SETACL", 3073b7fa0554SAndreas Gruenbacher }, 3074b7fa0554SAndreas Gruenbacher }; 3075b7fa0554SAndreas Gruenbacher 3076b7fa0554SAndreas Gruenbacher struct rpc_version nfsacl_version3 = { 3077b7fa0554SAndreas Gruenbacher .number = 3, 3078b7fa0554SAndreas Gruenbacher .nrprocs = sizeof(nfs3_acl_procedures)/ 3079b7fa0554SAndreas Gruenbacher sizeof(nfs3_acl_procedures[0]), 3080b7fa0554SAndreas Gruenbacher .procs = nfs3_acl_procedures, 3081b7fa0554SAndreas Gruenbacher }; 3082b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 3083