1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/fs/nfs/nfs3xdr.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * XDR functions to encode/decode NFSv3 RPC arguments and results. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Copyright (C) 1996, 1997 Olaf Kirch 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #include <linux/param.h> 111da177e4SLinus Torvalds #include <linux/time.h> 121da177e4SLinus Torvalds #include <linux/mm.h> 131da177e4SLinus Torvalds #include <linux/errno.h> 141da177e4SLinus Torvalds #include <linux/string.h> 151da177e4SLinus Torvalds #include <linux/in.h> 161da177e4SLinus Torvalds #include <linux/pagemap.h> 171da177e4SLinus Torvalds #include <linux/proc_fs.h> 181da177e4SLinus Torvalds #include <linux/kdev_t.h> 191da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 201da177e4SLinus Torvalds #include <linux/nfs.h> 211da177e4SLinus Torvalds #include <linux/nfs3.h> 221da177e4SLinus Torvalds #include <linux/nfs_fs.h> 23b7fa0554SAndreas Gruenbacher #include <linux/nfsacl.h> 24f7b422b1SDavid Howells #include "internal.h" 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #define NFSDBG_FACILITY NFSDBG_XDR 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */ 291da177e4SLinus Torvalds #define errno_NFSERR_IO EIO 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds /* 321da177e4SLinus Torvalds * Declare the space requirements for NFS arguments and replies as 331da177e4SLinus Torvalds * number of 32bit-words 341da177e4SLinus Torvalds */ 351da177e4SLinus Torvalds #define NFS3_fhandle_sz (1+16) 361da177e4SLinus Torvalds #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */ 371da177e4SLinus Torvalds #define NFS3_sattr_sz (15) 381da177e4SLinus Torvalds #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2)) 391da177e4SLinus Torvalds #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2)) 401da177e4SLinus Torvalds #define NFS3_fattr_sz (21) 41d9c407b1SChuck Lever #define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2) 421da177e4SLinus Torvalds #define NFS3_wcc_attr_sz (6) 431da177e4SLinus Torvalds #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz) 441da177e4SLinus Torvalds #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz) 451da177e4SLinus Torvalds #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz) 461da177e4SLinus Torvalds #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz) 47ad96b5b5SChuck Lever 48ad96b5b5SChuck Lever #define NFS3_getattrargs_sz (NFS3_fh_sz) 49ad96b5b5SChuck Lever #define NFS3_setattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3) 50ad96b5b5SChuck Lever #define NFS3_lookupargs_sz (NFS3_fh_sz+NFS3_filename_sz) 511da177e4SLinus Torvalds #define NFS3_accessargs_sz (NFS3_fh_sz+1) 521da177e4SLinus Torvalds #define NFS3_readlinkargs_sz (NFS3_fh_sz) 531da177e4SLinus Torvalds #define NFS3_readargs_sz (NFS3_fh_sz+3) 541da177e4SLinus Torvalds #define NFS3_writeargs_sz (NFS3_fh_sz+5) 551da177e4SLinus Torvalds #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 561da177e4SLinus Torvalds #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 5794a6d753SChuck Lever #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz) 581da177e4SLinus Torvalds #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) 59ad96b5b5SChuck Lever #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz) 601da177e4SLinus Torvalds #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) 611da177e4SLinus Torvalds #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) 62d9c407b1SChuck Lever #define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3) 63d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4) 641da177e4SLinus Torvalds #define NFS3_commitargs_sz (NFS3_fh_sz+3) 651da177e4SLinus Torvalds 66f5fc3c50SChuck Lever #define NFS3_getattrres_sz (1+NFS3_fattr_sz) 67f5fc3c50SChuck Lever #define NFS3_setattrres_sz (1+NFS3_wcc_data_sz) 68f5fc3c50SChuck Lever #define NFS3_removeres_sz (NFS3_setattrres_sz) 691da177e4SLinus Torvalds #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) 701da177e4SLinus Torvalds #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) 711da177e4SLinus Torvalds #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1) 721da177e4SLinus Torvalds #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3) 731da177e4SLinus Torvalds #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4) 741da177e4SLinus Torvalds #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 751da177e4SLinus Torvalds #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz)) 761da177e4SLinus Torvalds #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 771da177e4SLinus Torvalds #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2) 781da177e4SLinus Torvalds #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13) 791da177e4SLinus Torvalds #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12) 801da177e4SLinus Torvalds #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) 811da177e4SLinus Torvalds #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) 821da177e4SLinus Torvalds 83b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz (NFS3_fh_sz+1) 84ae46141fSTrond Myklebust #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \ 85ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 86ae46141fSTrond Myklebust #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \ 87ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 88b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) 89b7fa0554SAndreas Gruenbacher 905e7e5a0dSBryan Schumaker static int nfs3_stat_to_errno(enum nfs_stat); 915e7e5a0dSBryan Schumaker 921da177e4SLinus Torvalds /* 931da177e4SLinus Torvalds * Map file type to S_IFMT bits 941da177e4SLinus Torvalds */ 95bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = { 96bca79478STrond Myklebust [NF3BAD] = 0, 97bca79478STrond Myklebust [NF3REG] = S_IFREG, 98bca79478STrond Myklebust [NF3DIR] = S_IFDIR, 99bca79478STrond Myklebust [NF3BLK] = S_IFBLK, 100bca79478STrond Myklebust [NF3CHR] = S_IFCHR, 101bca79478STrond Myklebust [NF3LNK] = S_IFLNK, 102bca79478STrond Myklebust [NF3SOCK] = S_IFSOCK, 103bca79478STrond Myklebust [NF3FIFO] = S_IFIFO, 1041da177e4SLinus Torvalds }; 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /* 107d9c407b1SChuck Lever * While encoding arguments, set up the reply buffer in advance to 108d9c407b1SChuck Lever * receive reply data directly into the page cache. 109d9c407b1SChuck Lever */ 110d9c407b1SChuck Lever static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages, 111d9c407b1SChuck Lever unsigned int base, unsigned int len, 112d9c407b1SChuck Lever unsigned int bufsize) 113d9c407b1SChuck Lever { 114d9c407b1SChuck Lever struct rpc_auth *auth = req->rq_cred->cr_auth; 115d9c407b1SChuck Lever unsigned int replen; 116d9c407b1SChuck Lever 117d9c407b1SChuck Lever replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize; 118d9c407b1SChuck Lever xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len); 119d9c407b1SChuck Lever } 120d9c407b1SChuck Lever 121e4f93234SChuck Lever /* 122e4f93234SChuck Lever * Handle decode buffer overflows out-of-line. 123e4f93234SChuck Lever */ 124e4f93234SChuck Lever static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 125e4f93234SChuck Lever { 126e4f93234SChuck Lever dprintk("NFS: %s prematurely hit the end of our receive buffer. " 127e4f93234SChuck Lever "Remaining buffer length is %tu words.\n", 128e4f93234SChuck Lever func, xdr->end - xdr->p); 129e4f93234SChuck Lever } 130e4f93234SChuck Lever 131d9c407b1SChuck Lever 132d9c407b1SChuck Lever /* 133d9c407b1SChuck Lever * Encode/decode NFSv3 basic data types 134d9c407b1SChuck Lever * 135d9c407b1SChuck Lever * Basic NFSv3 data types are defined in section 2.5 of RFC 1813: 136d9c407b1SChuck Lever * "NFS Version 3 Protocol Specification". 137d9c407b1SChuck Lever * 138d9c407b1SChuck Lever * Not all basic data types have their own encoding and decoding 139d9c407b1SChuck Lever * functions. For run-time efficiency, some data types are encoded 140d9c407b1SChuck Lever * or decoded inline. 141d9c407b1SChuck Lever */ 142d9c407b1SChuck Lever 143d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value) 144d9c407b1SChuck Lever { 145d9c407b1SChuck Lever __be32 *p = xdr_reserve_space(xdr, 4); 146d9c407b1SChuck Lever *p = cpu_to_be32(value); 147d9c407b1SChuck Lever } 148d9c407b1SChuck Lever 149e4f93234SChuck Lever static int decode_uint32(struct xdr_stream *xdr, u32 *value) 150e4f93234SChuck Lever { 151e4f93234SChuck Lever __be32 *p; 152e4f93234SChuck Lever 153e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 154e4f93234SChuck Lever if (unlikely(p == NULL)) 155e4f93234SChuck Lever goto out_overflow; 156e4f93234SChuck Lever *value = be32_to_cpup(p); 157e4f93234SChuck Lever return 0; 158e4f93234SChuck Lever out_overflow: 159e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 160e4f93234SChuck Lever return -EIO; 161e4f93234SChuck Lever } 162e4f93234SChuck Lever 163e4f93234SChuck Lever static int decode_uint64(struct xdr_stream *xdr, u64 *value) 164e4f93234SChuck Lever { 165e4f93234SChuck Lever __be32 *p; 166e4f93234SChuck Lever 167e4f93234SChuck Lever p = xdr_inline_decode(xdr, 8); 168e4f93234SChuck Lever if (unlikely(p == NULL)) 169e4f93234SChuck Lever goto out_overflow; 170e4f93234SChuck Lever xdr_decode_hyper(p, value); 171e4f93234SChuck Lever return 0; 172e4f93234SChuck Lever out_overflow: 173e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 174e4f93234SChuck Lever return -EIO; 175e4f93234SChuck Lever } 176e4f93234SChuck Lever 177e4f93234SChuck Lever /* 178e4f93234SChuck Lever * fileid3 179e4f93234SChuck Lever * 180e4f93234SChuck Lever * typedef uint64 fileid3; 181e4f93234SChuck Lever */ 182f6048709SChuck Lever static __be32 *xdr_decode_fileid3(__be32 *p, u64 *fileid) 183f6048709SChuck Lever { 184f6048709SChuck Lever return xdr_decode_hyper(p, fileid); 185f6048709SChuck Lever } 186f6048709SChuck Lever 187e4f93234SChuck Lever static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid) 188e4f93234SChuck Lever { 189e4f93234SChuck Lever return decode_uint64(xdr, fileid); 190e4f93234SChuck Lever } 191e4f93234SChuck Lever 192d9c407b1SChuck Lever /* 193d9c407b1SChuck Lever * filename3 194d9c407b1SChuck Lever * 195d9c407b1SChuck Lever * typedef string filename3<>; 196d9c407b1SChuck Lever */ 197d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr, 198d9c407b1SChuck Lever const char *name, u32 length) 199d9c407b1SChuck Lever { 200d9c407b1SChuck Lever __be32 *p; 201d9c407b1SChuck Lever 2027fc38846STrond Myklebust WARN_ON_ONCE(length > NFS3_MAXNAMLEN); 203d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + length); 204d9c407b1SChuck Lever xdr_encode_opaque(p, name, length); 205d9c407b1SChuck Lever } 206d9c407b1SChuck Lever 207e4f93234SChuck Lever static int decode_inline_filename3(struct xdr_stream *xdr, 208e4f93234SChuck Lever const char **name, u32 *length) 209e4f93234SChuck Lever { 210e4f93234SChuck Lever __be32 *p; 211e4f93234SChuck Lever u32 count; 212e4f93234SChuck Lever 213e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 214e4f93234SChuck Lever if (unlikely(p == NULL)) 215e4f93234SChuck Lever goto out_overflow; 216e4f93234SChuck Lever count = be32_to_cpup(p); 217e4f93234SChuck Lever if (count > NFS3_MAXNAMLEN) 218e4f93234SChuck Lever goto out_nametoolong; 219e4f93234SChuck Lever p = xdr_inline_decode(xdr, count); 220e4f93234SChuck Lever if (unlikely(p == NULL)) 221e4f93234SChuck Lever goto out_overflow; 222e4f93234SChuck Lever *name = (const char *)p; 223e4f93234SChuck Lever *length = count; 224e4f93234SChuck Lever return 0; 225e4f93234SChuck Lever 226e4f93234SChuck Lever out_nametoolong: 227e4f93234SChuck Lever dprintk("NFS: returned filename too long: %u\n", count); 228e4f93234SChuck Lever return -ENAMETOOLONG; 229e4f93234SChuck Lever out_overflow: 230e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 231e4f93234SChuck Lever return -EIO; 232e4f93234SChuck Lever } 233e4f93234SChuck Lever 234d9c407b1SChuck Lever /* 235d9c407b1SChuck Lever * nfspath3 236d9c407b1SChuck Lever * 237d9c407b1SChuck Lever * typedef string nfspath3<>; 238d9c407b1SChuck Lever */ 239d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages, 240d9c407b1SChuck Lever const u32 length) 241d9c407b1SChuck Lever { 242d9c407b1SChuck Lever encode_uint32(xdr, length); 243d9c407b1SChuck Lever xdr_write_pages(xdr, pages, 0, length); 244d9c407b1SChuck Lever } 245d9c407b1SChuck Lever 246e4f93234SChuck Lever static int decode_nfspath3(struct xdr_stream *xdr) 247e4f93234SChuck Lever { 248e4f93234SChuck Lever u32 recvd, count; 249e4f93234SChuck Lever __be32 *p; 250e4f93234SChuck Lever 251e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 252e4f93234SChuck Lever if (unlikely(p == NULL)) 253e4f93234SChuck Lever goto out_overflow; 254e4f93234SChuck Lever count = be32_to_cpup(p); 255e4f93234SChuck Lever if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN)) 256e4f93234SChuck Lever goto out_nametoolong; 25764bd577eSTrond Myklebust recvd = xdr_read_pages(xdr, count); 258e4f93234SChuck Lever if (unlikely(count > recvd)) 259e4f93234SChuck Lever goto out_cheating; 260e4f93234SChuck Lever xdr_terminate_string(xdr->buf, count); 261e4f93234SChuck Lever return 0; 262e4f93234SChuck Lever 263e4f93234SChuck Lever out_nametoolong: 264e4f93234SChuck Lever dprintk("NFS: returned pathname too long: %u\n", count); 265e4f93234SChuck Lever return -ENAMETOOLONG; 266e4f93234SChuck Lever out_cheating: 267e4f93234SChuck Lever dprintk("NFS: server cheating in pathname result: " 268e4f93234SChuck Lever "count %u > recvd %u\n", count, recvd); 269e4f93234SChuck Lever return -EIO; 270e4f93234SChuck Lever out_overflow: 271e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 272e4f93234SChuck Lever return -EIO; 273e4f93234SChuck Lever } 274e4f93234SChuck Lever 275d9c407b1SChuck Lever /* 276d9c407b1SChuck Lever * cookie3 277d9c407b1SChuck Lever * 278d9c407b1SChuck Lever * typedef uint64 cookie3 279d9c407b1SChuck Lever */ 280d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie) 281d9c407b1SChuck Lever { 282d9c407b1SChuck Lever return xdr_encode_hyper(p, cookie); 283d9c407b1SChuck Lever } 284d9c407b1SChuck Lever 285e4f93234SChuck Lever static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie) 286e4f93234SChuck Lever { 287e4f93234SChuck Lever return decode_uint64(xdr, cookie); 288e4f93234SChuck Lever } 289e4f93234SChuck Lever 290d9c407b1SChuck Lever /* 291d9c407b1SChuck Lever * cookieverf3 292d9c407b1SChuck Lever * 293d9c407b1SChuck Lever * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; 294d9c407b1SChuck Lever */ 295d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier) 296d9c407b1SChuck Lever { 297d9c407b1SChuck Lever memcpy(p, verifier, NFS3_COOKIEVERFSIZE); 298d9c407b1SChuck Lever return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE); 299d9c407b1SChuck Lever } 300d9c407b1SChuck Lever 301e4f93234SChuck Lever static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier) 302e4f93234SChuck Lever { 303e4f93234SChuck Lever __be32 *p; 304e4f93234SChuck Lever 305e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); 306e4f93234SChuck Lever if (unlikely(p == NULL)) 307e4f93234SChuck Lever goto out_overflow; 308e4f93234SChuck Lever memcpy(verifier, p, NFS3_COOKIEVERFSIZE); 309e4f93234SChuck Lever return 0; 310e4f93234SChuck Lever out_overflow: 311e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 312e4f93234SChuck Lever return -EIO; 313e4f93234SChuck Lever } 314e4f93234SChuck Lever 315d9c407b1SChuck Lever /* 316d9c407b1SChuck Lever * createverf3 317d9c407b1SChuck Lever * 318d9c407b1SChuck Lever * typedef opaque createverf3[NFS3_CREATEVERFSIZE]; 319d9c407b1SChuck Lever */ 320d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier) 321d9c407b1SChuck Lever { 322d9c407b1SChuck Lever __be32 *p; 323d9c407b1SChuck Lever 324d9c407b1SChuck Lever p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE); 325d9c407b1SChuck Lever memcpy(p, verifier, NFS3_CREATEVERFSIZE); 326d9c407b1SChuck Lever } 327d9c407b1SChuck Lever 3282f2c63bcSTrond Myklebust static int decode_writeverf3(struct xdr_stream *xdr, struct nfs_write_verifier *verifier) 329e4f93234SChuck Lever { 330e4f93234SChuck Lever __be32 *p; 331e4f93234SChuck Lever 332e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE); 333e4f93234SChuck Lever if (unlikely(p == NULL)) 334e4f93234SChuck Lever goto out_overflow; 3352f2c63bcSTrond Myklebust memcpy(verifier->data, p, NFS3_WRITEVERFSIZE); 336e4f93234SChuck Lever return 0; 337e4f93234SChuck Lever out_overflow: 338e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 339e4f93234SChuck Lever return -EIO; 340e4f93234SChuck Lever } 341e4f93234SChuck Lever 342e4f93234SChuck Lever /* 343e4f93234SChuck Lever * size3 344e4f93234SChuck Lever * 345e4f93234SChuck Lever * typedef uint64 size3; 346e4f93234SChuck Lever */ 347e4f93234SChuck Lever static __be32 *xdr_decode_size3(__be32 *p, u64 *size) 348e4f93234SChuck Lever { 349e4f93234SChuck Lever return xdr_decode_hyper(p, size); 350e4f93234SChuck Lever } 351e4f93234SChuck Lever 352e4f93234SChuck Lever /* 353e4f93234SChuck Lever * nfsstat3 354e4f93234SChuck Lever * 355e4f93234SChuck Lever * enum nfsstat3 { 356e4f93234SChuck Lever * NFS3_OK = 0, 357e4f93234SChuck Lever * ... 358e4f93234SChuck Lever * } 359e4f93234SChuck Lever */ 360e4f93234SChuck Lever #define NFS3_OK NFS_OK 361e4f93234SChuck Lever 362e4f93234SChuck Lever static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status) 363e4f93234SChuck Lever { 364e4f93234SChuck Lever __be32 *p; 365e4f93234SChuck Lever 366e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 367e4f93234SChuck Lever if (unlikely(p == NULL)) 368e4f93234SChuck Lever goto out_overflow; 369e4f93234SChuck Lever *status = be32_to_cpup(p); 370e4f93234SChuck Lever return 0; 371e4f93234SChuck Lever out_overflow: 372e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 373e4f93234SChuck Lever return -EIO; 374e4f93234SChuck Lever } 375e4f93234SChuck Lever 376d9c407b1SChuck Lever /* 377d9c407b1SChuck Lever * ftype3 378d9c407b1SChuck Lever * 379d9c407b1SChuck Lever * enum ftype3 { 380d9c407b1SChuck Lever * NF3REG = 1, 381d9c407b1SChuck Lever * NF3DIR = 2, 382d9c407b1SChuck Lever * NF3BLK = 3, 383d9c407b1SChuck Lever * NF3CHR = 4, 384d9c407b1SChuck Lever * NF3LNK = 5, 385d9c407b1SChuck Lever * NF3SOCK = 6, 386d9c407b1SChuck Lever * NF3FIFO = 7 387d9c407b1SChuck Lever * }; 388d9c407b1SChuck Lever */ 389d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type) 390d9c407b1SChuck Lever { 391d9c407b1SChuck Lever encode_uint32(xdr, type); 392d9c407b1SChuck Lever } 393d9c407b1SChuck Lever 394f6048709SChuck Lever static __be32 *xdr_decode_ftype3(__be32 *p, umode_t *mode) 395f6048709SChuck Lever { 396f6048709SChuck Lever u32 type; 397f6048709SChuck Lever 398f6048709SChuck Lever type = be32_to_cpup(p++); 399f6048709SChuck Lever if (type > NF3FIFO) 400f6048709SChuck Lever type = NF3NON; 401f6048709SChuck Lever *mode = nfs_type2fmt[type]; 402f6048709SChuck Lever return p; 403f6048709SChuck Lever } 404f6048709SChuck Lever 405d9c407b1SChuck Lever /* 406d9c407b1SChuck Lever * specdata3 407d9c407b1SChuck Lever * 408d9c407b1SChuck Lever * struct specdata3 { 409d9c407b1SChuck Lever * uint32 specdata1; 410d9c407b1SChuck Lever * uint32 specdata2; 411d9c407b1SChuck Lever * }; 412d9c407b1SChuck Lever */ 413d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev) 414d9c407b1SChuck Lever { 415d9c407b1SChuck Lever __be32 *p; 416d9c407b1SChuck Lever 417d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8); 418d9c407b1SChuck Lever *p++ = cpu_to_be32(MAJOR(rdev)); 419d9c407b1SChuck Lever *p = cpu_to_be32(MINOR(rdev)); 420d9c407b1SChuck Lever } 421d9c407b1SChuck Lever 422f6048709SChuck Lever static __be32 *xdr_decode_specdata3(__be32 *p, dev_t *rdev) 423f6048709SChuck Lever { 424f6048709SChuck Lever unsigned int major, minor; 425f6048709SChuck Lever 426f6048709SChuck Lever major = be32_to_cpup(p++); 427f6048709SChuck Lever minor = be32_to_cpup(p++); 428f6048709SChuck Lever *rdev = MKDEV(major, minor); 429f6048709SChuck Lever if (MAJOR(*rdev) != major || MINOR(*rdev) != minor) 430f6048709SChuck Lever *rdev = 0; 431f6048709SChuck Lever return p; 432f6048709SChuck Lever } 433f6048709SChuck Lever 434d9c407b1SChuck Lever /* 435d9c407b1SChuck Lever * nfs_fh3 436d9c407b1SChuck Lever * 437d9c407b1SChuck Lever * struct nfs_fh3 { 438d9c407b1SChuck Lever * opaque data<NFS3_FHSIZE>; 439d9c407b1SChuck Lever * }; 440d9c407b1SChuck Lever */ 441d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh) 442d9c407b1SChuck Lever { 443d9c407b1SChuck Lever __be32 *p; 444d9c407b1SChuck Lever 4457fc38846STrond Myklebust WARN_ON_ONCE(fh->size > NFS3_FHSIZE); 446d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + fh->size); 447d9c407b1SChuck Lever xdr_encode_opaque(p, fh->data, fh->size); 448d9c407b1SChuck Lever } 449d9c407b1SChuck Lever 450e4f93234SChuck Lever static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) 451e4f93234SChuck Lever { 452e4f93234SChuck Lever u32 length; 453e4f93234SChuck Lever __be32 *p; 454e4f93234SChuck Lever 455e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 456e4f93234SChuck Lever if (unlikely(p == NULL)) 457e4f93234SChuck Lever goto out_overflow; 458e4f93234SChuck Lever length = be32_to_cpup(p++); 459e4f93234SChuck Lever if (unlikely(length > NFS3_FHSIZE)) 460e4f93234SChuck Lever goto out_toobig; 461e4f93234SChuck Lever p = xdr_inline_decode(xdr, length); 462e4f93234SChuck Lever if (unlikely(p == NULL)) 463e4f93234SChuck Lever goto out_overflow; 464e4f93234SChuck Lever fh->size = length; 465e4f93234SChuck Lever memcpy(fh->data, p, length); 466e4f93234SChuck Lever return 0; 467e4f93234SChuck Lever out_toobig: 468e4f93234SChuck Lever dprintk("NFS: file handle size (%u) too big\n", length); 469e4f93234SChuck Lever return -E2BIG; 470e4f93234SChuck Lever out_overflow: 471e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 472e4f93234SChuck Lever return -EIO; 473e4f93234SChuck Lever } 474e4f93234SChuck Lever 475e4f93234SChuck Lever static void zero_nfs_fh3(struct nfs_fh *fh) 476e4f93234SChuck Lever { 477e4f93234SChuck Lever memset(fh, 0, sizeof(*fh)); 478e4f93234SChuck Lever } 479e4f93234SChuck Lever 480d9c407b1SChuck Lever /* 4819d5a6434SChuck Lever * nfstime3 4829d5a6434SChuck Lever * 4839d5a6434SChuck Lever * struct nfstime3 { 4849d5a6434SChuck Lever * uint32 seconds; 4859d5a6434SChuck Lever * uint32 nseconds; 4869d5a6434SChuck Lever * }; 4879d5a6434SChuck Lever */ 4889d5a6434SChuck Lever static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep) 4899d5a6434SChuck Lever { 4909d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_sec); 4919d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_nsec); 4929d5a6434SChuck Lever return p; 4939d5a6434SChuck Lever } 4949d5a6434SChuck Lever 495f6048709SChuck Lever static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec *timep) 496f6048709SChuck Lever { 497f6048709SChuck Lever timep->tv_sec = be32_to_cpup(p++); 498f6048709SChuck Lever timep->tv_nsec = be32_to_cpup(p++); 499f6048709SChuck Lever return p; 500f6048709SChuck Lever } 501f6048709SChuck Lever 5029d5a6434SChuck Lever /* 503d9c407b1SChuck Lever * sattr3 504d9c407b1SChuck Lever * 505d9c407b1SChuck Lever * enum time_how { 506d9c407b1SChuck Lever * DONT_CHANGE = 0, 507d9c407b1SChuck Lever * SET_TO_SERVER_TIME = 1, 508d9c407b1SChuck Lever * SET_TO_CLIENT_TIME = 2 509d9c407b1SChuck Lever * }; 510d9c407b1SChuck Lever * 511d9c407b1SChuck Lever * union set_mode3 switch (bool set_it) { 512d9c407b1SChuck Lever * case TRUE: 513d9c407b1SChuck Lever * mode3 mode; 514d9c407b1SChuck Lever * default: 515d9c407b1SChuck Lever * void; 516d9c407b1SChuck Lever * }; 517d9c407b1SChuck Lever * 518d9c407b1SChuck Lever * union set_uid3 switch (bool set_it) { 519d9c407b1SChuck Lever * case TRUE: 520d9c407b1SChuck Lever * uid3 uid; 521d9c407b1SChuck Lever * default: 522d9c407b1SChuck Lever * void; 523d9c407b1SChuck Lever * }; 524d9c407b1SChuck Lever * 525d9c407b1SChuck Lever * union set_gid3 switch (bool set_it) { 526d9c407b1SChuck Lever * case TRUE: 527d9c407b1SChuck Lever * gid3 gid; 528d9c407b1SChuck Lever * default: 529d9c407b1SChuck Lever * void; 530d9c407b1SChuck Lever * }; 531d9c407b1SChuck Lever * 532d9c407b1SChuck Lever * union set_size3 switch (bool set_it) { 533d9c407b1SChuck Lever * case TRUE: 534d9c407b1SChuck Lever * size3 size; 535d9c407b1SChuck Lever * default: 536d9c407b1SChuck Lever * void; 537d9c407b1SChuck Lever * }; 538d9c407b1SChuck Lever * 539d9c407b1SChuck Lever * union set_atime switch (time_how set_it) { 540d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 541d9c407b1SChuck Lever * nfstime3 atime; 542d9c407b1SChuck Lever * default: 543d9c407b1SChuck Lever * void; 544d9c407b1SChuck Lever * }; 545d9c407b1SChuck Lever * 546d9c407b1SChuck Lever * union set_mtime switch (time_how set_it) { 547d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 548d9c407b1SChuck Lever * nfstime3 mtime; 549d9c407b1SChuck Lever * default: 550d9c407b1SChuck Lever * void; 551d9c407b1SChuck Lever * }; 552d9c407b1SChuck Lever * 553d9c407b1SChuck Lever * struct sattr3 { 554d9c407b1SChuck Lever * set_mode3 mode; 555d9c407b1SChuck Lever * set_uid3 uid; 556d9c407b1SChuck Lever * set_gid3 gid; 557d9c407b1SChuck Lever * set_size3 size; 558d9c407b1SChuck Lever * set_atime atime; 559d9c407b1SChuck Lever * set_mtime mtime; 560d9c407b1SChuck Lever * }; 561d9c407b1SChuck Lever */ 562d9c407b1SChuck Lever static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr) 563d9c407b1SChuck Lever { 56495582b00SDeepa Dinamani struct timespec ts; 565d9c407b1SChuck Lever u32 nbytes; 566d9c407b1SChuck Lever __be32 *p; 567d9c407b1SChuck Lever 568d9c407b1SChuck Lever /* 569d9c407b1SChuck Lever * In order to make only a single xdr_reserve_space() call, 570d9c407b1SChuck Lever * pre-compute the total number of bytes to be reserved. 571d9c407b1SChuck Lever * Six boolean values, one for each set_foo field, are always 572d9c407b1SChuck Lever * present in the encoded result, so start there. 573d9c407b1SChuck Lever */ 574d9c407b1SChuck Lever nbytes = 6 * 4; 575d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MODE) 576d9c407b1SChuck Lever nbytes += 4; 577d9c407b1SChuck Lever if (attr->ia_valid & ATTR_UID) 578d9c407b1SChuck Lever nbytes += 4; 579d9c407b1SChuck Lever if (attr->ia_valid & ATTR_GID) 580d9c407b1SChuck Lever nbytes += 4; 581d9c407b1SChuck Lever if (attr->ia_valid & ATTR_SIZE) 582d9c407b1SChuck Lever nbytes += 8; 583d9c407b1SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) 584d9c407b1SChuck Lever nbytes += 8; 585d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) 586d9c407b1SChuck Lever nbytes += 8; 587d9c407b1SChuck Lever p = xdr_reserve_space(xdr, nbytes); 588d9c407b1SChuck Lever 5899d5a6434SChuck Lever if (attr->ia_valid & ATTR_MODE) { 5909d5a6434SChuck Lever *p++ = xdr_one; 5919d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO); 5929d5a6434SChuck Lever } else 5939d5a6434SChuck Lever *p++ = xdr_zero; 5949d5a6434SChuck Lever 5959d5a6434SChuck Lever if (attr->ia_valid & ATTR_UID) { 5969d5a6434SChuck Lever *p++ = xdr_one; 59757a38daeSEric W. Biederman *p++ = cpu_to_be32(from_kuid(&init_user_ns, attr->ia_uid)); 5989d5a6434SChuck Lever } else 5999d5a6434SChuck Lever *p++ = xdr_zero; 6009d5a6434SChuck Lever 6019d5a6434SChuck Lever if (attr->ia_valid & ATTR_GID) { 6029d5a6434SChuck Lever *p++ = xdr_one; 60357a38daeSEric W. Biederman *p++ = cpu_to_be32(from_kgid(&init_user_ns, attr->ia_gid)); 6049d5a6434SChuck Lever } else 6059d5a6434SChuck Lever *p++ = xdr_zero; 6069d5a6434SChuck Lever 6079d5a6434SChuck Lever if (attr->ia_valid & ATTR_SIZE) { 6089d5a6434SChuck Lever *p++ = xdr_one; 6099d5a6434SChuck Lever p = xdr_encode_hyper(p, (u64)attr->ia_size); 6109d5a6434SChuck Lever } else 6119d5a6434SChuck Lever *p++ = xdr_zero; 6129d5a6434SChuck Lever 6139d5a6434SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) { 61495582b00SDeepa Dinamani struct timespec ts; 6159d5a6434SChuck Lever *p++ = xdr_two; 61695582b00SDeepa Dinamani ts = timespec64_to_timespec(attr->ia_atime); 61795582b00SDeepa Dinamani p = xdr_encode_nfstime3(p, &ts); 6189d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_ATIME) { 6199d5a6434SChuck Lever *p++ = xdr_one; 6209d5a6434SChuck Lever } else 6219d5a6434SChuck Lever *p++ = xdr_zero; 6229d5a6434SChuck Lever 6239d5a6434SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) { 6249d5a6434SChuck Lever *p++ = xdr_two; 62595582b00SDeepa Dinamani ts = timespec64_to_timespec(attr->ia_mtime); 62695582b00SDeepa Dinamani xdr_encode_nfstime3(p, &ts); 6279d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_MTIME) { 6289d5a6434SChuck Lever *p = xdr_one; 6299d5a6434SChuck Lever } else 6309d5a6434SChuck Lever *p = xdr_zero; 631d9c407b1SChuck Lever } 632d9c407b1SChuck Lever 633d9c407b1SChuck Lever /* 634e4f93234SChuck Lever * fattr3 635e4f93234SChuck Lever * 636e4f93234SChuck Lever * struct fattr3 { 637e4f93234SChuck Lever * ftype3 type; 638e4f93234SChuck Lever * mode3 mode; 639e4f93234SChuck Lever * uint32 nlink; 640e4f93234SChuck Lever * uid3 uid; 641e4f93234SChuck Lever * gid3 gid; 642e4f93234SChuck Lever * size3 size; 643e4f93234SChuck Lever * size3 used; 644e4f93234SChuck Lever * specdata3 rdev; 645e4f93234SChuck Lever * uint64 fsid; 646e4f93234SChuck Lever * fileid3 fileid; 647e4f93234SChuck Lever * nfstime3 atime; 648e4f93234SChuck Lever * nfstime3 mtime; 649e4f93234SChuck Lever * nfstime3 ctime; 650e4f93234SChuck Lever * }; 651e4f93234SChuck Lever */ 652e4f93234SChuck Lever static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr) 653e4f93234SChuck Lever { 654f6048709SChuck Lever umode_t fmode; 655e4f93234SChuck Lever __be32 *p; 656e4f93234SChuck Lever 657e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2); 658e4f93234SChuck Lever if (unlikely(p == NULL)) 659e4f93234SChuck Lever goto out_overflow; 660f6048709SChuck Lever 661f6048709SChuck Lever p = xdr_decode_ftype3(p, &fmode); 662f6048709SChuck Lever 663f6048709SChuck Lever fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode; 664f6048709SChuck Lever fattr->nlink = be32_to_cpup(p++); 66557a38daeSEric W. Biederman fattr->uid = make_kuid(&init_user_ns, be32_to_cpup(p++)); 66657a38daeSEric W. Biederman if (!uid_valid(fattr->uid)) 66757a38daeSEric W. Biederman goto out_uid; 66857a38daeSEric W. Biederman fattr->gid = make_kgid(&init_user_ns, be32_to_cpup(p++)); 66957a38daeSEric W. Biederman if (!gid_valid(fattr->gid)) 67057a38daeSEric W. Biederman goto out_gid; 671f6048709SChuck Lever 672f6048709SChuck Lever p = xdr_decode_size3(p, &fattr->size); 673f6048709SChuck Lever p = xdr_decode_size3(p, &fattr->du.nfs3.used); 674f6048709SChuck Lever p = xdr_decode_specdata3(p, &fattr->rdev); 675f6048709SChuck Lever 676f6048709SChuck Lever p = xdr_decode_hyper(p, &fattr->fsid.major); 677f6048709SChuck Lever fattr->fsid.minor = 0; 678f6048709SChuck Lever 679f6048709SChuck Lever p = xdr_decode_fileid3(p, &fattr->fileid); 680f6048709SChuck Lever p = xdr_decode_nfstime3(p, &fattr->atime); 681f6048709SChuck Lever p = xdr_decode_nfstime3(p, &fattr->mtime); 682f6048709SChuck Lever xdr_decode_nfstime3(p, &fattr->ctime); 6833a1556e8STrond Myklebust fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime); 684f6048709SChuck Lever 685f6048709SChuck Lever fattr->valid |= NFS_ATTR_FATTR_V3; 686e4f93234SChuck Lever return 0; 68757a38daeSEric W. Biederman out_uid: 68857a38daeSEric W. Biederman dprintk("NFS: returned invalid uid\n"); 68957a38daeSEric W. Biederman return -EINVAL; 69057a38daeSEric W. Biederman out_gid: 69157a38daeSEric W. Biederman dprintk("NFS: returned invalid gid\n"); 69257a38daeSEric W. Biederman return -EINVAL; 693e4f93234SChuck Lever out_overflow: 694e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 695e4f93234SChuck Lever return -EIO; 696e4f93234SChuck Lever } 697e4f93234SChuck Lever 698e4f93234SChuck Lever /* 699e4f93234SChuck Lever * post_op_attr 700e4f93234SChuck Lever * 701e4f93234SChuck Lever * union post_op_attr switch (bool attributes_follow) { 702e4f93234SChuck Lever * case TRUE: 703e4f93234SChuck Lever * fattr3 attributes; 704e4f93234SChuck Lever * case FALSE: 705e4f93234SChuck Lever * void; 706e4f93234SChuck Lever * }; 707e4f93234SChuck Lever */ 708e4f93234SChuck Lever static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 709e4f93234SChuck Lever { 710e4f93234SChuck Lever __be32 *p; 711e4f93234SChuck Lever 712e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 713e4f93234SChuck Lever if (unlikely(p == NULL)) 714e4f93234SChuck Lever goto out_overflow; 715e4f93234SChuck Lever if (*p != xdr_zero) 716e4f93234SChuck Lever return decode_fattr3(xdr, fattr); 717e4f93234SChuck Lever return 0; 718e4f93234SChuck Lever out_overflow: 719e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 720e4f93234SChuck Lever return -EIO; 721e4f93234SChuck Lever } 722e4f93234SChuck Lever 723e4f93234SChuck Lever /* 724e4f93234SChuck Lever * wcc_attr 725e4f93234SChuck Lever * struct wcc_attr { 726e4f93234SChuck Lever * size3 size; 727e4f93234SChuck Lever * nfstime3 mtime; 728e4f93234SChuck Lever * nfstime3 ctime; 729e4f93234SChuck Lever * }; 730e4f93234SChuck Lever */ 731e4f93234SChuck Lever static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 732e4f93234SChuck Lever { 733e4f93234SChuck Lever __be32 *p; 734e4f93234SChuck Lever 735e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2); 736e4f93234SChuck Lever if (unlikely(p == NULL)) 737e4f93234SChuck Lever goto out_overflow; 738f6048709SChuck Lever 739f6048709SChuck Lever fattr->valid |= NFS_ATTR_FATTR_PRESIZE 7403a1556e8STrond Myklebust | NFS_ATTR_FATTR_PRECHANGE 741f6048709SChuck Lever | NFS_ATTR_FATTR_PREMTIME 742f6048709SChuck Lever | NFS_ATTR_FATTR_PRECTIME; 743f6048709SChuck Lever 744f6048709SChuck Lever p = xdr_decode_size3(p, &fattr->pre_size); 745f6048709SChuck Lever p = xdr_decode_nfstime3(p, &fattr->pre_mtime); 746f6048709SChuck Lever xdr_decode_nfstime3(p, &fattr->pre_ctime); 7473a1556e8STrond Myklebust fattr->pre_change_attr = nfs_timespec_to_change_attr(&fattr->pre_ctime); 748f6048709SChuck Lever 749e4f93234SChuck Lever return 0; 750e4f93234SChuck Lever out_overflow: 751e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 752e4f93234SChuck Lever return -EIO; 753e4f93234SChuck Lever } 754e4f93234SChuck Lever 755e4f93234SChuck Lever /* 756e4f93234SChuck Lever * pre_op_attr 757e4f93234SChuck Lever * union pre_op_attr switch (bool attributes_follow) { 758e4f93234SChuck Lever * case TRUE: 759e4f93234SChuck Lever * wcc_attr attributes; 760e4f93234SChuck Lever * case FALSE: 761e4f93234SChuck Lever * void; 762e4f93234SChuck Lever * }; 763e4f93234SChuck Lever * 764e4f93234SChuck Lever * wcc_data 765e4f93234SChuck Lever * 766e4f93234SChuck Lever * struct wcc_data { 767e4f93234SChuck Lever * pre_op_attr before; 768e4f93234SChuck Lever * post_op_attr after; 769e4f93234SChuck Lever * }; 770e4f93234SChuck Lever */ 771e4f93234SChuck Lever static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 772e4f93234SChuck Lever { 773e4f93234SChuck Lever __be32 *p; 774e4f93234SChuck Lever 775e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 776e4f93234SChuck Lever if (unlikely(p == NULL)) 777e4f93234SChuck Lever goto out_overflow; 778e4f93234SChuck Lever if (*p != xdr_zero) 779e4f93234SChuck Lever return decode_wcc_attr(xdr, fattr); 780e4f93234SChuck Lever return 0; 781e4f93234SChuck Lever out_overflow: 782e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 783e4f93234SChuck Lever return -EIO; 784e4f93234SChuck Lever } 785e4f93234SChuck Lever 786e4f93234SChuck Lever static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr) 787e4f93234SChuck Lever { 788e4f93234SChuck Lever int error; 789e4f93234SChuck Lever 790e4f93234SChuck Lever error = decode_pre_op_attr(xdr, fattr); 791e4f93234SChuck Lever if (unlikely(error)) 792e4f93234SChuck Lever goto out; 793e4f93234SChuck Lever error = decode_post_op_attr(xdr, fattr); 794e4f93234SChuck Lever out: 795e4f93234SChuck Lever return error; 796e4f93234SChuck Lever } 797e4f93234SChuck Lever 798e4f93234SChuck Lever /* 799e4f93234SChuck Lever * post_op_fh3 800e4f93234SChuck Lever * 801e4f93234SChuck Lever * union post_op_fh3 switch (bool handle_follows) { 802e4f93234SChuck Lever * case TRUE: 803e4f93234SChuck Lever * nfs_fh3 handle; 804e4f93234SChuck Lever * case FALSE: 805e4f93234SChuck Lever * void; 806e4f93234SChuck Lever * }; 807e4f93234SChuck Lever */ 808e4f93234SChuck Lever static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) 809e4f93234SChuck Lever { 810e4f93234SChuck Lever __be32 *p = xdr_inline_decode(xdr, 4); 811e4f93234SChuck Lever if (unlikely(p == NULL)) 812e4f93234SChuck Lever goto out_overflow; 813e4f93234SChuck Lever if (*p != xdr_zero) 814e4f93234SChuck Lever return decode_nfs_fh3(xdr, fh); 815e4f93234SChuck Lever zero_nfs_fh3(fh); 816e4f93234SChuck Lever return 0; 817e4f93234SChuck Lever out_overflow: 818e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 819e4f93234SChuck Lever return -EIO; 820e4f93234SChuck Lever } 821e4f93234SChuck Lever 822e4f93234SChuck Lever /* 823d9c407b1SChuck Lever * diropargs3 824d9c407b1SChuck Lever * 825d9c407b1SChuck Lever * struct diropargs3 { 826d9c407b1SChuck Lever * nfs_fh3 dir; 827d9c407b1SChuck Lever * filename3 name; 828d9c407b1SChuck Lever * }; 829d9c407b1SChuck Lever */ 830d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh, 831d9c407b1SChuck Lever const char *name, u32 length) 832d9c407b1SChuck Lever { 833d9c407b1SChuck Lever encode_nfs_fh3(xdr, fh); 834d9c407b1SChuck Lever encode_filename3(xdr, name, length); 835d9c407b1SChuck Lever } 836d9c407b1SChuck Lever 837d9c407b1SChuck Lever 8381da177e4SLinus Torvalds /* 839499ff710SChuck Lever * NFSv3 XDR encode functions 840499ff710SChuck Lever * 841499ff710SChuck Lever * NFSv3 argument types are defined in section 3.3 of RFC 1813: 842499ff710SChuck Lever * "NFS Version 3 Protocol Specification". 8431da177e4SLinus Torvalds */ 8441da177e4SLinus Torvalds 8451da177e4SLinus Torvalds /* 846d9c407b1SChuck Lever * 3.3.1 GETATTR3args 847d9c407b1SChuck Lever * 848d9c407b1SChuck Lever * struct GETATTR3args { 849d9c407b1SChuck Lever * nfs_fh3 object; 850d9c407b1SChuck Lever * }; 851d9c407b1SChuck Lever */ 8529f06c719SChuck Lever static void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, 8539f06c719SChuck Lever struct xdr_stream *xdr, 854fcc85819SChristoph Hellwig const void *data) 855d9c407b1SChuck Lever { 856fcc85819SChristoph Hellwig const struct nfs_fh *fh = data; 857fcc85819SChristoph Hellwig 8589f06c719SChuck Lever encode_nfs_fh3(xdr, fh); 859d9c407b1SChuck Lever } 860d9c407b1SChuck Lever 861d9c407b1SChuck Lever /* 862d9c407b1SChuck Lever * 3.3.2 SETATTR3args 863d9c407b1SChuck Lever * 864d9c407b1SChuck Lever * union sattrguard3 switch (bool check) { 865d9c407b1SChuck Lever * case TRUE: 866d9c407b1SChuck Lever * nfstime3 obj_ctime; 867d9c407b1SChuck Lever * case FALSE: 868d9c407b1SChuck Lever * void; 869d9c407b1SChuck Lever * }; 870d9c407b1SChuck Lever * 871d9c407b1SChuck Lever * struct SETATTR3args { 872d9c407b1SChuck Lever * nfs_fh3 object; 873d9c407b1SChuck Lever * sattr3 new_attributes; 874d9c407b1SChuck Lever * sattrguard3 guard; 875d9c407b1SChuck Lever * }; 876d9c407b1SChuck Lever */ 877d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr, 878d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 879d9c407b1SChuck Lever { 880d9c407b1SChuck Lever __be32 *p; 881d9c407b1SChuck Lever 882d9c407b1SChuck Lever if (args->guard) { 883d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + 8); 884d9c407b1SChuck Lever *p++ = xdr_one; 8859d5a6434SChuck Lever xdr_encode_nfstime3(p, &args->guardtime); 886d9c407b1SChuck Lever } else { 887d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4); 888d9c407b1SChuck Lever *p = xdr_zero; 889d9c407b1SChuck Lever } 890d9c407b1SChuck Lever } 891d9c407b1SChuck Lever 8929f06c719SChuck Lever static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, 8939f06c719SChuck Lever struct xdr_stream *xdr, 894fcc85819SChristoph Hellwig const void *data) 895d9c407b1SChuck Lever { 896fcc85819SChristoph Hellwig const struct nfs3_sattrargs *args = data; 8979f06c719SChuck Lever encode_nfs_fh3(xdr, args->fh); 8989f06c719SChuck Lever encode_sattr3(xdr, args->sattr); 8999f06c719SChuck Lever encode_sattrguard3(xdr, args); 900d9c407b1SChuck Lever } 901d9c407b1SChuck Lever 902d9c407b1SChuck Lever /* 903d9c407b1SChuck Lever * 3.3.3 LOOKUP3args 904d9c407b1SChuck Lever * 905d9c407b1SChuck Lever * struct LOOKUP3args { 906d9c407b1SChuck Lever * diropargs3 what; 907d9c407b1SChuck Lever * }; 908d9c407b1SChuck Lever */ 9099f06c719SChuck Lever static void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, 9109f06c719SChuck Lever struct xdr_stream *xdr, 911fcc85819SChristoph Hellwig const void *data) 912d9c407b1SChuck Lever { 913fcc85819SChristoph Hellwig const struct nfs3_diropargs *args = data; 914fcc85819SChristoph Hellwig 9159f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 916d9c407b1SChuck Lever } 917d9c407b1SChuck Lever 918d9c407b1SChuck Lever /* 919d9c407b1SChuck Lever * 3.3.4 ACCESS3args 920d9c407b1SChuck Lever * 921d9c407b1SChuck Lever * struct ACCESS3args { 922d9c407b1SChuck Lever * nfs_fh3 object; 923d9c407b1SChuck Lever * uint32 access; 924d9c407b1SChuck Lever * }; 925d9c407b1SChuck Lever */ 926d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr, 927d9c407b1SChuck Lever const struct nfs3_accessargs *args) 928d9c407b1SChuck Lever { 929d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 930d9c407b1SChuck Lever encode_uint32(xdr, args->access); 931d9c407b1SChuck Lever } 932d9c407b1SChuck Lever 9339f06c719SChuck Lever static void nfs3_xdr_enc_access3args(struct rpc_rqst *req, 9349f06c719SChuck Lever struct xdr_stream *xdr, 935fcc85819SChristoph Hellwig const void *data) 936d9c407b1SChuck Lever { 937fcc85819SChristoph Hellwig const struct nfs3_accessargs *args = data; 938fcc85819SChristoph Hellwig 9399f06c719SChuck Lever encode_access3args(xdr, args); 940d9c407b1SChuck Lever } 941d9c407b1SChuck Lever 942d9c407b1SChuck Lever /* 943d9c407b1SChuck Lever * 3.3.5 READLINK3args 944d9c407b1SChuck Lever * 945d9c407b1SChuck Lever * struct READLINK3args { 946d9c407b1SChuck Lever * nfs_fh3 symlink; 947d9c407b1SChuck Lever * }; 948d9c407b1SChuck Lever */ 9499f06c719SChuck Lever static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, 9509f06c719SChuck Lever struct xdr_stream *xdr, 951fcc85819SChristoph Hellwig const void *data) 952d9c407b1SChuck Lever { 953fcc85819SChristoph Hellwig const struct nfs3_readlinkargs *args = data; 954fcc85819SChristoph Hellwig 9559f06c719SChuck Lever encode_nfs_fh3(xdr, args->fh); 956d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 957d9c407b1SChuck Lever args->pglen, NFS3_readlinkres_sz); 958d9c407b1SChuck Lever } 959d9c407b1SChuck Lever 960d9c407b1SChuck Lever /* 961d9c407b1SChuck Lever * 3.3.6 READ3args 962d9c407b1SChuck Lever * 963d9c407b1SChuck Lever * struct READ3args { 964d9c407b1SChuck Lever * nfs_fh3 file; 965d9c407b1SChuck Lever * offset3 offset; 966d9c407b1SChuck Lever * count3 count; 967d9c407b1SChuck Lever * }; 968d9c407b1SChuck Lever */ 969d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr, 9703c6b899cSAnna Schumaker const struct nfs_pgio_args *args) 971d9c407b1SChuck Lever { 972d9c407b1SChuck Lever __be32 *p; 973d9c407b1SChuck Lever 974d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 975d9c407b1SChuck Lever 976d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 977d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 978d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 979d9c407b1SChuck Lever } 980d9c407b1SChuck Lever 9819f06c719SChuck Lever static void nfs3_xdr_enc_read3args(struct rpc_rqst *req, 9829f06c719SChuck Lever struct xdr_stream *xdr, 983fcc85819SChristoph Hellwig const void *data) 984d9c407b1SChuck Lever { 985fcc85819SChristoph Hellwig const struct nfs_pgio_args *args = data; 986fcc85819SChristoph Hellwig 9879f06c719SChuck Lever encode_read3args(xdr, args); 988d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 989d9c407b1SChuck Lever args->count, NFS3_readres_sz); 990d9c407b1SChuck Lever req->rq_rcv_buf.flags |= XDRBUF_READ; 991d9c407b1SChuck Lever } 992d9c407b1SChuck Lever 993d9c407b1SChuck Lever /* 994d9c407b1SChuck Lever * 3.3.7 WRITE3args 995d9c407b1SChuck Lever * 996d9c407b1SChuck Lever * enum stable_how { 997d9c407b1SChuck Lever * UNSTABLE = 0, 998d9c407b1SChuck Lever * DATA_SYNC = 1, 999d9c407b1SChuck Lever * FILE_SYNC = 2 1000d9c407b1SChuck Lever * }; 1001d9c407b1SChuck Lever * 1002d9c407b1SChuck Lever * struct WRITE3args { 1003d9c407b1SChuck Lever * nfs_fh3 file; 1004d9c407b1SChuck Lever * offset3 offset; 1005d9c407b1SChuck Lever * count3 count; 1006d9c407b1SChuck Lever * stable_how stable; 1007d9c407b1SChuck Lever * opaque data<>; 1008d9c407b1SChuck Lever * }; 1009d9c407b1SChuck Lever */ 1010d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr, 10113c6b899cSAnna Schumaker const struct nfs_pgio_args *args) 1012d9c407b1SChuck Lever { 1013d9c407b1SChuck Lever __be32 *p; 1014d9c407b1SChuck Lever 1015d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1016d9c407b1SChuck Lever 1017d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4); 1018d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 1019d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count); 1020d9c407b1SChuck Lever *p++ = cpu_to_be32(args->stable); 1021d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1022d9c407b1SChuck Lever xdr_write_pages(xdr, args->pages, args->pgbase, args->count); 1023d9c407b1SChuck Lever } 1024d9c407b1SChuck Lever 10259f06c719SChuck Lever static void nfs3_xdr_enc_write3args(struct rpc_rqst *req, 10269f06c719SChuck Lever struct xdr_stream *xdr, 1027fcc85819SChristoph Hellwig const void *data) 1028d9c407b1SChuck Lever { 1029fcc85819SChristoph Hellwig const struct nfs_pgio_args *args = data; 1030fcc85819SChristoph Hellwig 10319f06c719SChuck Lever encode_write3args(xdr, args); 10329f06c719SChuck Lever xdr->buf->flags |= XDRBUF_WRITE; 1033d9c407b1SChuck Lever } 1034d9c407b1SChuck Lever 1035d9c407b1SChuck Lever /* 1036d9c407b1SChuck Lever * 3.3.8 CREATE3args 1037d9c407b1SChuck Lever * 1038d9c407b1SChuck Lever * enum createmode3 { 1039d9c407b1SChuck Lever * UNCHECKED = 0, 1040d9c407b1SChuck Lever * GUARDED = 1, 1041d9c407b1SChuck Lever * EXCLUSIVE = 2 1042d9c407b1SChuck Lever * }; 1043d9c407b1SChuck Lever * 1044d9c407b1SChuck Lever * union createhow3 switch (createmode3 mode) { 1045d9c407b1SChuck Lever * case UNCHECKED: 1046d9c407b1SChuck Lever * case GUARDED: 1047d9c407b1SChuck Lever * sattr3 obj_attributes; 1048d9c407b1SChuck Lever * case EXCLUSIVE: 1049d9c407b1SChuck Lever * createverf3 verf; 1050d9c407b1SChuck Lever * }; 1051d9c407b1SChuck Lever * 1052d9c407b1SChuck Lever * struct CREATE3args { 1053d9c407b1SChuck Lever * diropargs3 where; 1054d9c407b1SChuck Lever * createhow3 how; 1055d9c407b1SChuck Lever * }; 1056d9c407b1SChuck Lever */ 1057d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr, 1058d9c407b1SChuck Lever const struct nfs3_createargs *args) 1059d9c407b1SChuck Lever { 1060d9c407b1SChuck Lever encode_uint32(xdr, args->createmode); 1061d9c407b1SChuck Lever switch (args->createmode) { 1062d9c407b1SChuck Lever case NFS3_CREATE_UNCHECKED: 1063d9c407b1SChuck Lever case NFS3_CREATE_GUARDED: 1064d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1065d9c407b1SChuck Lever break; 1066d9c407b1SChuck Lever case NFS3_CREATE_EXCLUSIVE: 1067d9c407b1SChuck Lever encode_createverf3(xdr, args->verifier); 1068d9c407b1SChuck Lever break; 1069d9c407b1SChuck Lever default: 1070d9c407b1SChuck Lever BUG(); 1071d9c407b1SChuck Lever } 1072d9c407b1SChuck Lever } 1073d9c407b1SChuck Lever 10749f06c719SChuck Lever static void nfs3_xdr_enc_create3args(struct rpc_rqst *req, 10759f06c719SChuck Lever struct xdr_stream *xdr, 1076fcc85819SChristoph Hellwig const void *data) 1077d9c407b1SChuck Lever { 1078fcc85819SChristoph Hellwig const struct nfs3_createargs *args = data; 1079fcc85819SChristoph Hellwig 10809f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 10819f06c719SChuck Lever encode_createhow3(xdr, args); 1082d9c407b1SChuck Lever } 1083d9c407b1SChuck Lever 1084d9c407b1SChuck Lever /* 1085d9c407b1SChuck Lever * 3.3.9 MKDIR3args 1086d9c407b1SChuck Lever * 1087d9c407b1SChuck Lever * struct MKDIR3args { 1088d9c407b1SChuck Lever * diropargs3 where; 1089d9c407b1SChuck Lever * sattr3 attributes; 1090d9c407b1SChuck Lever * }; 1091d9c407b1SChuck Lever */ 10929f06c719SChuck Lever static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, 10939f06c719SChuck Lever struct xdr_stream *xdr, 1094fcc85819SChristoph Hellwig const void *data) 1095d9c407b1SChuck Lever { 1096fcc85819SChristoph Hellwig const struct nfs3_mkdirargs *args = data; 1097fcc85819SChristoph Hellwig 10989f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 10999f06c719SChuck Lever encode_sattr3(xdr, args->sattr); 1100d9c407b1SChuck Lever } 1101d9c407b1SChuck Lever 1102d9c407b1SChuck Lever /* 1103d9c407b1SChuck Lever * 3.3.10 SYMLINK3args 1104d9c407b1SChuck Lever * 1105d9c407b1SChuck Lever * struct symlinkdata3 { 1106d9c407b1SChuck Lever * sattr3 symlink_attributes; 1107d9c407b1SChuck Lever * nfspath3 symlink_data; 1108d9c407b1SChuck Lever * }; 1109d9c407b1SChuck Lever * 1110d9c407b1SChuck Lever * struct SYMLINK3args { 1111d9c407b1SChuck Lever * diropargs3 where; 1112d9c407b1SChuck Lever * symlinkdata3 symlink; 1113d9c407b1SChuck Lever * }; 1114d9c407b1SChuck Lever */ 1115d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr, 1116fcc85819SChristoph Hellwig const void *data) 1117d9c407b1SChuck Lever { 1118fcc85819SChristoph Hellwig const struct nfs3_symlinkargs *args = data; 1119fcc85819SChristoph Hellwig 1120d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1121d9c407b1SChuck Lever encode_nfspath3(xdr, args->pages, args->pathlen); 1122d9c407b1SChuck Lever } 1123d9c407b1SChuck Lever 11249f06c719SChuck Lever static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, 11259f06c719SChuck Lever struct xdr_stream *xdr, 1126fcc85819SChristoph Hellwig const void *data) 1127d9c407b1SChuck Lever { 1128fcc85819SChristoph Hellwig const struct nfs3_symlinkargs *args = data; 1129fcc85819SChristoph Hellwig 11309f06c719SChuck Lever encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen); 11319f06c719SChuck Lever encode_symlinkdata3(xdr, args); 11322fcc213aSChuck Lever xdr->buf->flags |= XDRBUF_WRITE; 1133d9c407b1SChuck Lever } 1134d9c407b1SChuck Lever 1135d9c407b1SChuck Lever /* 1136d9c407b1SChuck Lever * 3.3.11 MKNOD3args 1137d9c407b1SChuck Lever * 1138d9c407b1SChuck Lever * struct devicedata3 { 1139d9c407b1SChuck Lever * sattr3 dev_attributes; 1140d9c407b1SChuck Lever * specdata3 spec; 1141d9c407b1SChuck Lever * }; 1142d9c407b1SChuck Lever * 1143d9c407b1SChuck Lever * union mknoddata3 switch (ftype3 type) { 1144d9c407b1SChuck Lever * case NF3CHR: 1145d9c407b1SChuck Lever * case NF3BLK: 1146d9c407b1SChuck Lever * devicedata3 device; 1147d9c407b1SChuck Lever * case NF3SOCK: 1148d9c407b1SChuck Lever * case NF3FIFO: 1149d9c407b1SChuck Lever * sattr3 pipe_attributes; 1150d9c407b1SChuck Lever * default: 1151d9c407b1SChuck Lever * void; 1152d9c407b1SChuck Lever * }; 1153d9c407b1SChuck Lever * 1154d9c407b1SChuck Lever * struct MKNOD3args { 1155d9c407b1SChuck Lever * diropargs3 where; 1156d9c407b1SChuck Lever * mknoddata3 what; 1157d9c407b1SChuck Lever * }; 1158d9c407b1SChuck Lever */ 1159d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr, 1160d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1161d9c407b1SChuck Lever { 1162d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1163d9c407b1SChuck Lever encode_specdata3(xdr, args->rdev); 1164d9c407b1SChuck Lever } 1165d9c407b1SChuck Lever 1166d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr, 1167d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1168d9c407b1SChuck Lever { 1169d9c407b1SChuck Lever encode_ftype3(xdr, args->type); 1170d9c407b1SChuck Lever switch (args->type) { 1171d9c407b1SChuck Lever case NF3CHR: 1172d9c407b1SChuck Lever case NF3BLK: 1173d9c407b1SChuck Lever encode_devicedata3(xdr, args); 1174d9c407b1SChuck Lever break; 1175d9c407b1SChuck Lever case NF3SOCK: 1176d9c407b1SChuck Lever case NF3FIFO: 1177d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1178d9c407b1SChuck Lever break; 1179d9c407b1SChuck Lever case NF3REG: 1180d9c407b1SChuck Lever case NF3DIR: 1181d9c407b1SChuck Lever break; 1182d9c407b1SChuck Lever default: 1183d9c407b1SChuck Lever BUG(); 1184d9c407b1SChuck Lever } 1185d9c407b1SChuck Lever } 1186d9c407b1SChuck Lever 11879f06c719SChuck Lever static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, 11889f06c719SChuck Lever struct xdr_stream *xdr, 1189fcc85819SChristoph Hellwig const void *data) 1190d9c407b1SChuck Lever { 1191fcc85819SChristoph Hellwig const struct nfs3_mknodargs *args = data; 1192fcc85819SChristoph Hellwig 11939f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 11949f06c719SChuck Lever encode_mknoddata3(xdr, args); 1195d9c407b1SChuck Lever } 1196d9c407b1SChuck Lever 1197d9c407b1SChuck Lever /* 1198d9c407b1SChuck Lever * 3.3.12 REMOVE3args 1199d9c407b1SChuck Lever * 1200d9c407b1SChuck Lever * struct REMOVE3args { 1201d9c407b1SChuck Lever * diropargs3 object; 1202d9c407b1SChuck Lever * }; 1203d9c407b1SChuck Lever */ 12049f06c719SChuck Lever static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req, 12059f06c719SChuck Lever struct xdr_stream *xdr, 1206fcc85819SChristoph Hellwig const void *data) 1207d9c407b1SChuck Lever { 1208fcc85819SChristoph Hellwig const struct nfs_removeargs *args = data; 1209fcc85819SChristoph Hellwig 12109f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name.name, args->name.len); 1211d9c407b1SChuck Lever } 1212d9c407b1SChuck Lever 1213d9c407b1SChuck Lever /* 1214d9c407b1SChuck Lever * 3.3.14 RENAME3args 1215d9c407b1SChuck Lever * 1216d9c407b1SChuck Lever * struct RENAME3args { 1217d9c407b1SChuck Lever * diropargs3 from; 1218d9c407b1SChuck Lever * diropargs3 to; 1219d9c407b1SChuck Lever * }; 1220d9c407b1SChuck Lever */ 12219f06c719SChuck Lever static void nfs3_xdr_enc_rename3args(struct rpc_rqst *req, 12229f06c719SChuck Lever struct xdr_stream *xdr, 1223fcc85819SChristoph Hellwig const void *data) 1224d9c407b1SChuck Lever { 1225fcc85819SChristoph Hellwig const struct nfs_renameargs *args = data; 1226d9c407b1SChuck Lever const struct qstr *old = args->old_name; 1227d9c407b1SChuck Lever const struct qstr *new = args->new_name; 1228d9c407b1SChuck Lever 12299f06c719SChuck Lever encode_diropargs3(xdr, args->old_dir, old->name, old->len); 12309f06c719SChuck Lever encode_diropargs3(xdr, args->new_dir, new->name, new->len); 1231d9c407b1SChuck Lever } 1232d9c407b1SChuck Lever 1233d9c407b1SChuck Lever /* 1234d9c407b1SChuck Lever * 3.3.15 LINK3args 1235d9c407b1SChuck Lever * 1236d9c407b1SChuck Lever * struct LINK3args { 1237d9c407b1SChuck Lever * nfs_fh3 file; 1238d9c407b1SChuck Lever * diropargs3 link; 1239d9c407b1SChuck Lever * }; 1240d9c407b1SChuck Lever */ 12419f06c719SChuck Lever static void nfs3_xdr_enc_link3args(struct rpc_rqst *req, 12429f06c719SChuck Lever struct xdr_stream *xdr, 1243fcc85819SChristoph Hellwig const void *data) 1244d9c407b1SChuck Lever { 1245fcc85819SChristoph Hellwig const struct nfs3_linkargs *args = data; 1246fcc85819SChristoph Hellwig 12479f06c719SChuck Lever encode_nfs_fh3(xdr, args->fromfh); 12489f06c719SChuck Lever encode_diropargs3(xdr, args->tofh, args->toname, args->tolen); 1249d9c407b1SChuck Lever } 1250d9c407b1SChuck Lever 1251d9c407b1SChuck Lever /* 1252d9c407b1SChuck Lever * 3.3.16 READDIR3args 1253d9c407b1SChuck Lever * 1254d9c407b1SChuck Lever * struct READDIR3args { 1255d9c407b1SChuck Lever * nfs_fh3 dir; 1256d9c407b1SChuck Lever * cookie3 cookie; 1257d9c407b1SChuck Lever * cookieverf3 cookieverf; 1258d9c407b1SChuck Lever * count3 count; 1259d9c407b1SChuck Lever * }; 1260d9c407b1SChuck Lever */ 1261d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr, 1262d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1263d9c407b1SChuck Lever { 1264d9c407b1SChuck Lever __be32 *p; 1265d9c407b1SChuck Lever 1266d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1267d9c407b1SChuck Lever 1268d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4); 1269d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1270d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1271d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1272d9c407b1SChuck Lever } 1273d9c407b1SChuck Lever 12749f06c719SChuck Lever static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, 12759f06c719SChuck Lever struct xdr_stream *xdr, 1276fcc85819SChristoph Hellwig const void *data) 1277d9c407b1SChuck Lever { 1278fcc85819SChristoph Hellwig const struct nfs3_readdirargs *args = data; 1279fcc85819SChristoph Hellwig 12809f06c719SChuck Lever encode_readdir3args(xdr, args); 1281d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1282d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1283d9c407b1SChuck Lever } 1284d9c407b1SChuck Lever 1285d9c407b1SChuck Lever /* 1286d9c407b1SChuck Lever * 3.3.17 READDIRPLUS3args 1287d9c407b1SChuck Lever * 1288d9c407b1SChuck Lever * struct READDIRPLUS3args { 1289d9c407b1SChuck Lever * nfs_fh3 dir; 1290d9c407b1SChuck Lever * cookie3 cookie; 1291d9c407b1SChuck Lever * cookieverf3 cookieverf; 1292d9c407b1SChuck Lever * count3 dircount; 1293d9c407b1SChuck Lever * count3 maxcount; 1294d9c407b1SChuck Lever * }; 1295d9c407b1SChuck Lever */ 1296d9c407b1SChuck Lever static void encode_readdirplus3args(struct xdr_stream *xdr, 1297d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1298d9c407b1SChuck Lever { 1299d9c407b1SChuck Lever __be32 *p; 1300d9c407b1SChuck Lever 1301d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1302d9c407b1SChuck Lever 1303d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4); 1304d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1305d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1306d9c407b1SChuck Lever 1307d9c407b1SChuck Lever /* 1308d9c407b1SChuck Lever * readdirplus: need dircount + buffer size. 1309d9c407b1SChuck Lever * We just make sure we make dircount big enough 1310d9c407b1SChuck Lever */ 1311d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count >> 3); 1312d9c407b1SChuck Lever 1313d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1314d9c407b1SChuck Lever } 1315d9c407b1SChuck Lever 13169f06c719SChuck Lever static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, 13179f06c719SChuck Lever struct xdr_stream *xdr, 1318fcc85819SChristoph Hellwig const void *data) 1319d9c407b1SChuck Lever { 1320fcc85819SChristoph Hellwig const struct nfs3_readdirargs *args = data; 1321fcc85819SChristoph Hellwig 13229f06c719SChuck Lever encode_readdirplus3args(xdr, args); 1323d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1324d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1325d9c407b1SChuck Lever } 1326d9c407b1SChuck Lever 1327d9c407b1SChuck Lever /* 1328d9c407b1SChuck Lever * 3.3.21 COMMIT3args 1329d9c407b1SChuck Lever * 1330d9c407b1SChuck Lever * struct COMMIT3args { 1331d9c407b1SChuck Lever * nfs_fh3 file; 1332d9c407b1SChuck Lever * offset3 offset; 1333d9c407b1SChuck Lever * count3 count; 1334d9c407b1SChuck Lever * }; 1335d9c407b1SChuck Lever */ 1336d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr, 13370b7c0153SFred Isaman const struct nfs_commitargs *args) 1338d9c407b1SChuck Lever { 1339d9c407b1SChuck Lever __be32 *p; 1340d9c407b1SChuck Lever 1341d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1342d9c407b1SChuck Lever 1343d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 1344d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 1345d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1346d9c407b1SChuck Lever } 1347d9c407b1SChuck Lever 13489f06c719SChuck Lever static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req, 13499f06c719SChuck Lever struct xdr_stream *xdr, 1350fcc85819SChristoph Hellwig const void *data) 1351d9c407b1SChuck Lever { 1352fcc85819SChristoph Hellwig const struct nfs_commitargs *args = data; 1353fcc85819SChristoph Hellwig 13549f06c719SChuck Lever encode_commit3args(xdr, args); 1355d9c407b1SChuck Lever } 1356d9c407b1SChuck Lever 1357b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 1358b7fa0554SAndreas Gruenbacher 13599f06c719SChuck Lever static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, 13609f06c719SChuck Lever struct xdr_stream *xdr, 1361fcc85819SChristoph Hellwig const void *data) 1362d9c407b1SChuck Lever { 1363fcc85819SChristoph Hellwig const struct nfs3_getaclargs *args = data; 1364fcc85819SChristoph Hellwig 13659f06c719SChuck Lever encode_nfs_fh3(xdr, args->fh); 13669f06c719SChuck Lever encode_uint32(xdr, args->mask); 1367431f6eb3STrond Myklebust if (args->mask & (NFS_ACL | NFS_DFACL)) { 1368d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1369d9c407b1SChuck Lever NFSACL_MAXPAGES << PAGE_SHIFT, 1370d9c407b1SChuck Lever ACL3_getaclres_sz); 1371431f6eb3STrond Myklebust req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; 1372431f6eb3STrond Myklebust } 1373d9c407b1SChuck Lever } 1374d9c407b1SChuck Lever 13759f06c719SChuck Lever static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, 13769f06c719SChuck Lever struct xdr_stream *xdr, 1377fcc85819SChristoph Hellwig const void *data) 1378d9c407b1SChuck Lever { 1379fcc85819SChristoph Hellwig const struct nfs3_setaclargs *args = data; 1380d9c407b1SChuck Lever unsigned int base; 1381d9c407b1SChuck Lever int error; 1382d9c407b1SChuck Lever 13839f06c719SChuck Lever encode_nfs_fh3(xdr, NFS_FH(args->inode)); 13849f06c719SChuck Lever encode_uint32(xdr, args->mask); 1385d9c407b1SChuck Lever 1386d9c407b1SChuck Lever base = req->rq_slen; 1387ee5dc773SChuck Lever if (args->npages != 0) 1388ee5dc773SChuck Lever xdr_write_pages(xdr, args->pages, 0, args->len); 1389ee5dc773SChuck Lever else 1390d683cc49SChuck Lever xdr_reserve_space(xdr, args->len); 1391ee5dc773SChuck Lever 13929f06c719SChuck Lever error = nfsacl_encode(xdr->buf, base, args->inode, 1393d9c407b1SChuck Lever (args->mask & NFS_ACL) ? 1394d9c407b1SChuck Lever args->acl_access : NULL, 1, 0); 13957fc38846STrond Myklebust /* FIXME: this is just broken */ 1396d9c407b1SChuck Lever BUG_ON(error < 0); 13979f06c719SChuck Lever error = nfsacl_encode(xdr->buf, base + error, args->inode, 1398d9c407b1SChuck Lever (args->mask & NFS_DFACL) ? 1399d9c407b1SChuck Lever args->acl_default : NULL, 1, 1400d9c407b1SChuck Lever NFS_ACL_DEFAULT); 1401d9c407b1SChuck Lever BUG_ON(error < 0); 1402d9c407b1SChuck Lever } 1403d9c407b1SChuck Lever 1404b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 1405b7fa0554SAndreas Gruenbacher 14061da177e4SLinus Torvalds /* 1407b2cdd9c9SChuck Lever * NFSv3 XDR decode functions 1408b2cdd9c9SChuck Lever * 1409b2cdd9c9SChuck Lever * NFSv3 result types are defined in section 3.3 of RFC 1813: 1410b2cdd9c9SChuck Lever * "NFS Version 3 Protocol Specification". 14111da177e4SLinus Torvalds */ 14121da177e4SLinus Torvalds 14131da177e4SLinus Torvalds /* 1414e4f93234SChuck Lever * 3.3.1 GETATTR3res 1415e4f93234SChuck Lever * 1416e4f93234SChuck Lever * struct GETATTR3resok { 1417e4f93234SChuck Lever * fattr3 obj_attributes; 1418e4f93234SChuck Lever * }; 1419e4f93234SChuck Lever * 1420e4f93234SChuck Lever * union GETATTR3res switch (nfsstat3 status) { 1421e4f93234SChuck Lever * case NFS3_OK: 1422e4f93234SChuck Lever * GETATTR3resok resok; 1423e4f93234SChuck Lever * default: 1424e4f93234SChuck Lever * void; 1425e4f93234SChuck Lever * }; 1426e4f93234SChuck Lever */ 1427bf269551SChuck Lever static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req, 1428bf269551SChuck Lever struct xdr_stream *xdr, 1429fc016483SChristoph Hellwig void *result) 1430e4f93234SChuck Lever { 1431e4f93234SChuck Lever enum nfs_stat status; 1432e4f93234SChuck Lever int error; 1433e4f93234SChuck Lever 1434bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1435e4f93234SChuck Lever if (unlikely(error)) 1436e4f93234SChuck Lever goto out; 1437e4f93234SChuck Lever if (status != NFS3_OK) 1438e4f93234SChuck Lever goto out_default; 1439bf269551SChuck Lever error = decode_fattr3(xdr, result); 1440e4f93234SChuck Lever out: 1441e4f93234SChuck Lever return error; 1442e4f93234SChuck Lever out_default: 14435e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1444e4f93234SChuck Lever } 1445e4f93234SChuck Lever 1446e4f93234SChuck Lever /* 1447e4f93234SChuck Lever * 3.3.2 SETATTR3res 1448e4f93234SChuck Lever * 1449e4f93234SChuck Lever * struct SETATTR3resok { 1450e4f93234SChuck Lever * wcc_data obj_wcc; 1451e4f93234SChuck Lever * }; 1452e4f93234SChuck Lever * 1453e4f93234SChuck Lever * struct SETATTR3resfail { 1454e4f93234SChuck Lever * wcc_data obj_wcc; 1455e4f93234SChuck Lever * }; 1456e4f93234SChuck Lever * 1457e4f93234SChuck Lever * union SETATTR3res switch (nfsstat3 status) { 1458e4f93234SChuck Lever * case NFS3_OK: 1459e4f93234SChuck Lever * SETATTR3resok resok; 1460e4f93234SChuck Lever * default: 1461e4f93234SChuck Lever * SETATTR3resfail resfail; 1462e4f93234SChuck Lever * }; 1463e4f93234SChuck Lever */ 1464bf269551SChuck Lever static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req, 1465bf269551SChuck Lever struct xdr_stream *xdr, 1466fc016483SChristoph Hellwig void *result) 1467e4f93234SChuck Lever { 1468e4f93234SChuck Lever enum nfs_stat status; 1469e4f93234SChuck Lever int error; 1470e4f93234SChuck Lever 1471bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1472e4f93234SChuck Lever if (unlikely(error)) 1473e4f93234SChuck Lever goto out; 1474bf269551SChuck Lever error = decode_wcc_data(xdr, result); 1475e4f93234SChuck Lever if (unlikely(error)) 1476e4f93234SChuck Lever goto out; 1477e4f93234SChuck Lever if (status != NFS3_OK) 1478e4f93234SChuck Lever goto out_status; 1479e4f93234SChuck Lever out: 1480e4f93234SChuck Lever return error; 1481e4f93234SChuck Lever out_status: 14825e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1483e4f93234SChuck Lever } 1484e4f93234SChuck Lever 14851da177e4SLinus Torvalds /* 1486e4f93234SChuck Lever * 3.3.3 LOOKUP3res 1487e4f93234SChuck Lever * 1488e4f93234SChuck Lever * struct LOOKUP3resok { 1489e4f93234SChuck Lever * nfs_fh3 object; 1490e4f93234SChuck Lever * post_op_attr obj_attributes; 1491e4f93234SChuck Lever * post_op_attr dir_attributes; 1492e4f93234SChuck Lever * }; 1493e4f93234SChuck Lever * 1494e4f93234SChuck Lever * struct LOOKUP3resfail { 1495e4f93234SChuck Lever * post_op_attr dir_attributes; 1496e4f93234SChuck Lever * }; 1497e4f93234SChuck Lever * 1498e4f93234SChuck Lever * union LOOKUP3res switch (nfsstat3 status) { 1499e4f93234SChuck Lever * case NFS3_OK: 1500e4f93234SChuck Lever * LOOKUP3resok resok; 1501e4f93234SChuck Lever * default: 1502e4f93234SChuck Lever * LOOKUP3resfail resfail; 1503e4f93234SChuck Lever * }; 1504e4f93234SChuck Lever */ 1505bf269551SChuck Lever static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req, 1506bf269551SChuck Lever struct xdr_stream *xdr, 1507fc016483SChristoph Hellwig void *data) 1508e4f93234SChuck Lever { 1509fc016483SChristoph Hellwig struct nfs3_diropres *result = data; 1510e4f93234SChuck Lever enum nfs_stat status; 1511e4f93234SChuck Lever int error; 1512e4f93234SChuck Lever 1513bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1514e4f93234SChuck Lever if (unlikely(error)) 1515e4f93234SChuck Lever goto out; 1516e4f93234SChuck Lever if (status != NFS3_OK) 1517e4f93234SChuck Lever goto out_default; 1518bf269551SChuck Lever error = decode_nfs_fh3(xdr, result->fh); 1519e4f93234SChuck Lever if (unlikely(error)) 1520e4f93234SChuck Lever goto out; 1521bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1522e4f93234SChuck Lever if (unlikely(error)) 1523e4f93234SChuck Lever goto out; 1524bf269551SChuck Lever error = decode_post_op_attr(xdr, result->dir_attr); 1525e4f93234SChuck Lever out: 1526e4f93234SChuck Lever return error; 1527e4f93234SChuck Lever out_default: 1528bf269551SChuck Lever error = decode_post_op_attr(xdr, result->dir_attr); 1529e4f93234SChuck Lever if (unlikely(error)) 1530e4f93234SChuck Lever goto out; 15315e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1532e4f93234SChuck Lever } 1533e4f93234SChuck Lever 1534e4f93234SChuck Lever /* 1535e4f93234SChuck Lever * 3.3.4 ACCESS3res 1536e4f93234SChuck Lever * 1537e4f93234SChuck Lever * struct ACCESS3resok { 1538e4f93234SChuck Lever * post_op_attr obj_attributes; 1539e4f93234SChuck Lever * uint32 access; 1540e4f93234SChuck Lever * }; 1541e4f93234SChuck Lever * 1542e4f93234SChuck Lever * struct ACCESS3resfail { 1543e4f93234SChuck Lever * post_op_attr obj_attributes; 1544e4f93234SChuck Lever * }; 1545e4f93234SChuck Lever * 1546e4f93234SChuck Lever * union ACCESS3res switch (nfsstat3 status) { 1547e4f93234SChuck Lever * case NFS3_OK: 1548e4f93234SChuck Lever * ACCESS3resok resok; 1549e4f93234SChuck Lever * default: 1550e4f93234SChuck Lever * ACCESS3resfail resfail; 1551e4f93234SChuck Lever * }; 1552e4f93234SChuck Lever */ 1553bf269551SChuck Lever static int nfs3_xdr_dec_access3res(struct rpc_rqst *req, 1554bf269551SChuck Lever struct xdr_stream *xdr, 1555fc016483SChristoph Hellwig void *data) 1556e4f93234SChuck Lever { 1557fc016483SChristoph Hellwig struct nfs3_accessres *result = data; 1558e4f93234SChuck Lever enum nfs_stat status; 1559e4f93234SChuck Lever int error; 1560e4f93234SChuck Lever 1561bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1562e4f93234SChuck Lever if (unlikely(error)) 1563e4f93234SChuck Lever goto out; 1564bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1565e4f93234SChuck Lever if (unlikely(error)) 1566e4f93234SChuck Lever goto out; 1567e4f93234SChuck Lever if (status != NFS3_OK) 1568e4f93234SChuck Lever goto out_default; 1569bf269551SChuck Lever error = decode_uint32(xdr, &result->access); 1570e4f93234SChuck Lever out: 1571e4f93234SChuck Lever return error; 1572e4f93234SChuck Lever out_default: 15735e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1574e4f93234SChuck Lever } 1575e4f93234SChuck Lever 1576e4f93234SChuck Lever /* 1577e4f93234SChuck Lever * 3.3.5 READLINK3res 1578e4f93234SChuck Lever * 1579e4f93234SChuck Lever * struct READLINK3resok { 1580e4f93234SChuck Lever * post_op_attr symlink_attributes; 1581e4f93234SChuck Lever * nfspath3 data; 1582e4f93234SChuck Lever * }; 1583e4f93234SChuck Lever * 1584e4f93234SChuck Lever * struct READLINK3resfail { 1585e4f93234SChuck Lever * post_op_attr symlink_attributes; 1586e4f93234SChuck Lever * }; 1587e4f93234SChuck Lever * 1588e4f93234SChuck Lever * union READLINK3res switch (nfsstat3 status) { 1589e4f93234SChuck Lever * case NFS3_OK: 1590e4f93234SChuck Lever * READLINK3resok resok; 1591e4f93234SChuck Lever * default: 1592e4f93234SChuck Lever * READLINK3resfail resfail; 1593e4f93234SChuck Lever * }; 1594e4f93234SChuck Lever */ 1595bf269551SChuck Lever static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req, 1596bf269551SChuck Lever struct xdr_stream *xdr, 1597fc016483SChristoph Hellwig void *result) 1598e4f93234SChuck Lever { 1599e4f93234SChuck Lever enum nfs_stat status; 1600e4f93234SChuck Lever int error; 1601e4f93234SChuck Lever 1602bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1603e4f93234SChuck Lever if (unlikely(error)) 1604e4f93234SChuck Lever goto out; 1605bf269551SChuck Lever error = decode_post_op_attr(xdr, result); 1606e4f93234SChuck Lever if (unlikely(error)) 1607e4f93234SChuck Lever goto out; 1608e4f93234SChuck Lever if (status != NFS3_OK) 1609e4f93234SChuck Lever goto out_default; 1610bf269551SChuck Lever error = decode_nfspath3(xdr); 1611e4f93234SChuck Lever out: 1612e4f93234SChuck Lever return error; 1613e4f93234SChuck Lever out_default: 16145e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1615e4f93234SChuck Lever } 1616e4f93234SChuck Lever 1617e4f93234SChuck Lever /* 1618e4f93234SChuck Lever * 3.3.6 READ3res 1619e4f93234SChuck Lever * 1620e4f93234SChuck Lever * struct READ3resok { 1621e4f93234SChuck Lever * post_op_attr file_attributes; 1622e4f93234SChuck Lever * count3 count; 1623e4f93234SChuck Lever * bool eof; 1624e4f93234SChuck Lever * opaque data<>; 1625e4f93234SChuck Lever * }; 1626e4f93234SChuck Lever * 1627e4f93234SChuck Lever * struct READ3resfail { 1628e4f93234SChuck Lever * post_op_attr file_attributes; 1629e4f93234SChuck Lever * }; 1630e4f93234SChuck Lever * 1631e4f93234SChuck Lever * union READ3res switch (nfsstat3 status) { 1632e4f93234SChuck Lever * case NFS3_OK: 1633e4f93234SChuck Lever * READ3resok resok; 1634e4f93234SChuck Lever * default: 1635e4f93234SChuck Lever * READ3resfail resfail; 1636e4f93234SChuck Lever * }; 1637e4f93234SChuck Lever */ 1638e4f93234SChuck Lever static int decode_read3resok(struct xdr_stream *xdr, 16399137bdf3SAnna Schumaker struct nfs_pgio_res *result) 1640e4f93234SChuck Lever { 1641e4f93234SChuck Lever u32 eof, count, ocount, recvd; 1642e4f93234SChuck Lever __be32 *p; 1643e4f93234SChuck Lever 1644e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 + 4 + 4); 1645e4f93234SChuck Lever if (unlikely(p == NULL)) 1646e4f93234SChuck Lever goto out_overflow; 1647e4f93234SChuck Lever count = be32_to_cpup(p++); 1648e4f93234SChuck Lever eof = be32_to_cpup(p++); 1649e4f93234SChuck Lever ocount = be32_to_cpup(p++); 1650e4f93234SChuck Lever if (unlikely(ocount != count)) 1651e4f93234SChuck Lever goto out_mismatch; 165264bd577eSTrond Myklebust recvd = xdr_read_pages(xdr, count); 1653e4f93234SChuck Lever if (unlikely(count > recvd)) 1654e4f93234SChuck Lever goto out_cheating; 1655e4f93234SChuck Lever out: 1656e4f93234SChuck Lever result->eof = eof; 1657e4f93234SChuck Lever result->count = count; 1658e4f93234SChuck Lever return count; 1659e4f93234SChuck Lever out_mismatch: 1660e4f93234SChuck Lever dprintk("NFS: READ count doesn't match length of opaque: " 1661e4f93234SChuck Lever "count %u != ocount %u\n", count, ocount); 1662e4f93234SChuck Lever return -EIO; 1663e4f93234SChuck Lever out_cheating: 1664e4f93234SChuck Lever dprintk("NFS: server cheating in read result: " 1665e4f93234SChuck Lever "count %u > recvd %u\n", count, recvd); 1666e4f93234SChuck Lever count = recvd; 1667e4f93234SChuck Lever eof = 0; 1668e4f93234SChuck Lever goto out; 1669e4f93234SChuck Lever out_overflow: 1670e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 1671e4f93234SChuck Lever return -EIO; 1672e4f93234SChuck Lever } 1673e4f93234SChuck Lever 1674bf269551SChuck Lever static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, 1675fc016483SChristoph Hellwig void *data) 1676e4f93234SChuck Lever { 1677fc016483SChristoph Hellwig struct nfs_pgio_res *result = data; 1678e4f93234SChuck Lever enum nfs_stat status; 1679e4f93234SChuck Lever int error; 1680e4f93234SChuck Lever 1681bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1682e4f93234SChuck Lever if (unlikely(error)) 1683e4f93234SChuck Lever goto out; 1684bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1685e4f93234SChuck Lever if (unlikely(error)) 1686e4f93234SChuck Lever goto out; 1687aabff4ddSPeng Tao result->op_status = status; 1688e4f93234SChuck Lever if (status != NFS3_OK) 1689e4f93234SChuck Lever goto out_status; 1690bf269551SChuck Lever error = decode_read3resok(xdr, result); 1691e4f93234SChuck Lever out: 1692e4f93234SChuck Lever return error; 1693e4f93234SChuck Lever out_status: 16945e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1695e4f93234SChuck Lever } 1696e4f93234SChuck Lever 1697e4f93234SChuck Lever /* 1698e4f93234SChuck Lever * 3.3.7 WRITE3res 1699e4f93234SChuck Lever * 1700e4f93234SChuck Lever * enum stable_how { 1701e4f93234SChuck Lever * UNSTABLE = 0, 1702e4f93234SChuck Lever * DATA_SYNC = 1, 1703e4f93234SChuck Lever * FILE_SYNC = 2 1704e4f93234SChuck Lever * }; 1705e4f93234SChuck Lever * 1706e4f93234SChuck Lever * struct WRITE3resok { 1707e4f93234SChuck Lever * wcc_data file_wcc; 1708e4f93234SChuck Lever * count3 count; 1709e4f93234SChuck Lever * stable_how committed; 1710e4f93234SChuck Lever * writeverf3 verf; 1711e4f93234SChuck Lever * }; 1712e4f93234SChuck Lever * 1713e4f93234SChuck Lever * struct WRITE3resfail { 1714e4f93234SChuck Lever * wcc_data file_wcc; 1715e4f93234SChuck Lever * }; 1716e4f93234SChuck Lever * 1717e4f93234SChuck Lever * union WRITE3res switch (nfsstat3 status) { 1718e4f93234SChuck Lever * case NFS3_OK: 1719e4f93234SChuck Lever * WRITE3resok resok; 1720e4f93234SChuck Lever * default: 1721e4f93234SChuck Lever * WRITE3resfail resfail; 1722e4f93234SChuck Lever * }; 1723e4f93234SChuck Lever */ 1724e4f93234SChuck Lever static int decode_write3resok(struct xdr_stream *xdr, 17259137bdf3SAnna Schumaker struct nfs_pgio_res *result) 1726e4f93234SChuck Lever { 1727e4f93234SChuck Lever __be32 *p; 1728e4f93234SChuck Lever 17292f2c63bcSTrond Myklebust p = xdr_inline_decode(xdr, 4 + 4); 1730e4f93234SChuck Lever if (unlikely(p == NULL)) 1731e4f93234SChuck Lever goto out_overflow; 1732e4f93234SChuck Lever result->count = be32_to_cpup(p++); 1733e4f93234SChuck Lever result->verf->committed = be32_to_cpup(p++); 1734e4f93234SChuck Lever if (unlikely(result->verf->committed > NFS_FILE_SYNC)) 1735e4f93234SChuck Lever goto out_badvalue; 17362f2c63bcSTrond Myklebust if (decode_writeverf3(xdr, &result->verf->verifier)) 17372f2c63bcSTrond Myklebust goto out_eio; 1738e4f93234SChuck Lever return result->count; 1739e4f93234SChuck Lever out_badvalue: 1740e4f93234SChuck Lever dprintk("NFS: bad stable_how value: %u\n", result->verf->committed); 1741e4f93234SChuck Lever return -EIO; 1742e4f93234SChuck Lever out_overflow: 1743e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 17442f2c63bcSTrond Myklebust out_eio: 1745e4f93234SChuck Lever return -EIO; 1746e4f93234SChuck Lever } 1747e4f93234SChuck Lever 1748bf269551SChuck Lever static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr, 1749fc016483SChristoph Hellwig void *data) 1750e4f93234SChuck Lever { 1751fc016483SChristoph Hellwig struct nfs_pgio_res *result = data; 1752e4f93234SChuck Lever enum nfs_stat status; 1753e4f93234SChuck Lever int error; 1754e4f93234SChuck Lever 1755bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1756e4f93234SChuck Lever if (unlikely(error)) 1757e4f93234SChuck Lever goto out; 1758bf269551SChuck Lever error = decode_wcc_data(xdr, result->fattr); 1759e4f93234SChuck Lever if (unlikely(error)) 1760e4f93234SChuck Lever goto out; 1761aabff4ddSPeng Tao result->op_status = status; 1762e4f93234SChuck Lever if (status != NFS3_OK) 1763e4f93234SChuck Lever goto out_status; 1764bf269551SChuck Lever error = decode_write3resok(xdr, result); 1765e4f93234SChuck Lever out: 1766e4f93234SChuck Lever return error; 1767e4f93234SChuck Lever out_status: 17685e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1769e4f93234SChuck Lever } 1770e4f93234SChuck Lever 1771e4f93234SChuck Lever /* 1772e4f93234SChuck Lever * 3.3.8 CREATE3res 1773e4f93234SChuck Lever * 1774e4f93234SChuck Lever * struct CREATE3resok { 1775e4f93234SChuck Lever * post_op_fh3 obj; 1776e4f93234SChuck Lever * post_op_attr obj_attributes; 1777e4f93234SChuck Lever * wcc_data dir_wcc; 1778e4f93234SChuck Lever * }; 1779e4f93234SChuck Lever * 1780e4f93234SChuck Lever * struct CREATE3resfail { 1781e4f93234SChuck Lever * wcc_data dir_wcc; 1782e4f93234SChuck Lever * }; 1783e4f93234SChuck Lever * 1784e4f93234SChuck Lever * union CREATE3res switch (nfsstat3 status) { 1785e4f93234SChuck Lever * case NFS3_OK: 1786e4f93234SChuck Lever * CREATE3resok resok; 1787e4f93234SChuck Lever * default: 1788e4f93234SChuck Lever * CREATE3resfail resfail; 1789e4f93234SChuck Lever * }; 1790e4f93234SChuck Lever */ 1791e4f93234SChuck Lever static int decode_create3resok(struct xdr_stream *xdr, 1792e4f93234SChuck Lever struct nfs3_diropres *result) 1793e4f93234SChuck Lever { 1794e4f93234SChuck Lever int error; 1795e4f93234SChuck Lever 1796e4f93234SChuck Lever error = decode_post_op_fh3(xdr, result->fh); 1797e4f93234SChuck Lever if (unlikely(error)) 1798e4f93234SChuck Lever goto out; 1799e4f93234SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1800e4f93234SChuck Lever if (unlikely(error)) 1801e4f93234SChuck Lever goto out; 1802e4f93234SChuck Lever /* The server isn't required to return a file handle. 1803e4f93234SChuck Lever * If it didn't, force the client to perform a LOOKUP 1804e4f93234SChuck Lever * to determine the correct file handle and attribute 1805e4f93234SChuck Lever * values for the new object. */ 1806e4f93234SChuck Lever if (result->fh->size == 0) 1807e4f93234SChuck Lever result->fattr->valid = 0; 1808e4f93234SChuck Lever error = decode_wcc_data(xdr, result->dir_attr); 1809e4f93234SChuck Lever out: 1810e4f93234SChuck Lever return error; 1811e4f93234SChuck Lever } 1812e4f93234SChuck Lever 1813bf269551SChuck Lever static int nfs3_xdr_dec_create3res(struct rpc_rqst *req, 1814bf269551SChuck Lever struct xdr_stream *xdr, 1815fc016483SChristoph Hellwig void *data) 1816e4f93234SChuck Lever { 1817fc016483SChristoph Hellwig struct nfs3_diropres *result = data; 1818e4f93234SChuck Lever enum nfs_stat status; 1819e4f93234SChuck Lever int error; 1820e4f93234SChuck Lever 1821bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1822e4f93234SChuck Lever if (unlikely(error)) 1823e4f93234SChuck Lever goto out; 1824e4f93234SChuck Lever if (status != NFS3_OK) 1825e4f93234SChuck Lever goto out_default; 1826bf269551SChuck Lever error = decode_create3resok(xdr, result); 1827e4f93234SChuck Lever out: 1828e4f93234SChuck Lever return error; 1829e4f93234SChuck Lever out_default: 1830bf269551SChuck Lever error = decode_wcc_data(xdr, result->dir_attr); 1831e4f93234SChuck Lever if (unlikely(error)) 1832e4f93234SChuck Lever goto out; 18335e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1834e4f93234SChuck Lever } 1835e4f93234SChuck Lever 1836e4f93234SChuck Lever /* 1837e4f93234SChuck Lever * 3.3.12 REMOVE3res 1838e4f93234SChuck Lever * 1839e4f93234SChuck Lever * struct REMOVE3resok { 1840e4f93234SChuck Lever * wcc_data dir_wcc; 1841e4f93234SChuck Lever * }; 1842e4f93234SChuck Lever * 1843e4f93234SChuck Lever * struct REMOVE3resfail { 1844e4f93234SChuck Lever * wcc_data dir_wcc; 1845e4f93234SChuck Lever * }; 1846e4f93234SChuck Lever * 1847e4f93234SChuck Lever * union REMOVE3res switch (nfsstat3 status) { 1848e4f93234SChuck Lever * case NFS3_OK: 1849e4f93234SChuck Lever * REMOVE3resok resok; 1850e4f93234SChuck Lever * default: 1851e4f93234SChuck Lever * REMOVE3resfail resfail; 1852e4f93234SChuck Lever * }; 1853e4f93234SChuck Lever */ 1854bf269551SChuck Lever static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req, 1855bf269551SChuck Lever struct xdr_stream *xdr, 1856fc016483SChristoph Hellwig void *data) 1857e4f93234SChuck Lever { 1858fc016483SChristoph Hellwig struct nfs_removeres *result = data; 1859e4f93234SChuck Lever enum nfs_stat status; 1860e4f93234SChuck Lever int error; 1861e4f93234SChuck Lever 1862bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1863e4f93234SChuck Lever if (unlikely(error)) 1864e4f93234SChuck Lever goto out; 1865bf269551SChuck Lever error = decode_wcc_data(xdr, result->dir_attr); 1866e4f93234SChuck Lever if (unlikely(error)) 1867e4f93234SChuck Lever goto out; 1868e4f93234SChuck Lever if (status != NFS3_OK) 1869e4f93234SChuck Lever goto out_status; 1870e4f93234SChuck Lever out: 1871e4f93234SChuck Lever return error; 1872e4f93234SChuck Lever out_status: 18735e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1874e4f93234SChuck Lever } 1875e4f93234SChuck Lever 1876e4f93234SChuck Lever /* 1877e4f93234SChuck Lever * 3.3.14 RENAME3res 1878e4f93234SChuck Lever * 1879e4f93234SChuck Lever * struct RENAME3resok { 1880e4f93234SChuck Lever * wcc_data fromdir_wcc; 1881e4f93234SChuck Lever * wcc_data todir_wcc; 1882e4f93234SChuck Lever * }; 1883e4f93234SChuck Lever * 1884e4f93234SChuck Lever * struct RENAME3resfail { 1885e4f93234SChuck Lever * wcc_data fromdir_wcc; 1886e4f93234SChuck Lever * wcc_data todir_wcc; 1887e4f93234SChuck Lever * }; 1888e4f93234SChuck Lever * 1889e4f93234SChuck Lever * union RENAME3res switch (nfsstat3 status) { 1890e4f93234SChuck Lever * case NFS3_OK: 1891e4f93234SChuck Lever * RENAME3resok resok; 1892e4f93234SChuck Lever * default: 1893e4f93234SChuck Lever * RENAME3resfail resfail; 1894e4f93234SChuck Lever * }; 1895e4f93234SChuck Lever */ 1896bf269551SChuck Lever static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req, 1897bf269551SChuck Lever struct xdr_stream *xdr, 1898fc016483SChristoph Hellwig void *data) 1899e4f93234SChuck Lever { 1900fc016483SChristoph Hellwig struct nfs_renameres *result = data; 1901e4f93234SChuck Lever enum nfs_stat status; 1902e4f93234SChuck Lever int error; 1903e4f93234SChuck Lever 1904bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1905e4f93234SChuck Lever if (unlikely(error)) 1906e4f93234SChuck Lever goto out; 1907bf269551SChuck Lever error = decode_wcc_data(xdr, result->old_fattr); 1908e4f93234SChuck Lever if (unlikely(error)) 1909e4f93234SChuck Lever goto out; 1910bf269551SChuck Lever error = decode_wcc_data(xdr, result->new_fattr); 1911e4f93234SChuck Lever if (unlikely(error)) 1912e4f93234SChuck Lever goto out; 1913e4f93234SChuck Lever if (status != NFS3_OK) 1914e4f93234SChuck Lever goto out_status; 1915e4f93234SChuck Lever out: 1916e4f93234SChuck Lever return error; 1917e4f93234SChuck Lever out_status: 19185e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1919e4f93234SChuck Lever } 1920e4f93234SChuck Lever 1921e4f93234SChuck Lever /* 1922e4f93234SChuck Lever * 3.3.15 LINK3res 1923e4f93234SChuck Lever * 1924e4f93234SChuck Lever * struct LINK3resok { 1925e4f93234SChuck Lever * post_op_attr file_attributes; 1926e4f93234SChuck Lever * wcc_data linkdir_wcc; 1927e4f93234SChuck Lever * }; 1928e4f93234SChuck Lever * 1929e4f93234SChuck Lever * struct LINK3resfail { 1930e4f93234SChuck Lever * post_op_attr file_attributes; 1931e4f93234SChuck Lever * wcc_data linkdir_wcc; 1932e4f93234SChuck Lever * }; 1933e4f93234SChuck Lever * 1934e4f93234SChuck Lever * union LINK3res switch (nfsstat3 status) { 1935e4f93234SChuck Lever * case NFS3_OK: 1936e4f93234SChuck Lever * LINK3resok resok; 1937e4f93234SChuck Lever * default: 1938e4f93234SChuck Lever * LINK3resfail resfail; 1939e4f93234SChuck Lever * }; 1940e4f93234SChuck Lever */ 1941bf269551SChuck Lever static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr, 1942fc016483SChristoph Hellwig void *data) 1943e4f93234SChuck Lever { 1944fc016483SChristoph Hellwig struct nfs3_linkres *result = data; 1945e4f93234SChuck Lever enum nfs_stat status; 1946e4f93234SChuck Lever int error; 1947e4f93234SChuck Lever 1948bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1949e4f93234SChuck Lever if (unlikely(error)) 1950e4f93234SChuck Lever goto out; 1951bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1952e4f93234SChuck Lever if (unlikely(error)) 1953e4f93234SChuck Lever goto out; 1954bf269551SChuck Lever error = decode_wcc_data(xdr, result->dir_attr); 1955e4f93234SChuck Lever if (unlikely(error)) 1956e4f93234SChuck Lever goto out; 1957e4f93234SChuck Lever if (status != NFS3_OK) 1958e4f93234SChuck Lever goto out_status; 1959e4f93234SChuck Lever out: 1960e4f93234SChuck Lever return error; 1961e4f93234SChuck Lever out_status: 19625e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1963e4f93234SChuck Lever } 1964e4f93234SChuck Lever 1965e4f93234SChuck Lever /** 1966e4f93234SChuck Lever * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in 1967e4f93234SChuck Lever * the local page cache 1968e4f93234SChuck Lever * @xdr: XDR stream where entry resides 1969e4f93234SChuck Lever * @entry: buffer to fill in with entry data 1970e4f93234SChuck Lever * @plus: boolean indicating whether this should be a readdirplus entry 1971e4f93234SChuck Lever * 1972573c4e1eSChuck Lever * Returns zero if successful, otherwise a negative errno value is 1973573c4e1eSChuck Lever * returned. 1974e4f93234SChuck Lever * 1975e4f93234SChuck Lever * This function is not invoked during READDIR reply decoding, but 1976e4f93234SChuck Lever * rather whenever an application invokes the getdents(2) system call 1977e4f93234SChuck Lever * on a directory already in our cache. 1978e4f93234SChuck Lever * 1979e4f93234SChuck Lever * 3.3.16 entry3 1980e4f93234SChuck Lever * 1981e4f93234SChuck Lever * struct entry3 { 1982e4f93234SChuck Lever * fileid3 fileid; 1983e4f93234SChuck Lever * filename3 name; 1984e4f93234SChuck Lever * cookie3 cookie; 1985e4f93234SChuck Lever * fhandle3 filehandle; 1986e4f93234SChuck Lever * post_op_attr3 attributes; 1987e4f93234SChuck Lever * entry3 *nextentry; 1988e4f93234SChuck Lever * }; 1989e4f93234SChuck Lever * 1990e4f93234SChuck Lever * 3.3.17 entryplus3 1991e4f93234SChuck Lever * struct entryplus3 { 1992e4f93234SChuck Lever * fileid3 fileid; 1993e4f93234SChuck Lever * filename3 name; 1994e4f93234SChuck Lever * cookie3 cookie; 1995e4f93234SChuck Lever * post_op_attr name_attributes; 1996e4f93234SChuck Lever * post_op_fh3 name_handle; 1997e4f93234SChuck Lever * entryplus3 *nextentry; 1998e4f93234SChuck Lever * }; 1999e4f93234SChuck Lever */ 2000573c4e1eSChuck Lever int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, 2001a7a3b1e9SBenjamin Coddington bool plus) 2002e4f93234SChuck Lever { 2003e4f93234SChuck Lever struct nfs_entry old = *entry; 2004e4f93234SChuck Lever __be32 *p; 2005e4f93234SChuck Lever int error; 200698de9ce6SFrank Sorenson u64 new_cookie; 2007e4f93234SChuck Lever 2008e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 2009e4f93234SChuck Lever if (unlikely(p == NULL)) 2010e4f93234SChuck Lever goto out_overflow; 2011e4f93234SChuck Lever if (*p == xdr_zero) { 2012e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 2013e4f93234SChuck Lever if (unlikely(p == NULL)) 2014e4f93234SChuck Lever goto out_overflow; 2015e4f93234SChuck Lever if (*p == xdr_zero) 2016573c4e1eSChuck Lever return -EAGAIN; 2017e4f93234SChuck Lever entry->eof = 1; 2018573c4e1eSChuck Lever return -EBADCOOKIE; 2019e4f93234SChuck Lever } 2020e4f93234SChuck Lever 2021e4f93234SChuck Lever error = decode_fileid3(xdr, &entry->ino); 2022e4f93234SChuck Lever if (unlikely(error)) 2023573c4e1eSChuck Lever return error; 2024e4f93234SChuck Lever 2025e4f93234SChuck Lever error = decode_inline_filename3(xdr, &entry->name, &entry->len); 2026e4f93234SChuck Lever if (unlikely(error)) 2027573c4e1eSChuck Lever return error; 2028e4f93234SChuck Lever 202998de9ce6SFrank Sorenson error = decode_cookie3(xdr, &new_cookie); 2030e4f93234SChuck Lever if (unlikely(error)) 2031573c4e1eSChuck Lever return error; 2032e4f93234SChuck Lever 2033e4f93234SChuck Lever entry->d_type = DT_UNKNOWN; 2034e4f93234SChuck Lever 2035e4f93234SChuck Lever if (plus) { 2036e4f93234SChuck Lever entry->fattr->valid = 0; 2037e4f93234SChuck Lever error = decode_post_op_attr(xdr, entry->fattr); 2038e4f93234SChuck Lever if (unlikely(error)) 2039573c4e1eSChuck Lever return error; 2040e4f93234SChuck Lever if (entry->fattr->valid & NFS_ATTR_FATTR_V3) 2041e4f93234SChuck Lever entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); 2042e4f93234SChuck Lever 20431ae04b25STrond Myklebust if (entry->fattr->fileid != entry->ino) { 20441ae04b25STrond Myklebust entry->fattr->mounted_on_fileid = entry->ino; 20451ae04b25STrond Myklebust entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID; 20461ae04b25STrond Myklebust } 20471ae04b25STrond Myklebust 2048e4f93234SChuck Lever /* In fact, a post_op_fh3: */ 2049e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 2050e4f93234SChuck Lever if (unlikely(p == NULL)) 2051e4f93234SChuck Lever goto out_overflow; 2052e4f93234SChuck Lever if (*p != xdr_zero) { 2053e4f93234SChuck Lever error = decode_nfs_fh3(xdr, entry->fh); 2054e4f93234SChuck Lever if (unlikely(error)) { 2055e4f93234SChuck Lever if (error == -E2BIG) 2056e4f93234SChuck Lever goto out_truncated; 2057573c4e1eSChuck Lever return error; 2058e4f93234SChuck Lever } 2059e4f93234SChuck Lever } else 2060e4f93234SChuck Lever zero_nfs_fh3(entry->fh); 2061e4f93234SChuck Lever } 2062e4f93234SChuck Lever 206398de9ce6SFrank Sorenson entry->prev_cookie = entry->cookie; 206498de9ce6SFrank Sorenson entry->cookie = new_cookie; 206598de9ce6SFrank Sorenson 2066573c4e1eSChuck Lever return 0; 2067e4f93234SChuck Lever 2068e4f93234SChuck Lever out_overflow: 2069e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2070573c4e1eSChuck Lever return -EAGAIN; 2071e4f93234SChuck Lever out_truncated: 2072e4f93234SChuck Lever dprintk("NFS: directory entry contains invalid file handle\n"); 2073e4f93234SChuck Lever *entry = old; 2074573c4e1eSChuck Lever return -EAGAIN; 2075e4f93234SChuck Lever } 2076e4f93234SChuck Lever 2077e4f93234SChuck Lever /* 2078e4f93234SChuck Lever * 3.3.16 READDIR3res 2079e4f93234SChuck Lever * 2080e4f93234SChuck Lever * struct dirlist3 { 2081e4f93234SChuck Lever * entry3 *entries; 2082e4f93234SChuck Lever * bool eof; 2083e4f93234SChuck Lever * }; 2084e4f93234SChuck Lever * 2085e4f93234SChuck Lever * struct READDIR3resok { 2086e4f93234SChuck Lever * post_op_attr dir_attributes; 2087e4f93234SChuck Lever * cookieverf3 cookieverf; 2088e4f93234SChuck Lever * dirlist3 reply; 2089e4f93234SChuck Lever * }; 2090e4f93234SChuck Lever * 2091e4f93234SChuck Lever * struct READDIR3resfail { 2092e4f93234SChuck Lever * post_op_attr dir_attributes; 2093e4f93234SChuck Lever * }; 2094e4f93234SChuck Lever * 2095e4f93234SChuck Lever * union READDIR3res switch (nfsstat3 status) { 2096e4f93234SChuck Lever * case NFS3_OK: 2097e4f93234SChuck Lever * READDIR3resok resok; 2098e4f93234SChuck Lever * default: 2099e4f93234SChuck Lever * READDIR3resfail resfail; 2100e4f93234SChuck Lever * }; 2101e4f93234SChuck Lever * 2102e4f93234SChuck Lever * Read the directory contents into the page cache, but otherwise 2103e4f93234SChuck Lever * don't touch them. The actual decoding is done by nfs3_decode_entry() 2104e4f93234SChuck Lever * during subsequent nfs_readdir() calls. 2105e4f93234SChuck Lever */ 2106e4f93234SChuck Lever static int decode_dirlist3(struct xdr_stream *xdr) 2107e4f93234SChuck Lever { 210864bd577eSTrond Myklebust return xdr_read_pages(xdr, xdr->buf->page_len); 2109e4f93234SChuck Lever } 2110e4f93234SChuck Lever 2111e4f93234SChuck Lever static int decode_readdir3resok(struct xdr_stream *xdr, 2112e4f93234SChuck Lever struct nfs3_readdirres *result) 2113e4f93234SChuck Lever { 2114e4f93234SChuck Lever int error; 2115e4f93234SChuck Lever 2116e4f93234SChuck Lever error = decode_post_op_attr(xdr, result->dir_attr); 2117e4f93234SChuck Lever if (unlikely(error)) 2118e4f93234SChuck Lever goto out; 2119e4f93234SChuck Lever /* XXX: do we need to check if result->verf != NULL ? */ 2120e4f93234SChuck Lever error = decode_cookieverf3(xdr, result->verf); 2121e4f93234SChuck Lever if (unlikely(error)) 2122e4f93234SChuck Lever goto out; 2123e4f93234SChuck Lever error = decode_dirlist3(xdr); 2124e4f93234SChuck Lever out: 2125e4f93234SChuck Lever return error; 2126e4f93234SChuck Lever } 2127e4f93234SChuck Lever 2128bf269551SChuck Lever static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req, 2129bf269551SChuck Lever struct xdr_stream *xdr, 2130fc016483SChristoph Hellwig void *data) 2131e4f93234SChuck Lever { 2132fc016483SChristoph Hellwig struct nfs3_readdirres *result = data; 2133e4f93234SChuck Lever enum nfs_stat status; 2134e4f93234SChuck Lever int error; 2135e4f93234SChuck Lever 2136bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2137e4f93234SChuck Lever if (unlikely(error)) 2138e4f93234SChuck Lever goto out; 2139e4f93234SChuck Lever if (status != NFS3_OK) 2140e4f93234SChuck Lever goto out_default; 2141bf269551SChuck Lever error = decode_readdir3resok(xdr, result); 2142e4f93234SChuck Lever out: 2143e4f93234SChuck Lever return error; 2144e4f93234SChuck Lever out_default: 2145bf269551SChuck Lever error = decode_post_op_attr(xdr, result->dir_attr); 2146e4f93234SChuck Lever if (unlikely(error)) 2147e4f93234SChuck Lever goto out; 21485e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2149e4f93234SChuck Lever } 2150e4f93234SChuck Lever 2151e4f93234SChuck Lever /* 2152e4f93234SChuck Lever * 3.3.18 FSSTAT3res 2153e4f93234SChuck Lever * 2154e4f93234SChuck Lever * struct FSSTAT3resok { 2155e4f93234SChuck Lever * post_op_attr obj_attributes; 2156e4f93234SChuck Lever * size3 tbytes; 2157e4f93234SChuck Lever * size3 fbytes; 2158e4f93234SChuck Lever * size3 abytes; 2159e4f93234SChuck Lever * size3 tfiles; 2160e4f93234SChuck Lever * size3 ffiles; 2161e4f93234SChuck Lever * size3 afiles; 2162e4f93234SChuck Lever * uint32 invarsec; 2163e4f93234SChuck Lever * }; 2164e4f93234SChuck Lever * 2165e4f93234SChuck Lever * struct FSSTAT3resfail { 2166e4f93234SChuck Lever * post_op_attr obj_attributes; 2167e4f93234SChuck Lever * }; 2168e4f93234SChuck Lever * 2169e4f93234SChuck Lever * union FSSTAT3res switch (nfsstat3 status) { 2170e4f93234SChuck Lever * case NFS3_OK: 2171e4f93234SChuck Lever * FSSTAT3resok resok; 2172e4f93234SChuck Lever * default: 2173e4f93234SChuck Lever * FSSTAT3resfail resfail; 2174e4f93234SChuck Lever * }; 2175e4f93234SChuck Lever */ 2176e4f93234SChuck Lever static int decode_fsstat3resok(struct xdr_stream *xdr, 2177e4f93234SChuck Lever struct nfs_fsstat *result) 2178e4f93234SChuck Lever { 2179e4f93234SChuck Lever __be32 *p; 2180e4f93234SChuck Lever 2181e4f93234SChuck Lever p = xdr_inline_decode(xdr, 8 * 6 + 4); 2182e4f93234SChuck Lever if (unlikely(p == NULL)) 2183e4f93234SChuck Lever goto out_overflow; 2184e4f93234SChuck Lever p = xdr_decode_size3(p, &result->tbytes); 2185e4f93234SChuck Lever p = xdr_decode_size3(p, &result->fbytes); 2186e4f93234SChuck Lever p = xdr_decode_size3(p, &result->abytes); 2187e4f93234SChuck Lever p = xdr_decode_size3(p, &result->tfiles); 2188e4f93234SChuck Lever p = xdr_decode_size3(p, &result->ffiles); 2189e4f93234SChuck Lever xdr_decode_size3(p, &result->afiles); 2190e4f93234SChuck Lever /* ignore invarsec */ 2191e4f93234SChuck Lever return 0; 2192e4f93234SChuck Lever out_overflow: 2193e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2194e4f93234SChuck Lever return -EIO; 2195e4f93234SChuck Lever } 2196e4f93234SChuck Lever 2197bf269551SChuck Lever static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req, 2198bf269551SChuck Lever struct xdr_stream *xdr, 2199fc016483SChristoph Hellwig void *data) 2200e4f93234SChuck Lever { 2201fc016483SChristoph Hellwig struct nfs_fsstat *result = data; 2202e4f93234SChuck Lever enum nfs_stat status; 2203e4f93234SChuck Lever int error; 2204e4f93234SChuck Lever 2205bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2206e4f93234SChuck Lever if (unlikely(error)) 2207e4f93234SChuck Lever goto out; 2208bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2209e4f93234SChuck Lever if (unlikely(error)) 2210e4f93234SChuck Lever goto out; 2211e4f93234SChuck Lever if (status != NFS3_OK) 2212e4f93234SChuck Lever goto out_status; 2213bf269551SChuck Lever error = decode_fsstat3resok(xdr, result); 2214e4f93234SChuck Lever out: 2215e4f93234SChuck Lever return error; 2216e4f93234SChuck Lever out_status: 22175e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2218e4f93234SChuck Lever } 2219e4f93234SChuck Lever 2220e4f93234SChuck Lever /* 2221e4f93234SChuck Lever * 3.3.19 FSINFO3res 2222e4f93234SChuck Lever * 2223e4f93234SChuck Lever * struct FSINFO3resok { 2224e4f93234SChuck Lever * post_op_attr obj_attributes; 2225e4f93234SChuck Lever * uint32 rtmax; 2226e4f93234SChuck Lever * uint32 rtpref; 2227e4f93234SChuck Lever * uint32 rtmult; 2228e4f93234SChuck Lever * uint32 wtmax; 2229e4f93234SChuck Lever * uint32 wtpref; 2230e4f93234SChuck Lever * uint32 wtmult; 2231e4f93234SChuck Lever * uint32 dtpref; 2232e4f93234SChuck Lever * size3 maxfilesize; 2233e4f93234SChuck Lever * nfstime3 time_delta; 2234e4f93234SChuck Lever * uint32 properties; 2235e4f93234SChuck Lever * }; 2236e4f93234SChuck Lever * 2237e4f93234SChuck Lever * struct FSINFO3resfail { 2238e4f93234SChuck Lever * post_op_attr obj_attributes; 2239e4f93234SChuck Lever * }; 2240e4f93234SChuck Lever * 2241e4f93234SChuck Lever * union FSINFO3res switch (nfsstat3 status) { 2242e4f93234SChuck Lever * case NFS3_OK: 2243e4f93234SChuck Lever * FSINFO3resok resok; 2244e4f93234SChuck Lever * default: 2245e4f93234SChuck Lever * FSINFO3resfail resfail; 2246e4f93234SChuck Lever * }; 2247e4f93234SChuck Lever */ 2248e4f93234SChuck Lever static int decode_fsinfo3resok(struct xdr_stream *xdr, 2249e4f93234SChuck Lever struct nfs_fsinfo *result) 2250e4f93234SChuck Lever { 2251e4f93234SChuck Lever __be32 *p; 2252e4f93234SChuck Lever 2253e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4); 2254e4f93234SChuck Lever if (unlikely(p == NULL)) 2255e4f93234SChuck Lever goto out_overflow; 2256e4f93234SChuck Lever result->rtmax = be32_to_cpup(p++); 2257e4f93234SChuck Lever result->rtpref = be32_to_cpup(p++); 2258e4f93234SChuck Lever result->rtmult = be32_to_cpup(p++); 2259e4f93234SChuck Lever result->wtmax = be32_to_cpup(p++); 2260e4f93234SChuck Lever result->wtpref = be32_to_cpup(p++); 2261e4f93234SChuck Lever result->wtmult = be32_to_cpup(p++); 2262e4f93234SChuck Lever result->dtpref = be32_to_cpup(p++); 2263e4f93234SChuck Lever p = xdr_decode_size3(p, &result->maxfilesize); 2264f6048709SChuck Lever xdr_decode_nfstime3(p, &result->time_delta); 2265e4f93234SChuck Lever 2266e4f93234SChuck Lever /* ignore properties */ 2267e4f93234SChuck Lever result->lease_time = 0; 2268e4f93234SChuck Lever return 0; 2269e4f93234SChuck Lever out_overflow: 2270e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2271e4f93234SChuck Lever return -EIO; 2272e4f93234SChuck Lever } 2273e4f93234SChuck Lever 2274bf269551SChuck Lever static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req, 2275bf269551SChuck Lever struct xdr_stream *xdr, 2276fc016483SChristoph Hellwig void *data) 2277e4f93234SChuck Lever { 2278fc016483SChristoph Hellwig struct nfs_fsinfo *result = data; 2279e4f93234SChuck Lever enum nfs_stat status; 2280e4f93234SChuck Lever int error; 2281e4f93234SChuck Lever 2282bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2283e4f93234SChuck Lever if (unlikely(error)) 2284e4f93234SChuck Lever goto out; 2285bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2286e4f93234SChuck Lever if (unlikely(error)) 2287e4f93234SChuck Lever goto out; 2288e4f93234SChuck Lever if (status != NFS3_OK) 2289e4f93234SChuck Lever goto out_status; 2290bf269551SChuck Lever error = decode_fsinfo3resok(xdr, result); 2291e4f93234SChuck Lever out: 2292e4f93234SChuck Lever return error; 2293e4f93234SChuck Lever out_status: 22945e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2295e4f93234SChuck Lever } 2296e4f93234SChuck Lever 2297e4f93234SChuck Lever /* 2298e4f93234SChuck Lever * 3.3.20 PATHCONF3res 2299e4f93234SChuck Lever * 2300e4f93234SChuck Lever * struct PATHCONF3resok { 2301e4f93234SChuck Lever * post_op_attr obj_attributes; 2302e4f93234SChuck Lever * uint32 linkmax; 2303e4f93234SChuck Lever * uint32 name_max; 2304e4f93234SChuck Lever * bool no_trunc; 2305e4f93234SChuck Lever * bool chown_restricted; 2306e4f93234SChuck Lever * bool case_insensitive; 2307e4f93234SChuck Lever * bool case_preserving; 2308e4f93234SChuck Lever * }; 2309e4f93234SChuck Lever * 2310e4f93234SChuck Lever * struct PATHCONF3resfail { 2311e4f93234SChuck Lever * post_op_attr obj_attributes; 2312e4f93234SChuck Lever * }; 2313e4f93234SChuck Lever * 2314e4f93234SChuck Lever * union PATHCONF3res switch (nfsstat3 status) { 2315e4f93234SChuck Lever * case NFS3_OK: 2316e4f93234SChuck Lever * PATHCONF3resok resok; 2317e4f93234SChuck Lever * default: 2318e4f93234SChuck Lever * PATHCONF3resfail resfail; 2319e4f93234SChuck Lever * }; 2320e4f93234SChuck Lever */ 2321e4f93234SChuck Lever static int decode_pathconf3resok(struct xdr_stream *xdr, 2322e4f93234SChuck Lever struct nfs_pathconf *result) 2323e4f93234SChuck Lever { 2324e4f93234SChuck Lever __be32 *p; 2325e4f93234SChuck Lever 2326e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 * 6); 2327e4f93234SChuck Lever if (unlikely(p == NULL)) 2328e4f93234SChuck Lever goto out_overflow; 2329e4f93234SChuck Lever result->max_link = be32_to_cpup(p++); 2330e4f93234SChuck Lever result->max_namelen = be32_to_cpup(p); 2331e4f93234SChuck Lever /* ignore remaining fields */ 2332e4f93234SChuck Lever return 0; 2333e4f93234SChuck Lever out_overflow: 2334e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2335e4f93234SChuck Lever return -EIO; 2336e4f93234SChuck Lever } 2337e4f93234SChuck Lever 2338bf269551SChuck Lever static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req, 2339bf269551SChuck Lever struct xdr_stream *xdr, 2340fc016483SChristoph Hellwig void *data) 2341e4f93234SChuck Lever { 2342fc016483SChristoph Hellwig struct nfs_pathconf *result = data; 2343e4f93234SChuck Lever enum nfs_stat status; 2344e4f93234SChuck Lever int error; 2345e4f93234SChuck Lever 2346bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2347e4f93234SChuck Lever if (unlikely(error)) 2348e4f93234SChuck Lever goto out; 2349bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2350e4f93234SChuck Lever if (unlikely(error)) 2351e4f93234SChuck Lever goto out; 2352e4f93234SChuck Lever if (status != NFS3_OK) 2353e4f93234SChuck Lever goto out_status; 2354bf269551SChuck Lever error = decode_pathconf3resok(xdr, result); 2355e4f93234SChuck Lever out: 2356e4f93234SChuck Lever return error; 2357e4f93234SChuck Lever out_status: 23585e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2359e4f93234SChuck Lever } 2360e4f93234SChuck Lever 2361e4f93234SChuck Lever /* 2362e4f93234SChuck Lever * 3.3.21 COMMIT3res 2363e4f93234SChuck Lever * 2364e4f93234SChuck Lever * struct COMMIT3resok { 2365e4f93234SChuck Lever * wcc_data file_wcc; 2366e4f93234SChuck Lever * writeverf3 verf; 2367e4f93234SChuck Lever * }; 2368e4f93234SChuck Lever * 2369e4f93234SChuck Lever * struct COMMIT3resfail { 2370e4f93234SChuck Lever * wcc_data file_wcc; 2371e4f93234SChuck Lever * }; 2372e4f93234SChuck Lever * 2373e4f93234SChuck Lever * union COMMIT3res switch (nfsstat3 status) { 2374e4f93234SChuck Lever * case NFS3_OK: 2375e4f93234SChuck Lever * COMMIT3resok resok; 2376e4f93234SChuck Lever * default: 2377e4f93234SChuck Lever * COMMIT3resfail resfail; 2378e4f93234SChuck Lever * }; 2379e4f93234SChuck Lever */ 2380bf269551SChuck Lever static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, 2381bf269551SChuck Lever struct xdr_stream *xdr, 2382fc016483SChristoph Hellwig void *data) 2383e4f93234SChuck Lever { 2384fc016483SChristoph Hellwig struct nfs_commitres *result = data; 2385e4f93234SChuck Lever enum nfs_stat status; 2386e4f93234SChuck Lever int error; 2387e4f93234SChuck Lever 2388bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2389e4f93234SChuck Lever if (unlikely(error)) 2390e4f93234SChuck Lever goto out; 2391bf269551SChuck Lever error = decode_wcc_data(xdr, result->fattr); 2392e4f93234SChuck Lever if (unlikely(error)) 2393e4f93234SChuck Lever goto out; 2394aabff4ddSPeng Tao result->op_status = status; 2395e4f93234SChuck Lever if (status != NFS3_OK) 2396e4f93234SChuck Lever goto out_status; 23972f2c63bcSTrond Myklebust error = decode_writeverf3(xdr, &result->verf->verifier); 2398e4f93234SChuck Lever out: 2399e4f93234SChuck Lever return error; 2400e4f93234SChuck Lever out_status: 24015e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2402e4f93234SChuck Lever } 2403e4f93234SChuck Lever 2404b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 2405b7fa0554SAndreas Gruenbacher 2406e4f93234SChuck Lever static inline int decode_getacl3resok(struct xdr_stream *xdr, 2407e4f93234SChuck Lever struct nfs3_getaclres *result) 2408e4f93234SChuck Lever { 2409e4f93234SChuck Lever struct posix_acl **acl; 2410e4f93234SChuck Lever unsigned int *aclcnt; 2411e4f93234SChuck Lever size_t hdrlen; 2412e4f93234SChuck Lever int error; 2413e4f93234SChuck Lever 2414e4f93234SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2415e4f93234SChuck Lever if (unlikely(error)) 2416e4f93234SChuck Lever goto out; 2417e4f93234SChuck Lever error = decode_uint32(xdr, &result->mask); 2418e4f93234SChuck Lever if (unlikely(error)) 2419e4f93234SChuck Lever goto out; 2420e4f93234SChuck Lever error = -EINVAL; 2421e4f93234SChuck Lever if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 2422e4f93234SChuck Lever goto out; 2423e4f93234SChuck Lever 24241aecca3eSTrond Myklebust hdrlen = xdr_stream_pos(xdr); 2425e4f93234SChuck Lever 2426e4f93234SChuck Lever acl = NULL; 2427e4f93234SChuck Lever if (result->mask & NFS_ACL) 2428e4f93234SChuck Lever acl = &result->acl_access; 2429e4f93234SChuck Lever aclcnt = NULL; 2430e4f93234SChuck Lever if (result->mask & NFS_ACLCNT) 2431e4f93234SChuck Lever aclcnt = &result->acl_access_count; 2432e4f93234SChuck Lever error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl); 2433e4f93234SChuck Lever if (unlikely(error <= 0)) 2434e4f93234SChuck Lever goto out; 2435e4f93234SChuck Lever 2436e4f93234SChuck Lever acl = NULL; 2437e4f93234SChuck Lever if (result->mask & NFS_DFACL) 2438e4f93234SChuck Lever acl = &result->acl_default; 2439e4f93234SChuck Lever aclcnt = NULL; 2440e4f93234SChuck Lever if (result->mask & NFS_DFACLCNT) 2441e4f93234SChuck Lever aclcnt = &result->acl_default_count; 2442e4f93234SChuck Lever error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl); 2443e4f93234SChuck Lever if (unlikely(error <= 0)) 2444e4f93234SChuck Lever return error; 2445e4f93234SChuck Lever error = 0; 2446e4f93234SChuck Lever out: 2447e4f93234SChuck Lever return error; 2448e4f93234SChuck Lever } 2449e4f93234SChuck Lever 2450bf269551SChuck Lever static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req, 2451bf269551SChuck Lever struct xdr_stream *xdr, 2452fc016483SChristoph Hellwig void *result) 2453e4f93234SChuck Lever { 2454e4f93234SChuck Lever enum nfs_stat status; 2455e4f93234SChuck Lever int error; 2456e4f93234SChuck Lever 2457bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2458e4f93234SChuck Lever if (unlikely(error)) 2459e4f93234SChuck Lever goto out; 2460e4f93234SChuck Lever if (status != NFS3_OK) 2461e4f93234SChuck Lever goto out_default; 2462bf269551SChuck Lever error = decode_getacl3resok(xdr, result); 2463e4f93234SChuck Lever out: 2464e4f93234SChuck Lever return error; 2465e4f93234SChuck Lever out_default: 24665e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2467e4f93234SChuck Lever } 2468e4f93234SChuck Lever 2469bf269551SChuck Lever static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req, 2470bf269551SChuck Lever struct xdr_stream *xdr, 2471fc016483SChristoph Hellwig void *result) 2472e4f93234SChuck Lever { 2473e4f93234SChuck Lever enum nfs_stat status; 2474e4f93234SChuck Lever int error; 2475e4f93234SChuck Lever 2476bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2477e4f93234SChuck Lever if (unlikely(error)) 2478e4f93234SChuck Lever goto out; 2479e4f93234SChuck Lever if (status != NFS3_OK) 2480e4f93234SChuck Lever goto out_default; 2481bf269551SChuck Lever error = decode_post_op_attr(xdr, result); 2482e4f93234SChuck Lever out: 2483e4f93234SChuck Lever return error; 2484e4f93234SChuck Lever out_default: 24855e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2486e4f93234SChuck Lever } 2487e4f93234SChuck Lever 2488b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 2489b7fa0554SAndreas Gruenbacher 24905e7e5a0dSBryan Schumaker 24915e7e5a0dSBryan Schumaker /* 24925e7e5a0dSBryan Schumaker * We need to translate between nfs status return values and 24935e7e5a0dSBryan Schumaker * the local errno values which may not be the same. 24945e7e5a0dSBryan Schumaker */ 24955e7e5a0dSBryan Schumaker static const struct { 24965e7e5a0dSBryan Schumaker int stat; 24975e7e5a0dSBryan Schumaker int errno; 24985e7e5a0dSBryan Schumaker } nfs_errtbl[] = { 24995e7e5a0dSBryan Schumaker { NFS_OK, 0 }, 25005e7e5a0dSBryan Schumaker { NFSERR_PERM, -EPERM }, 25015e7e5a0dSBryan Schumaker { NFSERR_NOENT, -ENOENT }, 25025e7e5a0dSBryan Schumaker { NFSERR_IO, -errno_NFSERR_IO}, 25035e7e5a0dSBryan Schumaker { NFSERR_NXIO, -ENXIO }, 25045e7e5a0dSBryan Schumaker /* { NFSERR_EAGAIN, -EAGAIN }, */ 25055e7e5a0dSBryan Schumaker { NFSERR_ACCES, -EACCES }, 25065e7e5a0dSBryan Schumaker { NFSERR_EXIST, -EEXIST }, 25075e7e5a0dSBryan Schumaker { NFSERR_XDEV, -EXDEV }, 25085e7e5a0dSBryan Schumaker { NFSERR_NODEV, -ENODEV }, 25095e7e5a0dSBryan Schumaker { NFSERR_NOTDIR, -ENOTDIR }, 25105e7e5a0dSBryan Schumaker { NFSERR_ISDIR, -EISDIR }, 25115e7e5a0dSBryan Schumaker { NFSERR_INVAL, -EINVAL }, 25125e7e5a0dSBryan Schumaker { NFSERR_FBIG, -EFBIG }, 25135e7e5a0dSBryan Schumaker { NFSERR_NOSPC, -ENOSPC }, 25145e7e5a0dSBryan Schumaker { NFSERR_ROFS, -EROFS }, 25155e7e5a0dSBryan Schumaker { NFSERR_MLINK, -EMLINK }, 25165e7e5a0dSBryan Schumaker { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, 25175e7e5a0dSBryan Schumaker { NFSERR_NOTEMPTY, -ENOTEMPTY }, 25185e7e5a0dSBryan Schumaker { NFSERR_DQUOT, -EDQUOT }, 25195e7e5a0dSBryan Schumaker { NFSERR_STALE, -ESTALE }, 25205e7e5a0dSBryan Schumaker { NFSERR_REMOTE, -EREMOTE }, 25215e7e5a0dSBryan Schumaker #ifdef EWFLUSH 25225e7e5a0dSBryan Schumaker { NFSERR_WFLUSH, -EWFLUSH }, 25235e7e5a0dSBryan Schumaker #endif 25245e7e5a0dSBryan Schumaker { NFSERR_BADHANDLE, -EBADHANDLE }, 25255e7e5a0dSBryan Schumaker { NFSERR_NOT_SYNC, -ENOTSYNC }, 25265e7e5a0dSBryan Schumaker { NFSERR_BAD_COOKIE, -EBADCOOKIE }, 25275e7e5a0dSBryan Schumaker { NFSERR_NOTSUPP, -ENOTSUPP }, 25285e7e5a0dSBryan Schumaker { NFSERR_TOOSMALL, -ETOOSMALL }, 25295e7e5a0dSBryan Schumaker { NFSERR_SERVERFAULT, -EREMOTEIO }, 25305e7e5a0dSBryan Schumaker { NFSERR_BADTYPE, -EBADTYPE }, 25315e7e5a0dSBryan Schumaker { NFSERR_JUKEBOX, -EJUKEBOX }, 25325e7e5a0dSBryan Schumaker { -1, -EIO } 25335e7e5a0dSBryan Schumaker }; 25345e7e5a0dSBryan Schumaker 25355e7e5a0dSBryan Schumaker /** 25365e7e5a0dSBryan Schumaker * nfs3_stat_to_errno - convert an NFS status code to a local errno 25375e7e5a0dSBryan Schumaker * @status: NFS status code to convert 25385e7e5a0dSBryan Schumaker * 25395e7e5a0dSBryan Schumaker * Returns a local errno value, or -EIO if the NFS status code is 25405e7e5a0dSBryan Schumaker * not recognized. This function is used jointly by NFSv2 and NFSv3. 25415e7e5a0dSBryan Schumaker */ 25425e7e5a0dSBryan Schumaker static int nfs3_stat_to_errno(enum nfs_stat status) 25435e7e5a0dSBryan Schumaker { 25445e7e5a0dSBryan Schumaker int i; 25455e7e5a0dSBryan Schumaker 25465e7e5a0dSBryan Schumaker for (i = 0; nfs_errtbl[i].stat != -1; i++) { 25475e7e5a0dSBryan Schumaker if (nfs_errtbl[i].stat == (int)status) 25485e7e5a0dSBryan Schumaker return nfs_errtbl[i].errno; 25495e7e5a0dSBryan Schumaker } 25505e7e5a0dSBryan Schumaker dprintk("NFS: Unrecognized nfs status value: %u\n", status); 25515e7e5a0dSBryan Schumaker return nfs_errtbl[i].errno; 25525e7e5a0dSBryan Schumaker } 25535e7e5a0dSBryan Schumaker 25545e7e5a0dSBryan Schumaker 25551da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer) \ 25561da177e4SLinus Torvalds [NFS3PROC_##proc] = { \ 25571da177e4SLinus Torvalds .p_proc = NFS3PROC_##proc, \ 2558fcc85819SChristoph Hellwig .p_encode = nfs3_xdr_enc_##argtype##3args, \ 2559fc016483SChristoph Hellwig .p_decode = nfs3_xdr_dec_##restype##3res, \ 2560ad96b5b5SChuck Lever .p_arglen = NFS3_##argtype##args_sz, \ 2561f5fc3c50SChuck Lever .p_replen = NFS3_##restype##res_sz, \ 2562cc0175c1SChuck Lever .p_timer = timer, \ 2563cc0175c1SChuck Lever .p_statidx = NFS3PROC_##proc, \ 2564cc0175c1SChuck Lever .p_name = #proc, \ 25651da177e4SLinus Torvalds } 25661da177e4SLinus Torvalds 2567511e936bSChristoph Hellwig const struct rpc_procinfo nfs3_procedures[] = { 2568f5fc3c50SChuck Lever PROC(GETATTR, getattr, getattr, 1), 2569f5fc3c50SChuck Lever PROC(SETATTR, setattr, setattr, 0), 2570f5fc3c50SChuck Lever PROC(LOOKUP, lookup, lookup, 2), 2571f5fc3c50SChuck Lever PROC(ACCESS, access, access, 1), 2572f5fc3c50SChuck Lever PROC(READLINK, readlink, readlink, 3), 2573f5fc3c50SChuck Lever PROC(READ, read, read, 3), 2574f5fc3c50SChuck Lever PROC(WRITE, write, write, 4), 2575f5fc3c50SChuck Lever PROC(CREATE, create, create, 0), 2576f5fc3c50SChuck Lever PROC(MKDIR, mkdir, create, 0), 2577f5fc3c50SChuck Lever PROC(SYMLINK, symlink, create, 0), 2578f5fc3c50SChuck Lever PROC(MKNOD, mknod, create, 0), 2579f5fc3c50SChuck Lever PROC(REMOVE, remove, remove, 0), 2580f5fc3c50SChuck Lever PROC(RMDIR, lookup, setattr, 0), 2581f5fc3c50SChuck Lever PROC(RENAME, rename, rename, 0), 2582f5fc3c50SChuck Lever PROC(LINK, link, link, 0), 2583f5fc3c50SChuck Lever PROC(READDIR, readdir, readdir, 3), 2584f5fc3c50SChuck Lever PROC(READDIRPLUS, readdirplus, readdir, 3), 2585f5fc3c50SChuck Lever PROC(FSSTAT, getattr, fsstat, 0), 2586f5fc3c50SChuck Lever PROC(FSINFO, getattr, fsinfo, 0), 2587f5fc3c50SChuck Lever PROC(PATHCONF, getattr, pathconf, 0), 2588f5fc3c50SChuck Lever PROC(COMMIT, commit, commit, 5), 25891da177e4SLinus Torvalds }; 25901da177e4SLinus Torvalds 2591c551858aSChristoph Hellwig static unsigned int nfs_version3_counts[ARRAY_SIZE(nfs3_procedures)]; 2592a613fa16STrond Myklebust const struct rpc_version nfs_version3 = { 25931da177e4SLinus Torvalds .number = 3, 2594e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nfs3_procedures), 2595c551858aSChristoph Hellwig .procs = nfs3_procedures, 2596c551858aSChristoph Hellwig .counts = nfs_version3_counts, 25971da177e4SLinus Torvalds }; 25981da177e4SLinus Torvalds 2599b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 2600511e936bSChristoph Hellwig static const struct rpc_procinfo nfs3_acl_procedures[] = { 2601b7fa0554SAndreas Gruenbacher [ACLPROC3_GETACL] = { 2602b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_GETACL, 2603fcc85819SChristoph Hellwig .p_encode = nfs3_xdr_enc_getacl3args, 2604fc016483SChristoph Hellwig .p_decode = nfs3_xdr_dec_getacl3res, 26052bea90d4SChuck Lever .p_arglen = ACL3_getaclargs_sz, 26062bea90d4SChuck Lever .p_replen = ACL3_getaclres_sz, 2607b7fa0554SAndreas Gruenbacher .p_timer = 1, 2608cc0175c1SChuck Lever .p_name = "GETACL", 2609b7fa0554SAndreas Gruenbacher }, 2610b7fa0554SAndreas Gruenbacher [ACLPROC3_SETACL] = { 2611b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_SETACL, 2612fcc85819SChristoph Hellwig .p_encode = nfs3_xdr_enc_setacl3args, 2613fc016483SChristoph Hellwig .p_decode = nfs3_xdr_dec_setacl3res, 26142bea90d4SChuck Lever .p_arglen = ACL3_setaclargs_sz, 26152bea90d4SChuck Lever .p_replen = ACL3_setaclres_sz, 2616b7fa0554SAndreas Gruenbacher .p_timer = 0, 2617cc0175c1SChuck Lever .p_name = "SETACL", 2618b7fa0554SAndreas Gruenbacher }, 2619b7fa0554SAndreas Gruenbacher }; 2620b7fa0554SAndreas Gruenbacher 2621c551858aSChristoph Hellwig static unsigned int nfs3_acl_counts[ARRAY_SIZE(nfs3_acl_procedures)]; 2622a613fa16STrond Myklebust const struct rpc_version nfsacl_version3 = { 2623b7fa0554SAndreas Gruenbacher .number = 3, 26249ae7d8ffSChristoph Hellwig .nrprocs = ARRAY_SIZE(nfs3_acl_procedures), 2625b7fa0554SAndreas Gruenbacher .procs = nfs3_acl_procedures, 2626c551858aSChristoph Hellwig .counts = nfs3_acl_counts, 2627b7fa0554SAndreas Gruenbacher }; 2628b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 2629