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_fsstat_sz 461da177e4SLinus Torvalds #define NFS3_fsinfo_sz 471da177e4SLinus Torvalds #define NFS3_pathconf_sz 481da177e4SLinus Torvalds #define NFS3_entry_sz (NFS3_filename_sz+3) 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3) 511da177e4SLinus Torvalds #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz) 524fdc17b2STrond Myklebust #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz) 531da177e4SLinus Torvalds #define NFS3_accessargs_sz (NFS3_fh_sz+1) 541da177e4SLinus Torvalds #define NFS3_readlinkargs_sz (NFS3_fh_sz) 551da177e4SLinus Torvalds #define NFS3_readargs_sz (NFS3_fh_sz+3) 561da177e4SLinus Torvalds #define NFS3_writeargs_sz (NFS3_fh_sz+5) 571da177e4SLinus Torvalds #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 581da177e4SLinus Torvalds #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 5994a6d753SChuck Lever #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz) 601da177e4SLinus Torvalds #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) 611da177e4SLinus Torvalds #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) 621da177e4SLinus Torvalds #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) 63d9c407b1SChuck Lever #define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3) 64d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4) 651da177e4SLinus Torvalds #define NFS3_commitargs_sz (NFS3_fh_sz+3) 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds #define NFS3_attrstat_sz (1+NFS3_fattr_sz) 681da177e4SLinus Torvalds #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz) 694fdc17b2STrond Myklebust #define NFS3_removeres_sz (NFS3_wccstat_sz) 701da177e4SLinus Torvalds #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) 711da177e4SLinus Torvalds #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) 721da177e4SLinus Torvalds #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1) 731da177e4SLinus Torvalds #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3) 741da177e4SLinus Torvalds #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4) 751da177e4SLinus Torvalds #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 761da177e4SLinus Torvalds #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz)) 771da177e4SLinus Torvalds #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 781da177e4SLinus Torvalds #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2) 791da177e4SLinus Torvalds #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13) 801da177e4SLinus Torvalds #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12) 811da177e4SLinus Torvalds #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) 821da177e4SLinus Torvalds #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) 831da177e4SLinus Torvalds 84b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz (NFS3_fh_sz+1) 85ae46141fSTrond Myklebust #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \ 86ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 87ae46141fSTrond Myklebust #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \ 88ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 89b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) 90b7fa0554SAndreas Gruenbacher 911da177e4SLinus Torvalds /* 921da177e4SLinus Torvalds * Map file type to S_IFMT bits 931da177e4SLinus Torvalds */ 94bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = { 95bca79478STrond Myklebust [NF3BAD] = 0, 96bca79478STrond Myklebust [NF3REG] = S_IFREG, 97bca79478STrond Myklebust [NF3DIR] = S_IFDIR, 98bca79478STrond Myklebust [NF3BLK] = S_IFBLK, 99bca79478STrond Myklebust [NF3CHR] = S_IFCHR, 100bca79478STrond Myklebust [NF3LNK] = S_IFLNK, 101bca79478STrond Myklebust [NF3SOCK] = S_IFSOCK, 102bca79478STrond Myklebust [NF3FIFO] = S_IFIFO, 1031da177e4SLinus Torvalds }; 1041da177e4SLinus Torvalds 105babddc72SBryan Schumaker static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 106babddc72SBryan Schumaker { 107babddc72SBryan Schumaker dprintk("nfs: %s: prematurely hit end of receive buffer. " 108babddc72SBryan Schumaker "Remaining buffer length is %tu words.\n", 109babddc72SBryan Schumaker func, xdr->end - xdr->p); 110babddc72SBryan Schumaker } 111babddc72SBryan Schumaker 1121da177e4SLinus Torvalds /* 113d9c407b1SChuck Lever * While encoding arguments, set up the reply buffer in advance to 114d9c407b1SChuck Lever * receive reply data directly into the page cache. 115d9c407b1SChuck Lever */ 116d9c407b1SChuck Lever static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages, 117d9c407b1SChuck Lever unsigned int base, unsigned int len, 118d9c407b1SChuck Lever unsigned int bufsize) 119d9c407b1SChuck Lever { 120d9c407b1SChuck Lever struct rpc_auth *auth = req->rq_cred->cr_auth; 121d9c407b1SChuck Lever unsigned int replen; 122d9c407b1SChuck Lever 123d9c407b1SChuck Lever replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize; 124d9c407b1SChuck Lever xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len); 125d9c407b1SChuck Lever } 126d9c407b1SChuck Lever 127d9c407b1SChuck Lever 128d9c407b1SChuck Lever /* 1291da177e4SLinus Torvalds * Common NFS XDR functions as inlines 1301da177e4SLinus Torvalds */ 131d61005a6SAl Viro static inline __be32 * 1324fdc17b2STrond Myklebust xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds return xdr_encode_array(p, fh->data, fh->size); 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds 137d61005a6SAl Viro static inline __be32 * 138d61005a6SAl Viro xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) { 1411da177e4SLinus Torvalds memcpy(fh->data, p, fh->size); 1421da177e4SLinus Torvalds return p + XDR_QUADLEN(fh->size); 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds return NULL; 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds 147babddc72SBryan Schumaker static inline __be32 * 148babddc72SBryan Schumaker xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh) 149babddc72SBryan Schumaker { 150babddc72SBryan Schumaker __be32 *p; 151babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 152babddc72SBryan Schumaker if (unlikely(!p)) 153babddc72SBryan Schumaker goto out_overflow; 154babddc72SBryan Schumaker fh->size = ntohl(*p++); 155babddc72SBryan Schumaker 156babddc72SBryan Schumaker if (fh->size <= NFS3_FHSIZE) { 157babddc72SBryan Schumaker p = xdr_inline_decode(xdr, fh->size); 158babddc72SBryan Schumaker if (unlikely(!p)) 159babddc72SBryan Schumaker goto out_overflow; 160babddc72SBryan Schumaker memcpy(fh->data, p, fh->size); 161babddc72SBryan Schumaker return p + XDR_QUADLEN(fh->size); 162babddc72SBryan Schumaker } 163babddc72SBryan Schumaker return NULL; 164babddc72SBryan Schumaker 165babddc72SBryan Schumaker out_overflow: 166babddc72SBryan Schumaker print_overflow_msg(__func__, xdr); 167babddc72SBryan Schumaker return ERR_PTR(-EIO); 168babddc72SBryan Schumaker } 169babddc72SBryan Schumaker 1701da177e4SLinus Torvalds /* 1711da177e4SLinus Torvalds * Encode/decode time. 1721da177e4SLinus Torvalds */ 173d61005a6SAl Viro static inline __be32 * 174d9c407b1SChuck Lever xdr_encode_time3(__be32 *p, const struct timespec *timep) 1751da177e4SLinus Torvalds { 1761da177e4SLinus Torvalds *p++ = htonl(timep->tv_sec); 1771da177e4SLinus Torvalds *p++ = htonl(timep->tv_nsec); 1781da177e4SLinus Torvalds return p; 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds 181d61005a6SAl Viro static inline __be32 * 182d61005a6SAl Viro xdr_decode_time3(__be32 *p, struct timespec *timep) 1831da177e4SLinus Torvalds { 1841da177e4SLinus Torvalds timep->tv_sec = ntohl(*p++); 1851da177e4SLinus Torvalds timep->tv_nsec = ntohl(*p++); 1861da177e4SLinus Torvalds return p; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 189d61005a6SAl Viro static __be32 * 190d61005a6SAl Viro xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) 1911da177e4SLinus Torvalds { 1921da177e4SLinus Torvalds unsigned int type, major, minor; 193bca79478STrond Myklebust umode_t fmode; 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds type = ntohl(*p++); 196bca79478STrond Myklebust if (type > NF3FIFO) 197bca79478STrond Myklebust type = NF3NON; 198bca79478STrond Myklebust fmode = nfs_type2fmt[type]; 1991da177e4SLinus Torvalds fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode; 2001da177e4SLinus Torvalds fattr->nlink = ntohl(*p++); 2011da177e4SLinus Torvalds fattr->uid = ntohl(*p++); 2021da177e4SLinus Torvalds fattr->gid = ntohl(*p++); 2031da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->size); 2041da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->du.nfs3.used); 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds /* Turn remote device info into Linux-specific dev_t */ 2071da177e4SLinus Torvalds major = ntohl(*p++); 2081da177e4SLinus Torvalds minor = ntohl(*p++); 2091da177e4SLinus Torvalds fattr->rdev = MKDEV(major, minor); 2101da177e4SLinus Torvalds if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor) 2111da177e4SLinus Torvalds fattr->rdev = 0; 2121da177e4SLinus Torvalds 2138b4bdcf8STrond Myklebust p = xdr_decode_hyper(p, &fattr->fsid.major); 2148b4bdcf8STrond Myklebust fattr->fsid.minor = 0; 2151da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->fileid); 2161da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->atime); 2171da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->mtime); 2181da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->ctime); 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds /* Update the mode bits */ 2219e6e70f8STrond Myklebust fattr->valid |= NFS_ATTR_FATTR_V3; 2221da177e4SLinus Torvalds return p; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 225d61005a6SAl Viro static inline __be32 * 226d9c407b1SChuck Lever xdr_encode_sattr(__be32 *p, const struct iattr *attr) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds if (attr->ia_valid & ATTR_MODE) { 2291da177e4SLinus Torvalds *p++ = xdr_one; 230cf3fff54STrond Myklebust *p++ = htonl(attr->ia_mode & S_IALLUGO); 2311da177e4SLinus Torvalds } else { 2321da177e4SLinus Torvalds *p++ = xdr_zero; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds if (attr->ia_valid & ATTR_UID) { 2351da177e4SLinus Torvalds *p++ = xdr_one; 2361da177e4SLinus Torvalds *p++ = htonl(attr->ia_uid); 2371da177e4SLinus Torvalds } else { 2381da177e4SLinus Torvalds *p++ = xdr_zero; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds if (attr->ia_valid & ATTR_GID) { 2411da177e4SLinus Torvalds *p++ = xdr_one; 2421da177e4SLinus Torvalds *p++ = htonl(attr->ia_gid); 2431da177e4SLinus Torvalds } else { 2441da177e4SLinus Torvalds *p++ = xdr_zero; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds if (attr->ia_valid & ATTR_SIZE) { 2471da177e4SLinus Torvalds *p++ = xdr_one; 2481da177e4SLinus Torvalds p = xdr_encode_hyper(p, (__u64) attr->ia_size); 2491da177e4SLinus Torvalds } else { 2501da177e4SLinus Torvalds *p++ = xdr_zero; 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds if (attr->ia_valid & ATTR_ATIME_SET) { 2531da177e4SLinus Torvalds *p++ = xdr_two; 2541da177e4SLinus Torvalds p = xdr_encode_time3(p, &attr->ia_atime); 2551da177e4SLinus Torvalds } else if (attr->ia_valid & ATTR_ATIME) { 2561da177e4SLinus Torvalds *p++ = xdr_one; 2571da177e4SLinus Torvalds } else { 2581da177e4SLinus Torvalds *p++ = xdr_zero; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds if (attr->ia_valid & ATTR_MTIME_SET) { 2611da177e4SLinus Torvalds *p++ = xdr_two; 2621da177e4SLinus Torvalds p = xdr_encode_time3(p, &attr->ia_mtime); 2631da177e4SLinus Torvalds } else if (attr->ia_valid & ATTR_MTIME) { 2641da177e4SLinus Torvalds *p++ = xdr_one; 2651da177e4SLinus Torvalds } else { 2661da177e4SLinus Torvalds *p++ = xdr_zero; 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds return p; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 271d61005a6SAl Viro static inline __be32 * 272d61005a6SAl Viro xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr) 2731da177e4SLinus Torvalds { 2741da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->pre_size); 2751da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->pre_mtime); 2761da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->pre_ctime); 2779e6e70f8STrond Myklebust fattr->valid |= NFS_ATTR_FATTR_PRESIZE 2789e6e70f8STrond Myklebust | NFS_ATTR_FATTR_PREMTIME 2799e6e70f8STrond Myklebust | NFS_ATTR_FATTR_PRECTIME; 2801da177e4SLinus Torvalds return p; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 283d61005a6SAl Viro static inline __be32 * 284d61005a6SAl Viro xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr) 2851da177e4SLinus Torvalds { 2861da177e4SLinus Torvalds if (*p++) 2871da177e4SLinus Torvalds p = xdr_decode_fattr(p, fattr); 2881da177e4SLinus Torvalds return p; 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 291d61005a6SAl Viro static inline __be32 * 292babddc72SBryan Schumaker xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr) 293babddc72SBryan Schumaker { 294babddc72SBryan Schumaker __be32 *p; 295babddc72SBryan Schumaker 296babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 297babddc72SBryan Schumaker if (unlikely(!p)) 298babddc72SBryan Schumaker goto out_overflow; 299babddc72SBryan Schumaker if (ntohl(*p++)) { 300babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 84); 301babddc72SBryan Schumaker if (unlikely(!p)) 302babddc72SBryan Schumaker goto out_overflow; 303babddc72SBryan Schumaker p = xdr_decode_fattr(p, fattr); 304babddc72SBryan Schumaker } 305babddc72SBryan Schumaker return p; 306babddc72SBryan Schumaker out_overflow: 307babddc72SBryan Schumaker print_overflow_msg(__func__, xdr); 308babddc72SBryan Schumaker return ERR_PTR(-EIO); 309babddc72SBryan Schumaker } 310babddc72SBryan Schumaker 311babddc72SBryan Schumaker static inline __be32 * 312d61005a6SAl Viro xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr) 3131da177e4SLinus Torvalds { 3141da177e4SLinus Torvalds if (*p++) 3151da177e4SLinus Torvalds return xdr_decode_wcc_attr(p, fattr); 3161da177e4SLinus Torvalds return p; 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds 320d61005a6SAl Viro static inline __be32 * 321d61005a6SAl Viro xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr) 3221da177e4SLinus Torvalds { 3231da177e4SLinus Torvalds p = xdr_decode_pre_op_attr(p, fattr); 3241da177e4SLinus Torvalds return xdr_decode_post_op_attr(p, fattr); 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 327d9c407b1SChuck Lever 328d9c407b1SChuck Lever /* 329d9c407b1SChuck Lever * Encode/decode NFSv3 basic data types 330d9c407b1SChuck Lever * 331d9c407b1SChuck Lever * Basic NFSv3 data types are defined in section 2.5 of RFC 1813: 332d9c407b1SChuck Lever * "NFS Version 3 Protocol Specification". 333d9c407b1SChuck Lever * 334d9c407b1SChuck Lever * Not all basic data types have their own encoding and decoding 335d9c407b1SChuck Lever * functions. For run-time efficiency, some data types are encoded 336d9c407b1SChuck Lever * or decoded inline. 337d9c407b1SChuck Lever */ 338d9c407b1SChuck Lever 339d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value) 340d9c407b1SChuck Lever { 341d9c407b1SChuck Lever __be32 *p = xdr_reserve_space(xdr, 4); 342d9c407b1SChuck Lever *p = cpu_to_be32(value); 343d9c407b1SChuck Lever } 344d9c407b1SChuck Lever 345d9c407b1SChuck Lever /* 346d9c407b1SChuck Lever * filename3 347d9c407b1SChuck Lever * 348d9c407b1SChuck Lever * typedef string filename3<>; 349d9c407b1SChuck Lever */ 350d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr, 351d9c407b1SChuck Lever const char *name, u32 length) 352d9c407b1SChuck Lever { 353d9c407b1SChuck Lever __be32 *p; 354d9c407b1SChuck Lever 355d9c407b1SChuck Lever BUG_ON(length > NFS3_MAXNAMLEN); 356d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + length); 357d9c407b1SChuck Lever xdr_encode_opaque(p, name, length); 358d9c407b1SChuck Lever } 359d9c407b1SChuck Lever 360d9c407b1SChuck Lever /* 361d9c407b1SChuck Lever * nfspath3 362d9c407b1SChuck Lever * 363d9c407b1SChuck Lever * typedef string nfspath3<>; 364d9c407b1SChuck Lever */ 365d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages, 366d9c407b1SChuck Lever const u32 length) 367d9c407b1SChuck Lever { 368d9c407b1SChuck Lever BUG_ON(length > NFS3_MAXPATHLEN); 369d9c407b1SChuck Lever encode_uint32(xdr, length); 370d9c407b1SChuck Lever xdr_write_pages(xdr, pages, 0, length); 371d9c407b1SChuck Lever } 372d9c407b1SChuck Lever 373d9c407b1SChuck Lever /* 374d9c407b1SChuck Lever * cookie3 375d9c407b1SChuck Lever * 376d9c407b1SChuck Lever * typedef uint64 cookie3 377d9c407b1SChuck Lever */ 378d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie) 379d9c407b1SChuck Lever { 380d9c407b1SChuck Lever return xdr_encode_hyper(p, cookie); 381d9c407b1SChuck Lever } 382d9c407b1SChuck Lever 383d9c407b1SChuck Lever /* 384d9c407b1SChuck Lever * cookieverf3 385d9c407b1SChuck Lever * 386d9c407b1SChuck Lever * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; 387d9c407b1SChuck Lever */ 388d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier) 389d9c407b1SChuck Lever { 390d9c407b1SChuck Lever memcpy(p, verifier, NFS3_COOKIEVERFSIZE); 391d9c407b1SChuck Lever return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE); 392d9c407b1SChuck Lever } 393d9c407b1SChuck Lever 394d9c407b1SChuck Lever /* 395d9c407b1SChuck Lever * createverf3 396d9c407b1SChuck Lever * 397d9c407b1SChuck Lever * typedef opaque createverf3[NFS3_CREATEVERFSIZE]; 398d9c407b1SChuck Lever */ 399d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier) 400d9c407b1SChuck Lever { 401d9c407b1SChuck Lever __be32 *p; 402d9c407b1SChuck Lever 403d9c407b1SChuck Lever p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE); 404d9c407b1SChuck Lever memcpy(p, verifier, NFS3_CREATEVERFSIZE); 405d9c407b1SChuck Lever } 406d9c407b1SChuck Lever 407d9c407b1SChuck Lever /* 408d9c407b1SChuck Lever * ftype3 409d9c407b1SChuck Lever * 410d9c407b1SChuck Lever * enum ftype3 { 411d9c407b1SChuck Lever * NF3REG = 1, 412d9c407b1SChuck Lever * NF3DIR = 2, 413d9c407b1SChuck Lever * NF3BLK = 3, 414d9c407b1SChuck Lever * NF3CHR = 4, 415d9c407b1SChuck Lever * NF3LNK = 5, 416d9c407b1SChuck Lever * NF3SOCK = 6, 417d9c407b1SChuck Lever * NF3FIFO = 7 418d9c407b1SChuck Lever * }; 419d9c407b1SChuck Lever */ 420d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type) 421d9c407b1SChuck Lever { 422d9c407b1SChuck Lever BUG_ON(type > NF3FIFO); 423d9c407b1SChuck Lever encode_uint32(xdr, type); 424d9c407b1SChuck Lever } 425d9c407b1SChuck Lever 426d9c407b1SChuck Lever /* 427d9c407b1SChuck Lever * specdata3 428d9c407b1SChuck Lever * 429d9c407b1SChuck Lever * struct specdata3 { 430d9c407b1SChuck Lever * uint32 specdata1; 431d9c407b1SChuck Lever * uint32 specdata2; 432d9c407b1SChuck Lever * }; 433d9c407b1SChuck Lever */ 434d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev) 435d9c407b1SChuck Lever { 436d9c407b1SChuck Lever __be32 *p; 437d9c407b1SChuck Lever 438d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8); 439d9c407b1SChuck Lever *p++ = cpu_to_be32(MAJOR(rdev)); 440d9c407b1SChuck Lever *p = cpu_to_be32(MINOR(rdev)); 441d9c407b1SChuck Lever } 442d9c407b1SChuck Lever 443d9c407b1SChuck Lever /* 444d9c407b1SChuck Lever * nfs_fh3 445d9c407b1SChuck Lever * 446d9c407b1SChuck Lever * struct nfs_fh3 { 447d9c407b1SChuck Lever * opaque data<NFS3_FHSIZE>; 448d9c407b1SChuck Lever * }; 449d9c407b1SChuck Lever */ 450d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh) 451d9c407b1SChuck Lever { 452d9c407b1SChuck Lever __be32 *p; 453d9c407b1SChuck Lever 454d9c407b1SChuck Lever BUG_ON(fh->size > NFS3_FHSIZE); 455d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + fh->size); 456d9c407b1SChuck Lever xdr_encode_opaque(p, fh->data, fh->size); 457d9c407b1SChuck Lever } 458d9c407b1SChuck Lever 459d9c407b1SChuck Lever /* 460d9c407b1SChuck Lever * sattr3 461d9c407b1SChuck Lever * 462d9c407b1SChuck Lever * enum time_how { 463d9c407b1SChuck Lever * DONT_CHANGE = 0, 464d9c407b1SChuck Lever * SET_TO_SERVER_TIME = 1, 465d9c407b1SChuck Lever * SET_TO_CLIENT_TIME = 2 466d9c407b1SChuck Lever * }; 467d9c407b1SChuck Lever * 468d9c407b1SChuck Lever * union set_mode3 switch (bool set_it) { 469d9c407b1SChuck Lever * case TRUE: 470d9c407b1SChuck Lever * mode3 mode; 471d9c407b1SChuck Lever * default: 472d9c407b1SChuck Lever * void; 473d9c407b1SChuck Lever * }; 474d9c407b1SChuck Lever * 475d9c407b1SChuck Lever * union set_uid3 switch (bool set_it) { 476d9c407b1SChuck Lever * case TRUE: 477d9c407b1SChuck Lever * uid3 uid; 478d9c407b1SChuck Lever * default: 479d9c407b1SChuck Lever * void; 480d9c407b1SChuck Lever * }; 481d9c407b1SChuck Lever * 482d9c407b1SChuck Lever * union set_gid3 switch (bool set_it) { 483d9c407b1SChuck Lever * case TRUE: 484d9c407b1SChuck Lever * gid3 gid; 485d9c407b1SChuck Lever * default: 486d9c407b1SChuck Lever * void; 487d9c407b1SChuck Lever * }; 488d9c407b1SChuck Lever * 489d9c407b1SChuck Lever * union set_size3 switch (bool set_it) { 490d9c407b1SChuck Lever * case TRUE: 491d9c407b1SChuck Lever * size3 size; 492d9c407b1SChuck Lever * default: 493d9c407b1SChuck Lever * void; 494d9c407b1SChuck Lever * }; 495d9c407b1SChuck Lever * 496d9c407b1SChuck Lever * union set_atime switch (time_how set_it) { 497d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 498d9c407b1SChuck Lever * nfstime3 atime; 499d9c407b1SChuck Lever * default: 500d9c407b1SChuck Lever * void; 501d9c407b1SChuck Lever * }; 502d9c407b1SChuck Lever * 503d9c407b1SChuck Lever * union set_mtime switch (time_how set_it) { 504d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 505d9c407b1SChuck Lever * nfstime3 mtime; 506d9c407b1SChuck Lever * default: 507d9c407b1SChuck Lever * void; 508d9c407b1SChuck Lever * }; 509d9c407b1SChuck Lever * 510d9c407b1SChuck Lever * struct sattr3 { 511d9c407b1SChuck Lever * set_mode3 mode; 512d9c407b1SChuck Lever * set_uid3 uid; 513d9c407b1SChuck Lever * set_gid3 gid; 514d9c407b1SChuck Lever * set_size3 size; 515d9c407b1SChuck Lever * set_atime atime; 516d9c407b1SChuck Lever * set_mtime mtime; 517d9c407b1SChuck Lever * }; 518d9c407b1SChuck Lever */ 519d9c407b1SChuck Lever static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr) 520d9c407b1SChuck Lever { 521d9c407b1SChuck Lever u32 nbytes; 522d9c407b1SChuck Lever __be32 *p; 523d9c407b1SChuck Lever 524d9c407b1SChuck Lever /* 525d9c407b1SChuck Lever * In order to make only a single xdr_reserve_space() call, 526d9c407b1SChuck Lever * pre-compute the total number of bytes to be reserved. 527d9c407b1SChuck Lever * Six boolean values, one for each set_foo field, are always 528d9c407b1SChuck Lever * present in the encoded result, so start there. 529d9c407b1SChuck Lever */ 530d9c407b1SChuck Lever nbytes = 6 * 4; 531d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MODE) 532d9c407b1SChuck Lever nbytes += 4; 533d9c407b1SChuck Lever if (attr->ia_valid & ATTR_UID) 534d9c407b1SChuck Lever nbytes += 4; 535d9c407b1SChuck Lever if (attr->ia_valid & ATTR_GID) 536d9c407b1SChuck Lever nbytes += 4; 537d9c407b1SChuck Lever if (attr->ia_valid & ATTR_SIZE) 538d9c407b1SChuck Lever nbytes += 8; 539d9c407b1SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) 540d9c407b1SChuck Lever nbytes += 8; 541d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) 542d9c407b1SChuck Lever nbytes += 8; 543d9c407b1SChuck Lever p = xdr_reserve_space(xdr, nbytes); 544d9c407b1SChuck Lever 545d9c407b1SChuck Lever xdr_encode_sattr(p, attr); 546d9c407b1SChuck Lever } 547d9c407b1SChuck Lever 548d9c407b1SChuck Lever /* 549d9c407b1SChuck Lever * diropargs3 550d9c407b1SChuck Lever * 551d9c407b1SChuck Lever * struct diropargs3 { 552d9c407b1SChuck Lever * nfs_fh3 dir; 553d9c407b1SChuck Lever * filename3 name; 554d9c407b1SChuck Lever * }; 555d9c407b1SChuck Lever */ 556d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh, 557d9c407b1SChuck Lever const char *name, u32 length) 558d9c407b1SChuck Lever { 559d9c407b1SChuck Lever encode_nfs_fh3(xdr, fh); 560d9c407b1SChuck Lever encode_filename3(xdr, name, length); 561d9c407b1SChuck Lever } 562d9c407b1SChuck Lever 563d9c407b1SChuck Lever 5641da177e4SLinus Torvalds /* 5651da177e4SLinus Torvalds * NFS encode functions 5661da177e4SLinus Torvalds */ 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds /* 5691da177e4SLinus Torvalds * Encode file handle argument 5701da177e4SLinus Torvalds */ 5711da177e4SLinus Torvalds static int 572d61005a6SAl Viro nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh) 5731da177e4SLinus Torvalds { 5741da177e4SLinus Torvalds p = xdr_encode_fhandle(p, fh); 5751da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 5761da177e4SLinus Torvalds return 0; 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds /* 580d9c407b1SChuck Lever * 3.3.1 GETATTR3args 581d9c407b1SChuck Lever * 582d9c407b1SChuck Lever * struct GETATTR3args { 583d9c407b1SChuck Lever * nfs_fh3 object; 584d9c407b1SChuck Lever * }; 585d9c407b1SChuck Lever */ 586d9c407b1SChuck Lever static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p, 587d9c407b1SChuck Lever const struct nfs_fh *fh) 588d9c407b1SChuck Lever { 589d9c407b1SChuck Lever struct xdr_stream xdr; 590d9c407b1SChuck Lever 591d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 592d9c407b1SChuck Lever encode_nfs_fh3(&xdr, fh); 593d9c407b1SChuck Lever return 0; 594d9c407b1SChuck Lever } 595d9c407b1SChuck Lever 596d9c407b1SChuck Lever /* 5971da177e4SLinus Torvalds * Encode SETATTR arguments 5981da177e4SLinus Torvalds */ 5991da177e4SLinus Torvalds static int 600d61005a6SAl Viro nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args) 6011da177e4SLinus Torvalds { 6021da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 6031da177e4SLinus Torvalds p = xdr_encode_sattr(p, args->sattr); 6041da177e4SLinus Torvalds *p++ = htonl(args->guard); 6051da177e4SLinus Torvalds if (args->guard) 6061da177e4SLinus Torvalds p = xdr_encode_time3(p, &args->guardtime); 6071da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 6081da177e4SLinus Torvalds return 0; 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds /* 612d9c407b1SChuck Lever * 3.3.2 SETATTR3args 613d9c407b1SChuck Lever * 614d9c407b1SChuck Lever * union sattrguard3 switch (bool check) { 615d9c407b1SChuck Lever * case TRUE: 616d9c407b1SChuck Lever * nfstime3 obj_ctime; 617d9c407b1SChuck Lever * case FALSE: 618d9c407b1SChuck Lever * void; 619d9c407b1SChuck Lever * }; 620d9c407b1SChuck Lever * 621d9c407b1SChuck Lever * struct SETATTR3args { 622d9c407b1SChuck Lever * nfs_fh3 object; 623d9c407b1SChuck Lever * sattr3 new_attributes; 624d9c407b1SChuck Lever * sattrguard3 guard; 625d9c407b1SChuck Lever * }; 626d9c407b1SChuck Lever */ 627d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr, 628d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 629d9c407b1SChuck Lever { 630d9c407b1SChuck Lever __be32 *p; 631d9c407b1SChuck Lever 632d9c407b1SChuck Lever if (args->guard) { 633d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + 8); 634d9c407b1SChuck Lever *p++ = xdr_one; 635d9c407b1SChuck Lever xdr_encode_time3(p, &args->guardtime); 636d9c407b1SChuck Lever } else { 637d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4); 638d9c407b1SChuck Lever *p = xdr_zero; 639d9c407b1SChuck Lever } 640d9c407b1SChuck Lever } 641d9c407b1SChuck Lever 642d9c407b1SChuck Lever static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p, 643d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 644d9c407b1SChuck Lever { 645d9c407b1SChuck Lever struct xdr_stream xdr; 646d9c407b1SChuck Lever 647d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 648d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fh); 649d9c407b1SChuck Lever encode_sattr3(&xdr, args->sattr); 650d9c407b1SChuck Lever encode_sattrguard3(&xdr, args); 651d9c407b1SChuck Lever return 0; 652d9c407b1SChuck Lever } 653d9c407b1SChuck Lever 654d9c407b1SChuck Lever /* 6551da177e4SLinus Torvalds * Encode directory ops argument 6561da177e4SLinus Torvalds */ 6571da177e4SLinus Torvalds static int 658d61005a6SAl Viro nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args) 6591da177e4SLinus Torvalds { 6601da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 6611da177e4SLinus Torvalds p = xdr_encode_array(p, args->name, args->len); 6621da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 6631da177e4SLinus Torvalds return 0; 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds /* 667d9c407b1SChuck Lever * 3.3.3 LOOKUP3args 668d9c407b1SChuck Lever * 669d9c407b1SChuck Lever * struct LOOKUP3args { 670d9c407b1SChuck Lever * diropargs3 what; 671d9c407b1SChuck Lever * }; 672d9c407b1SChuck Lever */ 673d9c407b1SChuck Lever static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p, 674d9c407b1SChuck Lever const struct nfs3_diropargs *args) 675d9c407b1SChuck Lever { 676d9c407b1SChuck Lever struct xdr_stream xdr; 677d9c407b1SChuck Lever 678d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 679d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 680d9c407b1SChuck Lever return 0; 681d9c407b1SChuck Lever } 682d9c407b1SChuck Lever 683d9c407b1SChuck Lever /* 6844fdc17b2STrond Myklebust * Encode REMOVE argument 6854fdc17b2STrond Myklebust */ 6864fdc17b2STrond Myklebust static int 6874fdc17b2STrond Myklebust nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args) 6884fdc17b2STrond Myklebust { 6894fdc17b2STrond Myklebust p = xdr_encode_fhandle(p, args->fh); 6904fdc17b2STrond Myklebust p = xdr_encode_array(p, args->name.name, args->name.len); 6914fdc17b2STrond Myklebust req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 6924fdc17b2STrond Myklebust return 0; 6934fdc17b2STrond Myklebust } 6944fdc17b2STrond Myklebust 6954fdc17b2STrond Myklebust /* 6961da177e4SLinus Torvalds * Encode access() argument 6971da177e4SLinus Torvalds */ 6981da177e4SLinus Torvalds static int 699d61005a6SAl Viro nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args) 7001da177e4SLinus Torvalds { 7011da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 7021da177e4SLinus Torvalds *p++ = htonl(args->access); 7031da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 7041da177e4SLinus Torvalds return 0; 7051da177e4SLinus Torvalds } 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds /* 708d9c407b1SChuck Lever * 3.3.4 ACCESS3args 709d9c407b1SChuck Lever * 710d9c407b1SChuck Lever * struct ACCESS3args { 711d9c407b1SChuck Lever * nfs_fh3 object; 712d9c407b1SChuck Lever * uint32 access; 713d9c407b1SChuck Lever * }; 714d9c407b1SChuck Lever */ 715d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr, 716d9c407b1SChuck Lever const struct nfs3_accessargs *args) 717d9c407b1SChuck Lever { 718d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 719d9c407b1SChuck Lever encode_uint32(xdr, args->access); 720d9c407b1SChuck Lever } 721d9c407b1SChuck Lever 722d9c407b1SChuck Lever static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p, 723d9c407b1SChuck Lever const struct nfs3_accessargs *args) 724d9c407b1SChuck Lever { 725d9c407b1SChuck Lever struct xdr_stream xdr; 726d9c407b1SChuck Lever 727d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 728d9c407b1SChuck Lever encode_access3args(&xdr, args); 729d9c407b1SChuck Lever return 0; 730d9c407b1SChuck Lever } 731d9c407b1SChuck Lever 732d9c407b1SChuck Lever /* 733d9c407b1SChuck Lever * 3.3.5 READLINK3args 734d9c407b1SChuck Lever * 735d9c407b1SChuck Lever * struct READLINK3args { 736d9c407b1SChuck Lever * nfs_fh3 symlink; 737d9c407b1SChuck Lever * }; 738d9c407b1SChuck Lever */ 739d9c407b1SChuck Lever static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p, 740d9c407b1SChuck Lever const struct nfs3_readlinkargs *args) 741d9c407b1SChuck Lever { 742d9c407b1SChuck Lever struct xdr_stream xdr; 743d9c407b1SChuck Lever 744d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 745d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fh); 746d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 747d9c407b1SChuck Lever args->pglen, NFS3_readlinkres_sz); 748d9c407b1SChuck Lever return 0; 749d9c407b1SChuck Lever } 750d9c407b1SChuck Lever 751d9c407b1SChuck Lever /* 7521da177e4SLinus Torvalds * Arguments to a READ call. Since we read data directly into the page 7531da177e4SLinus Torvalds * cache, we also set up the reply iovec here so that iov[1] points 7541da177e4SLinus Torvalds * exactly to the page we want to fetch. 7551da177e4SLinus Torvalds */ 7561da177e4SLinus Torvalds static int 757d61005a6SAl Viro nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) 7581da177e4SLinus Torvalds { 759a17c2153STrond Myklebust struct rpc_auth *auth = req->rq_cred->cr_auth; 7601da177e4SLinus Torvalds unsigned int replen; 7611da177e4SLinus Torvalds u32 count = args->count; 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 7641da177e4SLinus Torvalds p = xdr_encode_hyper(p, args->offset); 7651da177e4SLinus Torvalds *p++ = htonl(count); 7661da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds /* Inline the page array */ 7691da177e4SLinus Torvalds replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2; 7701da177e4SLinus Torvalds xdr_inline_pages(&req->rq_rcv_buf, replen, 7711da177e4SLinus Torvalds args->pages, args->pgbase, count); 7724f22ccc3S\"Talpey, Thomas\ req->rq_rcv_buf.flags |= XDRBUF_READ; 7731da177e4SLinus Torvalds return 0; 7741da177e4SLinus Torvalds } 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds /* 777d9c407b1SChuck Lever * 3.3.6 READ3args 778d9c407b1SChuck Lever * 779d9c407b1SChuck Lever * struct READ3args { 780d9c407b1SChuck Lever * nfs_fh3 file; 781d9c407b1SChuck Lever * offset3 offset; 782d9c407b1SChuck Lever * count3 count; 783d9c407b1SChuck Lever * }; 784d9c407b1SChuck Lever */ 785d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr, 786d9c407b1SChuck Lever const struct nfs_readargs *args) 787d9c407b1SChuck Lever { 788d9c407b1SChuck Lever __be32 *p; 789d9c407b1SChuck Lever 790d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 791d9c407b1SChuck Lever 792d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 793d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 794d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 795d9c407b1SChuck Lever } 796d9c407b1SChuck Lever 797d9c407b1SChuck Lever static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p, 798d9c407b1SChuck Lever const struct nfs_readargs *args) 799d9c407b1SChuck Lever { 800d9c407b1SChuck Lever struct xdr_stream xdr; 801d9c407b1SChuck Lever 802d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 803d9c407b1SChuck Lever encode_read3args(&xdr, args); 804d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 805d9c407b1SChuck Lever args->count, NFS3_readres_sz); 806d9c407b1SChuck Lever req->rq_rcv_buf.flags |= XDRBUF_READ; 807d9c407b1SChuck Lever return 0; 808d9c407b1SChuck Lever } 809d9c407b1SChuck Lever 810d9c407b1SChuck Lever /* 8111da177e4SLinus Torvalds * Write arguments. Splice the buffer to be written into the iovec. 8121da177e4SLinus Torvalds */ 8131da177e4SLinus Torvalds static int 814d61005a6SAl Viro nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) 8151da177e4SLinus Torvalds { 8161da177e4SLinus Torvalds struct xdr_buf *sndbuf = &req->rq_snd_buf; 8171da177e4SLinus Torvalds u32 count = args->count; 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 8201da177e4SLinus Torvalds p = xdr_encode_hyper(p, args->offset); 8211da177e4SLinus Torvalds *p++ = htonl(count); 8221da177e4SLinus Torvalds *p++ = htonl(args->stable); 8231da177e4SLinus Torvalds *p++ = htonl(count); 8241da177e4SLinus Torvalds sndbuf->len = xdr_adjust_iovec(sndbuf->head, p); 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds /* Copy the page array */ 8271da177e4SLinus Torvalds xdr_encode_pages(sndbuf, args->pages, args->pgbase, count); 8284f22ccc3S\"Talpey, Thomas\ sndbuf->flags |= XDRBUF_WRITE; 8291da177e4SLinus Torvalds return 0; 8301da177e4SLinus Torvalds } 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds /* 833d9c407b1SChuck Lever * 3.3.7 WRITE3args 834d9c407b1SChuck Lever * 835d9c407b1SChuck Lever * enum stable_how { 836d9c407b1SChuck Lever * UNSTABLE = 0, 837d9c407b1SChuck Lever * DATA_SYNC = 1, 838d9c407b1SChuck Lever * FILE_SYNC = 2 839d9c407b1SChuck Lever * }; 840d9c407b1SChuck Lever * 841d9c407b1SChuck Lever * struct WRITE3args { 842d9c407b1SChuck Lever * nfs_fh3 file; 843d9c407b1SChuck Lever * offset3 offset; 844d9c407b1SChuck Lever * count3 count; 845d9c407b1SChuck Lever * stable_how stable; 846d9c407b1SChuck Lever * opaque data<>; 847d9c407b1SChuck Lever * }; 848d9c407b1SChuck Lever */ 849d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr, 850d9c407b1SChuck Lever const struct nfs_writeargs *args) 851d9c407b1SChuck Lever { 852d9c407b1SChuck Lever __be32 *p; 853d9c407b1SChuck Lever 854d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 855d9c407b1SChuck Lever 856d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4); 857d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 858d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count); 859d9c407b1SChuck Lever 860d9c407b1SChuck Lever BUG_ON(args->stable > NFS_FILE_SYNC); 861d9c407b1SChuck Lever *p++ = cpu_to_be32(args->stable); 862d9c407b1SChuck Lever 863d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 864d9c407b1SChuck Lever xdr_write_pages(xdr, args->pages, args->pgbase, args->count); 865d9c407b1SChuck Lever } 866d9c407b1SChuck Lever 867d9c407b1SChuck Lever static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p, 868d9c407b1SChuck Lever const struct nfs_writeargs *args) 869d9c407b1SChuck Lever { 870d9c407b1SChuck Lever struct xdr_stream xdr; 871d9c407b1SChuck Lever 872d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 873d9c407b1SChuck Lever encode_write3args(&xdr, args); 874d9c407b1SChuck Lever xdr.buf->flags |= XDRBUF_WRITE; 875d9c407b1SChuck Lever return 0; 876d9c407b1SChuck Lever } 877d9c407b1SChuck Lever 878d9c407b1SChuck Lever /* 8791da177e4SLinus Torvalds * Encode CREATE arguments 8801da177e4SLinus Torvalds */ 8811da177e4SLinus Torvalds static int 882d61005a6SAl Viro nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args) 8831da177e4SLinus Torvalds { 8841da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 8851da177e4SLinus Torvalds p = xdr_encode_array(p, args->name, args->len); 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds *p++ = htonl(args->createmode); 8881da177e4SLinus Torvalds if (args->createmode == NFS3_CREATE_EXCLUSIVE) { 8891da177e4SLinus Torvalds *p++ = args->verifier[0]; 8901da177e4SLinus Torvalds *p++ = args->verifier[1]; 8911da177e4SLinus Torvalds } else 8921da177e4SLinus Torvalds p = xdr_encode_sattr(p, args->sattr); 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 8951da177e4SLinus Torvalds return 0; 8961da177e4SLinus Torvalds } 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds /* 899d9c407b1SChuck Lever * 3.3.8 CREATE3args 900d9c407b1SChuck Lever * 901d9c407b1SChuck Lever * enum createmode3 { 902d9c407b1SChuck Lever * UNCHECKED = 0, 903d9c407b1SChuck Lever * GUARDED = 1, 904d9c407b1SChuck Lever * EXCLUSIVE = 2 905d9c407b1SChuck Lever * }; 906d9c407b1SChuck Lever * 907d9c407b1SChuck Lever * union createhow3 switch (createmode3 mode) { 908d9c407b1SChuck Lever * case UNCHECKED: 909d9c407b1SChuck Lever * case GUARDED: 910d9c407b1SChuck Lever * sattr3 obj_attributes; 911d9c407b1SChuck Lever * case EXCLUSIVE: 912d9c407b1SChuck Lever * createverf3 verf; 913d9c407b1SChuck Lever * }; 914d9c407b1SChuck Lever * 915d9c407b1SChuck Lever * struct CREATE3args { 916d9c407b1SChuck Lever * diropargs3 where; 917d9c407b1SChuck Lever * createhow3 how; 918d9c407b1SChuck Lever * }; 919d9c407b1SChuck Lever */ 920d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr, 921d9c407b1SChuck Lever const struct nfs3_createargs *args) 922d9c407b1SChuck Lever { 923d9c407b1SChuck Lever encode_uint32(xdr, args->createmode); 924d9c407b1SChuck Lever switch (args->createmode) { 925d9c407b1SChuck Lever case NFS3_CREATE_UNCHECKED: 926d9c407b1SChuck Lever case NFS3_CREATE_GUARDED: 927d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 928d9c407b1SChuck Lever break; 929d9c407b1SChuck Lever case NFS3_CREATE_EXCLUSIVE: 930d9c407b1SChuck Lever encode_createverf3(xdr, args->verifier); 931d9c407b1SChuck Lever break; 932d9c407b1SChuck Lever default: 933d9c407b1SChuck Lever BUG(); 934d9c407b1SChuck Lever } 935d9c407b1SChuck Lever } 936d9c407b1SChuck Lever 937d9c407b1SChuck Lever static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p, 938d9c407b1SChuck Lever const struct nfs3_createargs *args) 939d9c407b1SChuck Lever { 940d9c407b1SChuck Lever struct xdr_stream xdr; 941d9c407b1SChuck Lever 942d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 943d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 944d9c407b1SChuck Lever encode_createhow3(&xdr, args); 945d9c407b1SChuck Lever return 0; 946d9c407b1SChuck Lever } 947d9c407b1SChuck Lever 948d9c407b1SChuck Lever /* 9491da177e4SLinus Torvalds * Encode MKDIR arguments 9501da177e4SLinus Torvalds */ 9511da177e4SLinus Torvalds static int 952d61005a6SAl Viro nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args) 9531da177e4SLinus Torvalds { 9541da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 9551da177e4SLinus Torvalds p = xdr_encode_array(p, args->name, args->len); 9561da177e4SLinus Torvalds p = xdr_encode_sattr(p, args->sattr); 9571da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 9581da177e4SLinus Torvalds return 0; 9591da177e4SLinus Torvalds } 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds /* 962d9c407b1SChuck Lever * 3.3.9 MKDIR3args 963d9c407b1SChuck Lever * 964d9c407b1SChuck Lever * struct MKDIR3args { 965d9c407b1SChuck Lever * diropargs3 where; 966d9c407b1SChuck Lever * sattr3 attributes; 967d9c407b1SChuck Lever * }; 968d9c407b1SChuck Lever */ 969d9c407b1SChuck Lever static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p, 970d9c407b1SChuck Lever const struct nfs3_mkdirargs *args) 971d9c407b1SChuck Lever { 972d9c407b1SChuck Lever struct xdr_stream xdr; 973d9c407b1SChuck Lever 974d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 975d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 976d9c407b1SChuck Lever encode_sattr3(&xdr, args->sattr); 977d9c407b1SChuck Lever return 0; 978d9c407b1SChuck Lever } 979d9c407b1SChuck Lever 980d9c407b1SChuck Lever /* 9811da177e4SLinus Torvalds * Encode SYMLINK arguments 9821da177e4SLinus Torvalds */ 9831da177e4SLinus Torvalds static int 984d61005a6SAl Viro nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args) 9851da177e4SLinus Torvalds { 9861da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fromfh); 9871da177e4SLinus Torvalds p = xdr_encode_array(p, args->fromname, args->fromlen); 9881da177e4SLinus Torvalds p = xdr_encode_sattr(p, args->sattr); 98994a6d753SChuck Lever *p++ = htonl(args->pathlen); 9901da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 99194a6d753SChuck Lever 99294a6d753SChuck Lever /* Copy the page */ 99394a6d753SChuck Lever xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen); 9941da177e4SLinus Torvalds return 0; 9951da177e4SLinus Torvalds } 9961da177e4SLinus Torvalds 9971da177e4SLinus Torvalds /* 998d9c407b1SChuck Lever * 3.3.10 SYMLINK3args 999d9c407b1SChuck Lever * 1000d9c407b1SChuck Lever * struct symlinkdata3 { 1001d9c407b1SChuck Lever * sattr3 symlink_attributes; 1002d9c407b1SChuck Lever * nfspath3 symlink_data; 1003d9c407b1SChuck Lever * }; 1004d9c407b1SChuck Lever * 1005d9c407b1SChuck Lever * struct SYMLINK3args { 1006d9c407b1SChuck Lever * diropargs3 where; 1007d9c407b1SChuck Lever * symlinkdata3 symlink; 1008d9c407b1SChuck Lever * }; 1009d9c407b1SChuck Lever */ 1010d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr, 1011d9c407b1SChuck Lever const struct nfs3_symlinkargs *args) 1012d9c407b1SChuck Lever { 1013d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1014d9c407b1SChuck Lever encode_nfspath3(xdr, args->pages, args->pathlen); 1015d9c407b1SChuck Lever } 1016d9c407b1SChuck Lever 1017d9c407b1SChuck Lever static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p, 1018d9c407b1SChuck Lever const struct nfs3_symlinkargs *args) 1019d9c407b1SChuck Lever { 1020d9c407b1SChuck Lever struct xdr_stream xdr; 1021d9c407b1SChuck Lever 1022d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1023d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen); 1024d9c407b1SChuck Lever encode_symlinkdata3(&xdr, args); 1025d9c407b1SChuck Lever return 0; 1026d9c407b1SChuck Lever } 1027d9c407b1SChuck Lever 1028d9c407b1SChuck Lever /* 10291da177e4SLinus Torvalds * Encode MKNOD arguments 10301da177e4SLinus Torvalds */ 10311da177e4SLinus Torvalds static int 1032d61005a6SAl Viro nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args) 10331da177e4SLinus Torvalds { 10341da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 10351da177e4SLinus Torvalds p = xdr_encode_array(p, args->name, args->len); 10361da177e4SLinus Torvalds *p++ = htonl(args->type); 10371da177e4SLinus Torvalds p = xdr_encode_sattr(p, args->sattr); 10381da177e4SLinus Torvalds if (args->type == NF3CHR || args->type == NF3BLK) { 10391da177e4SLinus Torvalds *p++ = htonl(MAJOR(args->rdev)); 10401da177e4SLinus Torvalds *p++ = htonl(MINOR(args->rdev)); 10411da177e4SLinus Torvalds } 10421da177e4SLinus Torvalds 10431da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 10441da177e4SLinus Torvalds return 0; 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds 10471da177e4SLinus Torvalds /* 1048d9c407b1SChuck Lever * 3.3.11 MKNOD3args 1049d9c407b1SChuck Lever * 1050d9c407b1SChuck Lever * struct devicedata3 { 1051d9c407b1SChuck Lever * sattr3 dev_attributes; 1052d9c407b1SChuck Lever * specdata3 spec; 1053d9c407b1SChuck Lever * }; 1054d9c407b1SChuck Lever * 1055d9c407b1SChuck Lever * union mknoddata3 switch (ftype3 type) { 1056d9c407b1SChuck Lever * case NF3CHR: 1057d9c407b1SChuck Lever * case NF3BLK: 1058d9c407b1SChuck Lever * devicedata3 device; 1059d9c407b1SChuck Lever * case NF3SOCK: 1060d9c407b1SChuck Lever * case NF3FIFO: 1061d9c407b1SChuck Lever * sattr3 pipe_attributes; 1062d9c407b1SChuck Lever * default: 1063d9c407b1SChuck Lever * void; 1064d9c407b1SChuck Lever * }; 1065d9c407b1SChuck Lever * 1066d9c407b1SChuck Lever * struct MKNOD3args { 1067d9c407b1SChuck Lever * diropargs3 where; 1068d9c407b1SChuck Lever * mknoddata3 what; 1069d9c407b1SChuck Lever * }; 1070d9c407b1SChuck Lever */ 1071d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr, 1072d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1073d9c407b1SChuck Lever { 1074d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1075d9c407b1SChuck Lever encode_specdata3(xdr, args->rdev); 1076d9c407b1SChuck Lever } 1077d9c407b1SChuck Lever 1078d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr, 1079d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1080d9c407b1SChuck Lever { 1081d9c407b1SChuck Lever encode_ftype3(xdr, args->type); 1082d9c407b1SChuck Lever switch (args->type) { 1083d9c407b1SChuck Lever case NF3CHR: 1084d9c407b1SChuck Lever case NF3BLK: 1085d9c407b1SChuck Lever encode_devicedata3(xdr, args); 1086d9c407b1SChuck Lever break; 1087d9c407b1SChuck Lever case NF3SOCK: 1088d9c407b1SChuck Lever case NF3FIFO: 1089d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1090d9c407b1SChuck Lever break; 1091d9c407b1SChuck Lever case NF3REG: 1092d9c407b1SChuck Lever case NF3DIR: 1093d9c407b1SChuck Lever break; 1094d9c407b1SChuck Lever default: 1095d9c407b1SChuck Lever BUG(); 1096d9c407b1SChuck Lever } 1097d9c407b1SChuck Lever } 1098d9c407b1SChuck Lever 1099d9c407b1SChuck Lever static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p, 1100d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1101d9c407b1SChuck Lever { 1102d9c407b1SChuck Lever struct xdr_stream xdr; 1103d9c407b1SChuck Lever 1104d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1105d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 1106d9c407b1SChuck Lever encode_mknoddata3(&xdr, args); 1107d9c407b1SChuck Lever return 0; 1108d9c407b1SChuck Lever } 1109d9c407b1SChuck Lever 1110d9c407b1SChuck Lever /* 1111d9c407b1SChuck Lever * 3.3.12 REMOVE3args 1112d9c407b1SChuck Lever * 1113d9c407b1SChuck Lever * struct REMOVE3args { 1114d9c407b1SChuck Lever * diropargs3 object; 1115d9c407b1SChuck Lever * }; 1116d9c407b1SChuck Lever */ 1117d9c407b1SChuck Lever static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p, 1118d9c407b1SChuck Lever const struct nfs_removeargs *args) 1119d9c407b1SChuck Lever { 1120d9c407b1SChuck Lever struct xdr_stream xdr; 1121d9c407b1SChuck Lever 1122d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1123d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len); 1124d9c407b1SChuck Lever return 0; 1125d9c407b1SChuck Lever } 1126d9c407b1SChuck Lever 1127d9c407b1SChuck Lever /* 11281da177e4SLinus Torvalds * Encode RENAME arguments 11291da177e4SLinus Torvalds */ 11301da177e4SLinus Torvalds static int 1131920769f0SJeff Layton nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args) 11321da177e4SLinus Torvalds { 1133920769f0SJeff Layton p = xdr_encode_fhandle(p, args->old_dir); 1134920769f0SJeff Layton p = xdr_encode_array(p, args->old_name->name, args->old_name->len); 1135920769f0SJeff Layton p = xdr_encode_fhandle(p, args->new_dir); 1136920769f0SJeff Layton p = xdr_encode_array(p, args->new_name->name, args->new_name->len); 11371da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 11381da177e4SLinus Torvalds return 0; 11391da177e4SLinus Torvalds } 11401da177e4SLinus Torvalds 11411da177e4SLinus Torvalds /* 1142d9c407b1SChuck Lever * 3.3.14 RENAME3args 1143d9c407b1SChuck Lever * 1144d9c407b1SChuck Lever * struct RENAME3args { 1145d9c407b1SChuck Lever * diropargs3 from; 1146d9c407b1SChuck Lever * diropargs3 to; 1147d9c407b1SChuck Lever * }; 1148d9c407b1SChuck Lever */ 1149d9c407b1SChuck Lever static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p, 1150d9c407b1SChuck Lever const struct nfs_renameargs *args) 1151d9c407b1SChuck Lever { 1152d9c407b1SChuck Lever const struct qstr *old = args->old_name; 1153d9c407b1SChuck Lever const struct qstr *new = args->new_name; 1154d9c407b1SChuck Lever struct xdr_stream xdr; 1155d9c407b1SChuck Lever 1156d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1157d9c407b1SChuck Lever encode_diropargs3(&xdr, args->old_dir, old->name, old->len); 1158d9c407b1SChuck Lever encode_diropargs3(&xdr, args->new_dir, new->name, new->len); 1159d9c407b1SChuck Lever return 0; 1160d9c407b1SChuck Lever } 1161d9c407b1SChuck Lever 1162d9c407b1SChuck Lever /* 11631da177e4SLinus Torvalds * Encode LINK arguments 11641da177e4SLinus Torvalds */ 11651da177e4SLinus Torvalds static int 1166d61005a6SAl Viro nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args) 11671da177e4SLinus Torvalds { 11681da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fromfh); 11691da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->tofh); 11701da177e4SLinus Torvalds p = xdr_encode_array(p, args->toname, args->tolen); 11711da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 11721da177e4SLinus Torvalds return 0; 11731da177e4SLinus Torvalds } 11741da177e4SLinus Torvalds 11751da177e4SLinus Torvalds /* 1176d9c407b1SChuck Lever * 3.3.15 LINK3args 1177d9c407b1SChuck Lever * 1178d9c407b1SChuck Lever * struct LINK3args { 1179d9c407b1SChuck Lever * nfs_fh3 file; 1180d9c407b1SChuck Lever * diropargs3 link; 1181d9c407b1SChuck Lever * }; 1182d9c407b1SChuck Lever */ 1183d9c407b1SChuck Lever static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p, 1184d9c407b1SChuck Lever const struct nfs3_linkargs *args) 1185d9c407b1SChuck Lever { 1186d9c407b1SChuck Lever struct xdr_stream xdr; 1187d9c407b1SChuck Lever 1188d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1189d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fromfh); 1190d9c407b1SChuck Lever encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen); 1191d9c407b1SChuck Lever return 0; 1192d9c407b1SChuck Lever } 1193d9c407b1SChuck Lever 1194d9c407b1SChuck Lever /* 11951da177e4SLinus Torvalds * Encode arguments to readdir call 11961da177e4SLinus Torvalds */ 11971da177e4SLinus Torvalds static int 1198d61005a6SAl Viro nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args) 11991da177e4SLinus Torvalds { 1200a17c2153STrond Myklebust struct rpc_auth *auth = req->rq_cred->cr_auth; 12011da177e4SLinus Torvalds unsigned int replen; 12021da177e4SLinus Torvalds u32 count = args->count; 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 12051da177e4SLinus Torvalds p = xdr_encode_hyper(p, args->cookie); 12061da177e4SLinus Torvalds *p++ = args->verf[0]; 12071da177e4SLinus Torvalds *p++ = args->verf[1]; 12081da177e4SLinus Torvalds if (args->plus) { 12091da177e4SLinus Torvalds /* readdirplus: need dircount + buffer size. 12101da177e4SLinus Torvalds * We just make sure we make dircount big enough */ 12111da177e4SLinus Torvalds *p++ = htonl(count >> 3); 12121da177e4SLinus Torvalds } 12131da177e4SLinus Torvalds *p++ = htonl(count); 12141da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds /* Inline the page array */ 12171da177e4SLinus Torvalds replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2; 12181da177e4SLinus Torvalds xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count); 12191da177e4SLinus Torvalds return 0; 12201da177e4SLinus Torvalds } 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds /* 1223d9c407b1SChuck Lever * 3.3.16 READDIR3args 1224d9c407b1SChuck Lever * 1225d9c407b1SChuck Lever * struct READDIR3args { 1226d9c407b1SChuck Lever * nfs_fh3 dir; 1227d9c407b1SChuck Lever * cookie3 cookie; 1228d9c407b1SChuck Lever * cookieverf3 cookieverf; 1229d9c407b1SChuck Lever * count3 count; 1230d9c407b1SChuck Lever * }; 1231d9c407b1SChuck Lever */ 1232d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr, 1233d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1234d9c407b1SChuck Lever { 1235d9c407b1SChuck Lever __be32 *p; 1236d9c407b1SChuck Lever 1237d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1238d9c407b1SChuck Lever 1239d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4); 1240d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1241d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1242d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1243d9c407b1SChuck Lever } 1244d9c407b1SChuck Lever 1245d9c407b1SChuck Lever static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p, 1246d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1247d9c407b1SChuck Lever { 1248d9c407b1SChuck Lever struct xdr_stream xdr; 1249d9c407b1SChuck Lever 1250d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1251d9c407b1SChuck Lever encode_readdir3args(&xdr, args); 1252d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1253d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1254d9c407b1SChuck Lever return 0; 1255d9c407b1SChuck Lever } 1256d9c407b1SChuck Lever 1257d9c407b1SChuck Lever /* 1258d9c407b1SChuck Lever * 3.3.17 READDIRPLUS3args 1259d9c407b1SChuck Lever * 1260d9c407b1SChuck Lever * struct READDIRPLUS3args { 1261d9c407b1SChuck Lever * nfs_fh3 dir; 1262d9c407b1SChuck Lever * cookie3 cookie; 1263d9c407b1SChuck Lever * cookieverf3 cookieverf; 1264d9c407b1SChuck Lever * count3 dircount; 1265d9c407b1SChuck Lever * count3 maxcount; 1266d9c407b1SChuck Lever * }; 1267d9c407b1SChuck Lever */ 1268d9c407b1SChuck Lever static void encode_readdirplus3args(struct xdr_stream *xdr, 1269d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1270d9c407b1SChuck Lever { 1271d9c407b1SChuck Lever __be32 *p; 1272d9c407b1SChuck Lever 1273d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1274d9c407b1SChuck Lever 1275d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4); 1276d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1277d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1278d9c407b1SChuck Lever 1279d9c407b1SChuck Lever /* 1280d9c407b1SChuck Lever * readdirplus: need dircount + buffer size. 1281d9c407b1SChuck Lever * We just make sure we make dircount big enough 1282d9c407b1SChuck Lever */ 1283d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count >> 3); 1284d9c407b1SChuck Lever 1285d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1286d9c407b1SChuck Lever } 1287d9c407b1SChuck Lever 1288d9c407b1SChuck Lever static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p, 1289d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1290d9c407b1SChuck Lever { 1291d9c407b1SChuck Lever struct xdr_stream xdr; 1292d9c407b1SChuck Lever 1293d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1294d9c407b1SChuck Lever encode_readdirplus3args(&xdr, args); 1295d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1296d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1297d9c407b1SChuck Lever return 0; 1298d9c407b1SChuck Lever } 1299d9c407b1SChuck Lever 1300d9c407b1SChuck Lever /* 13011da177e4SLinus Torvalds * Decode the result of a readdir call. 13021da177e4SLinus Torvalds * We just check for syntactical correctness. 13031da177e4SLinus Torvalds */ 13041da177e4SLinus Torvalds static int 1305d61005a6SAl Viro nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res) 13061da177e4SLinus Torvalds { 13071da177e4SLinus Torvalds struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 13081da177e4SLinus Torvalds struct kvec *iov = rcvbuf->head; 13091da177e4SLinus Torvalds struct page **page; 1310c957c526SChuck Lever size_t hdrlen; 1311afa8ccc9SBryan Schumaker u32 recvd, pglen; 1312ac396128STrond Myklebust int status; 13131da177e4SLinus Torvalds 13141da177e4SLinus Torvalds status = ntohl(*p++); 13151da177e4SLinus Torvalds /* Decode post_op_attrs */ 13161da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->dir_attr); 13171da177e4SLinus Torvalds if (status) 1318856dff3dSBenny Halevy return nfs_stat_to_errno(status); 13191da177e4SLinus Torvalds /* Decode verifier cookie */ 13201da177e4SLinus Torvalds if (res->verf) { 13211da177e4SLinus Torvalds res->verf[0] = *p++; 13221da177e4SLinus Torvalds res->verf[1] = *p++; 13231da177e4SLinus Torvalds } else { 13241da177e4SLinus Torvalds p += 2; 13251da177e4SLinus Torvalds } 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 13281da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1329fe82a183SChuck Lever dprintk("NFS: READDIR reply header overflowed:" 1330c957c526SChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 13311da177e4SLinus Torvalds return -errno_NFSERR_IO; 13321da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 13331da177e4SLinus Torvalds dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); 13341da177e4SLinus Torvalds xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds pglen = rcvbuf->page_len; 13381da177e4SLinus Torvalds recvd = rcvbuf->len - hdrlen; 13391da177e4SLinus Torvalds if (pglen > recvd) 13401da177e4SLinus Torvalds pglen = recvd; 13411da177e4SLinus Torvalds page = rcvbuf->pages; 1342643f8111SJeff Layton 1343ac396128STrond Myklebust return pglen; 13441da177e4SLinus Torvalds } 13451da177e4SLinus Torvalds 13460dbb4c67SAl Viro __be32 * 134782f2e547SBryan Schumaker nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus) 13481da177e4SLinus Torvalds { 1349babddc72SBryan Schumaker __be32 *p; 13501da177e4SLinus Torvalds struct nfs_entry old = *entry; 13511da177e4SLinus Torvalds 1352babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 1353babddc72SBryan Schumaker if (unlikely(!p)) 1354babddc72SBryan Schumaker goto out_overflow; 1355babddc72SBryan Schumaker if (!ntohl(*p++)) { 1356babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 1357babddc72SBryan Schumaker if (unlikely(!p)) 1358babddc72SBryan Schumaker goto out_overflow; 1359babddc72SBryan Schumaker if (!ntohl(*p++)) 13601da177e4SLinus Torvalds return ERR_PTR(-EAGAIN); 13611da177e4SLinus Torvalds entry->eof = 1; 13621da177e4SLinus Torvalds return ERR_PTR(-EBADCOOKIE); 13631da177e4SLinus Torvalds } 13641da177e4SLinus Torvalds 1365babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 12); 1366babddc72SBryan Schumaker if (unlikely(!p)) 1367babddc72SBryan Schumaker goto out_overflow; 13681da177e4SLinus Torvalds p = xdr_decode_hyper(p, &entry->ino); 13691da177e4SLinus Torvalds entry->len = ntohl(*p++); 1370babddc72SBryan Schumaker 1371babddc72SBryan Schumaker p = xdr_inline_decode(xdr, entry->len + 8); 1372babddc72SBryan Schumaker if (unlikely(!p)) 1373babddc72SBryan Schumaker goto out_overflow; 13741da177e4SLinus Torvalds entry->name = (const char *) p; 13751da177e4SLinus Torvalds p += XDR_QUADLEN(entry->len); 13761da177e4SLinus Torvalds entry->prev_cookie = entry->cookie; 13771da177e4SLinus Torvalds p = xdr_decode_hyper(p, &entry->cookie); 13781da177e4SLinus Torvalds 13790b26a0bfSTrond Myklebust entry->d_type = DT_UNKNOWN; 13801da177e4SLinus Torvalds if (plus) { 13811da177e4SLinus Torvalds entry->fattr->valid = 0; 1382babddc72SBryan Schumaker p = xdr_decode_post_op_attr_stream(xdr, entry->fattr); 1383babddc72SBryan Schumaker if (IS_ERR(p)) 1384babddc72SBryan Schumaker goto out_overflow_exit; 13850b26a0bfSTrond Myklebust entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); 13861da177e4SLinus Torvalds /* In fact, a post_op_fh3: */ 1387babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 1388babddc72SBryan Schumaker if (unlikely(!p)) 1389babddc72SBryan Schumaker goto out_overflow; 13901da177e4SLinus Torvalds if (*p++) { 1391babddc72SBryan Schumaker p = xdr_decode_fhandle_stream(xdr, entry->fh); 1392babddc72SBryan Schumaker if (IS_ERR(p)) 1393babddc72SBryan Schumaker goto out_overflow_exit; 13941da177e4SLinus Torvalds /* Ugh -- server reply was truncated */ 13951da177e4SLinus Torvalds if (p == NULL) { 13961da177e4SLinus Torvalds dprintk("NFS: FH truncated\n"); 13971da177e4SLinus Torvalds *entry = old; 13981da177e4SLinus Torvalds return ERR_PTR(-EAGAIN); 13991da177e4SLinus Torvalds } 14001da177e4SLinus Torvalds } else 14011da177e4SLinus Torvalds memset((u8*)(entry->fh), 0, sizeof(*entry->fh)); 14021da177e4SLinus Torvalds } 14031da177e4SLinus Torvalds 1404babddc72SBryan Schumaker p = xdr_inline_peek(xdr, 8); 1405babddc72SBryan Schumaker if (p != NULL) 14061da177e4SLinus Torvalds entry->eof = !p[0] && p[1]; 1407babddc72SBryan Schumaker else 1408babddc72SBryan Schumaker entry->eof = 0; 1409babddc72SBryan Schumaker 14101da177e4SLinus Torvalds return p; 1411babddc72SBryan Schumaker 1412babddc72SBryan Schumaker out_overflow: 1413babddc72SBryan Schumaker print_overflow_msg(__func__, xdr); 1414babddc72SBryan Schumaker out_overflow_exit: 1415463a376eSTrond Myklebust return ERR_PTR(-EAGAIN); 14161da177e4SLinus Torvalds } 14171da177e4SLinus Torvalds 14181da177e4SLinus Torvalds /* 14191da177e4SLinus Torvalds * Encode COMMIT arguments 14201da177e4SLinus Torvalds */ 14211da177e4SLinus Torvalds static int 1422d61005a6SAl Viro nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) 14231da177e4SLinus Torvalds { 14241da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 14251da177e4SLinus Torvalds p = xdr_encode_hyper(p, args->offset); 14261da177e4SLinus Torvalds *p++ = htonl(args->count); 14271da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 14281da177e4SLinus Torvalds return 0; 14291da177e4SLinus Torvalds } 14301da177e4SLinus Torvalds 1431d9c407b1SChuck Lever /* 1432d9c407b1SChuck Lever * 3.3.21 COMMIT3args 1433d9c407b1SChuck Lever * 1434d9c407b1SChuck Lever * struct COMMIT3args { 1435d9c407b1SChuck Lever * nfs_fh3 file; 1436d9c407b1SChuck Lever * offset3 offset; 1437d9c407b1SChuck Lever * count3 count; 1438d9c407b1SChuck Lever * }; 1439d9c407b1SChuck Lever */ 1440d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr, 1441d9c407b1SChuck Lever const struct nfs_writeargs *args) 1442d9c407b1SChuck Lever { 1443d9c407b1SChuck Lever __be32 *p; 1444d9c407b1SChuck Lever 1445d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1446d9c407b1SChuck Lever 1447d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 1448d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 1449d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1450d9c407b1SChuck Lever } 1451d9c407b1SChuck Lever 1452d9c407b1SChuck Lever static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p, 1453d9c407b1SChuck Lever const struct nfs_writeargs *args) 1454d9c407b1SChuck Lever { 1455d9c407b1SChuck Lever struct xdr_stream xdr; 1456d9c407b1SChuck Lever 1457d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1458d9c407b1SChuck Lever encode_commit3args(&xdr, args); 1459d9c407b1SChuck Lever return 0; 1460d9c407b1SChuck Lever } 1461d9c407b1SChuck Lever 1462b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 1463b7fa0554SAndreas Gruenbacher /* 1464b7fa0554SAndreas Gruenbacher * Encode GETACL arguments 1465b7fa0554SAndreas Gruenbacher */ 1466b7fa0554SAndreas Gruenbacher static int 1467d61005a6SAl Viro nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p, 1468b7fa0554SAndreas Gruenbacher struct nfs3_getaclargs *args) 1469b7fa0554SAndreas Gruenbacher { 1470a17c2153STrond Myklebust struct rpc_auth *auth = req->rq_cred->cr_auth; 1471b7fa0554SAndreas Gruenbacher unsigned int replen; 1472b7fa0554SAndreas Gruenbacher 1473b7fa0554SAndreas Gruenbacher p = xdr_encode_fhandle(p, args->fh); 1474b7fa0554SAndreas Gruenbacher *p++ = htonl(args->mask); 1475b7fa0554SAndreas Gruenbacher req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 1476b7fa0554SAndreas Gruenbacher 1477b7fa0554SAndreas Gruenbacher if (args->mask & (NFS_ACL | NFS_DFACL)) { 1478b7fa0554SAndreas Gruenbacher /* Inline the page array */ 1479b7fa0554SAndreas Gruenbacher replen = (RPC_REPHDRSIZE + auth->au_rslack + 1480b7fa0554SAndreas Gruenbacher ACL3_getaclres_sz) << 2; 1481b7fa0554SAndreas Gruenbacher xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, 1482b7fa0554SAndreas Gruenbacher NFSACL_MAXPAGES << PAGE_SHIFT); 1483b7fa0554SAndreas Gruenbacher } 1484b7fa0554SAndreas Gruenbacher return 0; 1485b7fa0554SAndreas Gruenbacher } 1486b7fa0554SAndreas Gruenbacher 1487d9c407b1SChuck Lever static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p, 1488d9c407b1SChuck Lever const struct nfs3_getaclargs *args) 1489d9c407b1SChuck Lever { 1490d9c407b1SChuck Lever struct xdr_stream xdr; 1491d9c407b1SChuck Lever 1492d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1493d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fh); 1494d9c407b1SChuck Lever encode_uint32(&xdr, args->mask); 1495d9c407b1SChuck Lever if (args->mask & (NFS_ACL | NFS_DFACL)) 1496d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1497d9c407b1SChuck Lever NFSACL_MAXPAGES << PAGE_SHIFT, 1498d9c407b1SChuck Lever ACL3_getaclres_sz); 1499d9c407b1SChuck Lever return 0; 1500d9c407b1SChuck Lever } 1501d9c407b1SChuck Lever 1502b7fa0554SAndreas Gruenbacher /* 1503b7fa0554SAndreas Gruenbacher * Encode SETACL arguments 1504b7fa0554SAndreas Gruenbacher */ 1505b7fa0554SAndreas Gruenbacher static int 1506d61005a6SAl Viro nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p, 1507b7fa0554SAndreas Gruenbacher struct nfs3_setaclargs *args) 1508b7fa0554SAndreas Gruenbacher { 1509b7fa0554SAndreas Gruenbacher struct xdr_buf *buf = &req->rq_snd_buf; 1510ae46141fSTrond Myklebust unsigned int base; 1511ae46141fSTrond Myklebust int err; 1512b7fa0554SAndreas Gruenbacher 1513b7fa0554SAndreas Gruenbacher p = xdr_encode_fhandle(p, NFS_FH(args->inode)); 1514b7fa0554SAndreas Gruenbacher *p++ = htonl(args->mask); 1515ae46141fSTrond Myklebust req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 1516ae46141fSTrond Myklebust base = req->rq_slen; 1517b7fa0554SAndreas Gruenbacher 1518ae46141fSTrond Myklebust if (args->npages != 0) 1519ae46141fSTrond Myklebust xdr_encode_pages(buf, args->pages, 0, args->len); 1520ae46141fSTrond Myklebust else 152183404372STrond Myklebust req->rq_slen = xdr_adjust_iovec(req->rq_svec, 152283404372STrond Myklebust p + XDR_QUADLEN(args->len)); 1523b7fa0554SAndreas Gruenbacher 1524b7fa0554SAndreas Gruenbacher err = nfsacl_encode(buf, base, args->inode, 1525b7fa0554SAndreas Gruenbacher (args->mask & NFS_ACL) ? 1526b7fa0554SAndreas Gruenbacher args->acl_access : NULL, 1, 0); 1527b7fa0554SAndreas Gruenbacher if (err > 0) 1528b7fa0554SAndreas Gruenbacher err = nfsacl_encode(buf, base + err, args->inode, 1529b7fa0554SAndreas Gruenbacher (args->mask & NFS_DFACL) ? 1530b7fa0554SAndreas Gruenbacher args->acl_default : NULL, 1, 1531b7fa0554SAndreas Gruenbacher NFS_ACL_DEFAULT); 1532b7fa0554SAndreas Gruenbacher return (err > 0) ? 0 : err; 1533b7fa0554SAndreas Gruenbacher } 1534d9c407b1SChuck Lever 1535d9c407b1SChuck Lever static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p, 1536d9c407b1SChuck Lever const struct nfs3_setaclargs *args) 1537d9c407b1SChuck Lever { 1538d9c407b1SChuck Lever struct xdr_stream xdr; 1539d9c407b1SChuck Lever unsigned int base; 1540d9c407b1SChuck Lever int error; 1541d9c407b1SChuck Lever 1542d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1543d9c407b1SChuck Lever encode_nfs_fh3(&xdr, NFS_FH(args->inode)); 1544d9c407b1SChuck Lever encode_uint32(&xdr, args->mask); 1545d9c407b1SChuck Lever if (args->npages != 0) 1546d9c407b1SChuck Lever xdr_write_pages(&xdr, args->pages, 0, args->len); 1547d9c407b1SChuck Lever 1548d9c407b1SChuck Lever base = req->rq_slen; 1549d9c407b1SChuck Lever error = nfsacl_encode(xdr.buf, base, args->inode, 1550d9c407b1SChuck Lever (args->mask & NFS_ACL) ? 1551d9c407b1SChuck Lever args->acl_access : NULL, 1, 0); 1552d9c407b1SChuck Lever BUG_ON(error < 0); 1553d9c407b1SChuck Lever error = nfsacl_encode(xdr.buf, base + error, args->inode, 1554d9c407b1SChuck Lever (args->mask & NFS_DFACL) ? 1555d9c407b1SChuck Lever args->acl_default : NULL, 1, 1556d9c407b1SChuck Lever NFS_ACL_DEFAULT); 1557d9c407b1SChuck Lever BUG_ON(error < 0); 1558d9c407b1SChuck Lever return 0; 1559d9c407b1SChuck Lever } 1560d9c407b1SChuck Lever 1561b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 1562b7fa0554SAndreas Gruenbacher 15631da177e4SLinus Torvalds /* 15641da177e4SLinus Torvalds * NFS XDR decode functions 15651da177e4SLinus Torvalds */ 15661da177e4SLinus Torvalds 15671da177e4SLinus Torvalds /* 15681da177e4SLinus Torvalds * Decode attrstat reply. 15691da177e4SLinus Torvalds */ 15701da177e4SLinus Torvalds static int 1571d61005a6SAl Viro nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 15721da177e4SLinus Torvalds { 15731da177e4SLinus Torvalds int status; 15741da177e4SLinus Torvalds 15751da177e4SLinus Torvalds if ((status = ntohl(*p++))) 1576856dff3dSBenny Halevy return nfs_stat_to_errno(status); 15771da177e4SLinus Torvalds xdr_decode_fattr(p, fattr); 15781da177e4SLinus Torvalds return 0; 15791da177e4SLinus Torvalds } 15801da177e4SLinus Torvalds 15811da177e4SLinus Torvalds /* 15821da177e4SLinus Torvalds * Decode status+wcc_data reply 15831da177e4SLinus Torvalds * SATTR, REMOVE, RMDIR 15841da177e4SLinus Torvalds */ 15851da177e4SLinus Torvalds static int 1586d61005a6SAl Viro nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 15871da177e4SLinus Torvalds { 15881da177e4SLinus Torvalds int status; 15891da177e4SLinus Torvalds 15901da177e4SLinus Torvalds if ((status = ntohl(*p++))) 1591856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 15921da177e4SLinus Torvalds xdr_decode_wcc_data(p, fattr); 15931da177e4SLinus Torvalds return status; 15941da177e4SLinus Torvalds } 15951da177e4SLinus Torvalds 15964fdc17b2STrond Myklebust static int 15974fdc17b2STrond Myklebust nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res) 15984fdc17b2STrond Myklebust { 1599d346890bSTrond Myklebust return nfs3_xdr_wccstat(req, p, res->dir_attr); 16004fdc17b2STrond Myklebust } 16014fdc17b2STrond Myklebust 16021da177e4SLinus Torvalds /* 16031da177e4SLinus Torvalds * Decode LOOKUP reply 16041da177e4SLinus Torvalds */ 16051da177e4SLinus Torvalds static int 1606d61005a6SAl Viro nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) 16071da177e4SLinus Torvalds { 16081da177e4SLinus Torvalds int status; 16091da177e4SLinus Torvalds 16101da177e4SLinus Torvalds if ((status = ntohl(*p++))) { 1611856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 16121da177e4SLinus Torvalds } else { 16131da177e4SLinus Torvalds if (!(p = xdr_decode_fhandle(p, res->fh))) 16141da177e4SLinus Torvalds return -errno_NFSERR_IO; 16151da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 16161da177e4SLinus Torvalds } 16171da177e4SLinus Torvalds xdr_decode_post_op_attr(p, res->dir_attr); 16181da177e4SLinus Torvalds return status; 16191da177e4SLinus Torvalds } 16201da177e4SLinus Torvalds 16211da177e4SLinus Torvalds /* 16221da177e4SLinus Torvalds * Decode ACCESS reply 16231da177e4SLinus Torvalds */ 16241da177e4SLinus Torvalds static int 1625d61005a6SAl Viro nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) 16261da177e4SLinus Torvalds { 16271da177e4SLinus Torvalds int status = ntohl(*p++); 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 16301da177e4SLinus Torvalds if (status) 1631856dff3dSBenny Halevy return nfs_stat_to_errno(status); 16321da177e4SLinus Torvalds res->access = ntohl(*p++); 16331da177e4SLinus Torvalds return 0; 16341da177e4SLinus Torvalds } 16351da177e4SLinus Torvalds 16361da177e4SLinus Torvalds static int 1637d61005a6SAl Viro nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args) 16381da177e4SLinus Torvalds { 1639a17c2153STrond Myklebust struct rpc_auth *auth = req->rq_cred->cr_auth; 16401da177e4SLinus Torvalds unsigned int replen; 16411da177e4SLinus Torvalds 16421da177e4SLinus Torvalds p = xdr_encode_fhandle(p, args->fh); 16431da177e4SLinus Torvalds req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds /* Inline the page array */ 16461da177e4SLinus Torvalds replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2; 16471da177e4SLinus Torvalds xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen); 16481da177e4SLinus Torvalds return 0; 16491da177e4SLinus Torvalds } 16501da177e4SLinus Torvalds 16511da177e4SLinus Torvalds /* 16521da177e4SLinus Torvalds * Decode READLINK reply 16531da177e4SLinus Torvalds */ 16541da177e4SLinus Torvalds static int 1655d61005a6SAl Viro nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 16561da177e4SLinus Torvalds { 16571da177e4SLinus Torvalds struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 16581da177e4SLinus Torvalds struct kvec *iov = rcvbuf->head; 1659c957c526SChuck Lever size_t hdrlen; 1660c957c526SChuck Lever u32 len, recvd; 16611da177e4SLinus Torvalds int status; 16621da177e4SLinus Torvalds 16631da177e4SLinus Torvalds status = ntohl(*p++); 16641da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, fattr); 16651da177e4SLinus Torvalds 16661da177e4SLinus Torvalds if (status != 0) 1667856dff3dSBenny Halevy return nfs_stat_to_errno(status); 16681da177e4SLinus Torvalds 16691da177e4SLinus Torvalds /* Convert length of symlink */ 16701da177e4SLinus Torvalds len = ntohl(*p++); 1671c957c526SChuck Lever if (len >= rcvbuf->page_len) { 1672fe82a183SChuck Lever dprintk("nfs: server returned giant symlink!\n"); 16731da177e4SLinus Torvalds return -ENAMETOOLONG; 16741da177e4SLinus Torvalds } 16751da177e4SLinus Torvalds 16761da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 16771da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1678fe82a183SChuck Lever dprintk("NFS: READLINK reply header overflowed:" 1679c957c526SChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 16801da177e4SLinus Torvalds return -errno_NFSERR_IO; 16811da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 1682fe82a183SChuck Lever dprintk("NFS: READLINK header is short. " 1683fe82a183SChuck Lever "iovec will be shifted.\n"); 16841da177e4SLinus Torvalds xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 16851da177e4SLinus Torvalds } 16861da177e4SLinus Torvalds recvd = req->rq_rcv_buf.len - hdrlen; 16871da177e4SLinus Torvalds if (recvd < len) { 1688fe82a183SChuck Lever dprintk("NFS: server cheating in readlink reply: " 16891da177e4SLinus Torvalds "count %u > recvd %u\n", len, recvd); 16901da177e4SLinus Torvalds return -EIO; 16911da177e4SLinus Torvalds } 16921da177e4SLinus Torvalds 1693b4687da7SChuck Lever xdr_terminate_string(rcvbuf, len); 16941da177e4SLinus Torvalds return 0; 16951da177e4SLinus Torvalds } 16961da177e4SLinus Torvalds 16971da177e4SLinus Torvalds /* 16981da177e4SLinus Torvalds * Decode READ reply 16991da177e4SLinus Torvalds */ 17001da177e4SLinus Torvalds static int 1701d61005a6SAl Viro nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) 17021da177e4SLinus Torvalds { 17031da177e4SLinus Torvalds struct kvec *iov = req->rq_rcv_buf.head; 1704c957c526SChuck Lever size_t hdrlen; 1705c957c526SChuck Lever u32 count, ocount, recvd; 1706c957c526SChuck Lever int status; 17071da177e4SLinus Torvalds 17081da177e4SLinus Torvalds status = ntohl(*p++); 17091da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 17101da177e4SLinus Torvalds 17111da177e4SLinus Torvalds if (status != 0) 1712856dff3dSBenny Halevy return nfs_stat_to_errno(status); 17131da177e4SLinus Torvalds 1714c957c526SChuck Lever /* Decode reply count and EOF flag. NFSv3 is somewhat redundant 17151da177e4SLinus Torvalds * in that it puts the count both in the res struct and in the 17161da177e4SLinus Torvalds * opaque data count. */ 17171da177e4SLinus Torvalds count = ntohl(*p++); 17181da177e4SLinus Torvalds res->eof = ntohl(*p++); 17191da177e4SLinus Torvalds ocount = ntohl(*p++); 17201da177e4SLinus Torvalds 17211da177e4SLinus Torvalds if (ocount != count) { 1722fe82a183SChuck Lever dprintk("NFS: READ count doesn't match RPC opaque count.\n"); 17231da177e4SLinus Torvalds return -errno_NFSERR_IO; 17241da177e4SLinus Torvalds } 17251da177e4SLinus Torvalds 17261da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 17271da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1728fe82a183SChuck Lever dprintk("NFS: READ reply header overflowed:" 1729c957c526SChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 17301da177e4SLinus Torvalds return -errno_NFSERR_IO; 17311da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 17321da177e4SLinus Torvalds dprintk("NFS: READ header is short. iovec will be shifted.\n"); 17331da177e4SLinus Torvalds xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); 17341da177e4SLinus Torvalds } 17351da177e4SLinus Torvalds 17361da177e4SLinus Torvalds recvd = req->rq_rcv_buf.len - hdrlen; 17371da177e4SLinus Torvalds if (count > recvd) { 1738fe82a183SChuck Lever dprintk("NFS: server cheating in read reply: " 1739c957c526SChuck Lever "count %u > recvd %u\n", count, recvd); 17401da177e4SLinus Torvalds count = recvd; 17411da177e4SLinus Torvalds res->eof = 0; 17421da177e4SLinus Torvalds } 17431da177e4SLinus Torvalds 17441da177e4SLinus Torvalds if (count < res->count) 17451da177e4SLinus Torvalds res->count = count; 17461da177e4SLinus Torvalds 17471da177e4SLinus Torvalds return count; 17481da177e4SLinus Torvalds } 17491da177e4SLinus Torvalds 17501da177e4SLinus Torvalds /* 17511da177e4SLinus Torvalds * Decode WRITE response 17521da177e4SLinus Torvalds */ 17531da177e4SLinus Torvalds static int 1754d61005a6SAl Viro nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) 17551da177e4SLinus Torvalds { 17561da177e4SLinus Torvalds int status; 17571da177e4SLinus Torvalds 17581da177e4SLinus Torvalds status = ntohl(*p++); 17591da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->fattr); 17601da177e4SLinus Torvalds 17611da177e4SLinus Torvalds if (status != 0) 1762856dff3dSBenny Halevy return nfs_stat_to_errno(status); 17631da177e4SLinus Torvalds 17641da177e4SLinus Torvalds res->count = ntohl(*p++); 17651da177e4SLinus Torvalds res->verf->committed = (enum nfs3_stable_how)ntohl(*p++); 17661da177e4SLinus Torvalds res->verf->verifier[0] = *p++; 17671da177e4SLinus Torvalds res->verf->verifier[1] = *p++; 17681da177e4SLinus Torvalds 17691da177e4SLinus Torvalds return res->count; 17701da177e4SLinus Torvalds } 17711da177e4SLinus Torvalds 17721da177e4SLinus Torvalds /* 17731da177e4SLinus Torvalds * Decode a CREATE response 17741da177e4SLinus Torvalds */ 17751da177e4SLinus Torvalds static int 1776d61005a6SAl Viro nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) 17771da177e4SLinus Torvalds { 17781da177e4SLinus Torvalds int status; 17791da177e4SLinus Torvalds 17801da177e4SLinus Torvalds status = ntohl(*p++); 17811da177e4SLinus Torvalds if (status == 0) { 17821da177e4SLinus Torvalds if (*p++) { 17831da177e4SLinus Torvalds if (!(p = xdr_decode_fhandle(p, res->fh))) 17841da177e4SLinus Torvalds return -errno_NFSERR_IO; 17851da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 17861da177e4SLinus Torvalds } else { 17871da177e4SLinus Torvalds memset(res->fh, 0, sizeof(*res->fh)); 17881da177e4SLinus Torvalds /* Do decode post_op_attr but set it to NULL */ 17891da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 17901da177e4SLinus Torvalds res->fattr->valid = 0; 17911da177e4SLinus Torvalds } 17921da177e4SLinus Torvalds } else { 1793856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 17941da177e4SLinus Torvalds } 17951da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->dir_attr); 17961da177e4SLinus Torvalds return status; 17971da177e4SLinus Torvalds } 17981da177e4SLinus Torvalds 17991da177e4SLinus Torvalds /* 18001da177e4SLinus Torvalds * Decode RENAME reply 18011da177e4SLinus Torvalds */ 18021da177e4SLinus Torvalds static int 1803e8582a8bSJeff Layton nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res) 18041da177e4SLinus Torvalds { 18051da177e4SLinus Torvalds int status; 18061da177e4SLinus Torvalds 18071da177e4SLinus Torvalds if ((status = ntohl(*p++)) != 0) 1808856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 1809e8582a8bSJeff Layton p = xdr_decode_wcc_data(p, res->old_fattr); 1810e8582a8bSJeff Layton p = xdr_decode_wcc_data(p, res->new_fattr); 18111da177e4SLinus Torvalds return status; 18121da177e4SLinus Torvalds } 18131da177e4SLinus Torvalds 18141da177e4SLinus Torvalds /* 18151da177e4SLinus Torvalds * Decode LINK reply 18161da177e4SLinus Torvalds */ 18171da177e4SLinus Torvalds static int 1818d61005a6SAl Viro nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res) 18191da177e4SLinus Torvalds { 18201da177e4SLinus Torvalds int status; 18211da177e4SLinus Torvalds 18221da177e4SLinus Torvalds if ((status = ntohl(*p++)) != 0) 1823856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 18241da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 18251da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->dir_attr); 18261da177e4SLinus Torvalds return status; 18271da177e4SLinus Torvalds } 18281da177e4SLinus Torvalds 18291da177e4SLinus Torvalds /* 18301da177e4SLinus Torvalds * Decode FSSTAT reply 18311da177e4SLinus Torvalds */ 18321da177e4SLinus Torvalds static int 1833d61005a6SAl Viro nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res) 18341da177e4SLinus Torvalds { 18351da177e4SLinus Torvalds int status; 18361da177e4SLinus Torvalds 18371da177e4SLinus Torvalds status = ntohl(*p++); 18381da177e4SLinus Torvalds 18391da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 18401da177e4SLinus Torvalds if (status != 0) 1841856dff3dSBenny Halevy return nfs_stat_to_errno(status); 18421da177e4SLinus Torvalds 18431da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->tbytes); 18441da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->fbytes); 18451da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->abytes); 18461da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->tfiles); 18471da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->ffiles); 18481da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->afiles); 18491da177e4SLinus Torvalds 18501da177e4SLinus Torvalds /* ignore invarsec */ 18511da177e4SLinus Torvalds return 0; 18521da177e4SLinus Torvalds } 18531da177e4SLinus Torvalds 18541da177e4SLinus Torvalds /* 18551da177e4SLinus Torvalds * Decode FSINFO reply 18561da177e4SLinus Torvalds */ 18571da177e4SLinus Torvalds static int 1858d61005a6SAl Viro nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res) 18591da177e4SLinus Torvalds { 18601da177e4SLinus Torvalds int status; 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvalds status = ntohl(*p++); 18631da177e4SLinus Torvalds 18641da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 18651da177e4SLinus Torvalds if (status != 0) 1866856dff3dSBenny Halevy return nfs_stat_to_errno(status); 18671da177e4SLinus Torvalds 18681da177e4SLinus Torvalds res->rtmax = ntohl(*p++); 18691da177e4SLinus Torvalds res->rtpref = ntohl(*p++); 18701da177e4SLinus Torvalds res->rtmult = ntohl(*p++); 18711da177e4SLinus Torvalds res->wtmax = ntohl(*p++); 18721da177e4SLinus Torvalds res->wtpref = ntohl(*p++); 18731da177e4SLinus Torvalds res->wtmult = ntohl(*p++); 18741da177e4SLinus Torvalds res->dtpref = ntohl(*p++); 18751da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->maxfilesize); 18766b96724eSRicardo Labiaga p = xdr_decode_time3(p, &res->time_delta); 18771da177e4SLinus Torvalds 18786b96724eSRicardo Labiaga /* ignore properties */ 18791da177e4SLinus Torvalds res->lease_time = 0; 18801da177e4SLinus Torvalds return 0; 18811da177e4SLinus Torvalds } 18821da177e4SLinus Torvalds 18831da177e4SLinus Torvalds /* 18841da177e4SLinus Torvalds * Decode PATHCONF reply 18851da177e4SLinus Torvalds */ 18861da177e4SLinus Torvalds static int 1887d61005a6SAl Viro nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res) 18881da177e4SLinus Torvalds { 18891da177e4SLinus Torvalds int status; 18901da177e4SLinus Torvalds 18911da177e4SLinus Torvalds status = ntohl(*p++); 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 18941da177e4SLinus Torvalds if (status != 0) 1895856dff3dSBenny Halevy return nfs_stat_to_errno(status); 18961da177e4SLinus Torvalds res->max_link = ntohl(*p++); 18971da177e4SLinus Torvalds res->max_namelen = ntohl(*p++); 18981da177e4SLinus Torvalds 18991da177e4SLinus Torvalds /* ignore remaining fields */ 19001da177e4SLinus Torvalds return 0; 19011da177e4SLinus Torvalds } 19021da177e4SLinus Torvalds 19031da177e4SLinus Torvalds /* 19041da177e4SLinus Torvalds * Decode COMMIT reply 19051da177e4SLinus Torvalds */ 19061da177e4SLinus Torvalds static int 1907d61005a6SAl Viro nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) 19081da177e4SLinus Torvalds { 19091da177e4SLinus Torvalds int status; 19101da177e4SLinus Torvalds 19111da177e4SLinus Torvalds status = ntohl(*p++); 19121da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->fattr); 19131da177e4SLinus Torvalds if (status != 0) 1914856dff3dSBenny Halevy return nfs_stat_to_errno(status); 19151da177e4SLinus Torvalds 19161da177e4SLinus Torvalds res->verf->verifier[0] = *p++; 19171da177e4SLinus Torvalds res->verf->verifier[1] = *p++; 19181da177e4SLinus Torvalds return 0; 19191da177e4SLinus Torvalds } 19201da177e4SLinus Torvalds 1921b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 1922b7fa0554SAndreas Gruenbacher /* 1923b7fa0554SAndreas Gruenbacher * Decode GETACL reply 1924b7fa0554SAndreas Gruenbacher */ 1925b7fa0554SAndreas Gruenbacher static int 1926d61005a6SAl Viro nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p, 1927b7fa0554SAndreas Gruenbacher struct nfs3_getaclres *res) 1928b7fa0554SAndreas Gruenbacher { 1929b7fa0554SAndreas Gruenbacher struct xdr_buf *buf = &req->rq_rcv_buf; 1930b7fa0554SAndreas Gruenbacher int status = ntohl(*p++); 1931b7fa0554SAndreas Gruenbacher struct posix_acl **acl; 1932b7fa0554SAndreas Gruenbacher unsigned int *aclcnt; 1933b7fa0554SAndreas Gruenbacher int err, base; 1934b7fa0554SAndreas Gruenbacher 1935b7fa0554SAndreas Gruenbacher if (status != 0) 1936856dff3dSBenny Halevy return nfs_stat_to_errno(status); 1937b7fa0554SAndreas Gruenbacher p = xdr_decode_post_op_attr(p, res->fattr); 1938b7fa0554SAndreas Gruenbacher res->mask = ntohl(*p++); 1939b7fa0554SAndreas Gruenbacher if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 1940b7fa0554SAndreas Gruenbacher return -EINVAL; 1941b7fa0554SAndreas Gruenbacher base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base; 1942b7fa0554SAndreas Gruenbacher 1943b7fa0554SAndreas Gruenbacher acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL; 1944b7fa0554SAndreas Gruenbacher aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL; 1945b7fa0554SAndreas Gruenbacher err = nfsacl_decode(buf, base, aclcnt, acl); 1946b7fa0554SAndreas Gruenbacher 1947b7fa0554SAndreas Gruenbacher acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL; 1948b7fa0554SAndreas Gruenbacher aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL; 1949b7fa0554SAndreas Gruenbacher if (err > 0) 1950b7fa0554SAndreas Gruenbacher err = nfsacl_decode(buf, base + err, aclcnt, acl); 1951b7fa0554SAndreas Gruenbacher return (err > 0) ? 0 : err; 1952b7fa0554SAndreas Gruenbacher } 1953b7fa0554SAndreas Gruenbacher 1954b7fa0554SAndreas Gruenbacher /* 1955b7fa0554SAndreas Gruenbacher * Decode setacl reply. 1956b7fa0554SAndreas Gruenbacher */ 1957b7fa0554SAndreas Gruenbacher static int 1958d61005a6SAl Viro nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 1959b7fa0554SAndreas Gruenbacher { 1960b7fa0554SAndreas Gruenbacher int status = ntohl(*p++); 1961b7fa0554SAndreas Gruenbacher 1962b7fa0554SAndreas Gruenbacher if (status) 1963856dff3dSBenny Halevy return nfs_stat_to_errno(status); 1964b7fa0554SAndreas Gruenbacher xdr_decode_post_op_attr(p, fattr); 1965b7fa0554SAndreas Gruenbacher return 0; 1966b7fa0554SAndreas Gruenbacher } 1967b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 1968b7fa0554SAndreas Gruenbacher 19691da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer) \ 19701da177e4SLinus Torvalds [NFS3PROC_##proc] = { \ 19711da177e4SLinus Torvalds .p_proc = NFS3PROC_##proc, \ 19721da177e4SLinus Torvalds .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \ 19731da177e4SLinus Torvalds .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \ 19742bea90d4SChuck Lever .p_arglen = NFS3_##argtype##_sz, \ 19752bea90d4SChuck Lever .p_replen = NFS3_##restype##_sz, \ 1976cc0175c1SChuck Lever .p_timer = timer, \ 1977cc0175c1SChuck Lever .p_statidx = NFS3PROC_##proc, \ 1978cc0175c1SChuck Lever .p_name = #proc, \ 19791da177e4SLinus Torvalds } 19801da177e4SLinus Torvalds 19811da177e4SLinus Torvalds struct rpc_procinfo nfs3_procedures[] = { 19821da177e4SLinus Torvalds PROC(GETATTR, fhandle, attrstat, 1), 19831da177e4SLinus Torvalds PROC(SETATTR, sattrargs, wccstat, 0), 19841da177e4SLinus Torvalds PROC(LOOKUP, diropargs, lookupres, 2), 19851da177e4SLinus Torvalds PROC(ACCESS, accessargs, accessres, 1), 19861da177e4SLinus Torvalds PROC(READLINK, readlinkargs, readlinkres, 3), 19871da177e4SLinus Torvalds PROC(READ, readargs, readres, 3), 19881da177e4SLinus Torvalds PROC(WRITE, writeargs, writeres, 4), 19891da177e4SLinus Torvalds PROC(CREATE, createargs, createres, 0), 19901da177e4SLinus Torvalds PROC(MKDIR, mkdirargs, createres, 0), 19911da177e4SLinus Torvalds PROC(SYMLINK, symlinkargs, createres, 0), 19921da177e4SLinus Torvalds PROC(MKNOD, mknodargs, createres, 0), 19934fdc17b2STrond Myklebust PROC(REMOVE, removeargs, removeres, 0), 19941da177e4SLinus Torvalds PROC(RMDIR, diropargs, wccstat, 0), 19951da177e4SLinus Torvalds PROC(RENAME, renameargs, renameres, 0), 19961da177e4SLinus Torvalds PROC(LINK, linkargs, linkres, 0), 19971da177e4SLinus Torvalds PROC(READDIR, readdirargs, readdirres, 3), 19981da177e4SLinus Torvalds PROC(READDIRPLUS, readdirargs, readdirres, 3), 19991da177e4SLinus Torvalds PROC(FSSTAT, fhandle, fsstatres, 0), 20001da177e4SLinus Torvalds PROC(FSINFO, fhandle, fsinfores, 0), 20011da177e4SLinus Torvalds PROC(PATHCONF, fhandle, pathconfres, 0), 20021da177e4SLinus Torvalds PROC(COMMIT, commitargs, commitres, 5), 20031da177e4SLinus Torvalds }; 20041da177e4SLinus Torvalds 20051da177e4SLinus Torvalds struct rpc_version nfs_version3 = { 20061da177e4SLinus Torvalds .number = 3, 2007e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nfs3_procedures), 20081da177e4SLinus Torvalds .procs = nfs3_procedures 20091da177e4SLinus Torvalds }; 20101da177e4SLinus Torvalds 2011b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 2012b7fa0554SAndreas Gruenbacher static struct rpc_procinfo nfs3_acl_procedures[] = { 2013b7fa0554SAndreas Gruenbacher [ACLPROC3_GETACL] = { 2014b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_GETACL, 2015b7fa0554SAndreas Gruenbacher .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs, 2016b7fa0554SAndreas Gruenbacher .p_decode = (kxdrproc_t) nfs3_xdr_getaclres, 20172bea90d4SChuck Lever .p_arglen = ACL3_getaclargs_sz, 20182bea90d4SChuck Lever .p_replen = ACL3_getaclres_sz, 2019b7fa0554SAndreas Gruenbacher .p_timer = 1, 2020cc0175c1SChuck Lever .p_name = "GETACL", 2021b7fa0554SAndreas Gruenbacher }, 2022b7fa0554SAndreas Gruenbacher [ACLPROC3_SETACL] = { 2023b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_SETACL, 2024b7fa0554SAndreas Gruenbacher .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs, 2025b7fa0554SAndreas Gruenbacher .p_decode = (kxdrproc_t) nfs3_xdr_setaclres, 20262bea90d4SChuck Lever .p_arglen = ACL3_setaclargs_sz, 20272bea90d4SChuck Lever .p_replen = ACL3_setaclres_sz, 2028b7fa0554SAndreas Gruenbacher .p_timer = 0, 2029cc0175c1SChuck Lever .p_name = "SETACL", 2030b7fa0554SAndreas Gruenbacher }, 2031b7fa0554SAndreas Gruenbacher }; 2032b7fa0554SAndreas Gruenbacher 2033b7fa0554SAndreas Gruenbacher struct rpc_version nfsacl_version3 = { 2034b7fa0554SAndreas Gruenbacher .number = 3, 2035b7fa0554SAndreas Gruenbacher .nrprocs = sizeof(nfs3_acl_procedures)/ 2036b7fa0554SAndreas Gruenbacher sizeof(nfs3_acl_procedures[0]), 2037b7fa0554SAndreas Gruenbacher .procs = nfs3_acl_procedures, 2038b7fa0554SAndreas Gruenbacher }; 2039b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 2040