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> 24f23f6584SChuck Lever #include "nfstrace.h" 25f7b422b1SDavid Howells #include "internal.h" 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #define NFSDBG_FACILITY NFSDBG_XDR 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */ 301da177e4SLinus Torvalds #define errno_NFSERR_IO EIO 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds /* 331da177e4SLinus Torvalds * Declare the space requirements for NFS arguments and replies as 341da177e4SLinus Torvalds * number of 32bit-words 351da177e4SLinus Torvalds */ 361da177e4SLinus Torvalds #define NFS3_fhandle_sz (1+16) 371da177e4SLinus Torvalds #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */ 381da177e4SLinus Torvalds #define NFS3_sattr_sz (15) 391da177e4SLinus Torvalds #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2)) 401da177e4SLinus Torvalds #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2)) 411da177e4SLinus Torvalds #define NFS3_fattr_sz (21) 42d9c407b1SChuck Lever #define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2) 431da177e4SLinus Torvalds #define NFS3_wcc_attr_sz (6) 441da177e4SLinus Torvalds #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz) 451da177e4SLinus Torvalds #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz) 461da177e4SLinus Torvalds #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz) 471da177e4SLinus Torvalds #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz) 48ad96b5b5SChuck Lever 49ad96b5b5SChuck Lever #define NFS3_getattrargs_sz (NFS3_fh_sz) 50ad96b5b5SChuck Lever #define NFS3_setattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3) 51ad96b5b5SChuck Lever #define NFS3_lookupargs_sz (NFS3_fh_sz+NFS3_filename_sz) 521da177e4SLinus Torvalds #define NFS3_accessargs_sz (NFS3_fh_sz+1) 531da177e4SLinus Torvalds #define NFS3_readlinkargs_sz (NFS3_fh_sz) 541da177e4SLinus Torvalds #define NFS3_readargs_sz (NFS3_fh_sz+3) 551da177e4SLinus Torvalds #define NFS3_writeargs_sz (NFS3_fh_sz+5) 561da177e4SLinus Torvalds #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 571da177e4SLinus Torvalds #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 5894a6d753SChuck Lever #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz) 591da177e4SLinus Torvalds #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) 60ad96b5b5SChuck Lever #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz) 611da177e4SLinus Torvalds #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) 621da177e4SLinus Torvalds #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) 63d9c407b1SChuck Lever #define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3) 64d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4) 651da177e4SLinus Torvalds #define NFS3_commitargs_sz (NFS3_fh_sz+3) 661da177e4SLinus Torvalds 67f5fc3c50SChuck Lever #define NFS3_getattrres_sz (1+NFS3_fattr_sz) 68f5fc3c50SChuck Lever #define NFS3_setattrres_sz (1+NFS3_wcc_data_sz) 69f5fc3c50SChuck Lever #define NFS3_removeres_sz (NFS3_setattrres_sz) 701da177e4SLinus Torvalds #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) 711da177e4SLinus Torvalds #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) 7202ef04e4SChuck Lever #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1+1) 7302ef04e4SChuck Lever #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3+1) 741da177e4SLinus Torvalds #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4) 751da177e4SLinus Torvalds #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 761da177e4SLinus Torvalds #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz)) 771da177e4SLinus Torvalds #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 7802ef04e4SChuck Lever #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2+1) 791da177e4SLinus Torvalds #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13) 801da177e4SLinus Torvalds #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12) 811da177e4SLinus Torvalds #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) 821da177e4SLinus Torvalds #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) 831da177e4SLinus Torvalds 84b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz (NFS3_fh_sz+1) 85ae46141fSTrond Myklebust #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \ 86ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 87ae46141fSTrond Myklebust #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \ 8802ef04e4SChuck Lever XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)+1) 89b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) 90b7fa0554SAndreas Gruenbacher 915e7e5a0dSBryan Schumaker static int nfs3_stat_to_errno(enum nfs_stat); 925e7e5a0dSBryan Schumaker 931da177e4SLinus Torvalds /* 941da177e4SLinus Torvalds * Map file type to S_IFMT bits 951da177e4SLinus Torvalds */ 96bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = { 97bca79478STrond Myklebust [NF3BAD] = 0, 98bca79478STrond Myklebust [NF3REG] = S_IFREG, 99bca79478STrond Myklebust [NF3DIR] = S_IFDIR, 100bca79478STrond Myklebust [NF3BLK] = S_IFBLK, 101bca79478STrond Myklebust [NF3CHR] = S_IFCHR, 102bca79478STrond Myklebust [NF3LNK] = S_IFLNK, 103bca79478STrond Myklebust [NF3SOCK] = S_IFSOCK, 104bca79478STrond Myklebust [NF3FIFO] = S_IFIFO, 1051da177e4SLinus Torvalds }; 1061da177e4SLinus Torvalds 107264d948cSTrond Myklebust static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt) 108264d948cSTrond Myklebust { 109264d948cSTrond Myklebust if (clnt && clnt->cl_cred) 110264d948cSTrond Myklebust return clnt->cl_cred->user_ns; 111264d948cSTrond Myklebust return &init_user_ns; 112264d948cSTrond Myklebust } 113264d948cSTrond Myklebust 114264d948cSTrond Myklebust static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp) 115264d948cSTrond Myklebust { 116264d948cSTrond Myklebust if (rqstp->rq_task) 117264d948cSTrond Myklebust return rpc_userns(rqstp->rq_task->tk_client); 118264d948cSTrond Myklebust return &init_user_ns; 119264d948cSTrond Myklebust } 120264d948cSTrond Myklebust 1211da177e4SLinus Torvalds /* 122d9c407b1SChuck Lever * Encode/decode NFSv3 basic data types 123d9c407b1SChuck Lever * 124d9c407b1SChuck Lever * Basic NFSv3 data types are defined in section 2.5 of RFC 1813: 125d9c407b1SChuck Lever * "NFS Version 3 Protocol Specification". 126d9c407b1SChuck Lever * 127d9c407b1SChuck Lever * Not all basic data types have their own encoding and decoding 128d9c407b1SChuck Lever * functions. For run-time efficiency, some data types are encoded 129d9c407b1SChuck Lever * or decoded inline. 130d9c407b1SChuck Lever */ 131d9c407b1SChuck Lever 132d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value) 133d9c407b1SChuck Lever { 134d9c407b1SChuck Lever __be32 *p = xdr_reserve_space(xdr, 4); 135d9c407b1SChuck Lever *p = cpu_to_be32(value); 136d9c407b1SChuck Lever } 137d9c407b1SChuck Lever 138e4f93234SChuck Lever static int decode_uint32(struct xdr_stream *xdr, u32 *value) 139e4f93234SChuck Lever { 140e4f93234SChuck Lever __be32 *p; 141e4f93234SChuck Lever 142e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 143eb72f484SChuck Lever if (unlikely(!p)) 144eb72f484SChuck Lever return -EIO; 145e4f93234SChuck Lever *value = be32_to_cpup(p); 146e4f93234SChuck Lever return 0; 147e4f93234SChuck Lever } 148e4f93234SChuck Lever 149e4f93234SChuck Lever static int decode_uint64(struct xdr_stream *xdr, u64 *value) 150e4f93234SChuck Lever { 151e4f93234SChuck Lever __be32 *p; 152e4f93234SChuck Lever 153e4f93234SChuck Lever p = xdr_inline_decode(xdr, 8); 154eb72f484SChuck Lever if (unlikely(!p)) 155eb72f484SChuck Lever return -EIO; 156e4f93234SChuck Lever xdr_decode_hyper(p, value); 157e4f93234SChuck Lever return 0; 158e4f93234SChuck Lever } 159e4f93234SChuck Lever 160e4f93234SChuck Lever /* 161e4f93234SChuck Lever * fileid3 162e4f93234SChuck Lever * 163e4f93234SChuck Lever * typedef uint64 fileid3; 164e4f93234SChuck Lever */ 165f6048709SChuck Lever static __be32 *xdr_decode_fileid3(__be32 *p, u64 *fileid) 166f6048709SChuck Lever { 167f6048709SChuck Lever return xdr_decode_hyper(p, fileid); 168f6048709SChuck Lever } 169f6048709SChuck Lever 170e4f93234SChuck Lever static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid) 171e4f93234SChuck Lever { 172e4f93234SChuck Lever return decode_uint64(xdr, fileid); 173e4f93234SChuck Lever } 174e4f93234SChuck Lever 175d9c407b1SChuck Lever /* 176d9c407b1SChuck Lever * filename3 177d9c407b1SChuck Lever * 178d9c407b1SChuck Lever * typedef string filename3<>; 179d9c407b1SChuck Lever */ 180d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr, 181d9c407b1SChuck Lever const char *name, u32 length) 182d9c407b1SChuck Lever { 183d9c407b1SChuck Lever __be32 *p; 184d9c407b1SChuck Lever 1857fc38846STrond Myklebust WARN_ON_ONCE(length > NFS3_MAXNAMLEN); 186d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + length); 187d9c407b1SChuck Lever xdr_encode_opaque(p, name, length); 188d9c407b1SChuck Lever } 189d9c407b1SChuck Lever 190e4f93234SChuck Lever static int decode_inline_filename3(struct xdr_stream *xdr, 191e4f93234SChuck Lever const char **name, u32 *length) 192e4f93234SChuck Lever { 193e4f93234SChuck Lever __be32 *p; 194e4f93234SChuck Lever u32 count; 195e4f93234SChuck Lever 196e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 197eb72f484SChuck Lever if (unlikely(!p)) 198eb72f484SChuck Lever return -EIO; 199e4f93234SChuck Lever count = be32_to_cpup(p); 200e4f93234SChuck Lever if (count > NFS3_MAXNAMLEN) 201e4f93234SChuck Lever goto out_nametoolong; 202e4f93234SChuck Lever p = xdr_inline_decode(xdr, count); 203eb72f484SChuck Lever if (unlikely(!p)) 204eb72f484SChuck Lever return -EIO; 205e4f93234SChuck Lever *name = (const char *)p; 206e4f93234SChuck Lever *length = count; 207e4f93234SChuck Lever return 0; 208e4f93234SChuck Lever 209e4f93234SChuck Lever out_nametoolong: 210e4f93234SChuck Lever dprintk("NFS: returned filename too long: %u\n", count); 211e4f93234SChuck Lever return -ENAMETOOLONG; 212e4f93234SChuck Lever } 213e4f93234SChuck Lever 214d9c407b1SChuck Lever /* 215d9c407b1SChuck Lever * nfspath3 216d9c407b1SChuck Lever * 217d9c407b1SChuck Lever * typedef string nfspath3<>; 218d9c407b1SChuck Lever */ 219d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages, 220d9c407b1SChuck Lever const u32 length) 221d9c407b1SChuck Lever { 222d9c407b1SChuck Lever encode_uint32(xdr, length); 223d9c407b1SChuck Lever xdr_write_pages(xdr, pages, 0, length); 224d9c407b1SChuck Lever } 225d9c407b1SChuck Lever 226e4f93234SChuck Lever static int decode_nfspath3(struct xdr_stream *xdr) 227e4f93234SChuck Lever { 228e4f93234SChuck Lever u32 recvd, count; 229e4f93234SChuck Lever __be32 *p; 230e4f93234SChuck Lever 231e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 232eb72f484SChuck Lever if (unlikely(!p)) 233eb72f484SChuck Lever return -EIO; 234e4f93234SChuck Lever count = be32_to_cpup(p); 235e4f93234SChuck Lever if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN)) 236e4f93234SChuck Lever goto out_nametoolong; 23764bd577eSTrond Myklebust recvd = xdr_read_pages(xdr, count); 238e4f93234SChuck Lever if (unlikely(count > recvd)) 239e4f93234SChuck Lever goto out_cheating; 240e4f93234SChuck Lever xdr_terminate_string(xdr->buf, count); 241e4f93234SChuck Lever return 0; 242e4f93234SChuck Lever 243e4f93234SChuck Lever out_nametoolong: 244e4f93234SChuck Lever dprintk("NFS: returned pathname too long: %u\n", count); 245e4f93234SChuck Lever return -ENAMETOOLONG; 246e4f93234SChuck Lever out_cheating: 247e4f93234SChuck Lever dprintk("NFS: server cheating in pathname result: " 248e4f93234SChuck Lever "count %u > recvd %u\n", count, recvd); 249e4f93234SChuck Lever return -EIO; 250e4f93234SChuck Lever } 251e4f93234SChuck Lever 252d9c407b1SChuck Lever /* 253d9c407b1SChuck Lever * cookie3 254d9c407b1SChuck Lever * 255d9c407b1SChuck Lever * typedef uint64 cookie3 256d9c407b1SChuck Lever */ 257d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie) 258d9c407b1SChuck Lever { 259d9c407b1SChuck Lever return xdr_encode_hyper(p, cookie); 260d9c407b1SChuck Lever } 261d9c407b1SChuck Lever 262e4f93234SChuck Lever static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie) 263e4f93234SChuck Lever { 264e4f93234SChuck Lever return decode_uint64(xdr, cookie); 265e4f93234SChuck Lever } 266e4f93234SChuck Lever 267d9c407b1SChuck Lever /* 268d9c407b1SChuck Lever * cookieverf3 269d9c407b1SChuck Lever * 270d9c407b1SChuck Lever * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; 271d9c407b1SChuck Lever */ 272d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier) 273d9c407b1SChuck Lever { 274d9c407b1SChuck Lever memcpy(p, verifier, NFS3_COOKIEVERFSIZE); 275d9c407b1SChuck Lever return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE); 276d9c407b1SChuck Lever } 277d9c407b1SChuck Lever 278e4f93234SChuck Lever static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier) 279e4f93234SChuck Lever { 280e4f93234SChuck Lever __be32 *p; 281e4f93234SChuck Lever 282e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); 283eb72f484SChuck Lever if (unlikely(!p)) 284eb72f484SChuck Lever return -EIO; 285e4f93234SChuck Lever memcpy(verifier, p, NFS3_COOKIEVERFSIZE); 286e4f93234SChuck Lever return 0; 287e4f93234SChuck Lever } 288e4f93234SChuck Lever 289d9c407b1SChuck Lever /* 290d9c407b1SChuck Lever * createverf3 291d9c407b1SChuck Lever * 292d9c407b1SChuck Lever * typedef opaque createverf3[NFS3_CREATEVERFSIZE]; 293d9c407b1SChuck Lever */ 294d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier) 295d9c407b1SChuck Lever { 296d9c407b1SChuck Lever __be32 *p; 297d9c407b1SChuck Lever 298d9c407b1SChuck Lever p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE); 299d9c407b1SChuck Lever memcpy(p, verifier, NFS3_CREATEVERFSIZE); 300d9c407b1SChuck Lever } 301d9c407b1SChuck Lever 3022f2c63bcSTrond Myklebust static int decode_writeverf3(struct xdr_stream *xdr, struct nfs_write_verifier *verifier) 303e4f93234SChuck Lever { 304e4f93234SChuck Lever __be32 *p; 305e4f93234SChuck Lever 306e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE); 307eb72f484SChuck Lever if (unlikely(!p)) 308eb72f484SChuck Lever return -EIO; 3092f2c63bcSTrond Myklebust memcpy(verifier->data, p, NFS3_WRITEVERFSIZE); 310e4f93234SChuck Lever return 0; 311e4f93234SChuck Lever } 312e4f93234SChuck Lever 313e4f93234SChuck Lever /* 314e4f93234SChuck Lever * size3 315e4f93234SChuck Lever * 316e4f93234SChuck Lever * typedef uint64 size3; 317e4f93234SChuck Lever */ 318e4f93234SChuck Lever static __be32 *xdr_decode_size3(__be32 *p, u64 *size) 319e4f93234SChuck Lever { 320e4f93234SChuck Lever return xdr_decode_hyper(p, size); 321e4f93234SChuck Lever } 322e4f93234SChuck Lever 323e4f93234SChuck Lever /* 324e4f93234SChuck Lever * nfsstat3 325e4f93234SChuck Lever * 326e4f93234SChuck Lever * enum nfsstat3 { 327e4f93234SChuck Lever * NFS3_OK = 0, 328e4f93234SChuck Lever * ... 329e4f93234SChuck Lever * } 330e4f93234SChuck Lever */ 331e4f93234SChuck Lever #define NFS3_OK NFS_OK 332e4f93234SChuck Lever 333e4f93234SChuck Lever static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status) 334e4f93234SChuck Lever { 335e4f93234SChuck Lever __be32 *p; 336e4f93234SChuck Lever 337e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 338eb72f484SChuck Lever if (unlikely(!p)) 339eb72f484SChuck Lever return -EIO; 340f23f6584SChuck Lever if (unlikely(*p != cpu_to_be32(NFS3_OK))) 341f23f6584SChuck Lever goto out_status; 342f23f6584SChuck Lever *status = 0; 343f23f6584SChuck Lever return 0; 344f23f6584SChuck Lever out_status: 345e4f93234SChuck Lever *status = be32_to_cpup(p); 34662a92ba9SChuck Lever trace_nfs_xdr_status(xdr, (int)*status); 347e4f93234SChuck Lever return 0; 348e4f93234SChuck Lever } 349e4f93234SChuck Lever 350d9c407b1SChuck Lever /* 351d9c407b1SChuck Lever * ftype3 352d9c407b1SChuck Lever * 353d9c407b1SChuck Lever * enum ftype3 { 354d9c407b1SChuck Lever * NF3REG = 1, 355d9c407b1SChuck Lever * NF3DIR = 2, 356d9c407b1SChuck Lever * NF3BLK = 3, 357d9c407b1SChuck Lever * NF3CHR = 4, 358d9c407b1SChuck Lever * NF3LNK = 5, 359d9c407b1SChuck Lever * NF3SOCK = 6, 360d9c407b1SChuck Lever * NF3FIFO = 7 361d9c407b1SChuck Lever * }; 362d9c407b1SChuck Lever */ 363d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type) 364d9c407b1SChuck Lever { 365d9c407b1SChuck Lever encode_uint32(xdr, type); 366d9c407b1SChuck Lever } 367d9c407b1SChuck Lever 368f6048709SChuck Lever static __be32 *xdr_decode_ftype3(__be32 *p, umode_t *mode) 369f6048709SChuck Lever { 370f6048709SChuck Lever u32 type; 371f6048709SChuck Lever 372f6048709SChuck Lever type = be32_to_cpup(p++); 373f6048709SChuck Lever if (type > NF3FIFO) 374f6048709SChuck Lever type = NF3NON; 375f6048709SChuck Lever *mode = nfs_type2fmt[type]; 376f6048709SChuck Lever return p; 377f6048709SChuck Lever } 378f6048709SChuck Lever 379d9c407b1SChuck Lever /* 380d9c407b1SChuck Lever * specdata3 381d9c407b1SChuck Lever * 382d9c407b1SChuck Lever * struct specdata3 { 383d9c407b1SChuck Lever * uint32 specdata1; 384d9c407b1SChuck Lever * uint32 specdata2; 385d9c407b1SChuck Lever * }; 386d9c407b1SChuck Lever */ 387d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev) 388d9c407b1SChuck Lever { 389d9c407b1SChuck Lever __be32 *p; 390d9c407b1SChuck Lever 391d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8); 392d9c407b1SChuck Lever *p++ = cpu_to_be32(MAJOR(rdev)); 393d9c407b1SChuck Lever *p = cpu_to_be32(MINOR(rdev)); 394d9c407b1SChuck Lever } 395d9c407b1SChuck Lever 396f6048709SChuck Lever static __be32 *xdr_decode_specdata3(__be32 *p, dev_t *rdev) 397f6048709SChuck Lever { 398f6048709SChuck Lever unsigned int major, minor; 399f6048709SChuck Lever 400f6048709SChuck Lever major = be32_to_cpup(p++); 401f6048709SChuck Lever minor = be32_to_cpup(p++); 402f6048709SChuck Lever *rdev = MKDEV(major, minor); 403f6048709SChuck Lever if (MAJOR(*rdev) != major || MINOR(*rdev) != minor) 404f6048709SChuck Lever *rdev = 0; 405f6048709SChuck Lever return p; 406f6048709SChuck Lever } 407f6048709SChuck Lever 408d9c407b1SChuck Lever /* 409d9c407b1SChuck Lever * nfs_fh3 410d9c407b1SChuck Lever * 411d9c407b1SChuck Lever * struct nfs_fh3 { 412d9c407b1SChuck Lever * opaque data<NFS3_FHSIZE>; 413d9c407b1SChuck Lever * }; 414d9c407b1SChuck Lever */ 415d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh) 416d9c407b1SChuck Lever { 417d9c407b1SChuck Lever __be32 *p; 418d9c407b1SChuck Lever 4197fc38846STrond Myklebust WARN_ON_ONCE(fh->size > NFS3_FHSIZE); 420d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + fh->size); 421d9c407b1SChuck Lever xdr_encode_opaque(p, fh->data, fh->size); 422d9c407b1SChuck Lever } 423d9c407b1SChuck Lever 424e4f93234SChuck Lever static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) 425e4f93234SChuck Lever { 426e4f93234SChuck Lever u32 length; 427e4f93234SChuck Lever __be32 *p; 428e4f93234SChuck Lever 429e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 430eb72f484SChuck Lever if (unlikely(!p)) 431eb72f484SChuck Lever return -EIO; 432e4f93234SChuck Lever length = be32_to_cpup(p++); 433e4f93234SChuck Lever if (unlikely(length > NFS3_FHSIZE)) 434e4f93234SChuck Lever goto out_toobig; 435e4f93234SChuck Lever p = xdr_inline_decode(xdr, length); 436eb72f484SChuck Lever if (unlikely(!p)) 437eb72f484SChuck Lever return -EIO; 438e4f93234SChuck Lever fh->size = length; 439e4f93234SChuck Lever memcpy(fh->data, p, length); 440e4f93234SChuck Lever return 0; 441e4f93234SChuck Lever out_toobig: 442e4f93234SChuck Lever dprintk("NFS: file handle size (%u) too big\n", length); 443e4f93234SChuck Lever return -E2BIG; 444e4f93234SChuck Lever } 445e4f93234SChuck Lever 446e4f93234SChuck Lever static void zero_nfs_fh3(struct nfs_fh *fh) 447e4f93234SChuck Lever { 448e4f93234SChuck Lever memset(fh, 0, sizeof(*fh)); 449e4f93234SChuck Lever } 450e4f93234SChuck Lever 451d9c407b1SChuck Lever /* 4529d5a6434SChuck Lever * nfstime3 4539d5a6434SChuck Lever * 4549d5a6434SChuck Lever * struct nfstime3 { 4559d5a6434SChuck Lever * uint32 seconds; 4569d5a6434SChuck Lever * uint32 nseconds; 4579d5a6434SChuck Lever * }; 4589d5a6434SChuck Lever */ 4599d5a6434SChuck Lever static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep) 4609d5a6434SChuck Lever { 4619d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_sec); 4629d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_nsec); 4639d5a6434SChuck Lever return p; 4649d5a6434SChuck Lever } 4659d5a6434SChuck Lever 466f6048709SChuck Lever static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec *timep) 467f6048709SChuck Lever { 468f6048709SChuck Lever timep->tv_sec = be32_to_cpup(p++); 469f6048709SChuck Lever timep->tv_nsec = be32_to_cpup(p++); 470f6048709SChuck Lever return p; 471f6048709SChuck Lever } 472f6048709SChuck Lever 4739d5a6434SChuck Lever /* 474d9c407b1SChuck Lever * sattr3 475d9c407b1SChuck Lever * 476d9c407b1SChuck Lever * enum time_how { 477d9c407b1SChuck Lever * DONT_CHANGE = 0, 478d9c407b1SChuck Lever * SET_TO_SERVER_TIME = 1, 479d9c407b1SChuck Lever * SET_TO_CLIENT_TIME = 2 480d9c407b1SChuck Lever * }; 481d9c407b1SChuck Lever * 482d9c407b1SChuck Lever * union set_mode3 switch (bool set_it) { 483d9c407b1SChuck Lever * case TRUE: 484d9c407b1SChuck Lever * mode3 mode; 485d9c407b1SChuck Lever * default: 486d9c407b1SChuck Lever * void; 487d9c407b1SChuck Lever * }; 488d9c407b1SChuck Lever * 489d9c407b1SChuck Lever * union set_uid3 switch (bool set_it) { 490d9c407b1SChuck Lever * case TRUE: 491d9c407b1SChuck Lever * uid3 uid; 492d9c407b1SChuck Lever * default: 493d9c407b1SChuck Lever * void; 494d9c407b1SChuck Lever * }; 495d9c407b1SChuck Lever * 496d9c407b1SChuck Lever * union set_gid3 switch (bool set_it) { 497d9c407b1SChuck Lever * case TRUE: 498d9c407b1SChuck Lever * gid3 gid; 499d9c407b1SChuck Lever * default: 500d9c407b1SChuck Lever * void; 501d9c407b1SChuck Lever * }; 502d9c407b1SChuck Lever * 503d9c407b1SChuck Lever * union set_size3 switch (bool set_it) { 504d9c407b1SChuck Lever * case TRUE: 505d9c407b1SChuck Lever * size3 size; 506d9c407b1SChuck Lever * default: 507d9c407b1SChuck Lever * void; 508d9c407b1SChuck Lever * }; 509d9c407b1SChuck Lever * 510d9c407b1SChuck Lever * union set_atime switch (time_how set_it) { 511d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 512d9c407b1SChuck Lever * nfstime3 atime; 513d9c407b1SChuck Lever * default: 514d9c407b1SChuck Lever * void; 515d9c407b1SChuck Lever * }; 516d9c407b1SChuck Lever * 517d9c407b1SChuck Lever * union set_mtime switch (time_how set_it) { 518d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 519d9c407b1SChuck Lever * nfstime3 mtime; 520d9c407b1SChuck Lever * default: 521d9c407b1SChuck Lever * void; 522d9c407b1SChuck Lever * }; 523d9c407b1SChuck Lever * 524d9c407b1SChuck Lever * struct sattr3 { 525d9c407b1SChuck Lever * set_mode3 mode; 526d9c407b1SChuck Lever * set_uid3 uid; 527d9c407b1SChuck Lever * set_gid3 gid; 528d9c407b1SChuck Lever * set_size3 size; 529d9c407b1SChuck Lever * set_atime atime; 530d9c407b1SChuck Lever * set_mtime mtime; 531d9c407b1SChuck Lever * }; 532d9c407b1SChuck Lever */ 533264d948cSTrond Myklebust static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr, 534264d948cSTrond Myklebust struct user_namespace *userns) 535d9c407b1SChuck Lever { 53695582b00SDeepa Dinamani struct timespec ts; 537d9c407b1SChuck Lever u32 nbytes; 538d9c407b1SChuck Lever __be32 *p; 539d9c407b1SChuck Lever 540d9c407b1SChuck Lever /* 541d9c407b1SChuck Lever * In order to make only a single xdr_reserve_space() call, 542d9c407b1SChuck Lever * pre-compute the total number of bytes to be reserved. 543d9c407b1SChuck Lever * Six boolean values, one for each set_foo field, are always 544d9c407b1SChuck Lever * present in the encoded result, so start there. 545d9c407b1SChuck Lever */ 546d9c407b1SChuck Lever nbytes = 6 * 4; 547d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MODE) 548d9c407b1SChuck Lever nbytes += 4; 549d9c407b1SChuck Lever if (attr->ia_valid & ATTR_UID) 550d9c407b1SChuck Lever nbytes += 4; 551d9c407b1SChuck Lever if (attr->ia_valid & ATTR_GID) 552d9c407b1SChuck Lever nbytes += 4; 553d9c407b1SChuck Lever if (attr->ia_valid & ATTR_SIZE) 554d9c407b1SChuck Lever nbytes += 8; 555d9c407b1SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) 556d9c407b1SChuck Lever nbytes += 8; 557d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) 558d9c407b1SChuck Lever nbytes += 8; 559d9c407b1SChuck Lever p = xdr_reserve_space(xdr, nbytes); 560d9c407b1SChuck Lever 5619d5a6434SChuck Lever if (attr->ia_valid & ATTR_MODE) { 5629d5a6434SChuck Lever *p++ = xdr_one; 5639d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO); 5649d5a6434SChuck Lever } else 5659d5a6434SChuck Lever *p++ = xdr_zero; 5669d5a6434SChuck Lever 5679d5a6434SChuck Lever if (attr->ia_valid & ATTR_UID) { 5689d5a6434SChuck Lever *p++ = xdr_one; 569264d948cSTrond Myklebust *p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid)); 5709d5a6434SChuck Lever } else 5719d5a6434SChuck Lever *p++ = xdr_zero; 5729d5a6434SChuck Lever 5739d5a6434SChuck Lever if (attr->ia_valid & ATTR_GID) { 5749d5a6434SChuck Lever *p++ = xdr_one; 575264d948cSTrond Myklebust *p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid)); 5769d5a6434SChuck Lever } else 5779d5a6434SChuck Lever *p++ = xdr_zero; 5789d5a6434SChuck Lever 5799d5a6434SChuck Lever if (attr->ia_valid & ATTR_SIZE) { 5809d5a6434SChuck Lever *p++ = xdr_one; 5819d5a6434SChuck Lever p = xdr_encode_hyper(p, (u64)attr->ia_size); 5829d5a6434SChuck Lever } else 5839d5a6434SChuck Lever *p++ = xdr_zero; 5849d5a6434SChuck Lever 5859d5a6434SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) { 58695582b00SDeepa Dinamani struct timespec ts; 5879d5a6434SChuck Lever *p++ = xdr_two; 58895582b00SDeepa Dinamani ts = timespec64_to_timespec(attr->ia_atime); 58995582b00SDeepa Dinamani p = xdr_encode_nfstime3(p, &ts); 5909d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_ATIME) { 5919d5a6434SChuck Lever *p++ = xdr_one; 5929d5a6434SChuck Lever } else 5939d5a6434SChuck Lever *p++ = xdr_zero; 5949d5a6434SChuck Lever 5959d5a6434SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) { 5969d5a6434SChuck Lever *p++ = xdr_two; 59795582b00SDeepa Dinamani ts = timespec64_to_timespec(attr->ia_mtime); 59895582b00SDeepa Dinamani xdr_encode_nfstime3(p, &ts); 5999d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_MTIME) { 6009d5a6434SChuck Lever *p = xdr_one; 6019d5a6434SChuck Lever } else 6029d5a6434SChuck Lever *p = xdr_zero; 603d9c407b1SChuck Lever } 604d9c407b1SChuck Lever 605d9c407b1SChuck Lever /* 606e4f93234SChuck Lever * fattr3 607e4f93234SChuck Lever * 608e4f93234SChuck Lever * struct fattr3 { 609e4f93234SChuck Lever * ftype3 type; 610e4f93234SChuck Lever * mode3 mode; 611e4f93234SChuck Lever * uint32 nlink; 612e4f93234SChuck Lever * uid3 uid; 613e4f93234SChuck Lever * gid3 gid; 614e4f93234SChuck Lever * size3 size; 615e4f93234SChuck Lever * size3 used; 616e4f93234SChuck Lever * specdata3 rdev; 617e4f93234SChuck Lever * uint64 fsid; 618e4f93234SChuck Lever * fileid3 fileid; 619e4f93234SChuck Lever * nfstime3 atime; 620e4f93234SChuck Lever * nfstime3 mtime; 621e4f93234SChuck Lever * nfstime3 ctime; 622e4f93234SChuck Lever * }; 623e4f93234SChuck Lever */ 624264d948cSTrond Myklebust static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr, 625264d948cSTrond Myklebust struct user_namespace *userns) 626e4f93234SChuck Lever { 627f6048709SChuck Lever umode_t fmode; 628e4f93234SChuck Lever __be32 *p; 629e4f93234SChuck Lever 630e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2); 631eb72f484SChuck Lever if (unlikely(!p)) 632eb72f484SChuck Lever return -EIO; 633f6048709SChuck Lever 634f6048709SChuck Lever p = xdr_decode_ftype3(p, &fmode); 635f6048709SChuck Lever 636f6048709SChuck Lever fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode; 637f6048709SChuck Lever fattr->nlink = be32_to_cpup(p++); 638264d948cSTrond Myklebust fattr->uid = make_kuid(userns, be32_to_cpup(p++)); 63957a38daeSEric W. Biederman if (!uid_valid(fattr->uid)) 64057a38daeSEric W. Biederman goto out_uid; 641264d948cSTrond Myklebust fattr->gid = make_kgid(userns, be32_to_cpup(p++)); 64257a38daeSEric W. Biederman if (!gid_valid(fattr->gid)) 64357a38daeSEric W. Biederman goto out_gid; 644f6048709SChuck Lever 645f6048709SChuck Lever p = xdr_decode_size3(p, &fattr->size); 646f6048709SChuck Lever p = xdr_decode_size3(p, &fattr->du.nfs3.used); 647f6048709SChuck Lever p = xdr_decode_specdata3(p, &fattr->rdev); 648f6048709SChuck Lever 649f6048709SChuck Lever p = xdr_decode_hyper(p, &fattr->fsid.major); 650f6048709SChuck Lever fattr->fsid.minor = 0; 651f6048709SChuck Lever 652f6048709SChuck Lever p = xdr_decode_fileid3(p, &fattr->fileid); 653f6048709SChuck Lever p = xdr_decode_nfstime3(p, &fattr->atime); 654f6048709SChuck Lever p = xdr_decode_nfstime3(p, &fattr->mtime); 655f6048709SChuck Lever xdr_decode_nfstime3(p, &fattr->ctime); 6563a1556e8STrond Myklebust fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime); 657f6048709SChuck Lever 658f6048709SChuck Lever fattr->valid |= NFS_ATTR_FATTR_V3; 659e4f93234SChuck Lever return 0; 66057a38daeSEric W. Biederman out_uid: 66157a38daeSEric W. Biederman dprintk("NFS: returned invalid uid\n"); 66257a38daeSEric W. Biederman return -EINVAL; 66357a38daeSEric W. Biederman out_gid: 66457a38daeSEric W. Biederman dprintk("NFS: returned invalid gid\n"); 66557a38daeSEric W. Biederman return -EINVAL; 666e4f93234SChuck Lever } 667e4f93234SChuck Lever 668e4f93234SChuck Lever /* 669e4f93234SChuck Lever * post_op_attr 670e4f93234SChuck Lever * 671e4f93234SChuck Lever * union post_op_attr switch (bool attributes_follow) { 672e4f93234SChuck Lever * case TRUE: 673e4f93234SChuck Lever * fattr3 attributes; 674e4f93234SChuck Lever * case FALSE: 675e4f93234SChuck Lever * void; 676e4f93234SChuck Lever * }; 677e4f93234SChuck Lever */ 678264d948cSTrond Myklebust static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr, 679264d948cSTrond Myklebust struct user_namespace *userns) 680e4f93234SChuck Lever { 681e4f93234SChuck Lever __be32 *p; 682e4f93234SChuck Lever 683e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 684eb72f484SChuck Lever if (unlikely(!p)) 685eb72f484SChuck Lever return -EIO; 686e4f93234SChuck Lever if (*p != xdr_zero) 687264d948cSTrond Myklebust return decode_fattr3(xdr, fattr, userns); 688e4f93234SChuck Lever return 0; 689e4f93234SChuck Lever } 690e4f93234SChuck Lever 691e4f93234SChuck Lever /* 692e4f93234SChuck Lever * wcc_attr 693e4f93234SChuck Lever * struct wcc_attr { 694e4f93234SChuck Lever * size3 size; 695e4f93234SChuck Lever * nfstime3 mtime; 696e4f93234SChuck Lever * nfstime3 ctime; 697e4f93234SChuck Lever * }; 698e4f93234SChuck Lever */ 699e4f93234SChuck Lever static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 700e4f93234SChuck Lever { 701e4f93234SChuck Lever __be32 *p; 702e4f93234SChuck Lever 703e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2); 704eb72f484SChuck Lever if (unlikely(!p)) 705eb72f484SChuck Lever return -EIO; 706f6048709SChuck Lever 707f6048709SChuck Lever fattr->valid |= NFS_ATTR_FATTR_PRESIZE 7083a1556e8STrond Myklebust | NFS_ATTR_FATTR_PRECHANGE 709f6048709SChuck Lever | NFS_ATTR_FATTR_PREMTIME 710f6048709SChuck Lever | NFS_ATTR_FATTR_PRECTIME; 711f6048709SChuck Lever 712f6048709SChuck Lever p = xdr_decode_size3(p, &fattr->pre_size); 713f6048709SChuck Lever p = xdr_decode_nfstime3(p, &fattr->pre_mtime); 714f6048709SChuck Lever xdr_decode_nfstime3(p, &fattr->pre_ctime); 7153a1556e8STrond Myklebust fattr->pre_change_attr = nfs_timespec_to_change_attr(&fattr->pre_ctime); 716f6048709SChuck Lever 717e4f93234SChuck Lever return 0; 718e4f93234SChuck Lever } 719e4f93234SChuck Lever 720e4f93234SChuck Lever /* 721e4f93234SChuck Lever * pre_op_attr 722e4f93234SChuck Lever * union pre_op_attr switch (bool attributes_follow) { 723e4f93234SChuck Lever * case TRUE: 724e4f93234SChuck Lever * wcc_attr attributes; 725e4f93234SChuck Lever * case FALSE: 726e4f93234SChuck Lever * void; 727e4f93234SChuck Lever * }; 728e4f93234SChuck Lever * 729e4f93234SChuck Lever * wcc_data 730e4f93234SChuck Lever * 731e4f93234SChuck Lever * struct wcc_data { 732e4f93234SChuck Lever * pre_op_attr before; 733e4f93234SChuck Lever * post_op_attr after; 734e4f93234SChuck Lever * }; 735e4f93234SChuck Lever */ 736e4f93234SChuck Lever static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 737e4f93234SChuck Lever { 738e4f93234SChuck Lever __be32 *p; 739e4f93234SChuck Lever 740e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 741eb72f484SChuck Lever if (unlikely(!p)) 742eb72f484SChuck Lever return -EIO; 743e4f93234SChuck Lever if (*p != xdr_zero) 744e4f93234SChuck Lever return decode_wcc_attr(xdr, fattr); 745e4f93234SChuck Lever return 0; 746e4f93234SChuck Lever } 747e4f93234SChuck Lever 748264d948cSTrond Myklebust static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr, 749264d948cSTrond Myklebust struct user_namespace *userns) 750e4f93234SChuck Lever { 751e4f93234SChuck Lever int error; 752e4f93234SChuck Lever 753e4f93234SChuck Lever error = decode_pre_op_attr(xdr, fattr); 754e4f93234SChuck Lever if (unlikely(error)) 755e4f93234SChuck Lever goto out; 756264d948cSTrond Myklebust error = decode_post_op_attr(xdr, fattr, userns); 757e4f93234SChuck Lever out: 758e4f93234SChuck Lever return error; 759e4f93234SChuck Lever } 760e4f93234SChuck Lever 761e4f93234SChuck Lever /* 762e4f93234SChuck Lever * post_op_fh3 763e4f93234SChuck Lever * 764e4f93234SChuck Lever * union post_op_fh3 switch (bool handle_follows) { 765e4f93234SChuck Lever * case TRUE: 766e4f93234SChuck Lever * nfs_fh3 handle; 767e4f93234SChuck Lever * case FALSE: 768e4f93234SChuck Lever * void; 769e4f93234SChuck Lever * }; 770e4f93234SChuck Lever */ 771e4f93234SChuck Lever static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) 772e4f93234SChuck Lever { 773e4f93234SChuck Lever __be32 *p = xdr_inline_decode(xdr, 4); 774eb72f484SChuck Lever if (unlikely(!p)) 775eb72f484SChuck Lever return -EIO; 776e4f93234SChuck Lever if (*p != xdr_zero) 777e4f93234SChuck Lever return decode_nfs_fh3(xdr, fh); 778e4f93234SChuck Lever zero_nfs_fh3(fh); 779e4f93234SChuck Lever return 0; 780e4f93234SChuck Lever } 781e4f93234SChuck Lever 782e4f93234SChuck Lever /* 783d9c407b1SChuck Lever * diropargs3 784d9c407b1SChuck Lever * 785d9c407b1SChuck Lever * struct diropargs3 { 786d9c407b1SChuck Lever * nfs_fh3 dir; 787d9c407b1SChuck Lever * filename3 name; 788d9c407b1SChuck Lever * }; 789d9c407b1SChuck Lever */ 790d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh, 791d9c407b1SChuck Lever const char *name, u32 length) 792d9c407b1SChuck Lever { 793d9c407b1SChuck Lever encode_nfs_fh3(xdr, fh); 794d9c407b1SChuck Lever encode_filename3(xdr, name, length); 795d9c407b1SChuck Lever } 796d9c407b1SChuck Lever 797d9c407b1SChuck Lever 7981da177e4SLinus Torvalds /* 799499ff710SChuck Lever * NFSv3 XDR encode functions 800499ff710SChuck Lever * 801499ff710SChuck Lever * NFSv3 argument types are defined in section 3.3 of RFC 1813: 802499ff710SChuck Lever * "NFS Version 3 Protocol Specification". 8031da177e4SLinus Torvalds */ 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds /* 806d9c407b1SChuck Lever * 3.3.1 GETATTR3args 807d9c407b1SChuck Lever * 808d9c407b1SChuck Lever * struct GETATTR3args { 809d9c407b1SChuck Lever * nfs_fh3 object; 810d9c407b1SChuck Lever * }; 811d9c407b1SChuck Lever */ 8129f06c719SChuck Lever static void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, 8139f06c719SChuck Lever struct xdr_stream *xdr, 814fcc85819SChristoph Hellwig const void *data) 815d9c407b1SChuck Lever { 816fcc85819SChristoph Hellwig const struct nfs_fh *fh = data; 817fcc85819SChristoph Hellwig 8189f06c719SChuck Lever encode_nfs_fh3(xdr, fh); 819d9c407b1SChuck Lever } 820d9c407b1SChuck Lever 821d9c407b1SChuck Lever /* 822d9c407b1SChuck Lever * 3.3.2 SETATTR3args 823d9c407b1SChuck Lever * 824d9c407b1SChuck Lever * union sattrguard3 switch (bool check) { 825d9c407b1SChuck Lever * case TRUE: 826d9c407b1SChuck Lever * nfstime3 obj_ctime; 827d9c407b1SChuck Lever * case FALSE: 828d9c407b1SChuck Lever * void; 829d9c407b1SChuck Lever * }; 830d9c407b1SChuck Lever * 831d9c407b1SChuck Lever * struct SETATTR3args { 832d9c407b1SChuck Lever * nfs_fh3 object; 833d9c407b1SChuck Lever * sattr3 new_attributes; 834d9c407b1SChuck Lever * sattrguard3 guard; 835d9c407b1SChuck Lever * }; 836d9c407b1SChuck Lever */ 837d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr, 838d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 839d9c407b1SChuck Lever { 840d9c407b1SChuck Lever __be32 *p; 841d9c407b1SChuck Lever 842d9c407b1SChuck Lever if (args->guard) { 843d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + 8); 844d9c407b1SChuck Lever *p++ = xdr_one; 8459d5a6434SChuck Lever xdr_encode_nfstime3(p, &args->guardtime); 846d9c407b1SChuck Lever } else { 847d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4); 848d9c407b1SChuck Lever *p = xdr_zero; 849d9c407b1SChuck Lever } 850d9c407b1SChuck Lever } 851d9c407b1SChuck Lever 8529f06c719SChuck Lever static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, 8539f06c719SChuck Lever struct xdr_stream *xdr, 854fcc85819SChristoph Hellwig const void *data) 855d9c407b1SChuck Lever { 856fcc85819SChristoph Hellwig const struct nfs3_sattrargs *args = data; 8579f06c719SChuck Lever encode_nfs_fh3(xdr, args->fh); 858264d948cSTrond Myklebust encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req)); 8599f06c719SChuck Lever encode_sattrguard3(xdr, args); 860d9c407b1SChuck Lever } 861d9c407b1SChuck Lever 862d9c407b1SChuck Lever /* 863d9c407b1SChuck Lever * 3.3.3 LOOKUP3args 864d9c407b1SChuck Lever * 865d9c407b1SChuck Lever * struct LOOKUP3args { 866d9c407b1SChuck Lever * diropargs3 what; 867d9c407b1SChuck Lever * }; 868d9c407b1SChuck Lever */ 8699f06c719SChuck Lever static void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, 8709f06c719SChuck Lever struct xdr_stream *xdr, 871fcc85819SChristoph Hellwig const void *data) 872d9c407b1SChuck Lever { 873fcc85819SChristoph Hellwig const struct nfs3_diropargs *args = data; 874fcc85819SChristoph Hellwig 8759f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 876d9c407b1SChuck Lever } 877d9c407b1SChuck Lever 878d9c407b1SChuck Lever /* 879d9c407b1SChuck Lever * 3.3.4 ACCESS3args 880d9c407b1SChuck Lever * 881d9c407b1SChuck Lever * struct ACCESS3args { 882d9c407b1SChuck Lever * nfs_fh3 object; 883d9c407b1SChuck Lever * uint32 access; 884d9c407b1SChuck Lever * }; 885d9c407b1SChuck Lever */ 886d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr, 887d9c407b1SChuck Lever const struct nfs3_accessargs *args) 888d9c407b1SChuck Lever { 889d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 890d9c407b1SChuck Lever encode_uint32(xdr, args->access); 891d9c407b1SChuck Lever } 892d9c407b1SChuck Lever 8939f06c719SChuck Lever static void nfs3_xdr_enc_access3args(struct rpc_rqst *req, 8949f06c719SChuck Lever struct xdr_stream *xdr, 895fcc85819SChristoph Hellwig const void *data) 896d9c407b1SChuck Lever { 897fcc85819SChristoph Hellwig const struct nfs3_accessargs *args = data; 898fcc85819SChristoph Hellwig 8999f06c719SChuck Lever encode_access3args(xdr, args); 900d9c407b1SChuck Lever } 901d9c407b1SChuck Lever 902d9c407b1SChuck Lever /* 903d9c407b1SChuck Lever * 3.3.5 READLINK3args 904d9c407b1SChuck Lever * 905d9c407b1SChuck Lever * struct READLINK3args { 906d9c407b1SChuck Lever * nfs_fh3 symlink; 907d9c407b1SChuck Lever * }; 908d9c407b1SChuck Lever */ 9099f06c719SChuck Lever static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, 9109f06c719SChuck Lever struct xdr_stream *xdr, 911fcc85819SChristoph Hellwig const void *data) 912d9c407b1SChuck Lever { 913fcc85819SChristoph Hellwig const struct nfs3_readlinkargs *args = data; 914fcc85819SChristoph Hellwig 9159f06c719SChuck Lever encode_nfs_fh3(xdr, args->fh); 916cf500bacSChuck Lever rpc_prepare_reply_pages(req, args->pages, args->pgbase, 917d9c407b1SChuck Lever args->pglen, NFS3_readlinkres_sz); 918d9c407b1SChuck Lever } 919d9c407b1SChuck Lever 920d9c407b1SChuck Lever /* 921d9c407b1SChuck Lever * 3.3.6 READ3args 922d9c407b1SChuck Lever * 923d9c407b1SChuck Lever * struct READ3args { 924d9c407b1SChuck Lever * nfs_fh3 file; 925d9c407b1SChuck Lever * offset3 offset; 926d9c407b1SChuck Lever * count3 count; 927d9c407b1SChuck Lever * }; 928d9c407b1SChuck Lever */ 929d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr, 9303c6b899cSAnna Schumaker const struct nfs_pgio_args *args) 931d9c407b1SChuck Lever { 932d9c407b1SChuck Lever __be32 *p; 933d9c407b1SChuck Lever 934d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 935d9c407b1SChuck Lever 936d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 937d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 938d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 939d9c407b1SChuck Lever } 940d9c407b1SChuck Lever 9419f06c719SChuck Lever static void nfs3_xdr_enc_read3args(struct rpc_rqst *req, 9429f06c719SChuck Lever struct xdr_stream *xdr, 943fcc85819SChristoph Hellwig const void *data) 944d9c407b1SChuck Lever { 945fcc85819SChristoph Hellwig const struct nfs_pgio_args *args = data; 9468d8928d8STrond Myklebust unsigned int replen = args->replen ? args->replen : NFS3_readres_sz; 947fcc85819SChristoph Hellwig 9489f06c719SChuck Lever encode_read3args(xdr, args); 949cf500bacSChuck Lever rpc_prepare_reply_pages(req, args->pages, args->pgbase, 9508d8928d8STrond Myklebust args->count, replen); 951d9c407b1SChuck Lever req->rq_rcv_buf.flags |= XDRBUF_READ; 952d9c407b1SChuck Lever } 953d9c407b1SChuck Lever 954d9c407b1SChuck Lever /* 955d9c407b1SChuck Lever * 3.3.7 WRITE3args 956d9c407b1SChuck Lever * 957d9c407b1SChuck Lever * enum stable_how { 958d9c407b1SChuck Lever * UNSTABLE = 0, 959d9c407b1SChuck Lever * DATA_SYNC = 1, 960d9c407b1SChuck Lever * FILE_SYNC = 2 961d9c407b1SChuck Lever * }; 962d9c407b1SChuck Lever * 963d9c407b1SChuck Lever * struct WRITE3args { 964d9c407b1SChuck Lever * nfs_fh3 file; 965d9c407b1SChuck Lever * offset3 offset; 966d9c407b1SChuck Lever * count3 count; 967d9c407b1SChuck Lever * stable_how stable; 968d9c407b1SChuck Lever * opaque data<>; 969d9c407b1SChuck Lever * }; 970d9c407b1SChuck Lever */ 971d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr, 9723c6b899cSAnna Schumaker const struct nfs_pgio_args *args) 973d9c407b1SChuck Lever { 974d9c407b1SChuck Lever __be32 *p; 975d9c407b1SChuck Lever 976d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 977d9c407b1SChuck Lever 978d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4); 979d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 980d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count); 981d9c407b1SChuck Lever *p++ = cpu_to_be32(args->stable); 982d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 983d9c407b1SChuck Lever xdr_write_pages(xdr, args->pages, args->pgbase, args->count); 984d9c407b1SChuck Lever } 985d9c407b1SChuck Lever 9869f06c719SChuck Lever static void nfs3_xdr_enc_write3args(struct rpc_rqst *req, 9879f06c719SChuck Lever struct xdr_stream *xdr, 988fcc85819SChristoph Hellwig const void *data) 989d9c407b1SChuck Lever { 990fcc85819SChristoph Hellwig const struct nfs_pgio_args *args = data; 991fcc85819SChristoph Hellwig 9929f06c719SChuck Lever encode_write3args(xdr, args); 9939f06c719SChuck Lever xdr->buf->flags |= XDRBUF_WRITE; 994d9c407b1SChuck Lever } 995d9c407b1SChuck Lever 996d9c407b1SChuck Lever /* 997d9c407b1SChuck Lever * 3.3.8 CREATE3args 998d9c407b1SChuck Lever * 999d9c407b1SChuck Lever * enum createmode3 { 1000d9c407b1SChuck Lever * UNCHECKED = 0, 1001d9c407b1SChuck Lever * GUARDED = 1, 1002d9c407b1SChuck Lever * EXCLUSIVE = 2 1003d9c407b1SChuck Lever * }; 1004d9c407b1SChuck Lever * 1005d9c407b1SChuck Lever * union createhow3 switch (createmode3 mode) { 1006d9c407b1SChuck Lever * case UNCHECKED: 1007d9c407b1SChuck Lever * case GUARDED: 1008d9c407b1SChuck Lever * sattr3 obj_attributes; 1009d9c407b1SChuck Lever * case EXCLUSIVE: 1010d9c407b1SChuck Lever * createverf3 verf; 1011d9c407b1SChuck Lever * }; 1012d9c407b1SChuck Lever * 1013d9c407b1SChuck Lever * struct CREATE3args { 1014d9c407b1SChuck Lever * diropargs3 where; 1015d9c407b1SChuck Lever * createhow3 how; 1016d9c407b1SChuck Lever * }; 1017d9c407b1SChuck Lever */ 1018d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr, 1019264d948cSTrond Myklebust const struct nfs3_createargs *args, 1020264d948cSTrond Myklebust struct user_namespace *userns) 1021d9c407b1SChuck Lever { 1022d9c407b1SChuck Lever encode_uint32(xdr, args->createmode); 1023d9c407b1SChuck Lever switch (args->createmode) { 1024d9c407b1SChuck Lever case NFS3_CREATE_UNCHECKED: 1025d9c407b1SChuck Lever case NFS3_CREATE_GUARDED: 1026264d948cSTrond Myklebust encode_sattr3(xdr, args->sattr, userns); 1027d9c407b1SChuck Lever break; 1028d9c407b1SChuck Lever case NFS3_CREATE_EXCLUSIVE: 1029d9c407b1SChuck Lever encode_createverf3(xdr, args->verifier); 1030d9c407b1SChuck Lever break; 1031d9c407b1SChuck Lever default: 1032d9c407b1SChuck Lever BUG(); 1033d9c407b1SChuck Lever } 1034d9c407b1SChuck Lever } 1035d9c407b1SChuck Lever 10369f06c719SChuck Lever static void nfs3_xdr_enc_create3args(struct rpc_rqst *req, 10379f06c719SChuck Lever struct xdr_stream *xdr, 1038fcc85819SChristoph Hellwig const void *data) 1039d9c407b1SChuck Lever { 1040fcc85819SChristoph Hellwig const struct nfs3_createargs *args = data; 1041fcc85819SChristoph Hellwig 10429f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 1043264d948cSTrond Myklebust encode_createhow3(xdr, args, rpc_rqst_userns(req)); 1044d9c407b1SChuck Lever } 1045d9c407b1SChuck Lever 1046d9c407b1SChuck Lever /* 1047d9c407b1SChuck Lever * 3.3.9 MKDIR3args 1048d9c407b1SChuck Lever * 1049d9c407b1SChuck Lever * struct MKDIR3args { 1050d9c407b1SChuck Lever * diropargs3 where; 1051d9c407b1SChuck Lever * sattr3 attributes; 1052d9c407b1SChuck Lever * }; 1053d9c407b1SChuck Lever */ 10549f06c719SChuck Lever static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, 10559f06c719SChuck Lever struct xdr_stream *xdr, 1056fcc85819SChristoph Hellwig const void *data) 1057d9c407b1SChuck Lever { 1058fcc85819SChristoph Hellwig const struct nfs3_mkdirargs *args = data; 1059fcc85819SChristoph Hellwig 10609f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 1061264d948cSTrond Myklebust encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req)); 1062d9c407b1SChuck Lever } 1063d9c407b1SChuck Lever 1064d9c407b1SChuck Lever /* 1065d9c407b1SChuck Lever * 3.3.10 SYMLINK3args 1066d9c407b1SChuck Lever * 1067d9c407b1SChuck Lever * struct symlinkdata3 { 1068d9c407b1SChuck Lever * sattr3 symlink_attributes; 1069d9c407b1SChuck Lever * nfspath3 symlink_data; 1070d9c407b1SChuck Lever * }; 1071d9c407b1SChuck Lever * 1072d9c407b1SChuck Lever * struct SYMLINK3args { 1073d9c407b1SChuck Lever * diropargs3 where; 1074d9c407b1SChuck Lever * symlinkdata3 symlink; 1075d9c407b1SChuck Lever * }; 1076d9c407b1SChuck Lever */ 1077d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr, 1078264d948cSTrond Myklebust const void *data, 1079264d948cSTrond Myklebust struct user_namespace *userns) 1080d9c407b1SChuck Lever { 1081fcc85819SChristoph Hellwig const struct nfs3_symlinkargs *args = data; 1082fcc85819SChristoph Hellwig 1083264d948cSTrond Myklebust encode_sattr3(xdr, args->sattr, userns); 1084d9c407b1SChuck Lever encode_nfspath3(xdr, args->pages, args->pathlen); 1085d9c407b1SChuck Lever } 1086d9c407b1SChuck Lever 10879f06c719SChuck Lever static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, 10889f06c719SChuck Lever struct xdr_stream *xdr, 1089fcc85819SChristoph Hellwig const void *data) 1090d9c407b1SChuck Lever { 1091fcc85819SChristoph Hellwig const struct nfs3_symlinkargs *args = data; 1092fcc85819SChristoph Hellwig 10939f06c719SChuck Lever encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen); 1094264d948cSTrond Myklebust encode_symlinkdata3(xdr, args, rpc_rqst_userns(req)); 10952fcc213aSChuck Lever xdr->buf->flags |= XDRBUF_WRITE; 1096d9c407b1SChuck Lever } 1097d9c407b1SChuck Lever 1098d9c407b1SChuck Lever /* 1099d9c407b1SChuck Lever * 3.3.11 MKNOD3args 1100d9c407b1SChuck Lever * 1101d9c407b1SChuck Lever * struct devicedata3 { 1102d9c407b1SChuck Lever * sattr3 dev_attributes; 1103d9c407b1SChuck Lever * specdata3 spec; 1104d9c407b1SChuck Lever * }; 1105d9c407b1SChuck Lever * 1106d9c407b1SChuck Lever * union mknoddata3 switch (ftype3 type) { 1107d9c407b1SChuck Lever * case NF3CHR: 1108d9c407b1SChuck Lever * case NF3BLK: 1109d9c407b1SChuck Lever * devicedata3 device; 1110d9c407b1SChuck Lever * case NF3SOCK: 1111d9c407b1SChuck Lever * case NF3FIFO: 1112d9c407b1SChuck Lever * sattr3 pipe_attributes; 1113d9c407b1SChuck Lever * default: 1114d9c407b1SChuck Lever * void; 1115d9c407b1SChuck Lever * }; 1116d9c407b1SChuck Lever * 1117d9c407b1SChuck Lever * struct MKNOD3args { 1118d9c407b1SChuck Lever * diropargs3 where; 1119d9c407b1SChuck Lever * mknoddata3 what; 1120d9c407b1SChuck Lever * }; 1121d9c407b1SChuck Lever */ 1122d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr, 1123264d948cSTrond Myklebust const struct nfs3_mknodargs *args, 1124264d948cSTrond Myklebust struct user_namespace *userns) 1125d9c407b1SChuck Lever { 1126264d948cSTrond Myklebust encode_sattr3(xdr, args->sattr, userns); 1127d9c407b1SChuck Lever encode_specdata3(xdr, args->rdev); 1128d9c407b1SChuck Lever } 1129d9c407b1SChuck Lever 1130d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr, 1131264d948cSTrond Myklebust const struct nfs3_mknodargs *args, 1132264d948cSTrond Myklebust struct user_namespace *userns) 1133d9c407b1SChuck Lever { 1134d9c407b1SChuck Lever encode_ftype3(xdr, args->type); 1135d9c407b1SChuck Lever switch (args->type) { 1136d9c407b1SChuck Lever case NF3CHR: 1137d9c407b1SChuck Lever case NF3BLK: 1138264d948cSTrond Myklebust encode_devicedata3(xdr, args, userns); 1139d9c407b1SChuck Lever break; 1140d9c407b1SChuck Lever case NF3SOCK: 1141d9c407b1SChuck Lever case NF3FIFO: 1142264d948cSTrond Myklebust encode_sattr3(xdr, args->sattr, userns); 1143d9c407b1SChuck Lever break; 1144d9c407b1SChuck Lever case NF3REG: 1145d9c407b1SChuck Lever case NF3DIR: 1146d9c407b1SChuck Lever break; 1147d9c407b1SChuck Lever default: 1148d9c407b1SChuck Lever BUG(); 1149d9c407b1SChuck Lever } 1150d9c407b1SChuck Lever } 1151d9c407b1SChuck Lever 11529f06c719SChuck Lever static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, 11539f06c719SChuck Lever struct xdr_stream *xdr, 1154fcc85819SChristoph Hellwig const void *data) 1155d9c407b1SChuck Lever { 1156fcc85819SChristoph Hellwig const struct nfs3_mknodargs *args = data; 1157fcc85819SChristoph Hellwig 11589f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 1159264d948cSTrond Myklebust encode_mknoddata3(xdr, args, rpc_rqst_userns(req)); 1160d9c407b1SChuck Lever } 1161d9c407b1SChuck Lever 1162d9c407b1SChuck Lever /* 1163d9c407b1SChuck Lever * 3.3.12 REMOVE3args 1164d9c407b1SChuck Lever * 1165d9c407b1SChuck Lever * struct REMOVE3args { 1166d9c407b1SChuck Lever * diropargs3 object; 1167d9c407b1SChuck Lever * }; 1168d9c407b1SChuck Lever */ 11699f06c719SChuck Lever static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req, 11709f06c719SChuck Lever struct xdr_stream *xdr, 1171fcc85819SChristoph Hellwig const void *data) 1172d9c407b1SChuck Lever { 1173fcc85819SChristoph Hellwig const struct nfs_removeargs *args = data; 1174fcc85819SChristoph Hellwig 11759f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name.name, args->name.len); 1176d9c407b1SChuck Lever } 1177d9c407b1SChuck Lever 1178d9c407b1SChuck Lever /* 1179d9c407b1SChuck Lever * 3.3.14 RENAME3args 1180d9c407b1SChuck Lever * 1181d9c407b1SChuck Lever * struct RENAME3args { 1182d9c407b1SChuck Lever * diropargs3 from; 1183d9c407b1SChuck Lever * diropargs3 to; 1184d9c407b1SChuck Lever * }; 1185d9c407b1SChuck Lever */ 11869f06c719SChuck Lever static void nfs3_xdr_enc_rename3args(struct rpc_rqst *req, 11879f06c719SChuck Lever struct xdr_stream *xdr, 1188fcc85819SChristoph Hellwig const void *data) 1189d9c407b1SChuck Lever { 1190fcc85819SChristoph Hellwig const struct nfs_renameargs *args = data; 1191d9c407b1SChuck Lever const struct qstr *old = args->old_name; 1192d9c407b1SChuck Lever const struct qstr *new = args->new_name; 1193d9c407b1SChuck Lever 11949f06c719SChuck Lever encode_diropargs3(xdr, args->old_dir, old->name, old->len); 11959f06c719SChuck Lever encode_diropargs3(xdr, args->new_dir, new->name, new->len); 1196d9c407b1SChuck Lever } 1197d9c407b1SChuck Lever 1198d9c407b1SChuck Lever /* 1199d9c407b1SChuck Lever * 3.3.15 LINK3args 1200d9c407b1SChuck Lever * 1201d9c407b1SChuck Lever * struct LINK3args { 1202d9c407b1SChuck Lever * nfs_fh3 file; 1203d9c407b1SChuck Lever * diropargs3 link; 1204d9c407b1SChuck Lever * }; 1205d9c407b1SChuck Lever */ 12069f06c719SChuck Lever static void nfs3_xdr_enc_link3args(struct rpc_rqst *req, 12079f06c719SChuck Lever struct xdr_stream *xdr, 1208fcc85819SChristoph Hellwig const void *data) 1209d9c407b1SChuck Lever { 1210fcc85819SChristoph Hellwig const struct nfs3_linkargs *args = data; 1211fcc85819SChristoph Hellwig 12129f06c719SChuck Lever encode_nfs_fh3(xdr, args->fromfh); 12139f06c719SChuck Lever encode_diropargs3(xdr, args->tofh, args->toname, args->tolen); 1214d9c407b1SChuck Lever } 1215d9c407b1SChuck Lever 1216d9c407b1SChuck Lever /* 1217d9c407b1SChuck Lever * 3.3.16 READDIR3args 1218d9c407b1SChuck Lever * 1219d9c407b1SChuck Lever * struct READDIR3args { 1220d9c407b1SChuck Lever * nfs_fh3 dir; 1221d9c407b1SChuck Lever * cookie3 cookie; 1222d9c407b1SChuck Lever * cookieverf3 cookieverf; 1223d9c407b1SChuck Lever * count3 count; 1224d9c407b1SChuck Lever * }; 1225d9c407b1SChuck Lever */ 1226d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr, 1227d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1228d9c407b1SChuck Lever { 1229d9c407b1SChuck Lever __be32 *p; 1230d9c407b1SChuck Lever 1231d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1232d9c407b1SChuck Lever 1233d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4); 1234d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1235d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1236d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1237d9c407b1SChuck Lever } 1238d9c407b1SChuck Lever 12399f06c719SChuck Lever static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, 12409f06c719SChuck Lever struct xdr_stream *xdr, 1241fcc85819SChristoph Hellwig const void *data) 1242d9c407b1SChuck Lever { 1243fcc85819SChristoph Hellwig const struct nfs3_readdirargs *args = data; 1244fcc85819SChristoph Hellwig 12459f06c719SChuck Lever encode_readdir3args(xdr, args); 1246cf500bacSChuck Lever rpc_prepare_reply_pages(req, args->pages, 0, 1247d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1248d9c407b1SChuck Lever } 1249d9c407b1SChuck Lever 1250d9c407b1SChuck Lever /* 1251d9c407b1SChuck Lever * 3.3.17 READDIRPLUS3args 1252d9c407b1SChuck Lever * 1253d9c407b1SChuck Lever * struct READDIRPLUS3args { 1254d9c407b1SChuck Lever * nfs_fh3 dir; 1255d9c407b1SChuck Lever * cookie3 cookie; 1256d9c407b1SChuck Lever * cookieverf3 cookieverf; 1257d9c407b1SChuck Lever * count3 dircount; 1258d9c407b1SChuck Lever * count3 maxcount; 1259d9c407b1SChuck Lever * }; 1260d9c407b1SChuck Lever */ 1261d9c407b1SChuck Lever static void encode_readdirplus3args(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 + 4); 1269d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1270d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1271d9c407b1SChuck Lever 1272d9c407b1SChuck Lever /* 1273d9c407b1SChuck Lever * readdirplus: need dircount + buffer size. 1274d9c407b1SChuck Lever * We just make sure we make dircount big enough 1275d9c407b1SChuck Lever */ 1276d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count >> 3); 1277d9c407b1SChuck Lever 1278d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1279d9c407b1SChuck Lever } 1280d9c407b1SChuck Lever 12819f06c719SChuck Lever static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, 12829f06c719SChuck Lever struct xdr_stream *xdr, 1283fcc85819SChristoph Hellwig const void *data) 1284d9c407b1SChuck Lever { 1285fcc85819SChristoph Hellwig const struct nfs3_readdirargs *args = data; 1286fcc85819SChristoph Hellwig 12879f06c719SChuck Lever encode_readdirplus3args(xdr, args); 1288cf500bacSChuck Lever rpc_prepare_reply_pages(req, args->pages, 0, 1289d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1290d9c407b1SChuck Lever } 1291d9c407b1SChuck Lever 1292d9c407b1SChuck Lever /* 1293d9c407b1SChuck Lever * 3.3.21 COMMIT3args 1294d9c407b1SChuck Lever * 1295d9c407b1SChuck Lever * struct COMMIT3args { 1296d9c407b1SChuck Lever * nfs_fh3 file; 1297d9c407b1SChuck Lever * offset3 offset; 1298d9c407b1SChuck Lever * count3 count; 1299d9c407b1SChuck Lever * }; 1300d9c407b1SChuck Lever */ 1301d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr, 13020b7c0153SFred Isaman const struct nfs_commitargs *args) 1303d9c407b1SChuck Lever { 1304d9c407b1SChuck Lever __be32 *p; 1305d9c407b1SChuck Lever 1306d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1307d9c407b1SChuck Lever 1308d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 1309d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 1310d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1311d9c407b1SChuck Lever } 1312d9c407b1SChuck Lever 13139f06c719SChuck Lever static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req, 13149f06c719SChuck Lever struct xdr_stream *xdr, 1315fcc85819SChristoph Hellwig const void *data) 1316d9c407b1SChuck Lever { 1317fcc85819SChristoph Hellwig const struct nfs_commitargs *args = data; 1318fcc85819SChristoph Hellwig 13199f06c719SChuck Lever encode_commit3args(xdr, args); 1320d9c407b1SChuck Lever } 1321d9c407b1SChuck Lever 1322b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 1323b7fa0554SAndreas Gruenbacher 13249f06c719SChuck Lever static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, 13259f06c719SChuck Lever struct xdr_stream *xdr, 1326fcc85819SChristoph Hellwig const void *data) 1327d9c407b1SChuck Lever { 1328fcc85819SChristoph Hellwig const struct nfs3_getaclargs *args = data; 1329fcc85819SChristoph Hellwig 13309f06c719SChuck Lever encode_nfs_fh3(xdr, args->fh); 13319f06c719SChuck Lever encode_uint32(xdr, args->mask); 1332431f6eb3STrond Myklebust if (args->mask & (NFS_ACL | NFS_DFACL)) { 1333cf500bacSChuck Lever rpc_prepare_reply_pages(req, args->pages, 0, 1334d9c407b1SChuck Lever NFSACL_MAXPAGES << PAGE_SHIFT, 1335d9c407b1SChuck Lever ACL3_getaclres_sz); 1336431f6eb3STrond Myklebust req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; 1337431f6eb3STrond Myklebust } 1338d9c407b1SChuck Lever } 1339d9c407b1SChuck Lever 13409f06c719SChuck Lever static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, 13419f06c719SChuck Lever struct xdr_stream *xdr, 1342fcc85819SChristoph Hellwig const void *data) 1343d9c407b1SChuck Lever { 1344fcc85819SChristoph Hellwig const struct nfs3_setaclargs *args = data; 1345d9c407b1SChuck Lever unsigned int base; 1346d9c407b1SChuck Lever int error; 1347d9c407b1SChuck Lever 13489f06c719SChuck Lever encode_nfs_fh3(xdr, NFS_FH(args->inode)); 13499f06c719SChuck Lever encode_uint32(xdr, args->mask); 1350d9c407b1SChuck Lever 1351d9c407b1SChuck Lever base = req->rq_slen; 1352ee5dc773SChuck Lever if (args->npages != 0) 1353ee5dc773SChuck Lever xdr_write_pages(xdr, args->pages, 0, args->len); 1354ee5dc773SChuck Lever else 1355d683cc49SChuck Lever xdr_reserve_space(xdr, args->len); 1356ee5dc773SChuck Lever 13579f06c719SChuck Lever error = nfsacl_encode(xdr->buf, base, args->inode, 1358d9c407b1SChuck Lever (args->mask & NFS_ACL) ? 1359d9c407b1SChuck Lever args->acl_access : NULL, 1, 0); 13607fc38846STrond Myklebust /* FIXME: this is just broken */ 1361d9c407b1SChuck Lever BUG_ON(error < 0); 13629f06c719SChuck Lever error = nfsacl_encode(xdr->buf, base + error, args->inode, 1363d9c407b1SChuck Lever (args->mask & NFS_DFACL) ? 1364d9c407b1SChuck Lever args->acl_default : NULL, 1, 1365d9c407b1SChuck Lever NFS_ACL_DEFAULT); 1366d9c407b1SChuck Lever BUG_ON(error < 0); 1367d9c407b1SChuck Lever } 1368d9c407b1SChuck Lever 1369b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 1370b7fa0554SAndreas Gruenbacher 13711da177e4SLinus Torvalds /* 1372b2cdd9c9SChuck Lever * NFSv3 XDR decode functions 1373b2cdd9c9SChuck Lever * 1374b2cdd9c9SChuck Lever * NFSv3 result types are defined in section 3.3 of RFC 1813: 1375b2cdd9c9SChuck Lever * "NFS Version 3 Protocol Specification". 13761da177e4SLinus Torvalds */ 13771da177e4SLinus Torvalds 13781da177e4SLinus Torvalds /* 1379e4f93234SChuck Lever * 3.3.1 GETATTR3res 1380e4f93234SChuck Lever * 1381e4f93234SChuck Lever * struct GETATTR3resok { 1382e4f93234SChuck Lever * fattr3 obj_attributes; 1383e4f93234SChuck Lever * }; 1384e4f93234SChuck Lever * 1385e4f93234SChuck Lever * union GETATTR3res switch (nfsstat3 status) { 1386e4f93234SChuck Lever * case NFS3_OK: 1387e4f93234SChuck Lever * GETATTR3resok resok; 1388e4f93234SChuck Lever * default: 1389e4f93234SChuck Lever * void; 1390e4f93234SChuck Lever * }; 1391e4f93234SChuck Lever */ 1392bf269551SChuck Lever static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req, 1393bf269551SChuck Lever struct xdr_stream *xdr, 1394fc016483SChristoph Hellwig void *result) 1395e4f93234SChuck Lever { 1396e4f93234SChuck Lever enum nfs_stat status; 1397e4f93234SChuck Lever int error; 1398e4f93234SChuck Lever 1399bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1400e4f93234SChuck Lever if (unlikely(error)) 1401e4f93234SChuck Lever goto out; 1402e4f93234SChuck Lever if (status != NFS3_OK) 1403e4f93234SChuck Lever goto out_default; 1404264d948cSTrond Myklebust error = decode_fattr3(xdr, result, rpc_rqst_userns(req)); 1405e4f93234SChuck Lever out: 1406e4f93234SChuck Lever return error; 1407e4f93234SChuck Lever out_default: 14085e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1409e4f93234SChuck Lever } 1410e4f93234SChuck Lever 1411e4f93234SChuck Lever /* 1412e4f93234SChuck Lever * 3.3.2 SETATTR3res 1413e4f93234SChuck Lever * 1414e4f93234SChuck Lever * struct SETATTR3resok { 1415e4f93234SChuck Lever * wcc_data obj_wcc; 1416e4f93234SChuck Lever * }; 1417e4f93234SChuck Lever * 1418e4f93234SChuck Lever * struct SETATTR3resfail { 1419e4f93234SChuck Lever * wcc_data obj_wcc; 1420e4f93234SChuck Lever * }; 1421e4f93234SChuck Lever * 1422e4f93234SChuck Lever * union SETATTR3res switch (nfsstat3 status) { 1423e4f93234SChuck Lever * case NFS3_OK: 1424e4f93234SChuck Lever * SETATTR3resok resok; 1425e4f93234SChuck Lever * default: 1426e4f93234SChuck Lever * SETATTR3resfail resfail; 1427e4f93234SChuck Lever * }; 1428e4f93234SChuck Lever */ 1429bf269551SChuck Lever static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req, 1430bf269551SChuck Lever struct xdr_stream *xdr, 1431fc016483SChristoph Hellwig void *result) 1432e4f93234SChuck Lever { 1433e4f93234SChuck Lever enum nfs_stat status; 1434e4f93234SChuck Lever int error; 1435e4f93234SChuck Lever 1436bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1437e4f93234SChuck Lever if (unlikely(error)) 1438e4f93234SChuck Lever goto out; 1439264d948cSTrond Myklebust error = decode_wcc_data(xdr, result, rpc_rqst_userns(req)); 1440e4f93234SChuck Lever if (unlikely(error)) 1441e4f93234SChuck Lever goto out; 1442e4f93234SChuck Lever if (status != NFS3_OK) 1443e4f93234SChuck Lever goto out_status; 1444e4f93234SChuck Lever out: 1445e4f93234SChuck Lever return error; 1446e4f93234SChuck Lever out_status: 14475e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1448e4f93234SChuck Lever } 1449e4f93234SChuck Lever 14501da177e4SLinus Torvalds /* 1451e4f93234SChuck Lever * 3.3.3 LOOKUP3res 1452e4f93234SChuck Lever * 1453e4f93234SChuck Lever * struct LOOKUP3resok { 1454e4f93234SChuck Lever * nfs_fh3 object; 1455e4f93234SChuck Lever * post_op_attr obj_attributes; 1456e4f93234SChuck Lever * post_op_attr dir_attributes; 1457e4f93234SChuck Lever * }; 1458e4f93234SChuck Lever * 1459e4f93234SChuck Lever * struct LOOKUP3resfail { 1460e4f93234SChuck Lever * post_op_attr dir_attributes; 1461e4f93234SChuck Lever * }; 1462e4f93234SChuck Lever * 1463e4f93234SChuck Lever * union LOOKUP3res switch (nfsstat3 status) { 1464e4f93234SChuck Lever * case NFS3_OK: 1465e4f93234SChuck Lever * LOOKUP3resok resok; 1466e4f93234SChuck Lever * default: 1467e4f93234SChuck Lever * LOOKUP3resfail resfail; 1468e4f93234SChuck Lever * }; 1469e4f93234SChuck Lever */ 1470bf269551SChuck Lever static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req, 1471bf269551SChuck Lever struct xdr_stream *xdr, 1472fc016483SChristoph Hellwig void *data) 1473e4f93234SChuck Lever { 1474264d948cSTrond Myklebust struct user_namespace *userns = rpc_rqst_userns(req); 1475fc016483SChristoph Hellwig struct nfs3_diropres *result = data; 1476e4f93234SChuck Lever enum nfs_stat status; 1477e4f93234SChuck Lever int error; 1478e4f93234SChuck Lever 1479bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1480e4f93234SChuck Lever if (unlikely(error)) 1481e4f93234SChuck Lever goto out; 1482e4f93234SChuck Lever if (status != NFS3_OK) 1483e4f93234SChuck Lever goto out_default; 1484bf269551SChuck Lever error = decode_nfs_fh3(xdr, result->fh); 1485e4f93234SChuck Lever if (unlikely(error)) 1486e4f93234SChuck Lever goto out; 1487264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->fattr, userns); 1488e4f93234SChuck Lever if (unlikely(error)) 1489e4f93234SChuck Lever goto out; 1490264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->dir_attr, userns); 1491e4f93234SChuck Lever out: 1492e4f93234SChuck Lever return error; 1493e4f93234SChuck Lever out_default: 1494264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->dir_attr, userns); 1495e4f93234SChuck Lever if (unlikely(error)) 1496e4f93234SChuck Lever goto out; 14975e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1498e4f93234SChuck Lever } 1499e4f93234SChuck Lever 1500e4f93234SChuck Lever /* 1501e4f93234SChuck Lever * 3.3.4 ACCESS3res 1502e4f93234SChuck Lever * 1503e4f93234SChuck Lever * struct ACCESS3resok { 1504e4f93234SChuck Lever * post_op_attr obj_attributes; 1505e4f93234SChuck Lever * uint32 access; 1506e4f93234SChuck Lever * }; 1507e4f93234SChuck Lever * 1508e4f93234SChuck Lever * struct ACCESS3resfail { 1509e4f93234SChuck Lever * post_op_attr obj_attributes; 1510e4f93234SChuck Lever * }; 1511e4f93234SChuck Lever * 1512e4f93234SChuck Lever * union ACCESS3res switch (nfsstat3 status) { 1513e4f93234SChuck Lever * case NFS3_OK: 1514e4f93234SChuck Lever * ACCESS3resok resok; 1515e4f93234SChuck Lever * default: 1516e4f93234SChuck Lever * ACCESS3resfail resfail; 1517e4f93234SChuck Lever * }; 1518e4f93234SChuck Lever */ 1519bf269551SChuck Lever static int nfs3_xdr_dec_access3res(struct rpc_rqst *req, 1520bf269551SChuck Lever struct xdr_stream *xdr, 1521fc016483SChristoph Hellwig void *data) 1522e4f93234SChuck Lever { 1523fc016483SChristoph Hellwig struct nfs3_accessres *result = data; 1524e4f93234SChuck Lever enum nfs_stat status; 1525e4f93234SChuck Lever int error; 1526e4f93234SChuck Lever 1527bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1528e4f93234SChuck Lever if (unlikely(error)) 1529e4f93234SChuck Lever goto out; 1530264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req)); 1531e4f93234SChuck Lever if (unlikely(error)) 1532e4f93234SChuck Lever goto out; 1533e4f93234SChuck Lever if (status != NFS3_OK) 1534e4f93234SChuck Lever goto out_default; 1535bf269551SChuck Lever error = decode_uint32(xdr, &result->access); 1536e4f93234SChuck Lever out: 1537e4f93234SChuck Lever return error; 1538e4f93234SChuck Lever out_default: 15395e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1540e4f93234SChuck Lever } 1541e4f93234SChuck Lever 1542e4f93234SChuck Lever /* 1543e4f93234SChuck Lever * 3.3.5 READLINK3res 1544e4f93234SChuck Lever * 1545e4f93234SChuck Lever * struct READLINK3resok { 1546e4f93234SChuck Lever * post_op_attr symlink_attributes; 1547e4f93234SChuck Lever * nfspath3 data; 1548e4f93234SChuck Lever * }; 1549e4f93234SChuck Lever * 1550e4f93234SChuck Lever * struct READLINK3resfail { 1551e4f93234SChuck Lever * post_op_attr symlink_attributes; 1552e4f93234SChuck Lever * }; 1553e4f93234SChuck Lever * 1554e4f93234SChuck Lever * union READLINK3res switch (nfsstat3 status) { 1555e4f93234SChuck Lever * case NFS3_OK: 1556e4f93234SChuck Lever * READLINK3resok resok; 1557e4f93234SChuck Lever * default: 1558e4f93234SChuck Lever * READLINK3resfail resfail; 1559e4f93234SChuck Lever * }; 1560e4f93234SChuck Lever */ 1561bf269551SChuck Lever static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req, 1562bf269551SChuck Lever struct xdr_stream *xdr, 1563fc016483SChristoph Hellwig void *result) 1564e4f93234SChuck Lever { 1565e4f93234SChuck Lever enum nfs_stat status; 1566e4f93234SChuck Lever int error; 1567e4f93234SChuck Lever 1568bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1569e4f93234SChuck Lever if (unlikely(error)) 1570e4f93234SChuck Lever goto out; 1571264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req)); 1572e4f93234SChuck Lever if (unlikely(error)) 1573e4f93234SChuck Lever goto out; 1574e4f93234SChuck Lever if (status != NFS3_OK) 1575e4f93234SChuck Lever goto out_default; 1576bf269551SChuck Lever error = decode_nfspath3(xdr); 1577e4f93234SChuck Lever out: 1578e4f93234SChuck Lever return error; 1579e4f93234SChuck Lever out_default: 15805e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1581e4f93234SChuck Lever } 1582e4f93234SChuck Lever 1583e4f93234SChuck Lever /* 1584e4f93234SChuck Lever * 3.3.6 READ3res 1585e4f93234SChuck Lever * 1586e4f93234SChuck Lever * struct READ3resok { 1587e4f93234SChuck Lever * post_op_attr file_attributes; 1588e4f93234SChuck Lever * count3 count; 1589e4f93234SChuck Lever * bool eof; 1590e4f93234SChuck Lever * opaque data<>; 1591e4f93234SChuck Lever * }; 1592e4f93234SChuck Lever * 1593e4f93234SChuck Lever * struct READ3resfail { 1594e4f93234SChuck Lever * post_op_attr file_attributes; 1595e4f93234SChuck Lever * }; 1596e4f93234SChuck Lever * 1597e4f93234SChuck Lever * union READ3res switch (nfsstat3 status) { 1598e4f93234SChuck Lever * case NFS3_OK: 1599e4f93234SChuck Lever * READ3resok resok; 1600e4f93234SChuck Lever * default: 1601e4f93234SChuck Lever * READ3resfail resfail; 1602e4f93234SChuck Lever * }; 1603e4f93234SChuck Lever */ 1604e4f93234SChuck Lever static int decode_read3resok(struct xdr_stream *xdr, 16059137bdf3SAnna Schumaker struct nfs_pgio_res *result) 1606e4f93234SChuck Lever { 1607e4f93234SChuck Lever u32 eof, count, ocount, recvd; 1608e4f93234SChuck Lever __be32 *p; 1609e4f93234SChuck Lever 1610e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 + 4 + 4); 1611eb72f484SChuck Lever if (unlikely(!p)) 1612eb72f484SChuck Lever return -EIO; 1613e4f93234SChuck Lever count = be32_to_cpup(p++); 1614e4f93234SChuck Lever eof = be32_to_cpup(p++); 1615e4f93234SChuck Lever ocount = be32_to_cpup(p++); 1616e4f93234SChuck Lever if (unlikely(ocount != count)) 1617e4f93234SChuck Lever goto out_mismatch; 161864bd577eSTrond Myklebust recvd = xdr_read_pages(xdr, count); 1619e4f93234SChuck Lever if (unlikely(count > recvd)) 1620e4f93234SChuck Lever goto out_cheating; 1621e4f93234SChuck Lever out: 1622e4f93234SChuck Lever result->eof = eof; 1623e4f93234SChuck Lever result->count = count; 1624e4f93234SChuck Lever return count; 1625e4f93234SChuck Lever out_mismatch: 1626e4f93234SChuck Lever dprintk("NFS: READ count doesn't match length of opaque: " 1627e4f93234SChuck Lever "count %u != ocount %u\n", count, ocount); 1628e4f93234SChuck Lever return -EIO; 1629e4f93234SChuck Lever out_cheating: 1630e4f93234SChuck Lever dprintk("NFS: server cheating in read result: " 1631e4f93234SChuck Lever "count %u > recvd %u\n", count, recvd); 1632e4f93234SChuck Lever count = recvd; 1633e4f93234SChuck Lever eof = 0; 1634e4f93234SChuck Lever goto out; 1635e4f93234SChuck Lever } 1636e4f93234SChuck Lever 1637bf269551SChuck Lever static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, 1638fc016483SChristoph Hellwig void *data) 1639e4f93234SChuck Lever { 1640fc016483SChristoph Hellwig struct nfs_pgio_res *result = data; 16418d8928d8STrond Myklebust unsigned int pos; 1642e4f93234SChuck Lever enum nfs_stat status; 1643e4f93234SChuck Lever int error; 1644e4f93234SChuck Lever 16458d8928d8STrond Myklebust pos = xdr_stream_pos(xdr); 1646bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1647e4f93234SChuck Lever if (unlikely(error)) 1648e4f93234SChuck Lever goto out; 1649264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req)); 1650e4f93234SChuck Lever if (unlikely(error)) 1651e4f93234SChuck Lever goto out; 1652aabff4ddSPeng Tao result->op_status = status; 1653e4f93234SChuck Lever if (status != NFS3_OK) 1654e4f93234SChuck Lever goto out_status; 165502ef04e4SChuck Lever result->replen = 4 + ((xdr_stream_pos(xdr) - pos) >> 2); 1656bf269551SChuck Lever error = decode_read3resok(xdr, result); 1657e4f93234SChuck Lever out: 1658e4f93234SChuck Lever return error; 1659e4f93234SChuck Lever out_status: 16605e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1661e4f93234SChuck Lever } 1662e4f93234SChuck Lever 1663e4f93234SChuck Lever /* 1664e4f93234SChuck Lever * 3.3.7 WRITE3res 1665e4f93234SChuck Lever * 1666e4f93234SChuck Lever * enum stable_how { 1667e4f93234SChuck Lever * UNSTABLE = 0, 1668e4f93234SChuck Lever * DATA_SYNC = 1, 1669e4f93234SChuck Lever * FILE_SYNC = 2 1670e4f93234SChuck Lever * }; 1671e4f93234SChuck Lever * 1672e4f93234SChuck Lever * struct WRITE3resok { 1673e4f93234SChuck Lever * wcc_data file_wcc; 1674e4f93234SChuck Lever * count3 count; 1675e4f93234SChuck Lever * stable_how committed; 1676e4f93234SChuck Lever * writeverf3 verf; 1677e4f93234SChuck Lever * }; 1678e4f93234SChuck Lever * 1679e4f93234SChuck Lever * struct WRITE3resfail { 1680e4f93234SChuck Lever * wcc_data file_wcc; 1681e4f93234SChuck Lever * }; 1682e4f93234SChuck Lever * 1683e4f93234SChuck Lever * union WRITE3res switch (nfsstat3 status) { 1684e4f93234SChuck Lever * case NFS3_OK: 1685e4f93234SChuck Lever * WRITE3resok resok; 1686e4f93234SChuck Lever * default: 1687e4f93234SChuck Lever * WRITE3resfail resfail; 1688e4f93234SChuck Lever * }; 1689e4f93234SChuck Lever */ 1690e4f93234SChuck Lever static int decode_write3resok(struct xdr_stream *xdr, 16919137bdf3SAnna Schumaker struct nfs_pgio_res *result) 1692e4f93234SChuck Lever { 1693e4f93234SChuck Lever __be32 *p; 1694e4f93234SChuck Lever 16952f2c63bcSTrond Myklebust p = xdr_inline_decode(xdr, 4 + 4); 1696eb72f484SChuck Lever if (unlikely(!p)) 1697eb72f484SChuck Lever return -EIO; 1698e4f93234SChuck Lever result->count = be32_to_cpup(p++); 1699e4f93234SChuck Lever result->verf->committed = be32_to_cpup(p++); 1700e4f93234SChuck Lever if (unlikely(result->verf->committed > NFS_FILE_SYNC)) 1701e4f93234SChuck Lever goto out_badvalue; 17022f2c63bcSTrond Myklebust if (decode_writeverf3(xdr, &result->verf->verifier)) 1703eb72f484SChuck Lever return -EIO; 1704e4f93234SChuck Lever return result->count; 1705e4f93234SChuck Lever out_badvalue: 1706e4f93234SChuck Lever dprintk("NFS: bad stable_how value: %u\n", result->verf->committed); 1707e4f93234SChuck Lever return -EIO; 1708e4f93234SChuck Lever } 1709e4f93234SChuck Lever 1710bf269551SChuck Lever static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr, 1711fc016483SChristoph Hellwig void *data) 1712e4f93234SChuck Lever { 1713fc016483SChristoph Hellwig struct nfs_pgio_res *result = data; 1714e4f93234SChuck Lever enum nfs_stat status; 1715e4f93234SChuck Lever int error; 1716e4f93234SChuck Lever 1717bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1718e4f93234SChuck Lever if (unlikely(error)) 1719e4f93234SChuck Lever goto out; 1720264d948cSTrond Myklebust error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req)); 1721e4f93234SChuck Lever if (unlikely(error)) 1722e4f93234SChuck Lever goto out; 1723aabff4ddSPeng Tao result->op_status = status; 1724e4f93234SChuck Lever if (status != NFS3_OK) 1725e4f93234SChuck Lever goto out_status; 1726bf269551SChuck Lever error = decode_write3resok(xdr, result); 1727e4f93234SChuck Lever out: 1728e4f93234SChuck Lever return error; 1729e4f93234SChuck Lever out_status: 17305e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1731e4f93234SChuck Lever } 1732e4f93234SChuck Lever 1733e4f93234SChuck Lever /* 1734e4f93234SChuck Lever * 3.3.8 CREATE3res 1735e4f93234SChuck Lever * 1736e4f93234SChuck Lever * struct CREATE3resok { 1737e4f93234SChuck Lever * post_op_fh3 obj; 1738e4f93234SChuck Lever * post_op_attr obj_attributes; 1739e4f93234SChuck Lever * wcc_data dir_wcc; 1740e4f93234SChuck Lever * }; 1741e4f93234SChuck Lever * 1742e4f93234SChuck Lever * struct CREATE3resfail { 1743e4f93234SChuck Lever * wcc_data dir_wcc; 1744e4f93234SChuck Lever * }; 1745e4f93234SChuck Lever * 1746e4f93234SChuck Lever * union CREATE3res switch (nfsstat3 status) { 1747e4f93234SChuck Lever * case NFS3_OK: 1748e4f93234SChuck Lever * CREATE3resok resok; 1749e4f93234SChuck Lever * default: 1750e4f93234SChuck Lever * CREATE3resfail resfail; 1751e4f93234SChuck Lever * }; 1752e4f93234SChuck Lever */ 1753e4f93234SChuck Lever static int decode_create3resok(struct xdr_stream *xdr, 1754264d948cSTrond Myklebust struct nfs3_diropres *result, 1755264d948cSTrond Myklebust struct user_namespace *userns) 1756e4f93234SChuck Lever { 1757e4f93234SChuck Lever int error; 1758e4f93234SChuck Lever 1759e4f93234SChuck Lever error = decode_post_op_fh3(xdr, result->fh); 1760e4f93234SChuck Lever if (unlikely(error)) 1761e4f93234SChuck Lever goto out; 1762264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->fattr, userns); 1763e4f93234SChuck Lever if (unlikely(error)) 1764e4f93234SChuck Lever goto out; 1765e4f93234SChuck Lever /* The server isn't required to return a file handle. 1766e4f93234SChuck Lever * If it didn't, force the client to perform a LOOKUP 1767e4f93234SChuck Lever * to determine the correct file handle and attribute 1768e4f93234SChuck Lever * values for the new object. */ 1769e4f93234SChuck Lever if (result->fh->size == 0) 1770e4f93234SChuck Lever result->fattr->valid = 0; 1771264d948cSTrond Myklebust error = decode_wcc_data(xdr, result->dir_attr, userns); 1772e4f93234SChuck Lever out: 1773e4f93234SChuck Lever return error; 1774e4f93234SChuck Lever } 1775e4f93234SChuck Lever 1776bf269551SChuck Lever static int nfs3_xdr_dec_create3res(struct rpc_rqst *req, 1777bf269551SChuck Lever struct xdr_stream *xdr, 1778fc016483SChristoph Hellwig void *data) 1779e4f93234SChuck Lever { 1780264d948cSTrond Myklebust struct user_namespace *userns = rpc_rqst_userns(req); 1781fc016483SChristoph Hellwig struct nfs3_diropres *result = data; 1782e4f93234SChuck Lever enum nfs_stat status; 1783e4f93234SChuck Lever int error; 1784e4f93234SChuck Lever 1785bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1786e4f93234SChuck Lever if (unlikely(error)) 1787e4f93234SChuck Lever goto out; 1788e4f93234SChuck Lever if (status != NFS3_OK) 1789e4f93234SChuck Lever goto out_default; 1790264d948cSTrond Myklebust error = decode_create3resok(xdr, result, userns); 1791e4f93234SChuck Lever out: 1792e4f93234SChuck Lever return error; 1793e4f93234SChuck Lever out_default: 1794264d948cSTrond Myklebust error = decode_wcc_data(xdr, result->dir_attr, userns); 1795e4f93234SChuck Lever if (unlikely(error)) 1796e4f93234SChuck Lever goto out; 17975e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1798e4f93234SChuck Lever } 1799e4f93234SChuck Lever 1800e4f93234SChuck Lever /* 1801e4f93234SChuck Lever * 3.3.12 REMOVE3res 1802e4f93234SChuck Lever * 1803e4f93234SChuck Lever * struct REMOVE3resok { 1804e4f93234SChuck Lever * wcc_data dir_wcc; 1805e4f93234SChuck Lever * }; 1806e4f93234SChuck Lever * 1807e4f93234SChuck Lever * struct REMOVE3resfail { 1808e4f93234SChuck Lever * wcc_data dir_wcc; 1809e4f93234SChuck Lever * }; 1810e4f93234SChuck Lever * 1811e4f93234SChuck Lever * union REMOVE3res switch (nfsstat3 status) { 1812e4f93234SChuck Lever * case NFS3_OK: 1813e4f93234SChuck Lever * REMOVE3resok resok; 1814e4f93234SChuck Lever * default: 1815e4f93234SChuck Lever * REMOVE3resfail resfail; 1816e4f93234SChuck Lever * }; 1817e4f93234SChuck Lever */ 1818bf269551SChuck Lever static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req, 1819bf269551SChuck Lever struct xdr_stream *xdr, 1820fc016483SChristoph Hellwig void *data) 1821e4f93234SChuck Lever { 1822fc016483SChristoph Hellwig struct nfs_removeres *result = data; 1823e4f93234SChuck Lever enum nfs_stat status; 1824e4f93234SChuck Lever int error; 1825e4f93234SChuck Lever 1826bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1827e4f93234SChuck Lever if (unlikely(error)) 1828e4f93234SChuck Lever goto out; 1829264d948cSTrond Myklebust error = decode_wcc_data(xdr, result->dir_attr, rpc_rqst_userns(req)); 1830e4f93234SChuck Lever if (unlikely(error)) 1831e4f93234SChuck Lever goto out; 1832e4f93234SChuck Lever if (status != NFS3_OK) 1833e4f93234SChuck Lever goto out_status; 1834e4f93234SChuck Lever out: 1835e4f93234SChuck Lever return error; 1836e4f93234SChuck Lever out_status: 18375e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1838e4f93234SChuck Lever } 1839e4f93234SChuck Lever 1840e4f93234SChuck Lever /* 1841e4f93234SChuck Lever * 3.3.14 RENAME3res 1842e4f93234SChuck Lever * 1843e4f93234SChuck Lever * struct RENAME3resok { 1844e4f93234SChuck Lever * wcc_data fromdir_wcc; 1845e4f93234SChuck Lever * wcc_data todir_wcc; 1846e4f93234SChuck Lever * }; 1847e4f93234SChuck Lever * 1848e4f93234SChuck Lever * struct RENAME3resfail { 1849e4f93234SChuck Lever * wcc_data fromdir_wcc; 1850e4f93234SChuck Lever * wcc_data todir_wcc; 1851e4f93234SChuck Lever * }; 1852e4f93234SChuck Lever * 1853e4f93234SChuck Lever * union RENAME3res switch (nfsstat3 status) { 1854e4f93234SChuck Lever * case NFS3_OK: 1855e4f93234SChuck Lever * RENAME3resok resok; 1856e4f93234SChuck Lever * default: 1857e4f93234SChuck Lever * RENAME3resfail resfail; 1858e4f93234SChuck Lever * }; 1859e4f93234SChuck Lever */ 1860bf269551SChuck Lever static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req, 1861bf269551SChuck Lever struct xdr_stream *xdr, 1862fc016483SChristoph Hellwig void *data) 1863e4f93234SChuck Lever { 1864264d948cSTrond Myklebust struct user_namespace *userns = rpc_rqst_userns(req); 1865fc016483SChristoph Hellwig struct nfs_renameres *result = data; 1866e4f93234SChuck Lever enum nfs_stat status; 1867e4f93234SChuck Lever int error; 1868e4f93234SChuck Lever 1869bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1870e4f93234SChuck Lever if (unlikely(error)) 1871e4f93234SChuck Lever goto out; 1872264d948cSTrond Myklebust error = decode_wcc_data(xdr, result->old_fattr, userns); 1873e4f93234SChuck Lever if (unlikely(error)) 1874e4f93234SChuck Lever goto out; 1875264d948cSTrond Myklebust error = decode_wcc_data(xdr, result->new_fattr, userns); 1876e4f93234SChuck Lever if (unlikely(error)) 1877e4f93234SChuck Lever goto out; 1878e4f93234SChuck Lever if (status != NFS3_OK) 1879e4f93234SChuck Lever goto out_status; 1880e4f93234SChuck Lever out: 1881e4f93234SChuck Lever return error; 1882e4f93234SChuck Lever out_status: 18835e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1884e4f93234SChuck Lever } 1885e4f93234SChuck Lever 1886e4f93234SChuck Lever /* 1887e4f93234SChuck Lever * 3.3.15 LINK3res 1888e4f93234SChuck Lever * 1889e4f93234SChuck Lever * struct LINK3resok { 1890e4f93234SChuck Lever * post_op_attr file_attributes; 1891e4f93234SChuck Lever * wcc_data linkdir_wcc; 1892e4f93234SChuck Lever * }; 1893e4f93234SChuck Lever * 1894e4f93234SChuck Lever * struct LINK3resfail { 1895e4f93234SChuck Lever * post_op_attr file_attributes; 1896e4f93234SChuck Lever * wcc_data linkdir_wcc; 1897e4f93234SChuck Lever * }; 1898e4f93234SChuck Lever * 1899e4f93234SChuck Lever * union LINK3res switch (nfsstat3 status) { 1900e4f93234SChuck Lever * case NFS3_OK: 1901e4f93234SChuck Lever * LINK3resok resok; 1902e4f93234SChuck Lever * default: 1903e4f93234SChuck Lever * LINK3resfail resfail; 1904e4f93234SChuck Lever * }; 1905e4f93234SChuck Lever */ 1906bf269551SChuck Lever static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr, 1907fc016483SChristoph Hellwig void *data) 1908e4f93234SChuck Lever { 1909264d948cSTrond Myklebust struct user_namespace *userns = rpc_rqst_userns(req); 1910fc016483SChristoph Hellwig struct nfs3_linkres *result = data; 1911e4f93234SChuck Lever enum nfs_stat status; 1912e4f93234SChuck Lever int error; 1913e4f93234SChuck Lever 1914bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1915e4f93234SChuck Lever if (unlikely(error)) 1916e4f93234SChuck Lever goto out; 1917264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->fattr, userns); 1918e4f93234SChuck Lever if (unlikely(error)) 1919e4f93234SChuck Lever goto out; 1920264d948cSTrond Myklebust error = decode_wcc_data(xdr, result->dir_attr, userns); 1921e4f93234SChuck Lever if (unlikely(error)) 1922e4f93234SChuck Lever goto out; 1923e4f93234SChuck Lever if (status != NFS3_OK) 1924e4f93234SChuck Lever goto out_status; 1925e4f93234SChuck Lever out: 1926e4f93234SChuck Lever return error; 1927e4f93234SChuck Lever out_status: 19285e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1929e4f93234SChuck Lever } 1930e4f93234SChuck Lever 1931e4f93234SChuck Lever /** 1932e4f93234SChuck Lever * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in 1933e4f93234SChuck Lever * the local page cache 1934e4f93234SChuck Lever * @xdr: XDR stream where entry resides 1935e4f93234SChuck Lever * @entry: buffer to fill in with entry data 1936e4f93234SChuck Lever * @plus: boolean indicating whether this should be a readdirplus entry 1937e4f93234SChuck Lever * 1938573c4e1eSChuck Lever * Returns zero if successful, otherwise a negative errno value is 1939573c4e1eSChuck Lever * returned. 1940e4f93234SChuck Lever * 1941e4f93234SChuck Lever * This function is not invoked during READDIR reply decoding, but 1942e4f93234SChuck Lever * rather whenever an application invokes the getdents(2) system call 1943e4f93234SChuck Lever * on a directory already in our cache. 1944e4f93234SChuck Lever * 1945e4f93234SChuck Lever * 3.3.16 entry3 1946e4f93234SChuck Lever * 1947e4f93234SChuck Lever * struct entry3 { 1948e4f93234SChuck Lever * fileid3 fileid; 1949e4f93234SChuck Lever * filename3 name; 1950e4f93234SChuck Lever * cookie3 cookie; 1951e4f93234SChuck Lever * fhandle3 filehandle; 1952e4f93234SChuck Lever * post_op_attr3 attributes; 1953e4f93234SChuck Lever * entry3 *nextentry; 1954e4f93234SChuck Lever * }; 1955e4f93234SChuck Lever * 1956e4f93234SChuck Lever * 3.3.17 entryplus3 1957e4f93234SChuck Lever * struct entryplus3 { 1958e4f93234SChuck Lever * fileid3 fileid; 1959e4f93234SChuck Lever * filename3 name; 1960e4f93234SChuck Lever * cookie3 cookie; 1961e4f93234SChuck Lever * post_op_attr name_attributes; 1962e4f93234SChuck Lever * post_op_fh3 name_handle; 1963e4f93234SChuck Lever * entryplus3 *nextentry; 1964e4f93234SChuck Lever * }; 1965e4f93234SChuck Lever */ 1966573c4e1eSChuck Lever int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, 1967a7a3b1e9SBenjamin Coddington bool plus) 1968e4f93234SChuck Lever { 1969264d948cSTrond Myklebust struct user_namespace *userns = rpc_userns(entry->server->client); 1970e4f93234SChuck Lever struct nfs_entry old = *entry; 1971e4f93234SChuck Lever __be32 *p; 1972e4f93234SChuck Lever int error; 197398de9ce6SFrank Sorenson u64 new_cookie; 1974e4f93234SChuck Lever 1975e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 1976eb72f484SChuck Lever if (unlikely(!p)) 1977eb72f484SChuck Lever return -EAGAIN; 1978e4f93234SChuck Lever if (*p == xdr_zero) { 1979e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 1980eb72f484SChuck Lever if (unlikely(!p)) 1981eb72f484SChuck Lever return -EAGAIN; 1982e4f93234SChuck Lever if (*p == xdr_zero) 1983573c4e1eSChuck Lever return -EAGAIN; 1984e4f93234SChuck Lever entry->eof = 1; 1985573c4e1eSChuck Lever return -EBADCOOKIE; 1986e4f93234SChuck Lever } 1987e4f93234SChuck Lever 1988e4f93234SChuck Lever error = decode_fileid3(xdr, &entry->ino); 1989e4f93234SChuck Lever if (unlikely(error)) 1990573c4e1eSChuck Lever return error; 1991e4f93234SChuck Lever 1992e4f93234SChuck Lever error = decode_inline_filename3(xdr, &entry->name, &entry->len); 1993e4f93234SChuck Lever if (unlikely(error)) 1994573c4e1eSChuck Lever return error; 1995e4f93234SChuck Lever 199698de9ce6SFrank Sorenson error = decode_cookie3(xdr, &new_cookie); 1997e4f93234SChuck Lever if (unlikely(error)) 1998573c4e1eSChuck Lever return error; 1999e4f93234SChuck Lever 2000e4f93234SChuck Lever entry->d_type = DT_UNKNOWN; 2001e4f93234SChuck Lever 2002e4f93234SChuck Lever if (plus) { 2003e4f93234SChuck Lever entry->fattr->valid = 0; 2004264d948cSTrond Myklebust error = decode_post_op_attr(xdr, entry->fattr, userns); 2005e4f93234SChuck Lever if (unlikely(error)) 2006573c4e1eSChuck Lever return error; 2007e4f93234SChuck Lever if (entry->fattr->valid & NFS_ATTR_FATTR_V3) 2008e4f93234SChuck Lever entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); 2009e4f93234SChuck Lever 20101ae04b25STrond Myklebust if (entry->fattr->fileid != entry->ino) { 20111ae04b25STrond Myklebust entry->fattr->mounted_on_fileid = entry->ino; 20121ae04b25STrond Myklebust entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID; 20131ae04b25STrond Myklebust } 20141ae04b25STrond Myklebust 2015e4f93234SChuck Lever /* In fact, a post_op_fh3: */ 2016e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 2017eb72f484SChuck Lever if (unlikely(!p)) 2018eb72f484SChuck Lever return -EAGAIN; 2019e4f93234SChuck Lever if (*p != xdr_zero) { 2020e4f93234SChuck Lever error = decode_nfs_fh3(xdr, entry->fh); 2021e4f93234SChuck Lever if (unlikely(error)) { 2022e4f93234SChuck Lever if (error == -E2BIG) 2023e4f93234SChuck Lever goto out_truncated; 2024573c4e1eSChuck Lever return error; 2025e4f93234SChuck Lever } 2026e4f93234SChuck Lever } else 2027e4f93234SChuck Lever zero_nfs_fh3(entry->fh); 2028e4f93234SChuck Lever } 2029e4f93234SChuck Lever 203098de9ce6SFrank Sorenson entry->prev_cookie = entry->cookie; 203198de9ce6SFrank Sorenson entry->cookie = new_cookie; 203298de9ce6SFrank Sorenson 2033573c4e1eSChuck Lever return 0; 2034e4f93234SChuck Lever 2035e4f93234SChuck Lever out_truncated: 2036e4f93234SChuck Lever dprintk("NFS: directory entry contains invalid file handle\n"); 2037e4f93234SChuck Lever *entry = old; 2038573c4e1eSChuck Lever return -EAGAIN; 2039e4f93234SChuck Lever } 2040e4f93234SChuck Lever 2041e4f93234SChuck Lever /* 2042e4f93234SChuck Lever * 3.3.16 READDIR3res 2043e4f93234SChuck Lever * 2044e4f93234SChuck Lever * struct dirlist3 { 2045e4f93234SChuck Lever * entry3 *entries; 2046e4f93234SChuck Lever * bool eof; 2047e4f93234SChuck Lever * }; 2048e4f93234SChuck Lever * 2049e4f93234SChuck Lever * struct READDIR3resok { 2050e4f93234SChuck Lever * post_op_attr dir_attributes; 2051e4f93234SChuck Lever * cookieverf3 cookieverf; 2052e4f93234SChuck Lever * dirlist3 reply; 2053e4f93234SChuck Lever * }; 2054e4f93234SChuck Lever * 2055e4f93234SChuck Lever * struct READDIR3resfail { 2056e4f93234SChuck Lever * post_op_attr dir_attributes; 2057e4f93234SChuck Lever * }; 2058e4f93234SChuck Lever * 2059e4f93234SChuck Lever * union READDIR3res switch (nfsstat3 status) { 2060e4f93234SChuck Lever * case NFS3_OK: 2061e4f93234SChuck Lever * READDIR3resok resok; 2062e4f93234SChuck Lever * default: 2063e4f93234SChuck Lever * READDIR3resfail resfail; 2064e4f93234SChuck Lever * }; 2065e4f93234SChuck Lever * 2066e4f93234SChuck Lever * Read the directory contents into the page cache, but otherwise 2067e4f93234SChuck Lever * don't touch them. The actual decoding is done by nfs3_decode_entry() 2068e4f93234SChuck Lever * during subsequent nfs_readdir() calls. 2069e4f93234SChuck Lever */ 2070e4f93234SChuck Lever static int decode_dirlist3(struct xdr_stream *xdr) 2071e4f93234SChuck Lever { 207264bd577eSTrond Myklebust return xdr_read_pages(xdr, xdr->buf->page_len); 2073e4f93234SChuck Lever } 2074e4f93234SChuck Lever 2075e4f93234SChuck Lever static int decode_readdir3resok(struct xdr_stream *xdr, 2076264d948cSTrond Myklebust struct nfs3_readdirres *result, 2077264d948cSTrond Myklebust struct user_namespace *userns) 2078e4f93234SChuck Lever { 2079e4f93234SChuck Lever int error; 2080e4f93234SChuck Lever 2081264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->dir_attr, userns); 2082e4f93234SChuck Lever if (unlikely(error)) 2083e4f93234SChuck Lever goto out; 2084e4f93234SChuck Lever /* XXX: do we need to check if result->verf != NULL ? */ 2085e4f93234SChuck Lever error = decode_cookieverf3(xdr, result->verf); 2086e4f93234SChuck Lever if (unlikely(error)) 2087e4f93234SChuck Lever goto out; 2088e4f93234SChuck Lever error = decode_dirlist3(xdr); 2089e4f93234SChuck Lever out: 2090e4f93234SChuck Lever return error; 2091e4f93234SChuck Lever } 2092e4f93234SChuck Lever 2093bf269551SChuck Lever static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req, 2094bf269551SChuck Lever struct xdr_stream *xdr, 2095fc016483SChristoph Hellwig void *data) 2096e4f93234SChuck Lever { 2097fc016483SChristoph Hellwig struct nfs3_readdirres *result = data; 2098e4f93234SChuck Lever enum nfs_stat status; 2099e4f93234SChuck Lever int error; 2100e4f93234SChuck Lever 2101bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2102e4f93234SChuck Lever if (unlikely(error)) 2103e4f93234SChuck Lever goto out; 2104e4f93234SChuck Lever if (status != NFS3_OK) 2105e4f93234SChuck Lever goto out_default; 2106264d948cSTrond Myklebust error = decode_readdir3resok(xdr, result, rpc_rqst_userns(req)); 2107e4f93234SChuck Lever out: 2108e4f93234SChuck Lever return error; 2109e4f93234SChuck Lever out_default: 2110264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->dir_attr, rpc_rqst_userns(req)); 2111e4f93234SChuck Lever if (unlikely(error)) 2112e4f93234SChuck Lever goto out; 21135e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2114e4f93234SChuck Lever } 2115e4f93234SChuck Lever 2116e4f93234SChuck Lever /* 2117e4f93234SChuck Lever * 3.3.18 FSSTAT3res 2118e4f93234SChuck Lever * 2119e4f93234SChuck Lever * struct FSSTAT3resok { 2120e4f93234SChuck Lever * post_op_attr obj_attributes; 2121e4f93234SChuck Lever * size3 tbytes; 2122e4f93234SChuck Lever * size3 fbytes; 2123e4f93234SChuck Lever * size3 abytes; 2124e4f93234SChuck Lever * size3 tfiles; 2125e4f93234SChuck Lever * size3 ffiles; 2126e4f93234SChuck Lever * size3 afiles; 2127e4f93234SChuck Lever * uint32 invarsec; 2128e4f93234SChuck Lever * }; 2129e4f93234SChuck Lever * 2130e4f93234SChuck Lever * struct FSSTAT3resfail { 2131e4f93234SChuck Lever * post_op_attr obj_attributes; 2132e4f93234SChuck Lever * }; 2133e4f93234SChuck Lever * 2134e4f93234SChuck Lever * union FSSTAT3res switch (nfsstat3 status) { 2135e4f93234SChuck Lever * case NFS3_OK: 2136e4f93234SChuck Lever * FSSTAT3resok resok; 2137e4f93234SChuck Lever * default: 2138e4f93234SChuck Lever * FSSTAT3resfail resfail; 2139e4f93234SChuck Lever * }; 2140e4f93234SChuck Lever */ 2141e4f93234SChuck Lever static int decode_fsstat3resok(struct xdr_stream *xdr, 2142e4f93234SChuck Lever struct nfs_fsstat *result) 2143e4f93234SChuck Lever { 2144e4f93234SChuck Lever __be32 *p; 2145e4f93234SChuck Lever 2146e4f93234SChuck Lever p = xdr_inline_decode(xdr, 8 * 6 + 4); 2147eb72f484SChuck Lever if (unlikely(!p)) 2148eb72f484SChuck Lever return -EIO; 2149e4f93234SChuck Lever p = xdr_decode_size3(p, &result->tbytes); 2150e4f93234SChuck Lever p = xdr_decode_size3(p, &result->fbytes); 2151e4f93234SChuck Lever p = xdr_decode_size3(p, &result->abytes); 2152e4f93234SChuck Lever p = xdr_decode_size3(p, &result->tfiles); 2153e4f93234SChuck Lever p = xdr_decode_size3(p, &result->ffiles); 2154e4f93234SChuck Lever xdr_decode_size3(p, &result->afiles); 2155e4f93234SChuck Lever /* ignore invarsec */ 2156e4f93234SChuck Lever return 0; 2157e4f93234SChuck Lever } 2158e4f93234SChuck Lever 2159bf269551SChuck Lever static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req, 2160bf269551SChuck Lever struct xdr_stream *xdr, 2161fc016483SChristoph Hellwig void *data) 2162e4f93234SChuck Lever { 2163fc016483SChristoph Hellwig struct nfs_fsstat *result = data; 2164e4f93234SChuck Lever enum nfs_stat status; 2165e4f93234SChuck Lever int error; 2166e4f93234SChuck Lever 2167bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2168e4f93234SChuck Lever if (unlikely(error)) 2169e4f93234SChuck Lever goto out; 2170264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req)); 2171e4f93234SChuck Lever if (unlikely(error)) 2172e4f93234SChuck Lever goto out; 2173e4f93234SChuck Lever if (status != NFS3_OK) 2174e4f93234SChuck Lever goto out_status; 2175bf269551SChuck Lever error = decode_fsstat3resok(xdr, result); 2176e4f93234SChuck Lever out: 2177e4f93234SChuck Lever return error; 2178e4f93234SChuck Lever out_status: 21795e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2180e4f93234SChuck Lever } 2181e4f93234SChuck Lever 2182e4f93234SChuck Lever /* 2183e4f93234SChuck Lever * 3.3.19 FSINFO3res 2184e4f93234SChuck Lever * 2185e4f93234SChuck Lever * struct FSINFO3resok { 2186e4f93234SChuck Lever * post_op_attr obj_attributes; 2187e4f93234SChuck Lever * uint32 rtmax; 2188e4f93234SChuck Lever * uint32 rtpref; 2189e4f93234SChuck Lever * uint32 rtmult; 2190e4f93234SChuck Lever * uint32 wtmax; 2191e4f93234SChuck Lever * uint32 wtpref; 2192e4f93234SChuck Lever * uint32 wtmult; 2193e4f93234SChuck Lever * uint32 dtpref; 2194e4f93234SChuck Lever * size3 maxfilesize; 2195e4f93234SChuck Lever * nfstime3 time_delta; 2196e4f93234SChuck Lever * uint32 properties; 2197e4f93234SChuck Lever * }; 2198e4f93234SChuck Lever * 2199e4f93234SChuck Lever * struct FSINFO3resfail { 2200e4f93234SChuck Lever * post_op_attr obj_attributes; 2201e4f93234SChuck Lever * }; 2202e4f93234SChuck Lever * 2203e4f93234SChuck Lever * union FSINFO3res switch (nfsstat3 status) { 2204e4f93234SChuck Lever * case NFS3_OK: 2205e4f93234SChuck Lever * FSINFO3resok resok; 2206e4f93234SChuck Lever * default: 2207e4f93234SChuck Lever * FSINFO3resfail resfail; 2208e4f93234SChuck Lever * }; 2209e4f93234SChuck Lever */ 2210e4f93234SChuck Lever static int decode_fsinfo3resok(struct xdr_stream *xdr, 2211e4f93234SChuck Lever struct nfs_fsinfo *result) 2212e4f93234SChuck Lever { 2213e4f93234SChuck Lever __be32 *p; 2214e4f93234SChuck Lever 2215e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4); 2216eb72f484SChuck Lever if (unlikely(!p)) 2217eb72f484SChuck Lever return -EIO; 2218e4f93234SChuck Lever result->rtmax = be32_to_cpup(p++); 2219e4f93234SChuck Lever result->rtpref = be32_to_cpup(p++); 2220e4f93234SChuck Lever result->rtmult = be32_to_cpup(p++); 2221e4f93234SChuck Lever result->wtmax = be32_to_cpup(p++); 2222e4f93234SChuck Lever result->wtpref = be32_to_cpup(p++); 2223e4f93234SChuck Lever result->wtmult = be32_to_cpup(p++); 2224e4f93234SChuck Lever result->dtpref = be32_to_cpup(p++); 2225e4f93234SChuck Lever p = xdr_decode_size3(p, &result->maxfilesize); 2226f6048709SChuck Lever xdr_decode_nfstime3(p, &result->time_delta); 2227e4f93234SChuck Lever 2228e4f93234SChuck Lever /* ignore properties */ 2229e4f93234SChuck Lever result->lease_time = 0; 2230e4f93234SChuck Lever return 0; 2231e4f93234SChuck Lever } 2232e4f93234SChuck Lever 2233bf269551SChuck Lever static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req, 2234bf269551SChuck Lever struct xdr_stream *xdr, 2235fc016483SChristoph Hellwig void *data) 2236e4f93234SChuck Lever { 2237fc016483SChristoph Hellwig struct nfs_fsinfo *result = data; 2238e4f93234SChuck Lever enum nfs_stat status; 2239e4f93234SChuck Lever int error; 2240e4f93234SChuck Lever 2241bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2242e4f93234SChuck Lever if (unlikely(error)) 2243e4f93234SChuck Lever goto out; 2244264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req)); 2245e4f93234SChuck Lever if (unlikely(error)) 2246e4f93234SChuck Lever goto out; 2247e4f93234SChuck Lever if (status != NFS3_OK) 2248e4f93234SChuck Lever goto out_status; 2249bf269551SChuck Lever error = decode_fsinfo3resok(xdr, result); 2250e4f93234SChuck Lever out: 2251e4f93234SChuck Lever return error; 2252e4f93234SChuck Lever out_status: 22535e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2254e4f93234SChuck Lever } 2255e4f93234SChuck Lever 2256e4f93234SChuck Lever /* 2257e4f93234SChuck Lever * 3.3.20 PATHCONF3res 2258e4f93234SChuck Lever * 2259e4f93234SChuck Lever * struct PATHCONF3resok { 2260e4f93234SChuck Lever * post_op_attr obj_attributes; 2261e4f93234SChuck Lever * uint32 linkmax; 2262e4f93234SChuck Lever * uint32 name_max; 2263e4f93234SChuck Lever * bool no_trunc; 2264e4f93234SChuck Lever * bool chown_restricted; 2265e4f93234SChuck Lever * bool case_insensitive; 2266e4f93234SChuck Lever * bool case_preserving; 2267e4f93234SChuck Lever * }; 2268e4f93234SChuck Lever * 2269e4f93234SChuck Lever * struct PATHCONF3resfail { 2270e4f93234SChuck Lever * post_op_attr obj_attributes; 2271e4f93234SChuck Lever * }; 2272e4f93234SChuck Lever * 2273e4f93234SChuck Lever * union PATHCONF3res switch (nfsstat3 status) { 2274e4f93234SChuck Lever * case NFS3_OK: 2275e4f93234SChuck Lever * PATHCONF3resok resok; 2276e4f93234SChuck Lever * default: 2277e4f93234SChuck Lever * PATHCONF3resfail resfail; 2278e4f93234SChuck Lever * }; 2279e4f93234SChuck Lever */ 2280e4f93234SChuck Lever static int decode_pathconf3resok(struct xdr_stream *xdr, 2281e4f93234SChuck Lever struct nfs_pathconf *result) 2282e4f93234SChuck Lever { 2283e4f93234SChuck Lever __be32 *p; 2284e4f93234SChuck Lever 2285e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 * 6); 2286eb72f484SChuck Lever if (unlikely(!p)) 2287eb72f484SChuck Lever return -EIO; 2288e4f93234SChuck Lever result->max_link = be32_to_cpup(p++); 2289e4f93234SChuck Lever result->max_namelen = be32_to_cpup(p); 2290e4f93234SChuck Lever /* ignore remaining fields */ 2291e4f93234SChuck Lever return 0; 2292e4f93234SChuck Lever } 2293e4f93234SChuck Lever 2294bf269551SChuck Lever static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req, 2295bf269551SChuck Lever struct xdr_stream *xdr, 2296fc016483SChristoph Hellwig void *data) 2297e4f93234SChuck Lever { 2298fc016483SChristoph Hellwig struct nfs_pathconf *result = data; 2299e4f93234SChuck Lever enum nfs_stat status; 2300e4f93234SChuck Lever int error; 2301e4f93234SChuck Lever 2302bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2303e4f93234SChuck Lever if (unlikely(error)) 2304e4f93234SChuck Lever goto out; 2305264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req)); 2306e4f93234SChuck Lever if (unlikely(error)) 2307e4f93234SChuck Lever goto out; 2308e4f93234SChuck Lever if (status != NFS3_OK) 2309e4f93234SChuck Lever goto out_status; 2310bf269551SChuck Lever error = decode_pathconf3resok(xdr, result); 2311e4f93234SChuck Lever out: 2312e4f93234SChuck Lever return error; 2313e4f93234SChuck Lever out_status: 23145e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2315e4f93234SChuck Lever } 2316e4f93234SChuck Lever 2317e4f93234SChuck Lever /* 2318e4f93234SChuck Lever * 3.3.21 COMMIT3res 2319e4f93234SChuck Lever * 2320e4f93234SChuck Lever * struct COMMIT3resok { 2321e4f93234SChuck Lever * wcc_data file_wcc; 2322e4f93234SChuck Lever * writeverf3 verf; 2323e4f93234SChuck Lever * }; 2324e4f93234SChuck Lever * 2325e4f93234SChuck Lever * struct COMMIT3resfail { 2326e4f93234SChuck Lever * wcc_data file_wcc; 2327e4f93234SChuck Lever * }; 2328e4f93234SChuck Lever * 2329e4f93234SChuck Lever * union COMMIT3res switch (nfsstat3 status) { 2330e4f93234SChuck Lever * case NFS3_OK: 2331e4f93234SChuck Lever * COMMIT3resok resok; 2332e4f93234SChuck Lever * default: 2333e4f93234SChuck Lever * COMMIT3resfail resfail; 2334e4f93234SChuck Lever * }; 2335e4f93234SChuck Lever */ 2336bf269551SChuck Lever static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, 2337bf269551SChuck Lever struct xdr_stream *xdr, 2338fc016483SChristoph Hellwig void *data) 2339e4f93234SChuck Lever { 2340fc016483SChristoph Hellwig struct nfs_commitres *result = data; 2341e4f93234SChuck Lever enum nfs_stat status; 2342e4f93234SChuck Lever int error; 2343e4f93234SChuck Lever 2344bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2345e4f93234SChuck Lever if (unlikely(error)) 2346e4f93234SChuck Lever goto out; 2347264d948cSTrond Myklebust error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req)); 2348e4f93234SChuck Lever if (unlikely(error)) 2349e4f93234SChuck Lever goto out; 2350aabff4ddSPeng Tao result->op_status = status; 2351e4f93234SChuck Lever if (status != NFS3_OK) 2352e4f93234SChuck Lever goto out_status; 23532f2c63bcSTrond Myklebust error = decode_writeverf3(xdr, &result->verf->verifier); 2354e4f93234SChuck Lever out: 2355e4f93234SChuck Lever return error; 2356e4f93234SChuck Lever out_status: 23575e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2358e4f93234SChuck Lever } 2359e4f93234SChuck Lever 2360b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 2361b7fa0554SAndreas Gruenbacher 2362e4f93234SChuck Lever static inline int decode_getacl3resok(struct xdr_stream *xdr, 2363264d948cSTrond Myklebust struct nfs3_getaclres *result, 2364264d948cSTrond Myklebust struct user_namespace *userns) 2365e4f93234SChuck Lever { 2366e4f93234SChuck Lever struct posix_acl **acl; 2367e4f93234SChuck Lever unsigned int *aclcnt; 2368e4f93234SChuck Lever size_t hdrlen; 2369e4f93234SChuck Lever int error; 2370e4f93234SChuck Lever 2371264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result->fattr, userns); 2372e4f93234SChuck Lever if (unlikely(error)) 2373e4f93234SChuck Lever goto out; 2374e4f93234SChuck Lever error = decode_uint32(xdr, &result->mask); 2375e4f93234SChuck Lever if (unlikely(error)) 2376e4f93234SChuck Lever goto out; 2377e4f93234SChuck Lever error = -EINVAL; 2378e4f93234SChuck Lever if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 2379e4f93234SChuck Lever goto out; 2380e4f93234SChuck Lever 23811aecca3eSTrond Myklebust hdrlen = xdr_stream_pos(xdr); 2382e4f93234SChuck Lever 2383e4f93234SChuck Lever acl = NULL; 2384e4f93234SChuck Lever if (result->mask & NFS_ACL) 2385e4f93234SChuck Lever acl = &result->acl_access; 2386e4f93234SChuck Lever aclcnt = NULL; 2387e4f93234SChuck Lever if (result->mask & NFS_ACLCNT) 2388e4f93234SChuck Lever aclcnt = &result->acl_access_count; 2389e4f93234SChuck Lever error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl); 2390e4f93234SChuck Lever if (unlikely(error <= 0)) 2391e4f93234SChuck Lever goto out; 2392e4f93234SChuck Lever 2393e4f93234SChuck Lever acl = NULL; 2394e4f93234SChuck Lever if (result->mask & NFS_DFACL) 2395e4f93234SChuck Lever acl = &result->acl_default; 2396e4f93234SChuck Lever aclcnt = NULL; 2397e4f93234SChuck Lever if (result->mask & NFS_DFACLCNT) 2398e4f93234SChuck Lever aclcnt = &result->acl_default_count; 2399e4f93234SChuck Lever error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl); 2400e4f93234SChuck Lever if (unlikely(error <= 0)) 2401e4f93234SChuck Lever return error; 2402e4f93234SChuck Lever error = 0; 2403e4f93234SChuck Lever out: 2404e4f93234SChuck Lever return error; 2405e4f93234SChuck Lever } 2406e4f93234SChuck Lever 2407bf269551SChuck Lever static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req, 2408bf269551SChuck Lever struct xdr_stream *xdr, 2409fc016483SChristoph Hellwig void *result) 2410e4f93234SChuck Lever { 2411e4f93234SChuck Lever enum nfs_stat status; 2412e4f93234SChuck Lever int error; 2413e4f93234SChuck Lever 2414bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2415e4f93234SChuck Lever if (unlikely(error)) 2416e4f93234SChuck Lever goto out; 2417e4f93234SChuck Lever if (status != NFS3_OK) 2418e4f93234SChuck Lever goto out_default; 2419264d948cSTrond Myklebust error = decode_getacl3resok(xdr, result, rpc_rqst_userns(req)); 2420e4f93234SChuck Lever out: 2421e4f93234SChuck Lever return error; 2422e4f93234SChuck Lever out_default: 24235e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2424e4f93234SChuck Lever } 2425e4f93234SChuck Lever 2426bf269551SChuck Lever static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req, 2427bf269551SChuck Lever struct xdr_stream *xdr, 2428fc016483SChristoph Hellwig void *result) 2429e4f93234SChuck Lever { 2430e4f93234SChuck Lever enum nfs_stat status; 2431e4f93234SChuck Lever int error; 2432e4f93234SChuck Lever 2433bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2434e4f93234SChuck Lever if (unlikely(error)) 2435e4f93234SChuck Lever goto out; 2436e4f93234SChuck Lever if (status != NFS3_OK) 2437e4f93234SChuck Lever goto out_default; 2438264d948cSTrond Myklebust error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req)); 2439e4f93234SChuck Lever out: 2440e4f93234SChuck Lever return error; 2441e4f93234SChuck Lever out_default: 24425e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2443e4f93234SChuck Lever } 2444e4f93234SChuck Lever 2445b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 2446b7fa0554SAndreas Gruenbacher 24475e7e5a0dSBryan Schumaker 24485e7e5a0dSBryan Schumaker /* 24495e7e5a0dSBryan Schumaker * We need to translate between nfs status return values and 24505e7e5a0dSBryan Schumaker * the local errno values which may not be the same. 24515e7e5a0dSBryan Schumaker */ 24525e7e5a0dSBryan Schumaker static const struct { 24535e7e5a0dSBryan Schumaker int stat; 24545e7e5a0dSBryan Schumaker int errno; 24555e7e5a0dSBryan Schumaker } nfs_errtbl[] = { 24565e7e5a0dSBryan Schumaker { NFS_OK, 0 }, 24575e7e5a0dSBryan Schumaker { NFSERR_PERM, -EPERM }, 24585e7e5a0dSBryan Schumaker { NFSERR_NOENT, -ENOENT }, 24595e7e5a0dSBryan Schumaker { NFSERR_IO, -errno_NFSERR_IO}, 24605e7e5a0dSBryan Schumaker { NFSERR_NXIO, -ENXIO }, 24615e7e5a0dSBryan Schumaker /* { NFSERR_EAGAIN, -EAGAIN }, */ 24625e7e5a0dSBryan Schumaker { NFSERR_ACCES, -EACCES }, 24635e7e5a0dSBryan Schumaker { NFSERR_EXIST, -EEXIST }, 24645e7e5a0dSBryan Schumaker { NFSERR_XDEV, -EXDEV }, 24655e7e5a0dSBryan Schumaker { NFSERR_NODEV, -ENODEV }, 24665e7e5a0dSBryan Schumaker { NFSERR_NOTDIR, -ENOTDIR }, 24675e7e5a0dSBryan Schumaker { NFSERR_ISDIR, -EISDIR }, 24685e7e5a0dSBryan Schumaker { NFSERR_INVAL, -EINVAL }, 24695e7e5a0dSBryan Schumaker { NFSERR_FBIG, -EFBIG }, 24705e7e5a0dSBryan Schumaker { NFSERR_NOSPC, -ENOSPC }, 24715e7e5a0dSBryan Schumaker { NFSERR_ROFS, -EROFS }, 24725e7e5a0dSBryan Schumaker { NFSERR_MLINK, -EMLINK }, 24735e7e5a0dSBryan Schumaker { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, 24745e7e5a0dSBryan Schumaker { NFSERR_NOTEMPTY, -ENOTEMPTY }, 24755e7e5a0dSBryan Schumaker { NFSERR_DQUOT, -EDQUOT }, 24765e7e5a0dSBryan Schumaker { NFSERR_STALE, -ESTALE }, 24775e7e5a0dSBryan Schumaker { NFSERR_REMOTE, -EREMOTE }, 24785e7e5a0dSBryan Schumaker #ifdef EWFLUSH 24795e7e5a0dSBryan Schumaker { NFSERR_WFLUSH, -EWFLUSH }, 24805e7e5a0dSBryan Schumaker #endif 24815e7e5a0dSBryan Schumaker { NFSERR_BADHANDLE, -EBADHANDLE }, 24825e7e5a0dSBryan Schumaker { NFSERR_NOT_SYNC, -ENOTSYNC }, 24835e7e5a0dSBryan Schumaker { NFSERR_BAD_COOKIE, -EBADCOOKIE }, 24845e7e5a0dSBryan Schumaker { NFSERR_NOTSUPP, -ENOTSUPP }, 24855e7e5a0dSBryan Schumaker { NFSERR_TOOSMALL, -ETOOSMALL }, 24865e7e5a0dSBryan Schumaker { NFSERR_SERVERFAULT, -EREMOTEIO }, 24875e7e5a0dSBryan Schumaker { NFSERR_BADTYPE, -EBADTYPE }, 24885e7e5a0dSBryan Schumaker { NFSERR_JUKEBOX, -EJUKEBOX }, 24895e7e5a0dSBryan Schumaker { -1, -EIO } 24905e7e5a0dSBryan Schumaker }; 24915e7e5a0dSBryan Schumaker 24925e7e5a0dSBryan Schumaker /** 24935e7e5a0dSBryan Schumaker * nfs3_stat_to_errno - convert an NFS status code to a local errno 24945e7e5a0dSBryan Schumaker * @status: NFS status code to convert 24955e7e5a0dSBryan Schumaker * 24965e7e5a0dSBryan Schumaker * Returns a local errno value, or -EIO if the NFS status code is 24975e7e5a0dSBryan Schumaker * not recognized. This function is used jointly by NFSv2 and NFSv3. 24985e7e5a0dSBryan Schumaker */ 24995e7e5a0dSBryan Schumaker static int nfs3_stat_to_errno(enum nfs_stat status) 25005e7e5a0dSBryan Schumaker { 25015e7e5a0dSBryan Schumaker int i; 25025e7e5a0dSBryan Schumaker 25035e7e5a0dSBryan Schumaker for (i = 0; nfs_errtbl[i].stat != -1; i++) { 25045e7e5a0dSBryan Schumaker if (nfs_errtbl[i].stat == (int)status) 25055e7e5a0dSBryan Schumaker return nfs_errtbl[i].errno; 25065e7e5a0dSBryan Schumaker } 25075e7e5a0dSBryan Schumaker dprintk("NFS: Unrecognized nfs status value: %u\n", status); 25085e7e5a0dSBryan Schumaker return nfs_errtbl[i].errno; 25095e7e5a0dSBryan Schumaker } 25105e7e5a0dSBryan Schumaker 25115e7e5a0dSBryan Schumaker 25121da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer) \ 25131da177e4SLinus Torvalds [NFS3PROC_##proc] = { \ 25141da177e4SLinus Torvalds .p_proc = NFS3PROC_##proc, \ 2515fcc85819SChristoph Hellwig .p_encode = nfs3_xdr_enc_##argtype##3args, \ 2516fc016483SChristoph Hellwig .p_decode = nfs3_xdr_dec_##restype##3res, \ 2517ad96b5b5SChuck Lever .p_arglen = NFS3_##argtype##args_sz, \ 2518f5fc3c50SChuck Lever .p_replen = NFS3_##restype##res_sz, \ 2519cc0175c1SChuck Lever .p_timer = timer, \ 2520cc0175c1SChuck Lever .p_statidx = NFS3PROC_##proc, \ 2521cc0175c1SChuck Lever .p_name = #proc, \ 25221da177e4SLinus Torvalds } 25231da177e4SLinus Torvalds 2524511e936bSChristoph Hellwig const struct rpc_procinfo nfs3_procedures[] = { 2525f5fc3c50SChuck Lever PROC(GETATTR, getattr, getattr, 1), 2526f5fc3c50SChuck Lever PROC(SETATTR, setattr, setattr, 0), 2527f5fc3c50SChuck Lever PROC(LOOKUP, lookup, lookup, 2), 2528f5fc3c50SChuck Lever PROC(ACCESS, access, access, 1), 2529f5fc3c50SChuck Lever PROC(READLINK, readlink, readlink, 3), 2530f5fc3c50SChuck Lever PROC(READ, read, read, 3), 2531f5fc3c50SChuck Lever PROC(WRITE, write, write, 4), 2532f5fc3c50SChuck Lever PROC(CREATE, create, create, 0), 2533f5fc3c50SChuck Lever PROC(MKDIR, mkdir, create, 0), 2534f5fc3c50SChuck Lever PROC(SYMLINK, symlink, create, 0), 2535f5fc3c50SChuck Lever PROC(MKNOD, mknod, create, 0), 2536f5fc3c50SChuck Lever PROC(REMOVE, remove, remove, 0), 2537f5fc3c50SChuck Lever PROC(RMDIR, lookup, setattr, 0), 2538f5fc3c50SChuck Lever PROC(RENAME, rename, rename, 0), 2539f5fc3c50SChuck Lever PROC(LINK, link, link, 0), 2540f5fc3c50SChuck Lever PROC(READDIR, readdir, readdir, 3), 2541f5fc3c50SChuck Lever PROC(READDIRPLUS, readdirplus, readdir, 3), 2542f5fc3c50SChuck Lever PROC(FSSTAT, getattr, fsstat, 0), 2543f5fc3c50SChuck Lever PROC(FSINFO, getattr, fsinfo, 0), 2544f5fc3c50SChuck Lever PROC(PATHCONF, getattr, pathconf, 0), 2545f5fc3c50SChuck Lever PROC(COMMIT, commit, commit, 5), 25461da177e4SLinus Torvalds }; 25471da177e4SLinus Torvalds 2548c551858aSChristoph Hellwig static unsigned int nfs_version3_counts[ARRAY_SIZE(nfs3_procedures)]; 2549a613fa16STrond Myklebust const struct rpc_version nfs_version3 = { 25501da177e4SLinus Torvalds .number = 3, 2551e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nfs3_procedures), 2552c551858aSChristoph Hellwig .procs = nfs3_procedures, 2553c551858aSChristoph Hellwig .counts = nfs_version3_counts, 25541da177e4SLinus Torvalds }; 25551da177e4SLinus Torvalds 2556b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 2557511e936bSChristoph Hellwig static const struct rpc_procinfo nfs3_acl_procedures[] = { 2558b7fa0554SAndreas Gruenbacher [ACLPROC3_GETACL] = { 2559b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_GETACL, 2560fcc85819SChristoph Hellwig .p_encode = nfs3_xdr_enc_getacl3args, 2561fc016483SChristoph Hellwig .p_decode = nfs3_xdr_dec_getacl3res, 25622bea90d4SChuck Lever .p_arglen = ACL3_getaclargs_sz, 25632bea90d4SChuck Lever .p_replen = ACL3_getaclres_sz, 2564b7fa0554SAndreas Gruenbacher .p_timer = 1, 2565cc0175c1SChuck Lever .p_name = "GETACL", 2566b7fa0554SAndreas Gruenbacher }, 2567b7fa0554SAndreas Gruenbacher [ACLPROC3_SETACL] = { 2568b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_SETACL, 2569fcc85819SChristoph Hellwig .p_encode = nfs3_xdr_enc_setacl3args, 2570fc016483SChristoph Hellwig .p_decode = nfs3_xdr_dec_setacl3res, 25712bea90d4SChuck Lever .p_arglen = ACL3_setaclargs_sz, 25722bea90d4SChuck Lever .p_replen = ACL3_setaclres_sz, 2573b7fa0554SAndreas Gruenbacher .p_timer = 0, 2574cc0175c1SChuck Lever .p_name = "SETACL", 2575b7fa0554SAndreas Gruenbacher }, 2576b7fa0554SAndreas Gruenbacher }; 2577b7fa0554SAndreas Gruenbacher 2578c551858aSChristoph Hellwig static unsigned int nfs3_acl_counts[ARRAY_SIZE(nfs3_acl_procedures)]; 2579a613fa16STrond Myklebust const struct rpc_version nfsacl_version3 = { 2580b7fa0554SAndreas Gruenbacher .number = 3, 25819ae7d8ffSChristoph Hellwig .nrprocs = ARRAY_SIZE(nfs3_acl_procedures), 2582b7fa0554SAndreas Gruenbacher .procs = nfs3_acl_procedures, 2583c551858aSChristoph Hellwig .counts = nfs3_acl_counts, 2584b7fa0554SAndreas Gruenbacher }; 2585b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 2586