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 #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz) 50ad96b5b5SChuck Lever 51ad96b5b5SChuck Lever #define NFS3_getattrargs_sz (NFS3_fh_sz) 52ad96b5b5SChuck Lever #define NFS3_setattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3) 53ad96b5b5SChuck Lever #define NFS3_lookupargs_sz (NFS3_fh_sz+NFS3_filename_sz) 541da177e4SLinus Torvalds #define NFS3_accessargs_sz (NFS3_fh_sz+1) 551da177e4SLinus Torvalds #define NFS3_readlinkargs_sz (NFS3_fh_sz) 561da177e4SLinus Torvalds #define NFS3_readargs_sz (NFS3_fh_sz+3) 571da177e4SLinus Torvalds #define NFS3_writeargs_sz (NFS3_fh_sz+5) 581da177e4SLinus Torvalds #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 591da177e4SLinus Torvalds #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 6094a6d753SChuck Lever #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz) 611da177e4SLinus Torvalds #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) 62ad96b5b5SChuck Lever #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz) 631da177e4SLinus Torvalds #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) 641da177e4SLinus Torvalds #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) 65d9c407b1SChuck Lever #define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3) 66d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4) 671da177e4SLinus Torvalds #define NFS3_commitargs_sz (NFS3_fh_sz+3) 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds #define NFS3_attrstat_sz (1+NFS3_fattr_sz) 701da177e4SLinus Torvalds #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz) 714fdc17b2STrond Myklebust #define NFS3_removeres_sz (NFS3_wccstat_sz) 721da177e4SLinus Torvalds #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) 731da177e4SLinus Torvalds #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) 741da177e4SLinus Torvalds #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1) 751da177e4SLinus Torvalds #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3) 761da177e4SLinus Torvalds #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4) 771da177e4SLinus Torvalds #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 781da177e4SLinus Torvalds #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz)) 791da177e4SLinus Torvalds #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 801da177e4SLinus Torvalds #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2) 811da177e4SLinus Torvalds #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13) 821da177e4SLinus Torvalds #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12) 831da177e4SLinus Torvalds #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) 841da177e4SLinus Torvalds #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) 851da177e4SLinus Torvalds 86b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz (NFS3_fh_sz+1) 87ae46141fSTrond Myklebust #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \ 88ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 89ae46141fSTrond Myklebust #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \ 90ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 91b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) 92b7fa0554SAndreas Gruenbacher 931da177e4SLinus Torvalds /* 941da177e4SLinus Torvalds * Map file type to S_IFMT bits 951da177e4SLinus Torvalds */ 96bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = { 97bca79478STrond Myklebust [NF3BAD] = 0, 98bca79478STrond Myklebust [NF3REG] = S_IFREG, 99bca79478STrond Myklebust [NF3DIR] = S_IFDIR, 100bca79478STrond Myklebust [NF3BLK] = S_IFBLK, 101bca79478STrond Myklebust [NF3CHR] = S_IFCHR, 102bca79478STrond Myklebust [NF3LNK] = S_IFLNK, 103bca79478STrond Myklebust [NF3SOCK] = S_IFSOCK, 104bca79478STrond Myklebust [NF3FIFO] = S_IFIFO, 1051da177e4SLinus Torvalds }; 1061da177e4SLinus Torvalds 107babddc72SBryan Schumaker static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 108babddc72SBryan Schumaker { 109babddc72SBryan Schumaker dprintk("nfs: %s: prematurely hit end of receive buffer. " 110babddc72SBryan Schumaker "Remaining buffer length is %tu words.\n", 111babddc72SBryan Schumaker func, xdr->end - xdr->p); 112babddc72SBryan Schumaker } 113babddc72SBryan Schumaker 1141da177e4SLinus Torvalds /* 115d9c407b1SChuck Lever * While encoding arguments, set up the reply buffer in advance to 116d9c407b1SChuck Lever * receive reply data directly into the page cache. 117d9c407b1SChuck Lever */ 118d9c407b1SChuck Lever static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages, 119d9c407b1SChuck Lever unsigned int base, unsigned int len, 120d9c407b1SChuck Lever unsigned int bufsize) 121d9c407b1SChuck Lever { 122d9c407b1SChuck Lever struct rpc_auth *auth = req->rq_cred->cr_auth; 123d9c407b1SChuck Lever unsigned int replen; 124d9c407b1SChuck Lever 125d9c407b1SChuck Lever replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize; 126d9c407b1SChuck Lever xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len); 127d9c407b1SChuck Lever } 128d9c407b1SChuck Lever 129d9c407b1SChuck Lever 130d9c407b1SChuck Lever /* 1311da177e4SLinus Torvalds * Common NFS XDR functions as inlines 1321da177e4SLinus Torvalds */ 133d61005a6SAl Viro static inline __be32 * 134d61005a6SAl Viro xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh) 1351da177e4SLinus Torvalds { 1361da177e4SLinus Torvalds if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) { 1371da177e4SLinus Torvalds memcpy(fh->data, p, fh->size); 1381da177e4SLinus Torvalds return p + XDR_QUADLEN(fh->size); 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds return NULL; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 143babddc72SBryan Schumaker static inline __be32 * 144babddc72SBryan Schumaker xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh) 145babddc72SBryan Schumaker { 146babddc72SBryan Schumaker __be32 *p; 147babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 148babddc72SBryan Schumaker if (unlikely(!p)) 149babddc72SBryan Schumaker goto out_overflow; 150babddc72SBryan Schumaker fh->size = ntohl(*p++); 151babddc72SBryan Schumaker 152babddc72SBryan Schumaker if (fh->size <= NFS3_FHSIZE) { 153babddc72SBryan Schumaker p = xdr_inline_decode(xdr, fh->size); 154babddc72SBryan Schumaker if (unlikely(!p)) 155babddc72SBryan Schumaker goto out_overflow; 156babddc72SBryan Schumaker memcpy(fh->data, p, fh->size); 157babddc72SBryan Schumaker return p + XDR_QUADLEN(fh->size); 158babddc72SBryan Schumaker } 159babddc72SBryan Schumaker return NULL; 160babddc72SBryan Schumaker 161babddc72SBryan Schumaker out_overflow: 162babddc72SBryan Schumaker print_overflow_msg(__func__, xdr); 163babddc72SBryan Schumaker return ERR_PTR(-EIO); 164babddc72SBryan Schumaker } 165babddc72SBryan Schumaker 1661da177e4SLinus Torvalds /* 1671da177e4SLinus Torvalds * Encode/decode time. 1681da177e4SLinus Torvalds */ 169d61005a6SAl Viro static inline __be32 * 170d61005a6SAl Viro xdr_decode_time3(__be32 *p, struct timespec *timep) 1711da177e4SLinus Torvalds { 1721da177e4SLinus Torvalds timep->tv_sec = ntohl(*p++); 1731da177e4SLinus Torvalds timep->tv_nsec = ntohl(*p++); 1741da177e4SLinus Torvalds return p; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 177d61005a6SAl Viro static __be32 * 178d61005a6SAl Viro xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) 1791da177e4SLinus Torvalds { 1801da177e4SLinus Torvalds unsigned int type, major, minor; 181bca79478STrond Myklebust umode_t fmode; 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds type = ntohl(*p++); 184bca79478STrond Myklebust if (type > NF3FIFO) 185bca79478STrond Myklebust type = NF3NON; 186bca79478STrond Myklebust fmode = nfs_type2fmt[type]; 1871da177e4SLinus Torvalds fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode; 1881da177e4SLinus Torvalds fattr->nlink = ntohl(*p++); 1891da177e4SLinus Torvalds fattr->uid = ntohl(*p++); 1901da177e4SLinus Torvalds fattr->gid = ntohl(*p++); 1911da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->size); 1921da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->du.nfs3.used); 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds /* Turn remote device info into Linux-specific dev_t */ 1951da177e4SLinus Torvalds major = ntohl(*p++); 1961da177e4SLinus Torvalds minor = ntohl(*p++); 1971da177e4SLinus Torvalds fattr->rdev = MKDEV(major, minor); 1981da177e4SLinus Torvalds if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor) 1991da177e4SLinus Torvalds fattr->rdev = 0; 2001da177e4SLinus Torvalds 2018b4bdcf8STrond Myklebust p = xdr_decode_hyper(p, &fattr->fsid.major); 2028b4bdcf8STrond Myklebust fattr->fsid.minor = 0; 2031da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->fileid); 2041da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->atime); 2051da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->mtime); 2061da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->ctime); 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* Update the mode bits */ 2099e6e70f8STrond Myklebust fattr->valid |= NFS_ATTR_FATTR_V3; 2101da177e4SLinus Torvalds return p; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 213d61005a6SAl Viro static inline __be32 * 214d61005a6SAl Viro xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr) 2151da177e4SLinus Torvalds { 2161da177e4SLinus Torvalds p = xdr_decode_hyper(p, &fattr->pre_size); 2171da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->pre_mtime); 2181da177e4SLinus Torvalds p = xdr_decode_time3(p, &fattr->pre_ctime); 2199e6e70f8STrond Myklebust fattr->valid |= NFS_ATTR_FATTR_PRESIZE 2209e6e70f8STrond Myklebust | NFS_ATTR_FATTR_PREMTIME 2219e6e70f8STrond Myklebust | NFS_ATTR_FATTR_PRECTIME; 2221da177e4SLinus Torvalds return p; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 225d61005a6SAl Viro static inline __be32 * 226d61005a6SAl Viro xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds if (*p++) 2291da177e4SLinus Torvalds p = xdr_decode_fattr(p, fattr); 2301da177e4SLinus Torvalds return p; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 233d61005a6SAl Viro static inline __be32 * 234babddc72SBryan Schumaker xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr) 235babddc72SBryan Schumaker { 236babddc72SBryan Schumaker __be32 *p; 237babddc72SBryan Schumaker 238babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 239babddc72SBryan Schumaker if (unlikely(!p)) 240babddc72SBryan Schumaker goto out_overflow; 241babddc72SBryan Schumaker if (ntohl(*p++)) { 242babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 84); 243babddc72SBryan Schumaker if (unlikely(!p)) 244babddc72SBryan Schumaker goto out_overflow; 245babddc72SBryan Schumaker p = xdr_decode_fattr(p, fattr); 246babddc72SBryan Schumaker } 247babddc72SBryan Schumaker return p; 248babddc72SBryan Schumaker out_overflow: 249babddc72SBryan Schumaker print_overflow_msg(__func__, xdr); 250babddc72SBryan Schumaker return ERR_PTR(-EIO); 251babddc72SBryan Schumaker } 252babddc72SBryan Schumaker 253babddc72SBryan Schumaker static inline __be32 * 254d61005a6SAl Viro xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr) 2551da177e4SLinus Torvalds { 2561da177e4SLinus Torvalds if (*p++) 2571da177e4SLinus Torvalds return xdr_decode_wcc_attr(p, fattr); 2581da177e4SLinus Torvalds return p; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds 262d61005a6SAl Viro static inline __be32 * 263d61005a6SAl Viro xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr) 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds p = xdr_decode_pre_op_attr(p, fattr); 2661da177e4SLinus Torvalds return xdr_decode_post_op_attr(p, fattr); 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds 269d9c407b1SChuck Lever 270d9c407b1SChuck Lever /* 271d9c407b1SChuck Lever * Encode/decode NFSv3 basic data types 272d9c407b1SChuck Lever * 273d9c407b1SChuck Lever * Basic NFSv3 data types are defined in section 2.5 of RFC 1813: 274d9c407b1SChuck Lever * "NFS Version 3 Protocol Specification". 275d9c407b1SChuck Lever * 276d9c407b1SChuck Lever * Not all basic data types have their own encoding and decoding 277d9c407b1SChuck Lever * functions. For run-time efficiency, some data types are encoded 278d9c407b1SChuck Lever * or decoded inline. 279d9c407b1SChuck Lever */ 280d9c407b1SChuck Lever 281d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value) 282d9c407b1SChuck Lever { 283d9c407b1SChuck Lever __be32 *p = xdr_reserve_space(xdr, 4); 284d9c407b1SChuck Lever *p = cpu_to_be32(value); 285d9c407b1SChuck Lever } 286d9c407b1SChuck Lever 287d9c407b1SChuck Lever /* 288d9c407b1SChuck Lever * filename3 289d9c407b1SChuck Lever * 290d9c407b1SChuck Lever * typedef string filename3<>; 291d9c407b1SChuck Lever */ 292d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr, 293d9c407b1SChuck Lever const char *name, u32 length) 294d9c407b1SChuck Lever { 295d9c407b1SChuck Lever __be32 *p; 296d9c407b1SChuck Lever 297d9c407b1SChuck Lever BUG_ON(length > NFS3_MAXNAMLEN); 298d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + length); 299d9c407b1SChuck Lever xdr_encode_opaque(p, name, length); 300d9c407b1SChuck Lever } 301d9c407b1SChuck Lever 302d9c407b1SChuck Lever /* 303d9c407b1SChuck Lever * nfspath3 304d9c407b1SChuck Lever * 305d9c407b1SChuck Lever * typedef string nfspath3<>; 306d9c407b1SChuck Lever */ 307d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages, 308d9c407b1SChuck Lever const u32 length) 309d9c407b1SChuck Lever { 310d9c407b1SChuck Lever BUG_ON(length > NFS3_MAXPATHLEN); 311d9c407b1SChuck Lever encode_uint32(xdr, length); 312d9c407b1SChuck Lever xdr_write_pages(xdr, pages, 0, length); 313d9c407b1SChuck Lever } 314d9c407b1SChuck Lever 315d9c407b1SChuck Lever /* 316d9c407b1SChuck Lever * cookie3 317d9c407b1SChuck Lever * 318d9c407b1SChuck Lever * typedef uint64 cookie3 319d9c407b1SChuck Lever */ 320d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie) 321d9c407b1SChuck Lever { 322d9c407b1SChuck Lever return xdr_encode_hyper(p, cookie); 323d9c407b1SChuck Lever } 324d9c407b1SChuck Lever 325d9c407b1SChuck Lever /* 326d9c407b1SChuck Lever * cookieverf3 327d9c407b1SChuck Lever * 328d9c407b1SChuck Lever * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; 329d9c407b1SChuck Lever */ 330d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier) 331d9c407b1SChuck Lever { 332d9c407b1SChuck Lever memcpy(p, verifier, NFS3_COOKIEVERFSIZE); 333d9c407b1SChuck Lever return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE); 334d9c407b1SChuck Lever } 335d9c407b1SChuck Lever 336d9c407b1SChuck Lever /* 337d9c407b1SChuck Lever * createverf3 338d9c407b1SChuck Lever * 339d9c407b1SChuck Lever * typedef opaque createverf3[NFS3_CREATEVERFSIZE]; 340d9c407b1SChuck Lever */ 341d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier) 342d9c407b1SChuck Lever { 343d9c407b1SChuck Lever __be32 *p; 344d9c407b1SChuck Lever 345d9c407b1SChuck Lever p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE); 346d9c407b1SChuck Lever memcpy(p, verifier, NFS3_CREATEVERFSIZE); 347d9c407b1SChuck Lever } 348d9c407b1SChuck Lever 349d9c407b1SChuck Lever /* 350d9c407b1SChuck Lever * ftype3 351d9c407b1SChuck Lever * 352d9c407b1SChuck Lever * enum ftype3 { 353d9c407b1SChuck Lever * NF3REG = 1, 354d9c407b1SChuck Lever * NF3DIR = 2, 355d9c407b1SChuck Lever * NF3BLK = 3, 356d9c407b1SChuck Lever * NF3CHR = 4, 357d9c407b1SChuck Lever * NF3LNK = 5, 358d9c407b1SChuck Lever * NF3SOCK = 6, 359d9c407b1SChuck Lever * NF3FIFO = 7 360d9c407b1SChuck Lever * }; 361d9c407b1SChuck Lever */ 362d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type) 363d9c407b1SChuck Lever { 364d9c407b1SChuck Lever BUG_ON(type > NF3FIFO); 365d9c407b1SChuck Lever encode_uint32(xdr, type); 366d9c407b1SChuck Lever } 367d9c407b1SChuck Lever 368d9c407b1SChuck Lever /* 369d9c407b1SChuck Lever * specdata3 370d9c407b1SChuck Lever * 371d9c407b1SChuck Lever * struct specdata3 { 372d9c407b1SChuck Lever * uint32 specdata1; 373d9c407b1SChuck Lever * uint32 specdata2; 374d9c407b1SChuck Lever * }; 375d9c407b1SChuck Lever */ 376d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev) 377d9c407b1SChuck Lever { 378d9c407b1SChuck Lever __be32 *p; 379d9c407b1SChuck Lever 380d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8); 381d9c407b1SChuck Lever *p++ = cpu_to_be32(MAJOR(rdev)); 382d9c407b1SChuck Lever *p = cpu_to_be32(MINOR(rdev)); 383d9c407b1SChuck Lever } 384d9c407b1SChuck Lever 385d9c407b1SChuck Lever /* 386d9c407b1SChuck Lever * nfs_fh3 387d9c407b1SChuck Lever * 388d9c407b1SChuck Lever * struct nfs_fh3 { 389d9c407b1SChuck Lever * opaque data<NFS3_FHSIZE>; 390d9c407b1SChuck Lever * }; 391d9c407b1SChuck Lever */ 392d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh) 393d9c407b1SChuck Lever { 394d9c407b1SChuck Lever __be32 *p; 395d9c407b1SChuck Lever 396d9c407b1SChuck Lever BUG_ON(fh->size > NFS3_FHSIZE); 397d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + fh->size); 398d9c407b1SChuck Lever xdr_encode_opaque(p, fh->data, fh->size); 399d9c407b1SChuck Lever } 400d9c407b1SChuck Lever 401d9c407b1SChuck Lever /* 4029d5a6434SChuck Lever * nfstime3 4039d5a6434SChuck Lever * 4049d5a6434SChuck Lever * struct nfstime3 { 4059d5a6434SChuck Lever * uint32 seconds; 4069d5a6434SChuck Lever * uint32 nseconds; 4079d5a6434SChuck Lever * }; 4089d5a6434SChuck Lever */ 4099d5a6434SChuck Lever static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep) 4109d5a6434SChuck Lever { 4119d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_sec); 4129d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_nsec); 4139d5a6434SChuck Lever return p; 4149d5a6434SChuck Lever } 4159d5a6434SChuck Lever 4169d5a6434SChuck Lever /* 417d9c407b1SChuck Lever * sattr3 418d9c407b1SChuck Lever * 419d9c407b1SChuck Lever * enum time_how { 420d9c407b1SChuck Lever * DONT_CHANGE = 0, 421d9c407b1SChuck Lever * SET_TO_SERVER_TIME = 1, 422d9c407b1SChuck Lever * SET_TO_CLIENT_TIME = 2 423d9c407b1SChuck Lever * }; 424d9c407b1SChuck Lever * 425d9c407b1SChuck Lever * union set_mode3 switch (bool set_it) { 426d9c407b1SChuck Lever * case TRUE: 427d9c407b1SChuck Lever * mode3 mode; 428d9c407b1SChuck Lever * default: 429d9c407b1SChuck Lever * void; 430d9c407b1SChuck Lever * }; 431d9c407b1SChuck Lever * 432d9c407b1SChuck Lever * union set_uid3 switch (bool set_it) { 433d9c407b1SChuck Lever * case TRUE: 434d9c407b1SChuck Lever * uid3 uid; 435d9c407b1SChuck Lever * default: 436d9c407b1SChuck Lever * void; 437d9c407b1SChuck Lever * }; 438d9c407b1SChuck Lever * 439d9c407b1SChuck Lever * union set_gid3 switch (bool set_it) { 440d9c407b1SChuck Lever * case TRUE: 441d9c407b1SChuck Lever * gid3 gid; 442d9c407b1SChuck Lever * default: 443d9c407b1SChuck Lever * void; 444d9c407b1SChuck Lever * }; 445d9c407b1SChuck Lever * 446d9c407b1SChuck Lever * union set_size3 switch (bool set_it) { 447d9c407b1SChuck Lever * case TRUE: 448d9c407b1SChuck Lever * size3 size; 449d9c407b1SChuck Lever * default: 450d9c407b1SChuck Lever * void; 451d9c407b1SChuck Lever * }; 452d9c407b1SChuck Lever * 453d9c407b1SChuck Lever * union set_atime switch (time_how set_it) { 454d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 455d9c407b1SChuck Lever * nfstime3 atime; 456d9c407b1SChuck Lever * default: 457d9c407b1SChuck Lever * void; 458d9c407b1SChuck Lever * }; 459d9c407b1SChuck Lever * 460d9c407b1SChuck Lever * union set_mtime switch (time_how set_it) { 461d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 462d9c407b1SChuck Lever * nfstime3 mtime; 463d9c407b1SChuck Lever * default: 464d9c407b1SChuck Lever * void; 465d9c407b1SChuck Lever * }; 466d9c407b1SChuck Lever * 467d9c407b1SChuck Lever * struct sattr3 { 468d9c407b1SChuck Lever * set_mode3 mode; 469d9c407b1SChuck Lever * set_uid3 uid; 470d9c407b1SChuck Lever * set_gid3 gid; 471d9c407b1SChuck Lever * set_size3 size; 472d9c407b1SChuck Lever * set_atime atime; 473d9c407b1SChuck Lever * set_mtime mtime; 474d9c407b1SChuck Lever * }; 475d9c407b1SChuck Lever */ 476d9c407b1SChuck Lever static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr) 477d9c407b1SChuck Lever { 478d9c407b1SChuck Lever u32 nbytes; 479d9c407b1SChuck Lever __be32 *p; 480d9c407b1SChuck Lever 481d9c407b1SChuck Lever /* 482d9c407b1SChuck Lever * In order to make only a single xdr_reserve_space() call, 483d9c407b1SChuck Lever * pre-compute the total number of bytes to be reserved. 484d9c407b1SChuck Lever * Six boolean values, one for each set_foo field, are always 485d9c407b1SChuck Lever * present in the encoded result, so start there. 486d9c407b1SChuck Lever */ 487d9c407b1SChuck Lever nbytes = 6 * 4; 488d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MODE) 489d9c407b1SChuck Lever nbytes += 4; 490d9c407b1SChuck Lever if (attr->ia_valid & ATTR_UID) 491d9c407b1SChuck Lever nbytes += 4; 492d9c407b1SChuck Lever if (attr->ia_valid & ATTR_GID) 493d9c407b1SChuck Lever nbytes += 4; 494d9c407b1SChuck Lever if (attr->ia_valid & ATTR_SIZE) 495d9c407b1SChuck Lever nbytes += 8; 496d9c407b1SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) 497d9c407b1SChuck Lever nbytes += 8; 498d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) 499d9c407b1SChuck Lever nbytes += 8; 500d9c407b1SChuck Lever p = xdr_reserve_space(xdr, nbytes); 501d9c407b1SChuck Lever 5029d5a6434SChuck Lever if (attr->ia_valid & ATTR_MODE) { 5039d5a6434SChuck Lever *p++ = xdr_one; 5049d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO); 5059d5a6434SChuck Lever } else 5069d5a6434SChuck Lever *p++ = xdr_zero; 5079d5a6434SChuck Lever 5089d5a6434SChuck Lever if (attr->ia_valid & ATTR_UID) { 5099d5a6434SChuck Lever *p++ = xdr_one; 5109d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_uid); 5119d5a6434SChuck Lever } else 5129d5a6434SChuck Lever *p++ = xdr_zero; 5139d5a6434SChuck Lever 5149d5a6434SChuck Lever if (attr->ia_valid & ATTR_GID) { 5159d5a6434SChuck Lever *p++ = xdr_one; 5169d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_gid); 5179d5a6434SChuck Lever } else 5189d5a6434SChuck Lever *p++ = xdr_zero; 5199d5a6434SChuck Lever 5209d5a6434SChuck Lever if (attr->ia_valid & ATTR_SIZE) { 5219d5a6434SChuck Lever *p++ = xdr_one; 5229d5a6434SChuck Lever p = xdr_encode_hyper(p, (u64)attr->ia_size); 5239d5a6434SChuck Lever } else 5249d5a6434SChuck Lever *p++ = xdr_zero; 5259d5a6434SChuck Lever 5269d5a6434SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) { 5279d5a6434SChuck Lever *p++ = xdr_two; 5289d5a6434SChuck Lever p = xdr_encode_nfstime3(p, &attr->ia_atime); 5299d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_ATIME) { 5309d5a6434SChuck Lever *p++ = xdr_one; 5319d5a6434SChuck Lever } else 5329d5a6434SChuck Lever *p++ = xdr_zero; 5339d5a6434SChuck Lever 5349d5a6434SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) { 5359d5a6434SChuck Lever *p++ = xdr_two; 5369d5a6434SChuck Lever xdr_encode_nfstime3(p, &attr->ia_mtime); 5379d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_MTIME) { 5389d5a6434SChuck Lever *p = xdr_one; 5399d5a6434SChuck Lever } else 5409d5a6434SChuck Lever *p = xdr_zero; 541d9c407b1SChuck Lever } 542d9c407b1SChuck Lever 543d9c407b1SChuck Lever /* 544d9c407b1SChuck Lever * diropargs3 545d9c407b1SChuck Lever * 546d9c407b1SChuck Lever * struct diropargs3 { 547d9c407b1SChuck Lever * nfs_fh3 dir; 548d9c407b1SChuck Lever * filename3 name; 549d9c407b1SChuck Lever * }; 550d9c407b1SChuck Lever */ 551d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh, 552d9c407b1SChuck Lever const char *name, u32 length) 553d9c407b1SChuck Lever { 554d9c407b1SChuck Lever encode_nfs_fh3(xdr, fh); 555d9c407b1SChuck Lever encode_filename3(xdr, name, length); 556d9c407b1SChuck Lever } 557d9c407b1SChuck Lever 558d9c407b1SChuck Lever 5591da177e4SLinus Torvalds /* 560499ff710SChuck Lever * NFSv3 XDR encode functions 561499ff710SChuck Lever * 562499ff710SChuck Lever * NFSv3 argument types are defined in section 3.3 of RFC 1813: 563499ff710SChuck Lever * "NFS Version 3 Protocol Specification". 5641da177e4SLinus Torvalds */ 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds /* 567d9c407b1SChuck Lever * 3.3.1 GETATTR3args 568d9c407b1SChuck Lever * 569d9c407b1SChuck Lever * struct GETATTR3args { 570d9c407b1SChuck Lever * nfs_fh3 object; 571d9c407b1SChuck Lever * }; 572d9c407b1SChuck Lever */ 573d9c407b1SChuck Lever static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p, 574d9c407b1SChuck Lever const struct nfs_fh *fh) 575d9c407b1SChuck Lever { 576d9c407b1SChuck Lever struct xdr_stream xdr; 577d9c407b1SChuck Lever 578d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 579d9c407b1SChuck Lever encode_nfs_fh3(&xdr, fh); 580d9c407b1SChuck Lever return 0; 581d9c407b1SChuck Lever } 582d9c407b1SChuck Lever 583d9c407b1SChuck Lever /* 584d9c407b1SChuck Lever * 3.3.2 SETATTR3args 585d9c407b1SChuck Lever * 586d9c407b1SChuck Lever * union sattrguard3 switch (bool check) { 587d9c407b1SChuck Lever * case TRUE: 588d9c407b1SChuck Lever * nfstime3 obj_ctime; 589d9c407b1SChuck Lever * case FALSE: 590d9c407b1SChuck Lever * void; 591d9c407b1SChuck Lever * }; 592d9c407b1SChuck Lever * 593d9c407b1SChuck Lever * struct SETATTR3args { 594d9c407b1SChuck Lever * nfs_fh3 object; 595d9c407b1SChuck Lever * sattr3 new_attributes; 596d9c407b1SChuck Lever * sattrguard3 guard; 597d9c407b1SChuck Lever * }; 598d9c407b1SChuck Lever */ 599d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr, 600d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 601d9c407b1SChuck Lever { 602d9c407b1SChuck Lever __be32 *p; 603d9c407b1SChuck Lever 604d9c407b1SChuck Lever if (args->guard) { 605d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + 8); 606d9c407b1SChuck Lever *p++ = xdr_one; 6079d5a6434SChuck Lever xdr_encode_nfstime3(p, &args->guardtime); 608d9c407b1SChuck Lever } else { 609d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4); 610d9c407b1SChuck Lever *p = xdr_zero; 611d9c407b1SChuck Lever } 612d9c407b1SChuck Lever } 613d9c407b1SChuck Lever 614d9c407b1SChuck Lever static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p, 615d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 616d9c407b1SChuck Lever { 617d9c407b1SChuck Lever struct xdr_stream xdr; 618d9c407b1SChuck Lever 619d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 620d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fh); 621d9c407b1SChuck Lever encode_sattr3(&xdr, args->sattr); 622d9c407b1SChuck Lever encode_sattrguard3(&xdr, args); 623d9c407b1SChuck Lever return 0; 624d9c407b1SChuck Lever } 625d9c407b1SChuck Lever 626d9c407b1SChuck Lever /* 627d9c407b1SChuck Lever * 3.3.3 LOOKUP3args 628d9c407b1SChuck Lever * 629d9c407b1SChuck Lever * struct LOOKUP3args { 630d9c407b1SChuck Lever * diropargs3 what; 631d9c407b1SChuck Lever * }; 632d9c407b1SChuck Lever */ 633d9c407b1SChuck Lever static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p, 634d9c407b1SChuck Lever const struct nfs3_diropargs *args) 635d9c407b1SChuck Lever { 636d9c407b1SChuck Lever struct xdr_stream xdr; 637d9c407b1SChuck Lever 638d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 639d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 640d9c407b1SChuck Lever return 0; 641d9c407b1SChuck Lever } 642d9c407b1SChuck Lever 643d9c407b1SChuck Lever /* 644d9c407b1SChuck Lever * 3.3.4 ACCESS3args 645d9c407b1SChuck Lever * 646d9c407b1SChuck Lever * struct ACCESS3args { 647d9c407b1SChuck Lever * nfs_fh3 object; 648d9c407b1SChuck Lever * uint32 access; 649d9c407b1SChuck Lever * }; 650d9c407b1SChuck Lever */ 651d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr, 652d9c407b1SChuck Lever const struct nfs3_accessargs *args) 653d9c407b1SChuck Lever { 654d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 655d9c407b1SChuck Lever encode_uint32(xdr, args->access); 656d9c407b1SChuck Lever } 657d9c407b1SChuck Lever 658d9c407b1SChuck Lever static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p, 659d9c407b1SChuck Lever const struct nfs3_accessargs *args) 660d9c407b1SChuck Lever { 661d9c407b1SChuck Lever struct xdr_stream xdr; 662d9c407b1SChuck Lever 663d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 664d9c407b1SChuck Lever encode_access3args(&xdr, args); 665d9c407b1SChuck Lever return 0; 666d9c407b1SChuck Lever } 667d9c407b1SChuck Lever 668d9c407b1SChuck Lever /* 669d9c407b1SChuck Lever * 3.3.5 READLINK3args 670d9c407b1SChuck Lever * 671d9c407b1SChuck Lever * struct READLINK3args { 672d9c407b1SChuck Lever * nfs_fh3 symlink; 673d9c407b1SChuck Lever * }; 674d9c407b1SChuck Lever */ 675d9c407b1SChuck Lever static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p, 676d9c407b1SChuck Lever const struct nfs3_readlinkargs *args) 677d9c407b1SChuck Lever { 678d9c407b1SChuck Lever struct xdr_stream xdr; 679d9c407b1SChuck Lever 680d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 681d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fh); 682d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 683d9c407b1SChuck Lever args->pglen, NFS3_readlinkres_sz); 684d9c407b1SChuck Lever return 0; 685d9c407b1SChuck Lever } 686d9c407b1SChuck Lever 687d9c407b1SChuck Lever /* 688d9c407b1SChuck Lever * 3.3.6 READ3args 689d9c407b1SChuck Lever * 690d9c407b1SChuck Lever * struct READ3args { 691d9c407b1SChuck Lever * nfs_fh3 file; 692d9c407b1SChuck Lever * offset3 offset; 693d9c407b1SChuck Lever * count3 count; 694d9c407b1SChuck Lever * }; 695d9c407b1SChuck Lever */ 696d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr, 697d9c407b1SChuck Lever const struct nfs_readargs *args) 698d9c407b1SChuck Lever { 699d9c407b1SChuck Lever __be32 *p; 700d9c407b1SChuck Lever 701d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 702d9c407b1SChuck Lever 703d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 704d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 705d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 706d9c407b1SChuck Lever } 707d9c407b1SChuck Lever 708d9c407b1SChuck Lever static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p, 709d9c407b1SChuck Lever const struct nfs_readargs *args) 710d9c407b1SChuck Lever { 711d9c407b1SChuck Lever struct xdr_stream xdr; 712d9c407b1SChuck Lever 713d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 714d9c407b1SChuck Lever encode_read3args(&xdr, args); 715d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 716d9c407b1SChuck Lever args->count, NFS3_readres_sz); 717d9c407b1SChuck Lever req->rq_rcv_buf.flags |= XDRBUF_READ; 718d9c407b1SChuck Lever return 0; 719d9c407b1SChuck Lever } 720d9c407b1SChuck Lever 721d9c407b1SChuck Lever /* 722d9c407b1SChuck Lever * 3.3.7 WRITE3args 723d9c407b1SChuck Lever * 724d9c407b1SChuck Lever * enum stable_how { 725d9c407b1SChuck Lever * UNSTABLE = 0, 726d9c407b1SChuck Lever * DATA_SYNC = 1, 727d9c407b1SChuck Lever * FILE_SYNC = 2 728d9c407b1SChuck Lever * }; 729d9c407b1SChuck Lever * 730d9c407b1SChuck Lever * struct WRITE3args { 731d9c407b1SChuck Lever * nfs_fh3 file; 732d9c407b1SChuck Lever * offset3 offset; 733d9c407b1SChuck Lever * count3 count; 734d9c407b1SChuck Lever * stable_how stable; 735d9c407b1SChuck Lever * opaque data<>; 736d9c407b1SChuck Lever * }; 737d9c407b1SChuck Lever */ 738d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr, 739d9c407b1SChuck Lever const struct nfs_writeargs *args) 740d9c407b1SChuck Lever { 741d9c407b1SChuck Lever __be32 *p; 742d9c407b1SChuck Lever 743d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 744d9c407b1SChuck Lever 745d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4); 746d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 747d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count); 748d9c407b1SChuck Lever 749d9c407b1SChuck Lever BUG_ON(args->stable > NFS_FILE_SYNC); 750d9c407b1SChuck Lever *p++ = cpu_to_be32(args->stable); 751d9c407b1SChuck Lever 752d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 753d9c407b1SChuck Lever xdr_write_pages(xdr, args->pages, args->pgbase, args->count); 754d9c407b1SChuck Lever } 755d9c407b1SChuck Lever 756d9c407b1SChuck Lever static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p, 757d9c407b1SChuck Lever const struct nfs_writeargs *args) 758d9c407b1SChuck Lever { 759d9c407b1SChuck Lever struct xdr_stream xdr; 760d9c407b1SChuck Lever 761d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 762d9c407b1SChuck Lever encode_write3args(&xdr, args); 763d9c407b1SChuck Lever xdr.buf->flags |= XDRBUF_WRITE; 764d9c407b1SChuck Lever return 0; 765d9c407b1SChuck Lever } 766d9c407b1SChuck Lever 767d9c407b1SChuck Lever /* 768d9c407b1SChuck Lever * 3.3.8 CREATE3args 769d9c407b1SChuck Lever * 770d9c407b1SChuck Lever * enum createmode3 { 771d9c407b1SChuck Lever * UNCHECKED = 0, 772d9c407b1SChuck Lever * GUARDED = 1, 773d9c407b1SChuck Lever * EXCLUSIVE = 2 774d9c407b1SChuck Lever * }; 775d9c407b1SChuck Lever * 776d9c407b1SChuck Lever * union createhow3 switch (createmode3 mode) { 777d9c407b1SChuck Lever * case UNCHECKED: 778d9c407b1SChuck Lever * case GUARDED: 779d9c407b1SChuck Lever * sattr3 obj_attributes; 780d9c407b1SChuck Lever * case EXCLUSIVE: 781d9c407b1SChuck Lever * createverf3 verf; 782d9c407b1SChuck Lever * }; 783d9c407b1SChuck Lever * 784d9c407b1SChuck Lever * struct CREATE3args { 785d9c407b1SChuck Lever * diropargs3 where; 786d9c407b1SChuck Lever * createhow3 how; 787d9c407b1SChuck Lever * }; 788d9c407b1SChuck Lever */ 789d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr, 790d9c407b1SChuck Lever const struct nfs3_createargs *args) 791d9c407b1SChuck Lever { 792d9c407b1SChuck Lever encode_uint32(xdr, args->createmode); 793d9c407b1SChuck Lever switch (args->createmode) { 794d9c407b1SChuck Lever case NFS3_CREATE_UNCHECKED: 795d9c407b1SChuck Lever case NFS3_CREATE_GUARDED: 796d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 797d9c407b1SChuck Lever break; 798d9c407b1SChuck Lever case NFS3_CREATE_EXCLUSIVE: 799d9c407b1SChuck Lever encode_createverf3(xdr, args->verifier); 800d9c407b1SChuck Lever break; 801d9c407b1SChuck Lever default: 802d9c407b1SChuck Lever BUG(); 803d9c407b1SChuck Lever } 804d9c407b1SChuck Lever } 805d9c407b1SChuck Lever 806d9c407b1SChuck Lever static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p, 807d9c407b1SChuck Lever const struct nfs3_createargs *args) 808d9c407b1SChuck Lever { 809d9c407b1SChuck Lever struct xdr_stream xdr; 810d9c407b1SChuck Lever 811d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 812d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 813d9c407b1SChuck Lever encode_createhow3(&xdr, args); 814d9c407b1SChuck Lever return 0; 815d9c407b1SChuck Lever } 816d9c407b1SChuck Lever 817d9c407b1SChuck Lever /* 818d9c407b1SChuck Lever * 3.3.9 MKDIR3args 819d9c407b1SChuck Lever * 820d9c407b1SChuck Lever * struct MKDIR3args { 821d9c407b1SChuck Lever * diropargs3 where; 822d9c407b1SChuck Lever * sattr3 attributes; 823d9c407b1SChuck Lever * }; 824d9c407b1SChuck Lever */ 825d9c407b1SChuck Lever static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p, 826d9c407b1SChuck Lever const struct nfs3_mkdirargs *args) 827d9c407b1SChuck Lever { 828d9c407b1SChuck Lever struct xdr_stream xdr; 829d9c407b1SChuck Lever 830d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 831d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 832d9c407b1SChuck Lever encode_sattr3(&xdr, args->sattr); 833d9c407b1SChuck Lever return 0; 834d9c407b1SChuck Lever } 835d9c407b1SChuck Lever 836d9c407b1SChuck Lever /* 837d9c407b1SChuck Lever * 3.3.10 SYMLINK3args 838d9c407b1SChuck Lever * 839d9c407b1SChuck Lever * struct symlinkdata3 { 840d9c407b1SChuck Lever * sattr3 symlink_attributes; 841d9c407b1SChuck Lever * nfspath3 symlink_data; 842d9c407b1SChuck Lever * }; 843d9c407b1SChuck Lever * 844d9c407b1SChuck Lever * struct SYMLINK3args { 845d9c407b1SChuck Lever * diropargs3 where; 846d9c407b1SChuck Lever * symlinkdata3 symlink; 847d9c407b1SChuck Lever * }; 848d9c407b1SChuck Lever */ 849d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr, 850d9c407b1SChuck Lever const struct nfs3_symlinkargs *args) 851d9c407b1SChuck Lever { 852d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 853d9c407b1SChuck Lever encode_nfspath3(xdr, args->pages, args->pathlen); 854d9c407b1SChuck Lever } 855d9c407b1SChuck Lever 856d9c407b1SChuck Lever static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p, 857d9c407b1SChuck Lever const struct nfs3_symlinkargs *args) 858d9c407b1SChuck Lever { 859d9c407b1SChuck Lever struct xdr_stream xdr; 860d9c407b1SChuck Lever 861d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 862d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen); 863d9c407b1SChuck Lever encode_symlinkdata3(&xdr, args); 864d9c407b1SChuck Lever return 0; 865d9c407b1SChuck Lever } 866d9c407b1SChuck Lever 867d9c407b1SChuck Lever /* 868d9c407b1SChuck Lever * 3.3.11 MKNOD3args 869d9c407b1SChuck Lever * 870d9c407b1SChuck Lever * struct devicedata3 { 871d9c407b1SChuck Lever * sattr3 dev_attributes; 872d9c407b1SChuck Lever * specdata3 spec; 873d9c407b1SChuck Lever * }; 874d9c407b1SChuck Lever * 875d9c407b1SChuck Lever * union mknoddata3 switch (ftype3 type) { 876d9c407b1SChuck Lever * case NF3CHR: 877d9c407b1SChuck Lever * case NF3BLK: 878d9c407b1SChuck Lever * devicedata3 device; 879d9c407b1SChuck Lever * case NF3SOCK: 880d9c407b1SChuck Lever * case NF3FIFO: 881d9c407b1SChuck Lever * sattr3 pipe_attributes; 882d9c407b1SChuck Lever * default: 883d9c407b1SChuck Lever * void; 884d9c407b1SChuck Lever * }; 885d9c407b1SChuck Lever * 886d9c407b1SChuck Lever * struct MKNOD3args { 887d9c407b1SChuck Lever * diropargs3 where; 888d9c407b1SChuck Lever * mknoddata3 what; 889d9c407b1SChuck Lever * }; 890d9c407b1SChuck Lever */ 891d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr, 892d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 893d9c407b1SChuck Lever { 894d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 895d9c407b1SChuck Lever encode_specdata3(xdr, args->rdev); 896d9c407b1SChuck Lever } 897d9c407b1SChuck Lever 898d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr, 899d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 900d9c407b1SChuck Lever { 901d9c407b1SChuck Lever encode_ftype3(xdr, args->type); 902d9c407b1SChuck Lever switch (args->type) { 903d9c407b1SChuck Lever case NF3CHR: 904d9c407b1SChuck Lever case NF3BLK: 905d9c407b1SChuck Lever encode_devicedata3(xdr, args); 906d9c407b1SChuck Lever break; 907d9c407b1SChuck Lever case NF3SOCK: 908d9c407b1SChuck Lever case NF3FIFO: 909d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 910d9c407b1SChuck Lever break; 911d9c407b1SChuck Lever case NF3REG: 912d9c407b1SChuck Lever case NF3DIR: 913d9c407b1SChuck Lever break; 914d9c407b1SChuck Lever default: 915d9c407b1SChuck Lever BUG(); 916d9c407b1SChuck Lever } 917d9c407b1SChuck Lever } 918d9c407b1SChuck Lever 919d9c407b1SChuck Lever static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p, 920d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 921d9c407b1SChuck Lever { 922d9c407b1SChuck Lever struct xdr_stream xdr; 923d9c407b1SChuck Lever 924d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 925d9c407b1SChuck Lever encode_diropargs3(&xdr, args->fh, args->name, args->len); 926d9c407b1SChuck Lever encode_mknoddata3(&xdr, args); 927d9c407b1SChuck Lever return 0; 928d9c407b1SChuck Lever } 929d9c407b1SChuck Lever 930d9c407b1SChuck Lever /* 931d9c407b1SChuck Lever * 3.3.12 REMOVE3args 932d9c407b1SChuck Lever * 933d9c407b1SChuck Lever * struct REMOVE3args { 934d9c407b1SChuck Lever * diropargs3 object; 935d9c407b1SChuck Lever * }; 936d9c407b1SChuck Lever */ 937d9c407b1SChuck Lever static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p, 938d9c407b1SChuck Lever const struct nfs_removeargs *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.name, args->name.len); 944d9c407b1SChuck Lever return 0; 945d9c407b1SChuck Lever } 946d9c407b1SChuck Lever 947d9c407b1SChuck Lever /* 948d9c407b1SChuck Lever * 3.3.14 RENAME3args 949d9c407b1SChuck Lever * 950d9c407b1SChuck Lever * struct RENAME3args { 951d9c407b1SChuck Lever * diropargs3 from; 952d9c407b1SChuck Lever * diropargs3 to; 953d9c407b1SChuck Lever * }; 954d9c407b1SChuck Lever */ 955d9c407b1SChuck Lever static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p, 956d9c407b1SChuck Lever const struct nfs_renameargs *args) 957d9c407b1SChuck Lever { 958d9c407b1SChuck Lever const struct qstr *old = args->old_name; 959d9c407b1SChuck Lever const struct qstr *new = args->new_name; 960d9c407b1SChuck Lever struct xdr_stream xdr; 961d9c407b1SChuck Lever 962d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 963d9c407b1SChuck Lever encode_diropargs3(&xdr, args->old_dir, old->name, old->len); 964d9c407b1SChuck Lever encode_diropargs3(&xdr, args->new_dir, new->name, new->len); 965d9c407b1SChuck Lever return 0; 966d9c407b1SChuck Lever } 967d9c407b1SChuck Lever 968d9c407b1SChuck Lever /* 969d9c407b1SChuck Lever * 3.3.15 LINK3args 970d9c407b1SChuck Lever * 971d9c407b1SChuck Lever * struct LINK3args { 972d9c407b1SChuck Lever * nfs_fh3 file; 973d9c407b1SChuck Lever * diropargs3 link; 974d9c407b1SChuck Lever * }; 975d9c407b1SChuck Lever */ 976d9c407b1SChuck Lever static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p, 977d9c407b1SChuck Lever const struct nfs3_linkargs *args) 978d9c407b1SChuck Lever { 979d9c407b1SChuck Lever struct xdr_stream xdr; 980d9c407b1SChuck Lever 981d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 982d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fromfh); 983d9c407b1SChuck Lever encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen); 984d9c407b1SChuck Lever return 0; 985d9c407b1SChuck Lever } 986d9c407b1SChuck Lever 987d9c407b1SChuck Lever /* 988d9c407b1SChuck Lever * 3.3.16 READDIR3args 989d9c407b1SChuck Lever * 990d9c407b1SChuck Lever * struct READDIR3args { 991d9c407b1SChuck Lever * nfs_fh3 dir; 992d9c407b1SChuck Lever * cookie3 cookie; 993d9c407b1SChuck Lever * cookieverf3 cookieverf; 994d9c407b1SChuck Lever * count3 count; 995d9c407b1SChuck Lever * }; 996d9c407b1SChuck Lever */ 997d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr, 998d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 999d9c407b1SChuck Lever { 1000d9c407b1SChuck Lever __be32 *p; 1001d9c407b1SChuck Lever 1002d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1003d9c407b1SChuck Lever 1004d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4); 1005d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1006d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1007d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1008d9c407b1SChuck Lever } 1009d9c407b1SChuck Lever 1010d9c407b1SChuck Lever static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p, 1011d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1012d9c407b1SChuck Lever { 1013d9c407b1SChuck Lever struct xdr_stream xdr; 1014d9c407b1SChuck Lever 1015d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1016d9c407b1SChuck Lever encode_readdir3args(&xdr, args); 1017d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1018d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1019d9c407b1SChuck Lever return 0; 1020d9c407b1SChuck Lever } 1021d9c407b1SChuck Lever 1022d9c407b1SChuck Lever /* 1023d9c407b1SChuck Lever * 3.3.17 READDIRPLUS3args 1024d9c407b1SChuck Lever * 1025d9c407b1SChuck Lever * struct READDIRPLUS3args { 1026d9c407b1SChuck Lever * nfs_fh3 dir; 1027d9c407b1SChuck Lever * cookie3 cookie; 1028d9c407b1SChuck Lever * cookieverf3 cookieverf; 1029d9c407b1SChuck Lever * count3 dircount; 1030d9c407b1SChuck Lever * count3 maxcount; 1031d9c407b1SChuck Lever * }; 1032d9c407b1SChuck Lever */ 1033d9c407b1SChuck Lever static void encode_readdirplus3args(struct xdr_stream *xdr, 1034d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1035d9c407b1SChuck Lever { 1036d9c407b1SChuck Lever __be32 *p; 1037d9c407b1SChuck Lever 1038d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1039d9c407b1SChuck Lever 1040d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4); 1041d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1042d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1043d9c407b1SChuck Lever 1044d9c407b1SChuck Lever /* 1045d9c407b1SChuck Lever * readdirplus: need dircount + buffer size. 1046d9c407b1SChuck Lever * We just make sure we make dircount big enough 1047d9c407b1SChuck Lever */ 1048d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count >> 3); 1049d9c407b1SChuck Lever 1050d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1051d9c407b1SChuck Lever } 1052d9c407b1SChuck Lever 1053d9c407b1SChuck Lever static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p, 1054d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1055d9c407b1SChuck Lever { 1056d9c407b1SChuck Lever struct xdr_stream xdr; 1057d9c407b1SChuck Lever 1058d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1059d9c407b1SChuck Lever encode_readdirplus3args(&xdr, args); 1060d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1061d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1062d9c407b1SChuck Lever return 0; 1063d9c407b1SChuck Lever } 1064d9c407b1SChuck Lever 1065d9c407b1SChuck Lever /* 10661da177e4SLinus Torvalds * Decode the result of a readdir call. 10671da177e4SLinus Torvalds * We just check for syntactical correctness. 10681da177e4SLinus Torvalds */ 10691da177e4SLinus Torvalds static int 1070d61005a6SAl Viro nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res) 10711da177e4SLinus Torvalds { 10721da177e4SLinus Torvalds struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 10731da177e4SLinus Torvalds struct kvec *iov = rcvbuf->head; 10741da177e4SLinus Torvalds struct page **page; 1075c957c526SChuck Lever size_t hdrlen; 1076afa8ccc9SBryan Schumaker u32 recvd, pglen; 1077ac396128STrond Myklebust int status; 10781da177e4SLinus Torvalds 10791da177e4SLinus Torvalds status = ntohl(*p++); 10801da177e4SLinus Torvalds /* Decode post_op_attrs */ 10811da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->dir_attr); 10821da177e4SLinus Torvalds if (status) 1083856dff3dSBenny Halevy return nfs_stat_to_errno(status); 10841da177e4SLinus Torvalds /* Decode verifier cookie */ 10851da177e4SLinus Torvalds if (res->verf) { 10861da177e4SLinus Torvalds res->verf[0] = *p++; 10871da177e4SLinus Torvalds res->verf[1] = *p++; 10881da177e4SLinus Torvalds } else { 10891da177e4SLinus Torvalds p += 2; 10901da177e4SLinus Torvalds } 10911da177e4SLinus Torvalds 10921da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 10931da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1094fe82a183SChuck Lever dprintk("NFS: READDIR reply header overflowed:" 1095c957c526SChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 10961da177e4SLinus Torvalds return -errno_NFSERR_IO; 10971da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 10981da177e4SLinus Torvalds dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); 10991da177e4SLinus Torvalds xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 11001da177e4SLinus Torvalds } 11011da177e4SLinus Torvalds 11021da177e4SLinus Torvalds pglen = rcvbuf->page_len; 11031da177e4SLinus Torvalds recvd = rcvbuf->len - hdrlen; 11041da177e4SLinus Torvalds if (pglen > recvd) 11051da177e4SLinus Torvalds pglen = recvd; 11061da177e4SLinus Torvalds page = rcvbuf->pages; 1107643f8111SJeff Layton 1108ac396128STrond Myklebust return pglen; 11091da177e4SLinus Torvalds } 11101da177e4SLinus Torvalds 11110dbb4c67SAl Viro __be32 * 111282f2e547SBryan Schumaker nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus) 11131da177e4SLinus Torvalds { 1114babddc72SBryan Schumaker __be32 *p; 11151da177e4SLinus Torvalds struct nfs_entry old = *entry; 11161da177e4SLinus Torvalds 1117babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 1118babddc72SBryan Schumaker if (unlikely(!p)) 1119babddc72SBryan Schumaker goto out_overflow; 1120babddc72SBryan Schumaker if (!ntohl(*p++)) { 1121babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 1122babddc72SBryan Schumaker if (unlikely(!p)) 1123babddc72SBryan Schumaker goto out_overflow; 1124babddc72SBryan Schumaker if (!ntohl(*p++)) 11251da177e4SLinus Torvalds return ERR_PTR(-EAGAIN); 11261da177e4SLinus Torvalds entry->eof = 1; 11271da177e4SLinus Torvalds return ERR_PTR(-EBADCOOKIE); 11281da177e4SLinus Torvalds } 11291da177e4SLinus Torvalds 1130babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 12); 1131babddc72SBryan Schumaker if (unlikely(!p)) 1132babddc72SBryan Schumaker goto out_overflow; 11331da177e4SLinus Torvalds p = xdr_decode_hyper(p, &entry->ino); 11341da177e4SLinus Torvalds entry->len = ntohl(*p++); 1135babddc72SBryan Schumaker 1136babddc72SBryan Schumaker p = xdr_inline_decode(xdr, entry->len + 8); 1137babddc72SBryan Schumaker if (unlikely(!p)) 1138babddc72SBryan Schumaker goto out_overflow; 11391da177e4SLinus Torvalds entry->name = (const char *) p; 11401da177e4SLinus Torvalds p += XDR_QUADLEN(entry->len); 11411da177e4SLinus Torvalds entry->prev_cookie = entry->cookie; 11421da177e4SLinus Torvalds p = xdr_decode_hyper(p, &entry->cookie); 11431da177e4SLinus Torvalds 11440b26a0bfSTrond Myklebust entry->d_type = DT_UNKNOWN; 11451da177e4SLinus Torvalds if (plus) { 11461da177e4SLinus Torvalds entry->fattr->valid = 0; 1147babddc72SBryan Schumaker p = xdr_decode_post_op_attr_stream(xdr, entry->fattr); 1148babddc72SBryan Schumaker if (IS_ERR(p)) 1149babddc72SBryan Schumaker goto out_overflow_exit; 11500b26a0bfSTrond Myklebust entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); 11511da177e4SLinus Torvalds /* In fact, a post_op_fh3: */ 1152babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 1153babddc72SBryan Schumaker if (unlikely(!p)) 1154babddc72SBryan Schumaker goto out_overflow; 11551da177e4SLinus Torvalds if (*p++) { 1156babddc72SBryan Schumaker p = xdr_decode_fhandle_stream(xdr, entry->fh); 1157babddc72SBryan Schumaker if (IS_ERR(p)) 1158babddc72SBryan Schumaker goto out_overflow_exit; 11591da177e4SLinus Torvalds /* Ugh -- server reply was truncated */ 11601da177e4SLinus Torvalds if (p == NULL) { 11611da177e4SLinus Torvalds dprintk("NFS: FH truncated\n"); 11621da177e4SLinus Torvalds *entry = old; 11631da177e4SLinus Torvalds return ERR_PTR(-EAGAIN); 11641da177e4SLinus Torvalds } 11651da177e4SLinus Torvalds } else 11661da177e4SLinus Torvalds memset((u8*)(entry->fh), 0, sizeof(*entry->fh)); 11671da177e4SLinus Torvalds } 11681da177e4SLinus Torvalds 1169babddc72SBryan Schumaker p = xdr_inline_peek(xdr, 8); 1170babddc72SBryan Schumaker if (p != NULL) 11711da177e4SLinus Torvalds entry->eof = !p[0] && p[1]; 1172babddc72SBryan Schumaker else 1173babddc72SBryan Schumaker entry->eof = 0; 1174babddc72SBryan Schumaker 11751da177e4SLinus Torvalds return p; 1176babddc72SBryan Schumaker 1177babddc72SBryan Schumaker out_overflow: 1178babddc72SBryan Schumaker print_overflow_msg(__func__, xdr); 1179babddc72SBryan Schumaker out_overflow_exit: 1180463a376eSTrond Myklebust return ERR_PTR(-EAGAIN); 11811da177e4SLinus Torvalds } 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds /* 1184d9c407b1SChuck Lever * 3.3.21 COMMIT3args 1185d9c407b1SChuck Lever * 1186d9c407b1SChuck Lever * struct COMMIT3args { 1187d9c407b1SChuck Lever * nfs_fh3 file; 1188d9c407b1SChuck Lever * offset3 offset; 1189d9c407b1SChuck Lever * count3 count; 1190d9c407b1SChuck Lever * }; 1191d9c407b1SChuck Lever */ 1192d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr, 1193d9c407b1SChuck Lever const struct nfs_writeargs *args) 1194d9c407b1SChuck Lever { 1195d9c407b1SChuck Lever __be32 *p; 1196d9c407b1SChuck Lever 1197d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1198d9c407b1SChuck Lever 1199d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 1200d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 1201d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1202d9c407b1SChuck Lever } 1203d9c407b1SChuck Lever 1204d9c407b1SChuck Lever static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p, 1205d9c407b1SChuck Lever const struct nfs_writeargs *args) 1206d9c407b1SChuck Lever { 1207d9c407b1SChuck Lever struct xdr_stream xdr; 1208d9c407b1SChuck Lever 1209d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1210d9c407b1SChuck Lever encode_commit3args(&xdr, args); 1211d9c407b1SChuck Lever return 0; 1212d9c407b1SChuck Lever } 1213d9c407b1SChuck Lever 1214b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 1215b7fa0554SAndreas Gruenbacher 1216d9c407b1SChuck Lever static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p, 1217d9c407b1SChuck Lever const struct nfs3_getaclargs *args) 1218d9c407b1SChuck Lever { 1219d9c407b1SChuck Lever struct xdr_stream xdr; 1220d9c407b1SChuck Lever 1221d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1222d9c407b1SChuck Lever encode_nfs_fh3(&xdr, args->fh); 1223d9c407b1SChuck Lever encode_uint32(&xdr, args->mask); 1224d9c407b1SChuck Lever if (args->mask & (NFS_ACL | NFS_DFACL)) 1225d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1226d9c407b1SChuck Lever NFSACL_MAXPAGES << PAGE_SHIFT, 1227d9c407b1SChuck Lever ACL3_getaclres_sz); 1228d9c407b1SChuck Lever return 0; 1229d9c407b1SChuck Lever } 1230d9c407b1SChuck Lever 1231d9c407b1SChuck Lever static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p, 1232d9c407b1SChuck Lever const struct nfs3_setaclargs *args) 1233d9c407b1SChuck Lever { 1234d9c407b1SChuck Lever struct xdr_stream xdr; 1235d9c407b1SChuck Lever unsigned int base; 1236d9c407b1SChuck Lever int error; 1237d9c407b1SChuck Lever 1238d9c407b1SChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1239d9c407b1SChuck Lever encode_nfs_fh3(&xdr, NFS_FH(args->inode)); 1240d9c407b1SChuck Lever encode_uint32(&xdr, args->mask); 1241d9c407b1SChuck Lever if (args->npages != 0) 1242d9c407b1SChuck Lever xdr_write_pages(&xdr, args->pages, 0, args->len); 1243d9c407b1SChuck Lever 1244d9c407b1SChuck Lever base = req->rq_slen; 1245d9c407b1SChuck Lever error = nfsacl_encode(xdr.buf, base, args->inode, 1246d9c407b1SChuck Lever (args->mask & NFS_ACL) ? 1247d9c407b1SChuck Lever args->acl_access : NULL, 1, 0); 1248d9c407b1SChuck Lever BUG_ON(error < 0); 1249d9c407b1SChuck Lever error = nfsacl_encode(xdr.buf, base + error, args->inode, 1250d9c407b1SChuck Lever (args->mask & NFS_DFACL) ? 1251d9c407b1SChuck Lever args->acl_default : NULL, 1, 1252d9c407b1SChuck Lever NFS_ACL_DEFAULT); 1253d9c407b1SChuck Lever BUG_ON(error < 0); 1254d9c407b1SChuck Lever return 0; 1255d9c407b1SChuck Lever } 1256d9c407b1SChuck Lever 1257b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 1258b7fa0554SAndreas Gruenbacher 12591da177e4SLinus Torvalds /* 12601da177e4SLinus Torvalds * NFS XDR decode functions 12611da177e4SLinus Torvalds */ 12621da177e4SLinus Torvalds 12631da177e4SLinus Torvalds /* 12641da177e4SLinus Torvalds * Decode attrstat reply. 12651da177e4SLinus Torvalds */ 12661da177e4SLinus Torvalds static int 1267d61005a6SAl Viro nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 12681da177e4SLinus Torvalds { 12691da177e4SLinus Torvalds int status; 12701da177e4SLinus Torvalds 12711da177e4SLinus Torvalds if ((status = ntohl(*p++))) 1272856dff3dSBenny Halevy return nfs_stat_to_errno(status); 12731da177e4SLinus Torvalds xdr_decode_fattr(p, fattr); 12741da177e4SLinus Torvalds return 0; 12751da177e4SLinus Torvalds } 12761da177e4SLinus Torvalds 12771da177e4SLinus Torvalds /* 12781da177e4SLinus Torvalds * Decode status+wcc_data reply 12791da177e4SLinus Torvalds * SATTR, REMOVE, RMDIR 12801da177e4SLinus Torvalds */ 12811da177e4SLinus Torvalds static int 1282d61005a6SAl Viro nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 12831da177e4SLinus Torvalds { 12841da177e4SLinus Torvalds int status; 12851da177e4SLinus Torvalds 12861da177e4SLinus Torvalds if ((status = ntohl(*p++))) 1287856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 12881da177e4SLinus Torvalds xdr_decode_wcc_data(p, fattr); 12891da177e4SLinus Torvalds return status; 12901da177e4SLinus Torvalds } 12911da177e4SLinus Torvalds 12924fdc17b2STrond Myklebust static int 12934fdc17b2STrond Myklebust nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res) 12944fdc17b2STrond Myklebust { 1295d346890bSTrond Myklebust return nfs3_xdr_wccstat(req, p, res->dir_attr); 12964fdc17b2STrond Myklebust } 12974fdc17b2STrond Myklebust 12981da177e4SLinus Torvalds /* 12991da177e4SLinus Torvalds * Decode LOOKUP reply 13001da177e4SLinus Torvalds */ 13011da177e4SLinus Torvalds static int 1302d61005a6SAl Viro nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) 13031da177e4SLinus Torvalds { 13041da177e4SLinus Torvalds int status; 13051da177e4SLinus Torvalds 13061da177e4SLinus Torvalds if ((status = ntohl(*p++))) { 1307856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 13081da177e4SLinus Torvalds } else { 13091da177e4SLinus Torvalds if (!(p = xdr_decode_fhandle(p, res->fh))) 13101da177e4SLinus Torvalds return -errno_NFSERR_IO; 13111da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 13121da177e4SLinus Torvalds } 13131da177e4SLinus Torvalds xdr_decode_post_op_attr(p, res->dir_attr); 13141da177e4SLinus Torvalds return status; 13151da177e4SLinus Torvalds } 13161da177e4SLinus Torvalds 13171da177e4SLinus Torvalds /* 13181da177e4SLinus Torvalds * Decode ACCESS reply 13191da177e4SLinus Torvalds */ 13201da177e4SLinus Torvalds static int 1321d61005a6SAl Viro nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) 13221da177e4SLinus Torvalds { 13231da177e4SLinus Torvalds int status = ntohl(*p++); 13241da177e4SLinus Torvalds 13251da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 13261da177e4SLinus Torvalds if (status) 1327856dff3dSBenny Halevy return nfs_stat_to_errno(status); 13281da177e4SLinus Torvalds res->access = ntohl(*p++); 13291da177e4SLinus Torvalds return 0; 13301da177e4SLinus Torvalds } 13311da177e4SLinus Torvalds 13321da177e4SLinus Torvalds /* 13331da177e4SLinus Torvalds * Decode READLINK reply 13341da177e4SLinus Torvalds */ 13351da177e4SLinus Torvalds static int 1336d61005a6SAl Viro nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 13371da177e4SLinus Torvalds { 13381da177e4SLinus Torvalds struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 13391da177e4SLinus Torvalds struct kvec *iov = rcvbuf->head; 1340c957c526SChuck Lever size_t hdrlen; 1341c957c526SChuck Lever u32 len, recvd; 13421da177e4SLinus Torvalds int status; 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds status = ntohl(*p++); 13451da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, fattr); 13461da177e4SLinus Torvalds 13471da177e4SLinus Torvalds if (status != 0) 1348856dff3dSBenny Halevy return nfs_stat_to_errno(status); 13491da177e4SLinus Torvalds 13501da177e4SLinus Torvalds /* Convert length of symlink */ 13511da177e4SLinus Torvalds len = ntohl(*p++); 1352c957c526SChuck Lever if (len >= rcvbuf->page_len) { 1353fe82a183SChuck Lever dprintk("nfs: server returned giant symlink!\n"); 13541da177e4SLinus Torvalds return -ENAMETOOLONG; 13551da177e4SLinus Torvalds } 13561da177e4SLinus Torvalds 13571da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 13581da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1359fe82a183SChuck Lever dprintk("NFS: READLINK reply header overflowed:" 1360c957c526SChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 13611da177e4SLinus Torvalds return -errno_NFSERR_IO; 13621da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 1363fe82a183SChuck Lever dprintk("NFS: READLINK header is short. " 1364fe82a183SChuck Lever "iovec will be shifted.\n"); 13651da177e4SLinus Torvalds xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 13661da177e4SLinus Torvalds } 13671da177e4SLinus Torvalds recvd = req->rq_rcv_buf.len - hdrlen; 13681da177e4SLinus Torvalds if (recvd < len) { 1369fe82a183SChuck Lever dprintk("NFS: server cheating in readlink reply: " 13701da177e4SLinus Torvalds "count %u > recvd %u\n", len, recvd); 13711da177e4SLinus Torvalds return -EIO; 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds 1374b4687da7SChuck Lever xdr_terminate_string(rcvbuf, len); 13751da177e4SLinus Torvalds return 0; 13761da177e4SLinus Torvalds } 13771da177e4SLinus Torvalds 13781da177e4SLinus Torvalds /* 13791da177e4SLinus Torvalds * Decode READ reply 13801da177e4SLinus Torvalds */ 13811da177e4SLinus Torvalds static int 1382d61005a6SAl Viro nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) 13831da177e4SLinus Torvalds { 13841da177e4SLinus Torvalds struct kvec *iov = req->rq_rcv_buf.head; 1385c957c526SChuck Lever size_t hdrlen; 1386c957c526SChuck Lever u32 count, ocount, recvd; 1387c957c526SChuck Lever int status; 13881da177e4SLinus Torvalds 13891da177e4SLinus Torvalds status = ntohl(*p++); 13901da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds if (status != 0) 1393856dff3dSBenny Halevy return nfs_stat_to_errno(status); 13941da177e4SLinus Torvalds 1395c957c526SChuck Lever /* Decode reply count and EOF flag. NFSv3 is somewhat redundant 13961da177e4SLinus Torvalds * in that it puts the count both in the res struct and in the 13971da177e4SLinus Torvalds * opaque data count. */ 13981da177e4SLinus Torvalds count = ntohl(*p++); 13991da177e4SLinus Torvalds res->eof = ntohl(*p++); 14001da177e4SLinus Torvalds ocount = ntohl(*p++); 14011da177e4SLinus Torvalds 14021da177e4SLinus Torvalds if (ocount != count) { 1403fe82a183SChuck Lever dprintk("NFS: READ count doesn't match RPC opaque count.\n"); 14041da177e4SLinus Torvalds return -errno_NFSERR_IO; 14051da177e4SLinus Torvalds } 14061da177e4SLinus Torvalds 14071da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 14081da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1409fe82a183SChuck Lever dprintk("NFS: READ reply header overflowed:" 1410c957c526SChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 14111da177e4SLinus Torvalds return -errno_NFSERR_IO; 14121da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 14131da177e4SLinus Torvalds dprintk("NFS: READ header is short. iovec will be shifted.\n"); 14141da177e4SLinus Torvalds xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); 14151da177e4SLinus Torvalds } 14161da177e4SLinus Torvalds 14171da177e4SLinus Torvalds recvd = req->rq_rcv_buf.len - hdrlen; 14181da177e4SLinus Torvalds if (count > recvd) { 1419fe82a183SChuck Lever dprintk("NFS: server cheating in read reply: " 1420c957c526SChuck Lever "count %u > recvd %u\n", count, recvd); 14211da177e4SLinus Torvalds count = recvd; 14221da177e4SLinus Torvalds res->eof = 0; 14231da177e4SLinus Torvalds } 14241da177e4SLinus Torvalds 14251da177e4SLinus Torvalds if (count < res->count) 14261da177e4SLinus Torvalds res->count = count; 14271da177e4SLinus Torvalds 14281da177e4SLinus Torvalds return count; 14291da177e4SLinus Torvalds } 14301da177e4SLinus Torvalds 14311da177e4SLinus Torvalds /* 14321da177e4SLinus Torvalds * Decode WRITE response 14331da177e4SLinus Torvalds */ 14341da177e4SLinus Torvalds static int 1435d61005a6SAl Viro nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) 14361da177e4SLinus Torvalds { 14371da177e4SLinus Torvalds int status; 14381da177e4SLinus Torvalds 14391da177e4SLinus Torvalds status = ntohl(*p++); 14401da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->fattr); 14411da177e4SLinus Torvalds 14421da177e4SLinus Torvalds if (status != 0) 1443856dff3dSBenny Halevy return nfs_stat_to_errno(status); 14441da177e4SLinus Torvalds 14451da177e4SLinus Torvalds res->count = ntohl(*p++); 14461da177e4SLinus Torvalds res->verf->committed = (enum nfs3_stable_how)ntohl(*p++); 14471da177e4SLinus Torvalds res->verf->verifier[0] = *p++; 14481da177e4SLinus Torvalds res->verf->verifier[1] = *p++; 14491da177e4SLinus Torvalds 14501da177e4SLinus Torvalds return res->count; 14511da177e4SLinus Torvalds } 14521da177e4SLinus Torvalds 14531da177e4SLinus Torvalds /* 14541da177e4SLinus Torvalds * Decode a CREATE response 14551da177e4SLinus Torvalds */ 14561da177e4SLinus Torvalds static int 1457d61005a6SAl Viro nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) 14581da177e4SLinus Torvalds { 14591da177e4SLinus Torvalds int status; 14601da177e4SLinus Torvalds 14611da177e4SLinus Torvalds status = ntohl(*p++); 14621da177e4SLinus Torvalds if (status == 0) { 14631da177e4SLinus Torvalds if (*p++) { 14641da177e4SLinus Torvalds if (!(p = xdr_decode_fhandle(p, res->fh))) 14651da177e4SLinus Torvalds return -errno_NFSERR_IO; 14661da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 14671da177e4SLinus Torvalds } else { 14681da177e4SLinus Torvalds memset(res->fh, 0, sizeof(*res->fh)); 14691da177e4SLinus Torvalds /* Do decode post_op_attr but set it to NULL */ 14701da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 14711da177e4SLinus Torvalds res->fattr->valid = 0; 14721da177e4SLinus Torvalds } 14731da177e4SLinus Torvalds } else { 1474856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->dir_attr); 14771da177e4SLinus Torvalds return status; 14781da177e4SLinus Torvalds } 14791da177e4SLinus Torvalds 14801da177e4SLinus Torvalds /* 14811da177e4SLinus Torvalds * Decode RENAME reply 14821da177e4SLinus Torvalds */ 14831da177e4SLinus Torvalds static int 1484e8582a8bSJeff Layton nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res) 14851da177e4SLinus Torvalds { 14861da177e4SLinus Torvalds int status; 14871da177e4SLinus Torvalds 14881da177e4SLinus Torvalds if ((status = ntohl(*p++)) != 0) 1489856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 1490e8582a8bSJeff Layton p = xdr_decode_wcc_data(p, res->old_fattr); 1491e8582a8bSJeff Layton p = xdr_decode_wcc_data(p, res->new_fattr); 14921da177e4SLinus Torvalds return status; 14931da177e4SLinus Torvalds } 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds /* 14961da177e4SLinus Torvalds * Decode LINK reply 14971da177e4SLinus Torvalds */ 14981da177e4SLinus Torvalds static int 1499d61005a6SAl Viro nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res) 15001da177e4SLinus Torvalds { 15011da177e4SLinus Torvalds int status; 15021da177e4SLinus Torvalds 15031da177e4SLinus Torvalds if ((status = ntohl(*p++)) != 0) 1504856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 15051da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 15061da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->dir_attr); 15071da177e4SLinus Torvalds return status; 15081da177e4SLinus Torvalds } 15091da177e4SLinus Torvalds 15101da177e4SLinus Torvalds /* 15111da177e4SLinus Torvalds * Decode FSSTAT reply 15121da177e4SLinus Torvalds */ 15131da177e4SLinus Torvalds static int 1514d61005a6SAl Viro nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res) 15151da177e4SLinus Torvalds { 15161da177e4SLinus Torvalds int status; 15171da177e4SLinus Torvalds 15181da177e4SLinus Torvalds status = ntohl(*p++); 15191da177e4SLinus Torvalds 15201da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 15211da177e4SLinus Torvalds if (status != 0) 1522856dff3dSBenny Halevy return nfs_stat_to_errno(status); 15231da177e4SLinus Torvalds 15241da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->tbytes); 15251da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->fbytes); 15261da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->abytes); 15271da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->tfiles); 15281da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->ffiles); 15291da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->afiles); 15301da177e4SLinus Torvalds 15311da177e4SLinus Torvalds /* ignore invarsec */ 15321da177e4SLinus Torvalds return 0; 15331da177e4SLinus Torvalds } 15341da177e4SLinus Torvalds 15351da177e4SLinus Torvalds /* 15361da177e4SLinus Torvalds * Decode FSINFO reply 15371da177e4SLinus Torvalds */ 15381da177e4SLinus Torvalds static int 1539d61005a6SAl Viro nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res) 15401da177e4SLinus Torvalds { 15411da177e4SLinus Torvalds int status; 15421da177e4SLinus Torvalds 15431da177e4SLinus Torvalds status = ntohl(*p++); 15441da177e4SLinus Torvalds 15451da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 15461da177e4SLinus Torvalds if (status != 0) 1547856dff3dSBenny Halevy return nfs_stat_to_errno(status); 15481da177e4SLinus Torvalds 15491da177e4SLinus Torvalds res->rtmax = ntohl(*p++); 15501da177e4SLinus Torvalds res->rtpref = ntohl(*p++); 15511da177e4SLinus Torvalds res->rtmult = ntohl(*p++); 15521da177e4SLinus Torvalds res->wtmax = ntohl(*p++); 15531da177e4SLinus Torvalds res->wtpref = ntohl(*p++); 15541da177e4SLinus Torvalds res->wtmult = ntohl(*p++); 15551da177e4SLinus Torvalds res->dtpref = ntohl(*p++); 15561da177e4SLinus Torvalds p = xdr_decode_hyper(p, &res->maxfilesize); 15576b96724eSRicardo Labiaga p = xdr_decode_time3(p, &res->time_delta); 15581da177e4SLinus Torvalds 15596b96724eSRicardo Labiaga /* ignore properties */ 15601da177e4SLinus Torvalds res->lease_time = 0; 15611da177e4SLinus Torvalds return 0; 15621da177e4SLinus Torvalds } 15631da177e4SLinus Torvalds 15641da177e4SLinus Torvalds /* 15651da177e4SLinus Torvalds * Decode PATHCONF reply 15661da177e4SLinus Torvalds */ 15671da177e4SLinus Torvalds static int 1568d61005a6SAl Viro nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res) 15691da177e4SLinus Torvalds { 15701da177e4SLinus Torvalds int status; 15711da177e4SLinus Torvalds 15721da177e4SLinus Torvalds status = ntohl(*p++); 15731da177e4SLinus Torvalds 15741da177e4SLinus Torvalds p = xdr_decode_post_op_attr(p, res->fattr); 15751da177e4SLinus Torvalds if (status != 0) 1576856dff3dSBenny Halevy return nfs_stat_to_errno(status); 15771da177e4SLinus Torvalds res->max_link = ntohl(*p++); 15781da177e4SLinus Torvalds res->max_namelen = ntohl(*p++); 15791da177e4SLinus Torvalds 15801da177e4SLinus Torvalds /* ignore remaining fields */ 15811da177e4SLinus Torvalds return 0; 15821da177e4SLinus Torvalds } 15831da177e4SLinus Torvalds 15841da177e4SLinus Torvalds /* 15851da177e4SLinus Torvalds * Decode COMMIT reply 15861da177e4SLinus Torvalds */ 15871da177e4SLinus Torvalds static int 1588d61005a6SAl Viro nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) 15891da177e4SLinus Torvalds { 15901da177e4SLinus Torvalds int status; 15911da177e4SLinus Torvalds 15921da177e4SLinus Torvalds status = ntohl(*p++); 15931da177e4SLinus Torvalds p = xdr_decode_wcc_data(p, res->fattr); 15941da177e4SLinus Torvalds if (status != 0) 1595856dff3dSBenny Halevy return nfs_stat_to_errno(status); 15961da177e4SLinus Torvalds 15971da177e4SLinus Torvalds res->verf->verifier[0] = *p++; 15981da177e4SLinus Torvalds res->verf->verifier[1] = *p++; 15991da177e4SLinus Torvalds return 0; 16001da177e4SLinus Torvalds } 16011da177e4SLinus Torvalds 1602b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 1603b7fa0554SAndreas Gruenbacher /* 1604b7fa0554SAndreas Gruenbacher * Decode GETACL reply 1605b7fa0554SAndreas Gruenbacher */ 1606b7fa0554SAndreas Gruenbacher static int 1607d61005a6SAl Viro nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p, 1608b7fa0554SAndreas Gruenbacher struct nfs3_getaclres *res) 1609b7fa0554SAndreas Gruenbacher { 1610b7fa0554SAndreas Gruenbacher struct xdr_buf *buf = &req->rq_rcv_buf; 1611b7fa0554SAndreas Gruenbacher int status = ntohl(*p++); 1612b7fa0554SAndreas Gruenbacher struct posix_acl **acl; 1613b7fa0554SAndreas Gruenbacher unsigned int *aclcnt; 1614b7fa0554SAndreas Gruenbacher int err, base; 1615b7fa0554SAndreas Gruenbacher 1616b7fa0554SAndreas Gruenbacher if (status != 0) 1617856dff3dSBenny Halevy return nfs_stat_to_errno(status); 1618b7fa0554SAndreas Gruenbacher p = xdr_decode_post_op_attr(p, res->fattr); 1619b7fa0554SAndreas Gruenbacher res->mask = ntohl(*p++); 1620b7fa0554SAndreas Gruenbacher if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 1621b7fa0554SAndreas Gruenbacher return -EINVAL; 1622b7fa0554SAndreas Gruenbacher base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base; 1623b7fa0554SAndreas Gruenbacher 1624b7fa0554SAndreas Gruenbacher acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL; 1625b7fa0554SAndreas Gruenbacher aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL; 1626b7fa0554SAndreas Gruenbacher err = nfsacl_decode(buf, base, aclcnt, acl); 1627b7fa0554SAndreas Gruenbacher 1628b7fa0554SAndreas Gruenbacher acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL; 1629b7fa0554SAndreas Gruenbacher aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL; 1630b7fa0554SAndreas Gruenbacher if (err > 0) 1631b7fa0554SAndreas Gruenbacher err = nfsacl_decode(buf, base + err, aclcnt, acl); 1632b7fa0554SAndreas Gruenbacher return (err > 0) ? 0 : err; 1633b7fa0554SAndreas Gruenbacher } 1634b7fa0554SAndreas Gruenbacher 1635b7fa0554SAndreas Gruenbacher /* 1636b7fa0554SAndreas Gruenbacher * Decode setacl reply. 1637b7fa0554SAndreas Gruenbacher */ 1638b7fa0554SAndreas Gruenbacher static int 1639d61005a6SAl Viro nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 1640b7fa0554SAndreas Gruenbacher { 1641b7fa0554SAndreas Gruenbacher int status = ntohl(*p++); 1642b7fa0554SAndreas Gruenbacher 1643b7fa0554SAndreas Gruenbacher if (status) 1644856dff3dSBenny Halevy return nfs_stat_to_errno(status); 1645b7fa0554SAndreas Gruenbacher xdr_decode_post_op_attr(p, fattr); 1646b7fa0554SAndreas Gruenbacher return 0; 1647b7fa0554SAndreas Gruenbacher } 1648b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 1649b7fa0554SAndreas Gruenbacher 16501da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer) \ 16511da177e4SLinus Torvalds [NFS3PROC_##proc] = { \ 16521da177e4SLinus Torvalds .p_proc = NFS3PROC_##proc, \ 1653ad96b5b5SChuck Lever .p_encode = (kxdrproc_t)nfs3_xdr_enc_##argtype##3args, \ 16541da177e4SLinus Torvalds .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \ 1655ad96b5b5SChuck Lever .p_arglen = NFS3_##argtype##args_sz, \ 16562bea90d4SChuck Lever .p_replen = NFS3_##restype##_sz, \ 1657cc0175c1SChuck Lever .p_timer = timer, \ 1658cc0175c1SChuck Lever .p_statidx = NFS3PROC_##proc, \ 1659cc0175c1SChuck Lever .p_name = #proc, \ 16601da177e4SLinus Torvalds } 16611da177e4SLinus Torvalds 16621da177e4SLinus Torvalds struct rpc_procinfo nfs3_procedures[] = { 1663ad96b5b5SChuck Lever PROC(GETATTR, getattr, attrstat, 1), 1664ad96b5b5SChuck Lever PROC(SETATTR, setattr, wccstat, 0), 1665ad96b5b5SChuck Lever PROC(LOOKUP, lookup, lookupres, 2), 1666ad96b5b5SChuck Lever PROC(ACCESS, access, accessres, 1), 1667ad96b5b5SChuck Lever PROC(READLINK, readlink, readlinkres, 3), 1668ad96b5b5SChuck Lever PROC(READ, read, readres, 3), 1669ad96b5b5SChuck Lever PROC(WRITE, write, writeres, 4), 1670ad96b5b5SChuck Lever PROC(CREATE, create, createres, 0), 1671ad96b5b5SChuck Lever PROC(MKDIR, mkdir, createres, 0), 1672ad96b5b5SChuck Lever PROC(SYMLINK, symlink, createres, 0), 1673ad96b5b5SChuck Lever PROC(MKNOD, mknod, createres, 0), 1674ad96b5b5SChuck Lever PROC(REMOVE, remove, removeres, 0), 1675ad96b5b5SChuck Lever PROC(RMDIR, lookup, wccstat, 0), 1676ad96b5b5SChuck Lever PROC(RENAME, rename, renameres, 0), 1677ad96b5b5SChuck Lever PROC(LINK, link, linkres, 0), 1678ad96b5b5SChuck Lever PROC(READDIR, readdir, readdirres, 3), 1679ad96b5b5SChuck Lever PROC(READDIRPLUS, readdirplus, readdirres, 3), 1680ad96b5b5SChuck Lever PROC(FSSTAT, getattr, fsstatres, 0), 1681ad96b5b5SChuck Lever PROC(FSINFO, getattr, fsinfores, 0), 1682ad96b5b5SChuck Lever PROC(PATHCONF, getattr, pathconfres, 0), 1683ad96b5b5SChuck Lever PROC(COMMIT, commit, commitres, 5), 16841da177e4SLinus Torvalds }; 16851da177e4SLinus Torvalds 16861da177e4SLinus Torvalds struct rpc_version nfs_version3 = { 16871da177e4SLinus Torvalds .number = 3, 1688e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nfs3_procedures), 16891da177e4SLinus Torvalds .procs = nfs3_procedures 16901da177e4SLinus Torvalds }; 16911da177e4SLinus Torvalds 1692b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 1693b7fa0554SAndreas Gruenbacher static struct rpc_procinfo nfs3_acl_procedures[] = { 1694b7fa0554SAndreas Gruenbacher [ACLPROC3_GETACL] = { 1695b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_GETACL, 1696ad96b5b5SChuck Lever .p_encode = (kxdrproc_t)nfs3_xdr_enc_getacl3args, 1697b7fa0554SAndreas Gruenbacher .p_decode = (kxdrproc_t) nfs3_xdr_getaclres, 16982bea90d4SChuck Lever .p_arglen = ACL3_getaclargs_sz, 16992bea90d4SChuck Lever .p_replen = ACL3_getaclres_sz, 1700b7fa0554SAndreas Gruenbacher .p_timer = 1, 1701cc0175c1SChuck Lever .p_name = "GETACL", 1702b7fa0554SAndreas Gruenbacher }, 1703b7fa0554SAndreas Gruenbacher [ACLPROC3_SETACL] = { 1704b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_SETACL, 1705ad96b5b5SChuck Lever .p_encode = (kxdrproc_t)nfs3_xdr_enc_setacl3args, 1706b7fa0554SAndreas Gruenbacher .p_decode = (kxdrproc_t) nfs3_xdr_setaclres, 17072bea90d4SChuck Lever .p_arglen = ACL3_setaclargs_sz, 17082bea90d4SChuck Lever .p_replen = ACL3_setaclres_sz, 1709b7fa0554SAndreas Gruenbacher .p_timer = 0, 1710cc0175c1SChuck Lever .p_name = "SETACL", 1711b7fa0554SAndreas Gruenbacher }, 1712b7fa0554SAndreas Gruenbacher }; 1713b7fa0554SAndreas Gruenbacher 1714b7fa0554SAndreas Gruenbacher struct rpc_version nfsacl_version3 = { 1715b7fa0554SAndreas Gruenbacher .number = 3, 1716b7fa0554SAndreas Gruenbacher .nrprocs = sizeof(nfs3_acl_procedures)/ 1717b7fa0554SAndreas Gruenbacher sizeof(nfs3_acl_procedures[0]), 1718b7fa0554SAndreas Gruenbacher .procs = nfs3_acl_procedures, 1719b7fa0554SAndreas Gruenbacher }; 1720b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 1721