11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/nfs/nfs3xdr.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * XDR functions to encode/decode NFSv3 RPC arguments and results. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1996, 1997 Olaf Kirch 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/param.h> 101da177e4SLinus Torvalds #include <linux/time.h> 111da177e4SLinus Torvalds #include <linux/mm.h> 121da177e4SLinus Torvalds #include <linux/errno.h> 131da177e4SLinus Torvalds #include <linux/string.h> 141da177e4SLinus Torvalds #include <linux/in.h> 151da177e4SLinus Torvalds #include <linux/pagemap.h> 161da177e4SLinus Torvalds #include <linux/proc_fs.h> 171da177e4SLinus Torvalds #include <linux/kdev_t.h> 181da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 191da177e4SLinus Torvalds #include <linux/nfs.h> 201da177e4SLinus Torvalds #include <linux/nfs3.h> 211da177e4SLinus Torvalds #include <linux/nfs_fs.h> 22b7fa0554SAndreas Gruenbacher #include <linux/nfsacl.h> 23f7b422b1SDavid Howells #include "internal.h" 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #define NFSDBG_FACILITY NFSDBG_XDR 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */ 281da177e4SLinus Torvalds #define errno_NFSERR_IO EIO 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* 311da177e4SLinus Torvalds * Declare the space requirements for NFS arguments and replies as 321da177e4SLinus Torvalds * number of 32bit-words 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds #define NFS3_fhandle_sz (1+16) 351da177e4SLinus Torvalds #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */ 361da177e4SLinus Torvalds #define NFS3_sattr_sz (15) 371da177e4SLinus Torvalds #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2)) 381da177e4SLinus Torvalds #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2)) 391da177e4SLinus Torvalds #define NFS3_fattr_sz (21) 40d9c407b1SChuck Lever #define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2) 411da177e4SLinus Torvalds #define NFS3_wcc_attr_sz (6) 421da177e4SLinus Torvalds #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz) 431da177e4SLinus Torvalds #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz) 441da177e4SLinus Torvalds #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz) 451da177e4SLinus Torvalds #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz) 46ad96b5b5SChuck Lever 47ad96b5b5SChuck Lever #define NFS3_getattrargs_sz (NFS3_fh_sz) 48ad96b5b5SChuck Lever #define NFS3_setattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3) 49ad96b5b5SChuck Lever #define NFS3_lookupargs_sz (NFS3_fh_sz+NFS3_filename_sz) 501da177e4SLinus Torvalds #define NFS3_accessargs_sz (NFS3_fh_sz+1) 511da177e4SLinus Torvalds #define NFS3_readlinkargs_sz (NFS3_fh_sz) 521da177e4SLinus Torvalds #define NFS3_readargs_sz (NFS3_fh_sz+3) 531da177e4SLinus Torvalds #define NFS3_writeargs_sz (NFS3_fh_sz+5) 541da177e4SLinus Torvalds #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 551da177e4SLinus Torvalds #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 5694a6d753SChuck Lever #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz) 571da177e4SLinus Torvalds #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) 58ad96b5b5SChuck Lever #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz) 591da177e4SLinus Torvalds #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) 601da177e4SLinus Torvalds #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) 61d9c407b1SChuck Lever #define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3) 62d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4) 631da177e4SLinus Torvalds #define NFS3_commitargs_sz (NFS3_fh_sz+3) 641da177e4SLinus Torvalds 65f5fc3c50SChuck Lever #define NFS3_getattrres_sz (1+NFS3_fattr_sz) 66f5fc3c50SChuck Lever #define NFS3_setattrres_sz (1+NFS3_wcc_data_sz) 67f5fc3c50SChuck Lever #define NFS3_removeres_sz (NFS3_setattrres_sz) 681da177e4SLinus Torvalds #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) 691da177e4SLinus Torvalds #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) 701da177e4SLinus Torvalds #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1) 711da177e4SLinus Torvalds #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3) 721da177e4SLinus Torvalds #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4) 731da177e4SLinus Torvalds #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 741da177e4SLinus Torvalds #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz)) 751da177e4SLinus Torvalds #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) 761da177e4SLinus Torvalds #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2) 771da177e4SLinus Torvalds #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13) 781da177e4SLinus Torvalds #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12) 791da177e4SLinus Torvalds #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) 801da177e4SLinus Torvalds #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) 811da177e4SLinus Torvalds 82b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz (NFS3_fh_sz+1) 83ae46141fSTrond Myklebust #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \ 84ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 85ae46141fSTrond Myklebust #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \ 86ae46141fSTrond Myklebust XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) 87b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) 88b7fa0554SAndreas Gruenbacher 895e7e5a0dSBryan Schumaker static int nfs3_stat_to_errno(enum nfs_stat); 905e7e5a0dSBryan Schumaker 911da177e4SLinus Torvalds /* 921da177e4SLinus Torvalds * Map file type to S_IFMT bits 931da177e4SLinus Torvalds */ 94bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = { 95bca79478STrond Myklebust [NF3BAD] = 0, 96bca79478STrond Myklebust [NF3REG] = S_IFREG, 97bca79478STrond Myklebust [NF3DIR] = S_IFDIR, 98bca79478STrond Myklebust [NF3BLK] = S_IFBLK, 99bca79478STrond Myklebust [NF3CHR] = S_IFCHR, 100bca79478STrond Myklebust [NF3LNK] = S_IFLNK, 101bca79478STrond Myklebust [NF3SOCK] = S_IFSOCK, 102bca79478STrond Myklebust [NF3FIFO] = S_IFIFO, 1031da177e4SLinus Torvalds }; 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* 106d9c407b1SChuck Lever * While encoding arguments, set up the reply buffer in advance to 107d9c407b1SChuck Lever * receive reply data directly into the page cache. 108d9c407b1SChuck Lever */ 109d9c407b1SChuck Lever static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages, 110d9c407b1SChuck Lever unsigned int base, unsigned int len, 111d9c407b1SChuck Lever unsigned int bufsize) 112d9c407b1SChuck Lever { 113d9c407b1SChuck Lever struct rpc_auth *auth = req->rq_cred->cr_auth; 114d9c407b1SChuck Lever unsigned int replen; 115d9c407b1SChuck Lever 116d9c407b1SChuck Lever replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize; 117d9c407b1SChuck Lever xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len); 118d9c407b1SChuck Lever } 119d9c407b1SChuck Lever 120e4f93234SChuck Lever /* 121e4f93234SChuck Lever * Handle decode buffer overflows out-of-line. 122e4f93234SChuck Lever */ 123e4f93234SChuck Lever static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 124e4f93234SChuck Lever { 125e4f93234SChuck Lever dprintk("NFS: %s prematurely hit the end of our receive buffer. " 126e4f93234SChuck Lever "Remaining buffer length is %tu words.\n", 127e4f93234SChuck Lever func, xdr->end - xdr->p); 128e4f93234SChuck Lever } 129e4f93234SChuck Lever 130d9c407b1SChuck Lever 131d9c407b1SChuck Lever /* 132d9c407b1SChuck Lever * Encode/decode NFSv3 basic data types 133d9c407b1SChuck Lever * 134d9c407b1SChuck Lever * Basic NFSv3 data types are defined in section 2.5 of RFC 1813: 135d9c407b1SChuck Lever * "NFS Version 3 Protocol Specification". 136d9c407b1SChuck Lever * 137d9c407b1SChuck Lever * Not all basic data types have their own encoding and decoding 138d9c407b1SChuck Lever * functions. For run-time efficiency, some data types are encoded 139d9c407b1SChuck Lever * or decoded inline. 140d9c407b1SChuck Lever */ 141d9c407b1SChuck Lever 142d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value) 143d9c407b1SChuck Lever { 144d9c407b1SChuck Lever __be32 *p = xdr_reserve_space(xdr, 4); 145d9c407b1SChuck Lever *p = cpu_to_be32(value); 146d9c407b1SChuck Lever } 147d9c407b1SChuck Lever 148e4f93234SChuck Lever static int decode_uint32(struct xdr_stream *xdr, u32 *value) 149e4f93234SChuck Lever { 150e4f93234SChuck Lever __be32 *p; 151e4f93234SChuck Lever 152e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 153e4f93234SChuck Lever if (unlikely(p == NULL)) 154e4f93234SChuck Lever goto out_overflow; 155e4f93234SChuck Lever *value = be32_to_cpup(p); 156e4f93234SChuck Lever return 0; 157e4f93234SChuck Lever out_overflow: 158e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 159e4f93234SChuck Lever return -EIO; 160e4f93234SChuck Lever } 161e4f93234SChuck Lever 162e4f93234SChuck Lever static int decode_uint64(struct xdr_stream *xdr, u64 *value) 163e4f93234SChuck Lever { 164e4f93234SChuck Lever __be32 *p; 165e4f93234SChuck Lever 166e4f93234SChuck Lever p = xdr_inline_decode(xdr, 8); 167e4f93234SChuck Lever if (unlikely(p == NULL)) 168e4f93234SChuck Lever goto out_overflow; 169e4f93234SChuck Lever xdr_decode_hyper(p, value); 170e4f93234SChuck Lever return 0; 171e4f93234SChuck Lever out_overflow: 172e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 173e4f93234SChuck Lever return -EIO; 174e4f93234SChuck Lever } 175e4f93234SChuck Lever 176e4f93234SChuck Lever /* 177e4f93234SChuck Lever * fileid3 178e4f93234SChuck Lever * 179e4f93234SChuck Lever * typedef uint64 fileid3; 180e4f93234SChuck Lever */ 181f6048709SChuck Lever static __be32 *xdr_decode_fileid3(__be32 *p, u64 *fileid) 182f6048709SChuck Lever { 183f6048709SChuck Lever return xdr_decode_hyper(p, fileid); 184f6048709SChuck Lever } 185f6048709SChuck Lever 186e4f93234SChuck Lever static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid) 187e4f93234SChuck Lever { 188e4f93234SChuck Lever return decode_uint64(xdr, fileid); 189e4f93234SChuck Lever } 190e4f93234SChuck Lever 191d9c407b1SChuck Lever /* 192d9c407b1SChuck Lever * filename3 193d9c407b1SChuck Lever * 194d9c407b1SChuck Lever * typedef string filename3<>; 195d9c407b1SChuck Lever */ 196d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr, 197d9c407b1SChuck Lever const char *name, u32 length) 198d9c407b1SChuck Lever { 199d9c407b1SChuck Lever __be32 *p; 200d9c407b1SChuck Lever 201d9c407b1SChuck Lever BUG_ON(length > NFS3_MAXNAMLEN); 202d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + length); 203d9c407b1SChuck Lever xdr_encode_opaque(p, name, length); 204d9c407b1SChuck Lever } 205d9c407b1SChuck Lever 206e4f93234SChuck Lever static int decode_inline_filename3(struct xdr_stream *xdr, 207e4f93234SChuck Lever const char **name, u32 *length) 208e4f93234SChuck Lever { 209e4f93234SChuck Lever __be32 *p; 210e4f93234SChuck Lever u32 count; 211e4f93234SChuck Lever 212e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 213e4f93234SChuck Lever if (unlikely(p == NULL)) 214e4f93234SChuck Lever goto out_overflow; 215e4f93234SChuck Lever count = be32_to_cpup(p); 216e4f93234SChuck Lever if (count > NFS3_MAXNAMLEN) 217e4f93234SChuck Lever goto out_nametoolong; 218e4f93234SChuck Lever p = xdr_inline_decode(xdr, count); 219e4f93234SChuck Lever if (unlikely(p == NULL)) 220e4f93234SChuck Lever goto out_overflow; 221e4f93234SChuck Lever *name = (const char *)p; 222e4f93234SChuck Lever *length = count; 223e4f93234SChuck Lever return 0; 224e4f93234SChuck Lever 225e4f93234SChuck Lever out_nametoolong: 226e4f93234SChuck Lever dprintk("NFS: returned filename too long: %u\n", count); 227e4f93234SChuck Lever return -ENAMETOOLONG; 228e4f93234SChuck Lever out_overflow: 229e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 230e4f93234SChuck Lever return -EIO; 231e4f93234SChuck Lever } 232e4f93234SChuck Lever 233d9c407b1SChuck Lever /* 234d9c407b1SChuck Lever * nfspath3 235d9c407b1SChuck Lever * 236d9c407b1SChuck Lever * typedef string nfspath3<>; 237d9c407b1SChuck Lever */ 238d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages, 239d9c407b1SChuck Lever const u32 length) 240d9c407b1SChuck Lever { 241d9c407b1SChuck Lever BUG_ON(length > NFS3_MAXPATHLEN); 242d9c407b1SChuck Lever encode_uint32(xdr, length); 243d9c407b1SChuck Lever xdr_write_pages(xdr, pages, 0, length); 244d9c407b1SChuck Lever } 245d9c407b1SChuck Lever 246e4f93234SChuck Lever static int decode_nfspath3(struct xdr_stream *xdr) 247e4f93234SChuck Lever { 248e4f93234SChuck Lever u32 recvd, count; 249e4f93234SChuck Lever size_t hdrlen; 250e4f93234SChuck Lever __be32 *p; 251e4f93234SChuck Lever 252e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 253e4f93234SChuck Lever if (unlikely(p == NULL)) 254e4f93234SChuck Lever goto out_overflow; 255e4f93234SChuck Lever count = be32_to_cpup(p); 256e4f93234SChuck Lever if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN)) 257e4f93234SChuck Lever goto out_nametoolong; 258e4f93234SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 259e4f93234SChuck Lever recvd = xdr->buf->len - hdrlen; 260e4f93234SChuck Lever if (unlikely(count > recvd)) 261e4f93234SChuck Lever goto out_cheating; 262e4f93234SChuck Lever 263e4f93234SChuck Lever xdr_read_pages(xdr, count); 264e4f93234SChuck Lever xdr_terminate_string(xdr->buf, count); 265e4f93234SChuck Lever return 0; 266e4f93234SChuck Lever 267e4f93234SChuck Lever out_nametoolong: 268e4f93234SChuck Lever dprintk("NFS: returned pathname too long: %u\n", count); 269e4f93234SChuck Lever return -ENAMETOOLONG; 270e4f93234SChuck Lever out_cheating: 271e4f93234SChuck Lever dprintk("NFS: server cheating in pathname result: " 272e4f93234SChuck Lever "count %u > recvd %u\n", count, recvd); 273e4f93234SChuck Lever return -EIO; 274e4f93234SChuck Lever out_overflow: 275e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 276e4f93234SChuck Lever return -EIO; 277e4f93234SChuck Lever } 278e4f93234SChuck Lever 279d9c407b1SChuck Lever /* 280d9c407b1SChuck Lever * cookie3 281d9c407b1SChuck Lever * 282d9c407b1SChuck Lever * typedef uint64 cookie3 283d9c407b1SChuck Lever */ 284d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie) 285d9c407b1SChuck Lever { 286d9c407b1SChuck Lever return xdr_encode_hyper(p, cookie); 287d9c407b1SChuck Lever } 288d9c407b1SChuck Lever 289e4f93234SChuck Lever static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie) 290e4f93234SChuck Lever { 291e4f93234SChuck Lever return decode_uint64(xdr, cookie); 292e4f93234SChuck Lever } 293e4f93234SChuck Lever 294d9c407b1SChuck Lever /* 295d9c407b1SChuck Lever * cookieverf3 296d9c407b1SChuck Lever * 297d9c407b1SChuck Lever * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE]; 298d9c407b1SChuck Lever */ 299d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier) 300d9c407b1SChuck Lever { 301d9c407b1SChuck Lever memcpy(p, verifier, NFS3_COOKIEVERFSIZE); 302d9c407b1SChuck Lever return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE); 303d9c407b1SChuck Lever } 304d9c407b1SChuck Lever 305e4f93234SChuck Lever static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier) 306e4f93234SChuck Lever { 307e4f93234SChuck Lever __be32 *p; 308e4f93234SChuck Lever 309e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); 310e4f93234SChuck Lever if (unlikely(p == NULL)) 311e4f93234SChuck Lever goto out_overflow; 312e4f93234SChuck Lever memcpy(verifier, p, NFS3_COOKIEVERFSIZE); 313e4f93234SChuck Lever return 0; 314e4f93234SChuck Lever out_overflow: 315e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 316e4f93234SChuck Lever return -EIO; 317e4f93234SChuck Lever } 318e4f93234SChuck Lever 319d9c407b1SChuck Lever /* 320d9c407b1SChuck Lever * createverf3 321d9c407b1SChuck Lever * 322d9c407b1SChuck Lever * typedef opaque createverf3[NFS3_CREATEVERFSIZE]; 323d9c407b1SChuck Lever */ 324d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier) 325d9c407b1SChuck Lever { 326d9c407b1SChuck Lever __be32 *p; 327d9c407b1SChuck Lever 328d9c407b1SChuck Lever p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE); 329d9c407b1SChuck Lever memcpy(p, verifier, NFS3_CREATEVERFSIZE); 330d9c407b1SChuck Lever } 331d9c407b1SChuck Lever 332e4f93234SChuck Lever static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier) 333e4f93234SChuck Lever { 334e4f93234SChuck Lever __be32 *p; 335e4f93234SChuck Lever 336e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE); 337e4f93234SChuck Lever if (unlikely(p == NULL)) 338e4f93234SChuck Lever goto out_overflow; 339e4f93234SChuck Lever memcpy(verifier, p, NFS3_WRITEVERFSIZE); 340e4f93234SChuck Lever return 0; 341e4f93234SChuck Lever out_overflow: 342e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 343e4f93234SChuck Lever return -EIO; 344e4f93234SChuck Lever } 345e4f93234SChuck Lever 346e4f93234SChuck Lever /* 347e4f93234SChuck Lever * size3 348e4f93234SChuck Lever * 349e4f93234SChuck Lever * typedef uint64 size3; 350e4f93234SChuck Lever */ 351e4f93234SChuck Lever static __be32 *xdr_decode_size3(__be32 *p, u64 *size) 352e4f93234SChuck Lever { 353e4f93234SChuck Lever return xdr_decode_hyper(p, size); 354e4f93234SChuck Lever } 355e4f93234SChuck Lever 356e4f93234SChuck Lever /* 357e4f93234SChuck Lever * nfsstat3 358e4f93234SChuck Lever * 359e4f93234SChuck Lever * enum nfsstat3 { 360e4f93234SChuck Lever * NFS3_OK = 0, 361e4f93234SChuck Lever * ... 362e4f93234SChuck Lever * } 363e4f93234SChuck Lever */ 364e4f93234SChuck Lever #define NFS3_OK NFS_OK 365e4f93234SChuck Lever 366e4f93234SChuck Lever static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status) 367e4f93234SChuck Lever { 368e4f93234SChuck Lever __be32 *p; 369e4f93234SChuck Lever 370e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 371e4f93234SChuck Lever if (unlikely(p == NULL)) 372e4f93234SChuck Lever goto out_overflow; 373e4f93234SChuck Lever *status = be32_to_cpup(p); 374e4f93234SChuck Lever return 0; 375e4f93234SChuck Lever out_overflow: 376e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 377e4f93234SChuck Lever return -EIO; 378e4f93234SChuck Lever } 379e4f93234SChuck Lever 380d9c407b1SChuck Lever /* 381d9c407b1SChuck Lever * ftype3 382d9c407b1SChuck Lever * 383d9c407b1SChuck Lever * enum ftype3 { 384d9c407b1SChuck Lever * NF3REG = 1, 385d9c407b1SChuck Lever * NF3DIR = 2, 386d9c407b1SChuck Lever * NF3BLK = 3, 387d9c407b1SChuck Lever * NF3CHR = 4, 388d9c407b1SChuck Lever * NF3LNK = 5, 389d9c407b1SChuck Lever * NF3SOCK = 6, 390d9c407b1SChuck Lever * NF3FIFO = 7 391d9c407b1SChuck Lever * }; 392d9c407b1SChuck Lever */ 393d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type) 394d9c407b1SChuck Lever { 395d9c407b1SChuck Lever BUG_ON(type > NF3FIFO); 396d9c407b1SChuck Lever encode_uint32(xdr, type); 397d9c407b1SChuck Lever } 398d9c407b1SChuck Lever 399f6048709SChuck Lever static __be32 *xdr_decode_ftype3(__be32 *p, umode_t *mode) 400f6048709SChuck Lever { 401f6048709SChuck Lever u32 type; 402f6048709SChuck Lever 403f6048709SChuck Lever type = be32_to_cpup(p++); 404f6048709SChuck Lever if (type > NF3FIFO) 405f6048709SChuck Lever type = NF3NON; 406f6048709SChuck Lever *mode = nfs_type2fmt[type]; 407f6048709SChuck Lever return p; 408f6048709SChuck Lever } 409f6048709SChuck Lever 410d9c407b1SChuck Lever /* 411d9c407b1SChuck Lever * specdata3 412d9c407b1SChuck Lever * 413d9c407b1SChuck Lever * struct specdata3 { 414d9c407b1SChuck Lever * uint32 specdata1; 415d9c407b1SChuck Lever * uint32 specdata2; 416d9c407b1SChuck Lever * }; 417d9c407b1SChuck Lever */ 418d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev) 419d9c407b1SChuck Lever { 420d9c407b1SChuck Lever __be32 *p; 421d9c407b1SChuck Lever 422d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8); 423d9c407b1SChuck Lever *p++ = cpu_to_be32(MAJOR(rdev)); 424d9c407b1SChuck Lever *p = cpu_to_be32(MINOR(rdev)); 425d9c407b1SChuck Lever } 426d9c407b1SChuck Lever 427f6048709SChuck Lever static __be32 *xdr_decode_specdata3(__be32 *p, dev_t *rdev) 428f6048709SChuck Lever { 429f6048709SChuck Lever unsigned int major, minor; 430f6048709SChuck Lever 431f6048709SChuck Lever major = be32_to_cpup(p++); 432f6048709SChuck Lever minor = be32_to_cpup(p++); 433f6048709SChuck Lever *rdev = MKDEV(major, minor); 434f6048709SChuck Lever if (MAJOR(*rdev) != major || MINOR(*rdev) != minor) 435f6048709SChuck Lever *rdev = 0; 436f6048709SChuck Lever return p; 437f6048709SChuck Lever } 438f6048709SChuck Lever 439d9c407b1SChuck Lever /* 440d9c407b1SChuck Lever * nfs_fh3 441d9c407b1SChuck Lever * 442d9c407b1SChuck Lever * struct nfs_fh3 { 443d9c407b1SChuck Lever * opaque data<NFS3_FHSIZE>; 444d9c407b1SChuck Lever * }; 445d9c407b1SChuck Lever */ 446d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh) 447d9c407b1SChuck Lever { 448d9c407b1SChuck Lever __be32 *p; 449d9c407b1SChuck Lever 450d9c407b1SChuck Lever BUG_ON(fh->size > NFS3_FHSIZE); 451d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + fh->size); 452d9c407b1SChuck Lever xdr_encode_opaque(p, fh->data, fh->size); 453d9c407b1SChuck Lever } 454d9c407b1SChuck Lever 455e4f93234SChuck Lever static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) 456e4f93234SChuck Lever { 457e4f93234SChuck Lever u32 length; 458e4f93234SChuck Lever __be32 *p; 459e4f93234SChuck Lever 460e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 461e4f93234SChuck Lever if (unlikely(p == NULL)) 462e4f93234SChuck Lever goto out_overflow; 463e4f93234SChuck Lever length = be32_to_cpup(p++); 464e4f93234SChuck Lever if (unlikely(length > NFS3_FHSIZE)) 465e4f93234SChuck Lever goto out_toobig; 466e4f93234SChuck Lever p = xdr_inline_decode(xdr, length); 467e4f93234SChuck Lever if (unlikely(p == NULL)) 468e4f93234SChuck Lever goto out_overflow; 469e4f93234SChuck Lever fh->size = length; 470e4f93234SChuck Lever memcpy(fh->data, p, length); 471e4f93234SChuck Lever return 0; 472e4f93234SChuck Lever out_toobig: 473e4f93234SChuck Lever dprintk("NFS: file handle size (%u) too big\n", length); 474e4f93234SChuck Lever return -E2BIG; 475e4f93234SChuck Lever out_overflow: 476e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 477e4f93234SChuck Lever return -EIO; 478e4f93234SChuck Lever } 479e4f93234SChuck Lever 480e4f93234SChuck Lever static void zero_nfs_fh3(struct nfs_fh *fh) 481e4f93234SChuck Lever { 482e4f93234SChuck Lever memset(fh, 0, sizeof(*fh)); 483e4f93234SChuck Lever } 484e4f93234SChuck Lever 485d9c407b1SChuck Lever /* 4869d5a6434SChuck Lever * nfstime3 4879d5a6434SChuck Lever * 4889d5a6434SChuck Lever * struct nfstime3 { 4899d5a6434SChuck Lever * uint32 seconds; 4909d5a6434SChuck Lever * uint32 nseconds; 4919d5a6434SChuck Lever * }; 4929d5a6434SChuck Lever */ 4939d5a6434SChuck Lever static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep) 4949d5a6434SChuck Lever { 4959d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_sec); 4969d5a6434SChuck Lever *p++ = cpu_to_be32(timep->tv_nsec); 4979d5a6434SChuck Lever return p; 4989d5a6434SChuck Lever } 4999d5a6434SChuck Lever 500f6048709SChuck Lever static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec *timep) 501f6048709SChuck Lever { 502f6048709SChuck Lever timep->tv_sec = be32_to_cpup(p++); 503f6048709SChuck Lever timep->tv_nsec = be32_to_cpup(p++); 504f6048709SChuck Lever return p; 505f6048709SChuck Lever } 506f6048709SChuck Lever 5079d5a6434SChuck Lever /* 508d9c407b1SChuck Lever * sattr3 509d9c407b1SChuck Lever * 510d9c407b1SChuck Lever * enum time_how { 511d9c407b1SChuck Lever * DONT_CHANGE = 0, 512d9c407b1SChuck Lever * SET_TO_SERVER_TIME = 1, 513d9c407b1SChuck Lever * SET_TO_CLIENT_TIME = 2 514d9c407b1SChuck Lever * }; 515d9c407b1SChuck Lever * 516d9c407b1SChuck Lever * union set_mode3 switch (bool set_it) { 517d9c407b1SChuck Lever * case TRUE: 518d9c407b1SChuck Lever * mode3 mode; 519d9c407b1SChuck Lever * default: 520d9c407b1SChuck Lever * void; 521d9c407b1SChuck Lever * }; 522d9c407b1SChuck Lever * 523d9c407b1SChuck Lever * union set_uid3 switch (bool set_it) { 524d9c407b1SChuck Lever * case TRUE: 525d9c407b1SChuck Lever * uid3 uid; 526d9c407b1SChuck Lever * default: 527d9c407b1SChuck Lever * void; 528d9c407b1SChuck Lever * }; 529d9c407b1SChuck Lever * 530d9c407b1SChuck Lever * union set_gid3 switch (bool set_it) { 531d9c407b1SChuck Lever * case TRUE: 532d9c407b1SChuck Lever * gid3 gid; 533d9c407b1SChuck Lever * default: 534d9c407b1SChuck Lever * void; 535d9c407b1SChuck Lever * }; 536d9c407b1SChuck Lever * 537d9c407b1SChuck Lever * union set_size3 switch (bool set_it) { 538d9c407b1SChuck Lever * case TRUE: 539d9c407b1SChuck Lever * size3 size; 540d9c407b1SChuck Lever * default: 541d9c407b1SChuck Lever * void; 542d9c407b1SChuck Lever * }; 543d9c407b1SChuck Lever * 544d9c407b1SChuck Lever * union set_atime switch (time_how set_it) { 545d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 546d9c407b1SChuck Lever * nfstime3 atime; 547d9c407b1SChuck Lever * default: 548d9c407b1SChuck Lever * void; 549d9c407b1SChuck Lever * }; 550d9c407b1SChuck Lever * 551d9c407b1SChuck Lever * union set_mtime switch (time_how set_it) { 552d9c407b1SChuck Lever * case SET_TO_CLIENT_TIME: 553d9c407b1SChuck Lever * nfstime3 mtime; 554d9c407b1SChuck Lever * default: 555d9c407b1SChuck Lever * void; 556d9c407b1SChuck Lever * }; 557d9c407b1SChuck Lever * 558d9c407b1SChuck Lever * struct sattr3 { 559d9c407b1SChuck Lever * set_mode3 mode; 560d9c407b1SChuck Lever * set_uid3 uid; 561d9c407b1SChuck Lever * set_gid3 gid; 562d9c407b1SChuck Lever * set_size3 size; 563d9c407b1SChuck Lever * set_atime atime; 564d9c407b1SChuck Lever * set_mtime mtime; 565d9c407b1SChuck Lever * }; 566d9c407b1SChuck Lever */ 567d9c407b1SChuck Lever static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr) 568d9c407b1SChuck Lever { 569d9c407b1SChuck Lever u32 nbytes; 570d9c407b1SChuck Lever __be32 *p; 571d9c407b1SChuck Lever 572d9c407b1SChuck Lever /* 573d9c407b1SChuck Lever * In order to make only a single xdr_reserve_space() call, 574d9c407b1SChuck Lever * pre-compute the total number of bytes to be reserved. 575d9c407b1SChuck Lever * Six boolean values, one for each set_foo field, are always 576d9c407b1SChuck Lever * present in the encoded result, so start there. 577d9c407b1SChuck Lever */ 578d9c407b1SChuck Lever nbytes = 6 * 4; 579d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MODE) 580d9c407b1SChuck Lever nbytes += 4; 581d9c407b1SChuck Lever if (attr->ia_valid & ATTR_UID) 582d9c407b1SChuck Lever nbytes += 4; 583d9c407b1SChuck Lever if (attr->ia_valid & ATTR_GID) 584d9c407b1SChuck Lever nbytes += 4; 585d9c407b1SChuck Lever if (attr->ia_valid & ATTR_SIZE) 586d9c407b1SChuck Lever nbytes += 8; 587d9c407b1SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) 588d9c407b1SChuck Lever nbytes += 8; 589d9c407b1SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) 590d9c407b1SChuck Lever nbytes += 8; 591d9c407b1SChuck Lever p = xdr_reserve_space(xdr, nbytes); 592d9c407b1SChuck Lever 5939d5a6434SChuck Lever if (attr->ia_valid & ATTR_MODE) { 5949d5a6434SChuck Lever *p++ = xdr_one; 5959d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO); 5969d5a6434SChuck Lever } else 5979d5a6434SChuck Lever *p++ = xdr_zero; 5989d5a6434SChuck Lever 5999d5a6434SChuck Lever if (attr->ia_valid & ATTR_UID) { 6009d5a6434SChuck Lever *p++ = xdr_one; 6019d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_uid); 6029d5a6434SChuck Lever } else 6039d5a6434SChuck Lever *p++ = xdr_zero; 6049d5a6434SChuck Lever 6059d5a6434SChuck Lever if (attr->ia_valid & ATTR_GID) { 6069d5a6434SChuck Lever *p++ = xdr_one; 6079d5a6434SChuck Lever *p++ = cpu_to_be32(attr->ia_gid); 6089d5a6434SChuck Lever } else 6099d5a6434SChuck Lever *p++ = xdr_zero; 6109d5a6434SChuck Lever 6119d5a6434SChuck Lever if (attr->ia_valid & ATTR_SIZE) { 6129d5a6434SChuck Lever *p++ = xdr_one; 6139d5a6434SChuck Lever p = xdr_encode_hyper(p, (u64)attr->ia_size); 6149d5a6434SChuck Lever } else 6159d5a6434SChuck Lever *p++ = xdr_zero; 6169d5a6434SChuck Lever 6179d5a6434SChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) { 6189d5a6434SChuck Lever *p++ = xdr_two; 6199d5a6434SChuck Lever p = xdr_encode_nfstime3(p, &attr->ia_atime); 6209d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_ATIME) { 6219d5a6434SChuck Lever *p++ = xdr_one; 6229d5a6434SChuck Lever } else 6239d5a6434SChuck Lever *p++ = xdr_zero; 6249d5a6434SChuck Lever 6259d5a6434SChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) { 6269d5a6434SChuck Lever *p++ = xdr_two; 6279d5a6434SChuck Lever xdr_encode_nfstime3(p, &attr->ia_mtime); 6289d5a6434SChuck Lever } else if (attr->ia_valid & ATTR_MTIME) { 6299d5a6434SChuck Lever *p = xdr_one; 6309d5a6434SChuck Lever } else 6319d5a6434SChuck Lever *p = xdr_zero; 632d9c407b1SChuck Lever } 633d9c407b1SChuck Lever 634d9c407b1SChuck Lever /* 635e4f93234SChuck Lever * fattr3 636e4f93234SChuck Lever * 637e4f93234SChuck Lever * struct fattr3 { 638e4f93234SChuck Lever * ftype3 type; 639e4f93234SChuck Lever * mode3 mode; 640e4f93234SChuck Lever * uint32 nlink; 641e4f93234SChuck Lever * uid3 uid; 642e4f93234SChuck Lever * gid3 gid; 643e4f93234SChuck Lever * size3 size; 644e4f93234SChuck Lever * size3 used; 645e4f93234SChuck Lever * specdata3 rdev; 646e4f93234SChuck Lever * uint64 fsid; 647e4f93234SChuck Lever * fileid3 fileid; 648e4f93234SChuck Lever * nfstime3 atime; 649e4f93234SChuck Lever * nfstime3 mtime; 650e4f93234SChuck Lever * nfstime3 ctime; 651e4f93234SChuck Lever * }; 652e4f93234SChuck Lever */ 653e4f93234SChuck Lever static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr) 654e4f93234SChuck Lever { 655f6048709SChuck Lever umode_t fmode; 656e4f93234SChuck Lever __be32 *p; 657e4f93234SChuck Lever 658e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2); 659e4f93234SChuck Lever if (unlikely(p == NULL)) 660e4f93234SChuck Lever goto out_overflow; 661f6048709SChuck Lever 662f6048709SChuck Lever p = xdr_decode_ftype3(p, &fmode); 663f6048709SChuck Lever 664f6048709SChuck Lever fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode; 665f6048709SChuck Lever fattr->nlink = be32_to_cpup(p++); 666f6048709SChuck Lever fattr->uid = be32_to_cpup(p++); 667f6048709SChuck Lever fattr->gid = be32_to_cpup(p++); 668f6048709SChuck Lever 669f6048709SChuck Lever p = xdr_decode_size3(p, &fattr->size); 670f6048709SChuck Lever p = xdr_decode_size3(p, &fattr->du.nfs3.used); 671f6048709SChuck Lever p = xdr_decode_specdata3(p, &fattr->rdev); 672f6048709SChuck Lever 673f6048709SChuck Lever p = xdr_decode_hyper(p, &fattr->fsid.major); 674f6048709SChuck Lever fattr->fsid.minor = 0; 675f6048709SChuck Lever 676f6048709SChuck Lever p = xdr_decode_fileid3(p, &fattr->fileid); 677f6048709SChuck Lever p = xdr_decode_nfstime3(p, &fattr->atime); 678f6048709SChuck Lever p = xdr_decode_nfstime3(p, &fattr->mtime); 679f6048709SChuck Lever xdr_decode_nfstime3(p, &fattr->ctime); 6803a1556e8STrond Myklebust fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime); 681f6048709SChuck Lever 682f6048709SChuck Lever fattr->valid |= NFS_ATTR_FATTR_V3; 683e4f93234SChuck Lever return 0; 684e4f93234SChuck Lever out_overflow: 685e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 686e4f93234SChuck Lever return -EIO; 687e4f93234SChuck Lever } 688e4f93234SChuck Lever 689e4f93234SChuck Lever /* 690e4f93234SChuck Lever * post_op_attr 691e4f93234SChuck Lever * 692e4f93234SChuck Lever * union post_op_attr switch (bool attributes_follow) { 693e4f93234SChuck Lever * case TRUE: 694e4f93234SChuck Lever * fattr3 attributes; 695e4f93234SChuck Lever * case FALSE: 696e4f93234SChuck Lever * void; 697e4f93234SChuck Lever * }; 698e4f93234SChuck Lever */ 699e4f93234SChuck Lever static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 700e4f93234SChuck Lever { 701e4f93234SChuck Lever __be32 *p; 702e4f93234SChuck Lever 703e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 704e4f93234SChuck Lever if (unlikely(p == NULL)) 705e4f93234SChuck Lever goto out_overflow; 706e4f93234SChuck Lever if (*p != xdr_zero) 707e4f93234SChuck Lever return decode_fattr3(xdr, fattr); 708e4f93234SChuck Lever return 0; 709e4f93234SChuck Lever out_overflow: 710e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 711e4f93234SChuck Lever return -EIO; 712e4f93234SChuck Lever } 713e4f93234SChuck Lever 714e4f93234SChuck Lever /* 715e4f93234SChuck Lever * wcc_attr 716e4f93234SChuck Lever * struct wcc_attr { 717e4f93234SChuck Lever * size3 size; 718e4f93234SChuck Lever * nfstime3 mtime; 719e4f93234SChuck Lever * nfstime3 ctime; 720e4f93234SChuck Lever * }; 721e4f93234SChuck Lever */ 722e4f93234SChuck Lever static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 723e4f93234SChuck Lever { 724e4f93234SChuck Lever __be32 *p; 725e4f93234SChuck Lever 726e4f93234SChuck Lever p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2); 727e4f93234SChuck Lever if (unlikely(p == NULL)) 728e4f93234SChuck Lever goto out_overflow; 729f6048709SChuck Lever 730f6048709SChuck Lever fattr->valid |= NFS_ATTR_FATTR_PRESIZE 7313a1556e8STrond Myklebust | NFS_ATTR_FATTR_PRECHANGE 732f6048709SChuck Lever | NFS_ATTR_FATTR_PREMTIME 733f6048709SChuck Lever | NFS_ATTR_FATTR_PRECTIME; 734f6048709SChuck Lever 735f6048709SChuck Lever p = xdr_decode_size3(p, &fattr->pre_size); 736f6048709SChuck Lever p = xdr_decode_nfstime3(p, &fattr->pre_mtime); 737f6048709SChuck Lever xdr_decode_nfstime3(p, &fattr->pre_ctime); 7383a1556e8STrond Myklebust fattr->pre_change_attr = nfs_timespec_to_change_attr(&fattr->pre_ctime); 739f6048709SChuck Lever 740e4f93234SChuck Lever return 0; 741e4f93234SChuck Lever out_overflow: 742e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 743e4f93234SChuck Lever return -EIO; 744e4f93234SChuck Lever } 745e4f93234SChuck Lever 746e4f93234SChuck Lever /* 747e4f93234SChuck Lever * pre_op_attr 748e4f93234SChuck Lever * union pre_op_attr switch (bool attributes_follow) { 749e4f93234SChuck Lever * case TRUE: 750e4f93234SChuck Lever * wcc_attr attributes; 751e4f93234SChuck Lever * case FALSE: 752e4f93234SChuck Lever * void; 753e4f93234SChuck Lever * }; 754e4f93234SChuck Lever * 755e4f93234SChuck Lever * wcc_data 756e4f93234SChuck Lever * 757e4f93234SChuck Lever * struct wcc_data { 758e4f93234SChuck Lever * pre_op_attr before; 759e4f93234SChuck Lever * post_op_attr after; 760e4f93234SChuck Lever * }; 761e4f93234SChuck Lever */ 762e4f93234SChuck Lever static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 763e4f93234SChuck Lever { 764e4f93234SChuck Lever __be32 *p; 765e4f93234SChuck Lever 766e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 767e4f93234SChuck Lever if (unlikely(p == NULL)) 768e4f93234SChuck Lever goto out_overflow; 769e4f93234SChuck Lever if (*p != xdr_zero) 770e4f93234SChuck Lever return decode_wcc_attr(xdr, fattr); 771e4f93234SChuck Lever return 0; 772e4f93234SChuck Lever out_overflow: 773e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 774e4f93234SChuck Lever return -EIO; 775e4f93234SChuck Lever } 776e4f93234SChuck Lever 777e4f93234SChuck Lever static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr) 778e4f93234SChuck Lever { 779e4f93234SChuck Lever int error; 780e4f93234SChuck Lever 781e4f93234SChuck Lever error = decode_pre_op_attr(xdr, fattr); 782e4f93234SChuck Lever if (unlikely(error)) 783e4f93234SChuck Lever goto out; 784e4f93234SChuck Lever error = decode_post_op_attr(xdr, fattr); 785e4f93234SChuck Lever out: 786e4f93234SChuck Lever return error; 787e4f93234SChuck Lever } 788e4f93234SChuck Lever 789e4f93234SChuck Lever /* 790e4f93234SChuck Lever * post_op_fh3 791e4f93234SChuck Lever * 792e4f93234SChuck Lever * union post_op_fh3 switch (bool handle_follows) { 793e4f93234SChuck Lever * case TRUE: 794e4f93234SChuck Lever * nfs_fh3 handle; 795e4f93234SChuck Lever * case FALSE: 796e4f93234SChuck Lever * void; 797e4f93234SChuck Lever * }; 798e4f93234SChuck Lever */ 799e4f93234SChuck Lever static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) 800e4f93234SChuck Lever { 801e4f93234SChuck Lever __be32 *p = xdr_inline_decode(xdr, 4); 802e4f93234SChuck Lever if (unlikely(p == NULL)) 803e4f93234SChuck Lever goto out_overflow; 804e4f93234SChuck Lever if (*p != xdr_zero) 805e4f93234SChuck Lever return decode_nfs_fh3(xdr, fh); 806e4f93234SChuck Lever zero_nfs_fh3(fh); 807e4f93234SChuck Lever return 0; 808e4f93234SChuck Lever out_overflow: 809e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 810e4f93234SChuck Lever return -EIO; 811e4f93234SChuck Lever } 812e4f93234SChuck Lever 813e4f93234SChuck Lever /* 814d9c407b1SChuck Lever * diropargs3 815d9c407b1SChuck Lever * 816d9c407b1SChuck Lever * struct diropargs3 { 817d9c407b1SChuck Lever * nfs_fh3 dir; 818d9c407b1SChuck Lever * filename3 name; 819d9c407b1SChuck Lever * }; 820d9c407b1SChuck Lever */ 821d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh, 822d9c407b1SChuck Lever const char *name, u32 length) 823d9c407b1SChuck Lever { 824d9c407b1SChuck Lever encode_nfs_fh3(xdr, fh); 825d9c407b1SChuck Lever encode_filename3(xdr, name, length); 826d9c407b1SChuck Lever } 827d9c407b1SChuck Lever 828d9c407b1SChuck Lever 8291da177e4SLinus Torvalds /* 830499ff710SChuck Lever * NFSv3 XDR encode functions 831499ff710SChuck Lever * 832499ff710SChuck Lever * NFSv3 argument types are defined in section 3.3 of RFC 1813: 833499ff710SChuck Lever * "NFS Version 3 Protocol Specification". 8341da177e4SLinus Torvalds */ 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds /* 837d9c407b1SChuck Lever * 3.3.1 GETATTR3args 838d9c407b1SChuck Lever * 839d9c407b1SChuck Lever * struct GETATTR3args { 840d9c407b1SChuck Lever * nfs_fh3 object; 841d9c407b1SChuck Lever * }; 842d9c407b1SChuck Lever */ 8439f06c719SChuck Lever static void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, 8449f06c719SChuck Lever struct xdr_stream *xdr, 845d9c407b1SChuck Lever const struct nfs_fh *fh) 846d9c407b1SChuck Lever { 8479f06c719SChuck Lever encode_nfs_fh3(xdr, fh); 848d9c407b1SChuck Lever } 849d9c407b1SChuck Lever 850d9c407b1SChuck Lever /* 851d9c407b1SChuck Lever * 3.3.2 SETATTR3args 852d9c407b1SChuck Lever * 853d9c407b1SChuck Lever * union sattrguard3 switch (bool check) { 854d9c407b1SChuck Lever * case TRUE: 855d9c407b1SChuck Lever * nfstime3 obj_ctime; 856d9c407b1SChuck Lever * case FALSE: 857d9c407b1SChuck Lever * void; 858d9c407b1SChuck Lever * }; 859d9c407b1SChuck Lever * 860d9c407b1SChuck Lever * struct SETATTR3args { 861d9c407b1SChuck Lever * nfs_fh3 object; 862d9c407b1SChuck Lever * sattr3 new_attributes; 863d9c407b1SChuck Lever * sattrguard3 guard; 864d9c407b1SChuck Lever * }; 865d9c407b1SChuck Lever */ 866d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr, 867d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 868d9c407b1SChuck Lever { 869d9c407b1SChuck Lever __be32 *p; 870d9c407b1SChuck Lever 871d9c407b1SChuck Lever if (args->guard) { 872d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4 + 8); 873d9c407b1SChuck Lever *p++ = xdr_one; 8749d5a6434SChuck Lever xdr_encode_nfstime3(p, &args->guardtime); 875d9c407b1SChuck Lever } else { 876d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 4); 877d9c407b1SChuck Lever *p = xdr_zero; 878d9c407b1SChuck Lever } 879d9c407b1SChuck Lever } 880d9c407b1SChuck Lever 8819f06c719SChuck Lever static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, 8829f06c719SChuck Lever struct xdr_stream *xdr, 883d9c407b1SChuck Lever const struct nfs3_sattrargs *args) 884d9c407b1SChuck Lever { 8859f06c719SChuck Lever encode_nfs_fh3(xdr, args->fh); 8869f06c719SChuck Lever encode_sattr3(xdr, args->sattr); 8879f06c719SChuck Lever encode_sattrguard3(xdr, args); 888d9c407b1SChuck Lever } 889d9c407b1SChuck Lever 890d9c407b1SChuck Lever /* 891d9c407b1SChuck Lever * 3.3.3 LOOKUP3args 892d9c407b1SChuck Lever * 893d9c407b1SChuck Lever * struct LOOKUP3args { 894d9c407b1SChuck Lever * diropargs3 what; 895d9c407b1SChuck Lever * }; 896d9c407b1SChuck Lever */ 8979f06c719SChuck Lever static void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, 8989f06c719SChuck Lever struct xdr_stream *xdr, 899d9c407b1SChuck Lever const struct nfs3_diropargs *args) 900d9c407b1SChuck Lever { 9019f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 902d9c407b1SChuck Lever } 903d9c407b1SChuck Lever 904d9c407b1SChuck Lever /* 905d9c407b1SChuck Lever * 3.3.4 ACCESS3args 906d9c407b1SChuck Lever * 907d9c407b1SChuck Lever * struct ACCESS3args { 908d9c407b1SChuck Lever * nfs_fh3 object; 909d9c407b1SChuck Lever * uint32 access; 910d9c407b1SChuck Lever * }; 911d9c407b1SChuck Lever */ 912d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr, 913d9c407b1SChuck Lever const struct nfs3_accessargs *args) 914d9c407b1SChuck Lever { 915d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 916d9c407b1SChuck Lever encode_uint32(xdr, args->access); 917d9c407b1SChuck Lever } 918d9c407b1SChuck Lever 9199f06c719SChuck Lever static void nfs3_xdr_enc_access3args(struct rpc_rqst *req, 9209f06c719SChuck Lever struct xdr_stream *xdr, 921d9c407b1SChuck Lever const struct nfs3_accessargs *args) 922d9c407b1SChuck Lever { 9239f06c719SChuck Lever encode_access3args(xdr, args); 924d9c407b1SChuck Lever } 925d9c407b1SChuck Lever 926d9c407b1SChuck Lever /* 927d9c407b1SChuck Lever * 3.3.5 READLINK3args 928d9c407b1SChuck Lever * 929d9c407b1SChuck Lever * struct READLINK3args { 930d9c407b1SChuck Lever * nfs_fh3 symlink; 931d9c407b1SChuck Lever * }; 932d9c407b1SChuck Lever */ 9339f06c719SChuck Lever static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, 9349f06c719SChuck Lever struct xdr_stream *xdr, 935d9c407b1SChuck Lever const struct nfs3_readlinkargs *args) 936d9c407b1SChuck Lever { 9379f06c719SChuck Lever encode_nfs_fh3(xdr, args->fh); 938d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 939d9c407b1SChuck Lever args->pglen, NFS3_readlinkres_sz); 940d9c407b1SChuck Lever } 941d9c407b1SChuck Lever 942d9c407b1SChuck Lever /* 943d9c407b1SChuck Lever * 3.3.6 READ3args 944d9c407b1SChuck Lever * 945d9c407b1SChuck Lever * struct READ3args { 946d9c407b1SChuck Lever * nfs_fh3 file; 947d9c407b1SChuck Lever * offset3 offset; 948d9c407b1SChuck Lever * count3 count; 949d9c407b1SChuck Lever * }; 950d9c407b1SChuck Lever */ 951d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr, 952d9c407b1SChuck Lever const struct nfs_readargs *args) 953d9c407b1SChuck Lever { 954d9c407b1SChuck Lever __be32 *p; 955d9c407b1SChuck Lever 956d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 957d9c407b1SChuck Lever 958d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 959d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 960d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 961d9c407b1SChuck Lever } 962d9c407b1SChuck Lever 9639f06c719SChuck Lever static void nfs3_xdr_enc_read3args(struct rpc_rqst *req, 9649f06c719SChuck Lever struct xdr_stream *xdr, 965d9c407b1SChuck Lever const struct nfs_readargs *args) 966d9c407b1SChuck Lever { 9679f06c719SChuck Lever encode_read3args(xdr, args); 968d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 969d9c407b1SChuck Lever args->count, NFS3_readres_sz); 970d9c407b1SChuck Lever req->rq_rcv_buf.flags |= XDRBUF_READ; 971d9c407b1SChuck Lever } 972d9c407b1SChuck Lever 973d9c407b1SChuck Lever /* 974d9c407b1SChuck Lever * 3.3.7 WRITE3args 975d9c407b1SChuck Lever * 976d9c407b1SChuck Lever * enum stable_how { 977d9c407b1SChuck Lever * UNSTABLE = 0, 978d9c407b1SChuck Lever * DATA_SYNC = 1, 979d9c407b1SChuck Lever * FILE_SYNC = 2 980d9c407b1SChuck Lever * }; 981d9c407b1SChuck Lever * 982d9c407b1SChuck Lever * struct WRITE3args { 983d9c407b1SChuck Lever * nfs_fh3 file; 984d9c407b1SChuck Lever * offset3 offset; 985d9c407b1SChuck Lever * count3 count; 986d9c407b1SChuck Lever * stable_how stable; 987d9c407b1SChuck Lever * opaque data<>; 988d9c407b1SChuck Lever * }; 989d9c407b1SChuck Lever */ 990d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr, 991d9c407b1SChuck Lever const struct nfs_writeargs *args) 992d9c407b1SChuck Lever { 993d9c407b1SChuck Lever __be32 *p; 994d9c407b1SChuck Lever 995d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 996d9c407b1SChuck Lever 997d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4); 998d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 999d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count); 1000d9c407b1SChuck Lever *p++ = cpu_to_be32(args->stable); 1001d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1002d9c407b1SChuck Lever xdr_write_pages(xdr, args->pages, args->pgbase, args->count); 1003d9c407b1SChuck Lever } 1004d9c407b1SChuck Lever 10059f06c719SChuck Lever static void nfs3_xdr_enc_write3args(struct rpc_rqst *req, 10069f06c719SChuck Lever struct xdr_stream *xdr, 1007d9c407b1SChuck Lever const struct nfs_writeargs *args) 1008d9c407b1SChuck Lever { 10099f06c719SChuck Lever encode_write3args(xdr, args); 10109f06c719SChuck Lever xdr->buf->flags |= XDRBUF_WRITE; 1011d9c407b1SChuck Lever } 1012d9c407b1SChuck Lever 1013d9c407b1SChuck Lever /* 1014d9c407b1SChuck Lever * 3.3.8 CREATE3args 1015d9c407b1SChuck Lever * 1016d9c407b1SChuck Lever * enum createmode3 { 1017d9c407b1SChuck Lever * UNCHECKED = 0, 1018d9c407b1SChuck Lever * GUARDED = 1, 1019d9c407b1SChuck Lever * EXCLUSIVE = 2 1020d9c407b1SChuck Lever * }; 1021d9c407b1SChuck Lever * 1022d9c407b1SChuck Lever * union createhow3 switch (createmode3 mode) { 1023d9c407b1SChuck Lever * case UNCHECKED: 1024d9c407b1SChuck Lever * case GUARDED: 1025d9c407b1SChuck Lever * sattr3 obj_attributes; 1026d9c407b1SChuck Lever * case EXCLUSIVE: 1027d9c407b1SChuck Lever * createverf3 verf; 1028d9c407b1SChuck Lever * }; 1029d9c407b1SChuck Lever * 1030d9c407b1SChuck Lever * struct CREATE3args { 1031d9c407b1SChuck Lever * diropargs3 where; 1032d9c407b1SChuck Lever * createhow3 how; 1033d9c407b1SChuck Lever * }; 1034d9c407b1SChuck Lever */ 1035d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr, 1036d9c407b1SChuck Lever const struct nfs3_createargs *args) 1037d9c407b1SChuck Lever { 1038d9c407b1SChuck Lever encode_uint32(xdr, args->createmode); 1039d9c407b1SChuck Lever switch (args->createmode) { 1040d9c407b1SChuck Lever case NFS3_CREATE_UNCHECKED: 1041d9c407b1SChuck Lever case NFS3_CREATE_GUARDED: 1042d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1043d9c407b1SChuck Lever break; 1044d9c407b1SChuck Lever case NFS3_CREATE_EXCLUSIVE: 1045d9c407b1SChuck Lever encode_createverf3(xdr, args->verifier); 1046d9c407b1SChuck Lever break; 1047d9c407b1SChuck Lever default: 1048d9c407b1SChuck Lever BUG(); 1049d9c407b1SChuck Lever } 1050d9c407b1SChuck Lever } 1051d9c407b1SChuck Lever 10529f06c719SChuck Lever static void nfs3_xdr_enc_create3args(struct rpc_rqst *req, 10539f06c719SChuck Lever struct xdr_stream *xdr, 1054d9c407b1SChuck Lever const struct nfs3_createargs *args) 1055d9c407b1SChuck Lever { 10569f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 10579f06c719SChuck Lever encode_createhow3(xdr, args); 1058d9c407b1SChuck Lever } 1059d9c407b1SChuck Lever 1060d9c407b1SChuck Lever /* 1061d9c407b1SChuck Lever * 3.3.9 MKDIR3args 1062d9c407b1SChuck Lever * 1063d9c407b1SChuck Lever * struct MKDIR3args { 1064d9c407b1SChuck Lever * diropargs3 where; 1065d9c407b1SChuck Lever * sattr3 attributes; 1066d9c407b1SChuck Lever * }; 1067d9c407b1SChuck Lever */ 10689f06c719SChuck Lever static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, 10699f06c719SChuck Lever struct xdr_stream *xdr, 1070d9c407b1SChuck Lever const struct nfs3_mkdirargs *args) 1071d9c407b1SChuck Lever { 10729f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 10739f06c719SChuck Lever encode_sattr3(xdr, args->sattr); 1074d9c407b1SChuck Lever } 1075d9c407b1SChuck Lever 1076d9c407b1SChuck Lever /* 1077d9c407b1SChuck Lever * 3.3.10 SYMLINK3args 1078d9c407b1SChuck Lever * 1079d9c407b1SChuck Lever * struct symlinkdata3 { 1080d9c407b1SChuck Lever * sattr3 symlink_attributes; 1081d9c407b1SChuck Lever * nfspath3 symlink_data; 1082d9c407b1SChuck Lever * }; 1083d9c407b1SChuck Lever * 1084d9c407b1SChuck Lever * struct SYMLINK3args { 1085d9c407b1SChuck Lever * diropargs3 where; 1086d9c407b1SChuck Lever * symlinkdata3 symlink; 1087d9c407b1SChuck Lever * }; 1088d9c407b1SChuck Lever */ 1089d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr, 1090d9c407b1SChuck Lever const struct nfs3_symlinkargs *args) 1091d9c407b1SChuck Lever { 1092d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1093d9c407b1SChuck Lever encode_nfspath3(xdr, args->pages, args->pathlen); 1094d9c407b1SChuck Lever } 1095d9c407b1SChuck Lever 10969f06c719SChuck Lever static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, 10979f06c719SChuck Lever struct xdr_stream *xdr, 1098d9c407b1SChuck Lever const struct nfs3_symlinkargs *args) 1099d9c407b1SChuck Lever { 11009f06c719SChuck Lever encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen); 11019f06c719SChuck Lever encode_symlinkdata3(xdr, args); 1102d9c407b1SChuck Lever } 1103d9c407b1SChuck Lever 1104d9c407b1SChuck Lever /* 1105d9c407b1SChuck Lever * 3.3.11 MKNOD3args 1106d9c407b1SChuck Lever * 1107d9c407b1SChuck Lever * struct devicedata3 { 1108d9c407b1SChuck Lever * sattr3 dev_attributes; 1109d9c407b1SChuck Lever * specdata3 spec; 1110d9c407b1SChuck Lever * }; 1111d9c407b1SChuck Lever * 1112d9c407b1SChuck Lever * union mknoddata3 switch (ftype3 type) { 1113d9c407b1SChuck Lever * case NF3CHR: 1114d9c407b1SChuck Lever * case NF3BLK: 1115d9c407b1SChuck Lever * devicedata3 device; 1116d9c407b1SChuck Lever * case NF3SOCK: 1117d9c407b1SChuck Lever * case NF3FIFO: 1118d9c407b1SChuck Lever * sattr3 pipe_attributes; 1119d9c407b1SChuck Lever * default: 1120d9c407b1SChuck Lever * void; 1121d9c407b1SChuck Lever * }; 1122d9c407b1SChuck Lever * 1123d9c407b1SChuck Lever * struct MKNOD3args { 1124d9c407b1SChuck Lever * diropargs3 where; 1125d9c407b1SChuck Lever * mknoddata3 what; 1126d9c407b1SChuck Lever * }; 1127d9c407b1SChuck Lever */ 1128d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr, 1129d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1130d9c407b1SChuck Lever { 1131d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1132d9c407b1SChuck Lever encode_specdata3(xdr, args->rdev); 1133d9c407b1SChuck Lever } 1134d9c407b1SChuck Lever 1135d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr, 1136d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1137d9c407b1SChuck Lever { 1138d9c407b1SChuck Lever encode_ftype3(xdr, args->type); 1139d9c407b1SChuck Lever switch (args->type) { 1140d9c407b1SChuck Lever case NF3CHR: 1141d9c407b1SChuck Lever case NF3BLK: 1142d9c407b1SChuck Lever encode_devicedata3(xdr, args); 1143d9c407b1SChuck Lever break; 1144d9c407b1SChuck Lever case NF3SOCK: 1145d9c407b1SChuck Lever case NF3FIFO: 1146d9c407b1SChuck Lever encode_sattr3(xdr, args->sattr); 1147d9c407b1SChuck Lever break; 1148d9c407b1SChuck Lever case NF3REG: 1149d9c407b1SChuck Lever case NF3DIR: 1150d9c407b1SChuck Lever break; 1151d9c407b1SChuck Lever default: 1152d9c407b1SChuck Lever BUG(); 1153d9c407b1SChuck Lever } 1154d9c407b1SChuck Lever } 1155d9c407b1SChuck Lever 11569f06c719SChuck Lever static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, 11579f06c719SChuck Lever struct xdr_stream *xdr, 1158d9c407b1SChuck Lever const struct nfs3_mknodargs *args) 1159d9c407b1SChuck Lever { 11609f06c719SChuck Lever encode_diropargs3(xdr, args->fh, args->name, args->len); 11619f06c719SChuck Lever encode_mknoddata3(xdr, args); 1162d9c407b1SChuck Lever } 1163d9c407b1SChuck Lever 1164d9c407b1SChuck Lever /* 1165d9c407b1SChuck Lever * 3.3.12 REMOVE3args 1166d9c407b1SChuck Lever * 1167d9c407b1SChuck Lever * struct REMOVE3args { 1168d9c407b1SChuck Lever * diropargs3 object; 1169d9c407b1SChuck Lever * }; 1170d9c407b1SChuck Lever */ 11719f06c719SChuck Lever static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req, 11729f06c719SChuck Lever struct xdr_stream *xdr, 1173d9c407b1SChuck Lever const struct nfs_removeargs *args) 1174d9c407b1SChuck Lever { 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, 1188d9c407b1SChuck Lever const struct nfs_renameargs *args) 1189d9c407b1SChuck Lever { 1190d9c407b1SChuck Lever const struct qstr *old = args->old_name; 1191d9c407b1SChuck Lever const struct qstr *new = args->new_name; 1192d9c407b1SChuck Lever 11939f06c719SChuck Lever encode_diropargs3(xdr, args->old_dir, old->name, old->len); 11949f06c719SChuck Lever encode_diropargs3(xdr, args->new_dir, new->name, new->len); 1195d9c407b1SChuck Lever } 1196d9c407b1SChuck Lever 1197d9c407b1SChuck Lever /* 1198d9c407b1SChuck Lever * 3.3.15 LINK3args 1199d9c407b1SChuck Lever * 1200d9c407b1SChuck Lever * struct LINK3args { 1201d9c407b1SChuck Lever * nfs_fh3 file; 1202d9c407b1SChuck Lever * diropargs3 link; 1203d9c407b1SChuck Lever * }; 1204d9c407b1SChuck Lever */ 12059f06c719SChuck Lever static void nfs3_xdr_enc_link3args(struct rpc_rqst *req, 12069f06c719SChuck Lever struct xdr_stream *xdr, 1207d9c407b1SChuck Lever const struct nfs3_linkargs *args) 1208d9c407b1SChuck Lever { 12099f06c719SChuck Lever encode_nfs_fh3(xdr, args->fromfh); 12109f06c719SChuck Lever encode_diropargs3(xdr, args->tofh, args->toname, args->tolen); 1211d9c407b1SChuck Lever } 1212d9c407b1SChuck Lever 1213d9c407b1SChuck Lever /* 1214d9c407b1SChuck Lever * 3.3.16 READDIR3args 1215d9c407b1SChuck Lever * 1216d9c407b1SChuck Lever * struct READDIR3args { 1217d9c407b1SChuck Lever * nfs_fh3 dir; 1218d9c407b1SChuck Lever * cookie3 cookie; 1219d9c407b1SChuck Lever * cookieverf3 cookieverf; 1220d9c407b1SChuck Lever * count3 count; 1221d9c407b1SChuck Lever * }; 1222d9c407b1SChuck Lever */ 1223d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr, 1224d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1225d9c407b1SChuck Lever { 1226d9c407b1SChuck Lever __be32 *p; 1227d9c407b1SChuck Lever 1228d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1229d9c407b1SChuck Lever 1230d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4); 1231d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1232d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1233d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1234d9c407b1SChuck Lever } 1235d9c407b1SChuck Lever 12369f06c719SChuck Lever static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, 12379f06c719SChuck Lever struct xdr_stream *xdr, 1238d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1239d9c407b1SChuck Lever { 12409f06c719SChuck Lever encode_readdir3args(xdr, args); 1241d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1242d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1243d9c407b1SChuck Lever } 1244d9c407b1SChuck Lever 1245d9c407b1SChuck Lever /* 1246d9c407b1SChuck Lever * 3.3.17 READDIRPLUS3args 1247d9c407b1SChuck Lever * 1248d9c407b1SChuck Lever * struct READDIRPLUS3args { 1249d9c407b1SChuck Lever * nfs_fh3 dir; 1250d9c407b1SChuck Lever * cookie3 cookie; 1251d9c407b1SChuck Lever * cookieverf3 cookieverf; 1252d9c407b1SChuck Lever * count3 dircount; 1253d9c407b1SChuck Lever * count3 maxcount; 1254d9c407b1SChuck Lever * }; 1255d9c407b1SChuck Lever */ 1256d9c407b1SChuck Lever static void encode_readdirplus3args(struct xdr_stream *xdr, 1257d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1258d9c407b1SChuck Lever { 1259d9c407b1SChuck Lever __be32 *p; 1260d9c407b1SChuck Lever 1261d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1262d9c407b1SChuck Lever 1263d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4); 1264d9c407b1SChuck Lever p = xdr_encode_cookie3(p, args->cookie); 1265d9c407b1SChuck Lever p = xdr_encode_cookieverf3(p, args->verf); 1266d9c407b1SChuck Lever 1267d9c407b1SChuck Lever /* 1268d9c407b1SChuck Lever * readdirplus: need dircount + buffer size. 1269d9c407b1SChuck Lever * We just make sure we make dircount big enough 1270d9c407b1SChuck Lever */ 1271d9c407b1SChuck Lever *p++ = cpu_to_be32(args->count >> 3); 1272d9c407b1SChuck Lever 1273d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1274d9c407b1SChuck Lever } 1275d9c407b1SChuck Lever 12769f06c719SChuck Lever static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, 12779f06c719SChuck Lever struct xdr_stream *xdr, 1278d9c407b1SChuck Lever const struct nfs3_readdirargs *args) 1279d9c407b1SChuck Lever { 12809f06c719SChuck Lever encode_readdirplus3args(xdr, args); 1281d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1282d9c407b1SChuck Lever args->count, NFS3_readdirres_sz); 1283d9c407b1SChuck Lever } 1284d9c407b1SChuck Lever 1285d9c407b1SChuck Lever /* 1286d9c407b1SChuck Lever * 3.3.21 COMMIT3args 1287d9c407b1SChuck Lever * 1288d9c407b1SChuck Lever * struct COMMIT3args { 1289d9c407b1SChuck Lever * nfs_fh3 file; 1290d9c407b1SChuck Lever * offset3 offset; 1291d9c407b1SChuck Lever * count3 count; 1292d9c407b1SChuck Lever * }; 1293d9c407b1SChuck Lever */ 1294d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr, 12950b7c0153SFred Isaman const struct nfs_commitargs *args) 1296d9c407b1SChuck Lever { 1297d9c407b1SChuck Lever __be32 *p; 1298d9c407b1SChuck Lever 1299d9c407b1SChuck Lever encode_nfs_fh3(xdr, args->fh); 1300d9c407b1SChuck Lever 1301d9c407b1SChuck Lever p = xdr_reserve_space(xdr, 8 + 4); 1302d9c407b1SChuck Lever p = xdr_encode_hyper(p, args->offset); 1303d9c407b1SChuck Lever *p = cpu_to_be32(args->count); 1304d9c407b1SChuck Lever } 1305d9c407b1SChuck Lever 13069f06c719SChuck Lever static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req, 13079f06c719SChuck Lever struct xdr_stream *xdr, 13080b7c0153SFred Isaman const struct nfs_commitargs *args) 1309d9c407b1SChuck Lever { 13109f06c719SChuck Lever encode_commit3args(xdr, args); 1311d9c407b1SChuck Lever } 1312d9c407b1SChuck Lever 1313b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 1314b7fa0554SAndreas Gruenbacher 13159f06c719SChuck Lever static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, 13169f06c719SChuck Lever struct xdr_stream *xdr, 1317d9c407b1SChuck Lever const struct nfs3_getaclargs *args) 1318d9c407b1SChuck Lever { 13199f06c719SChuck Lever encode_nfs_fh3(xdr, args->fh); 13209f06c719SChuck Lever encode_uint32(xdr, args->mask); 1321d9c407b1SChuck Lever if (args->mask & (NFS_ACL | NFS_DFACL)) 1322d9c407b1SChuck Lever prepare_reply_buffer(req, args->pages, 0, 1323d9c407b1SChuck Lever NFSACL_MAXPAGES << PAGE_SHIFT, 1324d9c407b1SChuck Lever ACL3_getaclres_sz); 1325d9c407b1SChuck Lever } 1326d9c407b1SChuck Lever 13279f06c719SChuck Lever static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, 13289f06c719SChuck Lever struct xdr_stream *xdr, 1329d9c407b1SChuck Lever const struct nfs3_setaclargs *args) 1330d9c407b1SChuck Lever { 1331d9c407b1SChuck Lever unsigned int base; 1332d9c407b1SChuck Lever int error; 1333d9c407b1SChuck Lever 13349f06c719SChuck Lever encode_nfs_fh3(xdr, NFS_FH(args->inode)); 13359f06c719SChuck Lever encode_uint32(xdr, args->mask); 1336d9c407b1SChuck Lever 1337d9c407b1SChuck Lever base = req->rq_slen; 1338ee5dc773SChuck Lever if (args->npages != 0) 1339ee5dc773SChuck Lever xdr_write_pages(xdr, args->pages, 0, args->len); 1340ee5dc773SChuck Lever else 1341ee5dc773SChuck Lever xdr_reserve_space(xdr, NFS_ACL_INLINE_BUFSIZE); 1342ee5dc773SChuck Lever 13439f06c719SChuck Lever error = nfsacl_encode(xdr->buf, base, args->inode, 1344d9c407b1SChuck Lever (args->mask & NFS_ACL) ? 1345d9c407b1SChuck Lever args->acl_access : NULL, 1, 0); 1346d9c407b1SChuck Lever BUG_ON(error < 0); 13479f06c719SChuck Lever error = nfsacl_encode(xdr->buf, base + error, args->inode, 1348d9c407b1SChuck Lever (args->mask & NFS_DFACL) ? 1349d9c407b1SChuck Lever args->acl_default : NULL, 1, 1350d9c407b1SChuck Lever NFS_ACL_DEFAULT); 1351d9c407b1SChuck Lever BUG_ON(error < 0); 1352d9c407b1SChuck Lever } 1353d9c407b1SChuck Lever 1354b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 1355b7fa0554SAndreas Gruenbacher 13561da177e4SLinus Torvalds /* 1357b2cdd9c9SChuck Lever * NFSv3 XDR decode functions 1358b2cdd9c9SChuck Lever * 1359b2cdd9c9SChuck Lever * NFSv3 result types are defined in section 3.3 of RFC 1813: 1360b2cdd9c9SChuck Lever * "NFS Version 3 Protocol Specification". 13611da177e4SLinus Torvalds */ 13621da177e4SLinus Torvalds 13631da177e4SLinus Torvalds /* 1364e4f93234SChuck Lever * 3.3.1 GETATTR3res 1365e4f93234SChuck Lever * 1366e4f93234SChuck Lever * struct GETATTR3resok { 1367e4f93234SChuck Lever * fattr3 obj_attributes; 1368e4f93234SChuck Lever * }; 1369e4f93234SChuck Lever * 1370e4f93234SChuck Lever * union GETATTR3res switch (nfsstat3 status) { 1371e4f93234SChuck Lever * case NFS3_OK: 1372e4f93234SChuck Lever * GETATTR3resok resok; 1373e4f93234SChuck Lever * default: 1374e4f93234SChuck Lever * void; 1375e4f93234SChuck Lever * }; 1376e4f93234SChuck Lever */ 1377bf269551SChuck Lever static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req, 1378bf269551SChuck Lever struct xdr_stream *xdr, 1379e4f93234SChuck Lever struct nfs_fattr *result) 1380e4f93234SChuck Lever { 1381e4f93234SChuck Lever enum nfs_stat status; 1382e4f93234SChuck Lever int error; 1383e4f93234SChuck Lever 1384bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1385e4f93234SChuck Lever if (unlikely(error)) 1386e4f93234SChuck Lever goto out; 1387e4f93234SChuck Lever if (status != NFS3_OK) 1388e4f93234SChuck Lever goto out_default; 1389bf269551SChuck Lever error = decode_fattr3(xdr, result); 1390e4f93234SChuck Lever out: 1391e4f93234SChuck Lever return error; 1392e4f93234SChuck Lever out_default: 13935e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1394e4f93234SChuck Lever } 1395e4f93234SChuck Lever 1396e4f93234SChuck Lever /* 1397e4f93234SChuck Lever * 3.3.2 SETATTR3res 1398e4f93234SChuck Lever * 1399e4f93234SChuck Lever * struct SETATTR3resok { 1400e4f93234SChuck Lever * wcc_data obj_wcc; 1401e4f93234SChuck Lever * }; 1402e4f93234SChuck Lever * 1403e4f93234SChuck Lever * struct SETATTR3resfail { 1404e4f93234SChuck Lever * wcc_data obj_wcc; 1405e4f93234SChuck Lever * }; 1406e4f93234SChuck Lever * 1407e4f93234SChuck Lever * union SETATTR3res switch (nfsstat3 status) { 1408e4f93234SChuck Lever * case NFS3_OK: 1409e4f93234SChuck Lever * SETATTR3resok resok; 1410e4f93234SChuck Lever * default: 1411e4f93234SChuck Lever * SETATTR3resfail resfail; 1412e4f93234SChuck Lever * }; 1413e4f93234SChuck Lever */ 1414bf269551SChuck Lever static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req, 1415bf269551SChuck Lever struct xdr_stream *xdr, 1416e4f93234SChuck Lever struct nfs_fattr *result) 1417e4f93234SChuck Lever { 1418e4f93234SChuck Lever enum nfs_stat status; 1419e4f93234SChuck Lever int error; 1420e4f93234SChuck Lever 1421bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1422e4f93234SChuck Lever if (unlikely(error)) 1423e4f93234SChuck Lever goto out; 1424bf269551SChuck Lever error = decode_wcc_data(xdr, result); 1425e4f93234SChuck Lever if (unlikely(error)) 1426e4f93234SChuck Lever goto out; 1427e4f93234SChuck Lever if (status != NFS3_OK) 1428e4f93234SChuck Lever goto out_status; 1429e4f93234SChuck Lever out: 1430e4f93234SChuck Lever return error; 1431e4f93234SChuck Lever out_status: 14325e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1433e4f93234SChuck Lever } 1434e4f93234SChuck Lever 14351da177e4SLinus Torvalds /* 1436e4f93234SChuck Lever * 3.3.3 LOOKUP3res 1437e4f93234SChuck Lever * 1438e4f93234SChuck Lever * struct LOOKUP3resok { 1439e4f93234SChuck Lever * nfs_fh3 object; 1440e4f93234SChuck Lever * post_op_attr obj_attributes; 1441e4f93234SChuck Lever * post_op_attr dir_attributes; 1442e4f93234SChuck Lever * }; 1443e4f93234SChuck Lever * 1444e4f93234SChuck Lever * struct LOOKUP3resfail { 1445e4f93234SChuck Lever * post_op_attr dir_attributes; 1446e4f93234SChuck Lever * }; 1447e4f93234SChuck Lever * 1448e4f93234SChuck Lever * union LOOKUP3res switch (nfsstat3 status) { 1449e4f93234SChuck Lever * case NFS3_OK: 1450e4f93234SChuck Lever * LOOKUP3resok resok; 1451e4f93234SChuck Lever * default: 1452e4f93234SChuck Lever * LOOKUP3resfail resfail; 1453e4f93234SChuck Lever * }; 1454e4f93234SChuck Lever */ 1455bf269551SChuck Lever static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req, 1456bf269551SChuck Lever struct xdr_stream *xdr, 1457e4f93234SChuck Lever struct nfs3_diropres *result) 1458e4f93234SChuck Lever { 1459e4f93234SChuck Lever enum nfs_stat status; 1460e4f93234SChuck Lever int error; 1461e4f93234SChuck Lever 1462bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1463e4f93234SChuck Lever if (unlikely(error)) 1464e4f93234SChuck Lever goto out; 1465e4f93234SChuck Lever if (status != NFS3_OK) 1466e4f93234SChuck Lever goto out_default; 1467bf269551SChuck Lever error = decode_nfs_fh3(xdr, result->fh); 1468e4f93234SChuck Lever if (unlikely(error)) 1469e4f93234SChuck Lever goto out; 1470bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1471e4f93234SChuck Lever if (unlikely(error)) 1472e4f93234SChuck Lever goto out; 1473bf269551SChuck Lever error = decode_post_op_attr(xdr, result->dir_attr); 1474e4f93234SChuck Lever out: 1475e4f93234SChuck Lever return error; 1476e4f93234SChuck Lever out_default: 1477bf269551SChuck Lever error = decode_post_op_attr(xdr, result->dir_attr); 1478e4f93234SChuck Lever if (unlikely(error)) 1479e4f93234SChuck Lever goto out; 14805e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1481e4f93234SChuck Lever } 1482e4f93234SChuck Lever 1483e4f93234SChuck Lever /* 1484e4f93234SChuck Lever * 3.3.4 ACCESS3res 1485e4f93234SChuck Lever * 1486e4f93234SChuck Lever * struct ACCESS3resok { 1487e4f93234SChuck Lever * post_op_attr obj_attributes; 1488e4f93234SChuck Lever * uint32 access; 1489e4f93234SChuck Lever * }; 1490e4f93234SChuck Lever * 1491e4f93234SChuck Lever * struct ACCESS3resfail { 1492e4f93234SChuck Lever * post_op_attr obj_attributes; 1493e4f93234SChuck Lever * }; 1494e4f93234SChuck Lever * 1495e4f93234SChuck Lever * union ACCESS3res switch (nfsstat3 status) { 1496e4f93234SChuck Lever * case NFS3_OK: 1497e4f93234SChuck Lever * ACCESS3resok resok; 1498e4f93234SChuck Lever * default: 1499e4f93234SChuck Lever * ACCESS3resfail resfail; 1500e4f93234SChuck Lever * }; 1501e4f93234SChuck Lever */ 1502bf269551SChuck Lever static int nfs3_xdr_dec_access3res(struct rpc_rqst *req, 1503bf269551SChuck Lever struct xdr_stream *xdr, 1504e4f93234SChuck Lever struct nfs3_accessres *result) 1505e4f93234SChuck Lever { 1506e4f93234SChuck Lever enum nfs_stat status; 1507e4f93234SChuck Lever int error; 1508e4f93234SChuck Lever 1509bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1510e4f93234SChuck Lever if (unlikely(error)) 1511e4f93234SChuck Lever goto out; 1512bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1513e4f93234SChuck Lever if (unlikely(error)) 1514e4f93234SChuck Lever goto out; 1515e4f93234SChuck Lever if (status != NFS3_OK) 1516e4f93234SChuck Lever goto out_default; 1517bf269551SChuck Lever error = decode_uint32(xdr, &result->access); 1518e4f93234SChuck Lever out: 1519e4f93234SChuck Lever return error; 1520e4f93234SChuck Lever out_default: 15215e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1522e4f93234SChuck Lever } 1523e4f93234SChuck Lever 1524e4f93234SChuck Lever /* 1525e4f93234SChuck Lever * 3.3.5 READLINK3res 1526e4f93234SChuck Lever * 1527e4f93234SChuck Lever * struct READLINK3resok { 1528e4f93234SChuck Lever * post_op_attr symlink_attributes; 1529e4f93234SChuck Lever * nfspath3 data; 1530e4f93234SChuck Lever * }; 1531e4f93234SChuck Lever * 1532e4f93234SChuck Lever * struct READLINK3resfail { 1533e4f93234SChuck Lever * post_op_attr symlink_attributes; 1534e4f93234SChuck Lever * }; 1535e4f93234SChuck Lever * 1536e4f93234SChuck Lever * union READLINK3res switch (nfsstat3 status) { 1537e4f93234SChuck Lever * case NFS3_OK: 1538e4f93234SChuck Lever * READLINK3resok resok; 1539e4f93234SChuck Lever * default: 1540e4f93234SChuck Lever * READLINK3resfail resfail; 1541e4f93234SChuck Lever * }; 1542e4f93234SChuck Lever */ 1543bf269551SChuck Lever static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req, 1544bf269551SChuck Lever struct xdr_stream *xdr, 1545e4f93234SChuck Lever struct nfs_fattr *result) 1546e4f93234SChuck Lever { 1547e4f93234SChuck Lever enum nfs_stat status; 1548e4f93234SChuck Lever int error; 1549e4f93234SChuck Lever 1550bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1551e4f93234SChuck Lever if (unlikely(error)) 1552e4f93234SChuck Lever goto out; 1553bf269551SChuck Lever error = decode_post_op_attr(xdr, result); 1554e4f93234SChuck Lever if (unlikely(error)) 1555e4f93234SChuck Lever goto out; 1556e4f93234SChuck Lever if (status != NFS3_OK) 1557e4f93234SChuck Lever goto out_default; 1558bf269551SChuck Lever error = decode_nfspath3(xdr); 1559e4f93234SChuck Lever out: 1560e4f93234SChuck Lever return error; 1561e4f93234SChuck Lever out_default: 15625e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1563e4f93234SChuck Lever } 1564e4f93234SChuck Lever 1565e4f93234SChuck Lever /* 1566e4f93234SChuck Lever * 3.3.6 READ3res 1567e4f93234SChuck Lever * 1568e4f93234SChuck Lever * struct READ3resok { 1569e4f93234SChuck Lever * post_op_attr file_attributes; 1570e4f93234SChuck Lever * count3 count; 1571e4f93234SChuck Lever * bool eof; 1572e4f93234SChuck Lever * opaque data<>; 1573e4f93234SChuck Lever * }; 1574e4f93234SChuck Lever * 1575e4f93234SChuck Lever * struct READ3resfail { 1576e4f93234SChuck Lever * post_op_attr file_attributes; 1577e4f93234SChuck Lever * }; 1578e4f93234SChuck Lever * 1579e4f93234SChuck Lever * union READ3res switch (nfsstat3 status) { 1580e4f93234SChuck Lever * case NFS3_OK: 1581e4f93234SChuck Lever * READ3resok resok; 1582e4f93234SChuck Lever * default: 1583e4f93234SChuck Lever * READ3resfail resfail; 1584e4f93234SChuck Lever * }; 1585e4f93234SChuck Lever */ 1586e4f93234SChuck Lever static int decode_read3resok(struct xdr_stream *xdr, 1587e4f93234SChuck Lever struct nfs_readres *result) 1588e4f93234SChuck Lever { 1589e4f93234SChuck Lever u32 eof, count, ocount, recvd; 1590e4f93234SChuck Lever size_t hdrlen; 1591e4f93234SChuck Lever __be32 *p; 1592e4f93234SChuck Lever 1593e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 + 4 + 4); 1594e4f93234SChuck Lever if (unlikely(p == NULL)) 1595e4f93234SChuck Lever goto out_overflow; 1596e4f93234SChuck Lever count = be32_to_cpup(p++); 1597e4f93234SChuck Lever eof = be32_to_cpup(p++); 1598e4f93234SChuck Lever ocount = be32_to_cpup(p++); 1599e4f93234SChuck Lever if (unlikely(ocount != count)) 1600e4f93234SChuck Lever goto out_mismatch; 1601e4f93234SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 1602e4f93234SChuck Lever recvd = xdr->buf->len - hdrlen; 1603e4f93234SChuck Lever if (unlikely(count > recvd)) 1604e4f93234SChuck Lever goto out_cheating; 1605e4f93234SChuck Lever 1606e4f93234SChuck Lever out: 1607e4f93234SChuck Lever xdr_read_pages(xdr, count); 1608e4f93234SChuck Lever result->eof = eof; 1609e4f93234SChuck Lever result->count = count; 1610e4f93234SChuck Lever return count; 1611e4f93234SChuck Lever out_mismatch: 1612e4f93234SChuck Lever dprintk("NFS: READ count doesn't match length of opaque: " 1613e4f93234SChuck Lever "count %u != ocount %u\n", count, ocount); 1614e4f93234SChuck Lever return -EIO; 1615e4f93234SChuck Lever out_cheating: 1616e4f93234SChuck Lever dprintk("NFS: server cheating in read result: " 1617e4f93234SChuck Lever "count %u > recvd %u\n", count, recvd); 1618e4f93234SChuck Lever count = recvd; 1619e4f93234SChuck Lever eof = 0; 1620e4f93234SChuck Lever goto out; 1621e4f93234SChuck Lever out_overflow: 1622e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 1623e4f93234SChuck Lever return -EIO; 1624e4f93234SChuck Lever } 1625e4f93234SChuck Lever 1626bf269551SChuck Lever static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, 1627e4f93234SChuck Lever struct nfs_readres *result) 1628e4f93234SChuck Lever { 1629e4f93234SChuck Lever enum nfs_stat status; 1630e4f93234SChuck Lever int error; 1631e4f93234SChuck Lever 1632bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1633e4f93234SChuck Lever if (unlikely(error)) 1634e4f93234SChuck Lever goto out; 1635bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1636e4f93234SChuck Lever if (unlikely(error)) 1637e4f93234SChuck Lever goto out; 1638e4f93234SChuck Lever if (status != NFS3_OK) 1639e4f93234SChuck Lever goto out_status; 1640bf269551SChuck Lever error = decode_read3resok(xdr, result); 1641e4f93234SChuck Lever out: 1642e4f93234SChuck Lever return error; 1643e4f93234SChuck Lever out_status: 16445e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1645e4f93234SChuck Lever } 1646e4f93234SChuck Lever 1647e4f93234SChuck Lever /* 1648e4f93234SChuck Lever * 3.3.7 WRITE3res 1649e4f93234SChuck Lever * 1650e4f93234SChuck Lever * enum stable_how { 1651e4f93234SChuck Lever * UNSTABLE = 0, 1652e4f93234SChuck Lever * DATA_SYNC = 1, 1653e4f93234SChuck Lever * FILE_SYNC = 2 1654e4f93234SChuck Lever * }; 1655e4f93234SChuck Lever * 1656e4f93234SChuck Lever * struct WRITE3resok { 1657e4f93234SChuck Lever * wcc_data file_wcc; 1658e4f93234SChuck Lever * count3 count; 1659e4f93234SChuck Lever * stable_how committed; 1660e4f93234SChuck Lever * writeverf3 verf; 1661e4f93234SChuck Lever * }; 1662e4f93234SChuck Lever * 1663e4f93234SChuck Lever * struct WRITE3resfail { 1664e4f93234SChuck Lever * wcc_data file_wcc; 1665e4f93234SChuck Lever * }; 1666e4f93234SChuck Lever * 1667e4f93234SChuck Lever * union WRITE3res switch (nfsstat3 status) { 1668e4f93234SChuck Lever * case NFS3_OK: 1669e4f93234SChuck Lever * WRITE3resok resok; 1670e4f93234SChuck Lever * default: 1671e4f93234SChuck Lever * WRITE3resfail resfail; 1672e4f93234SChuck Lever * }; 1673e4f93234SChuck Lever */ 1674e4f93234SChuck Lever static int decode_write3resok(struct xdr_stream *xdr, 1675e4f93234SChuck Lever struct nfs_writeres *result) 1676e4f93234SChuck Lever { 1677e4f93234SChuck Lever __be32 *p; 1678e4f93234SChuck Lever 1679e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE); 1680e4f93234SChuck Lever if (unlikely(p == NULL)) 1681e4f93234SChuck Lever goto out_overflow; 1682e4f93234SChuck Lever result->count = be32_to_cpup(p++); 1683e4f93234SChuck Lever result->verf->committed = be32_to_cpup(p++); 1684e4f93234SChuck Lever if (unlikely(result->verf->committed > NFS_FILE_SYNC)) 1685e4f93234SChuck Lever goto out_badvalue; 1686e4f93234SChuck Lever memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE); 1687e4f93234SChuck Lever return result->count; 1688e4f93234SChuck Lever out_badvalue: 1689e4f93234SChuck Lever dprintk("NFS: bad stable_how value: %u\n", result->verf->committed); 1690e4f93234SChuck Lever return -EIO; 1691e4f93234SChuck Lever out_overflow: 1692e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 1693e4f93234SChuck Lever return -EIO; 1694e4f93234SChuck Lever } 1695e4f93234SChuck Lever 1696bf269551SChuck Lever static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr, 1697e4f93234SChuck Lever struct nfs_writeres *result) 1698e4f93234SChuck Lever { 1699e4f93234SChuck Lever enum nfs_stat status; 1700e4f93234SChuck Lever int error; 1701e4f93234SChuck Lever 1702bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1703e4f93234SChuck Lever if (unlikely(error)) 1704e4f93234SChuck Lever goto out; 1705bf269551SChuck Lever error = decode_wcc_data(xdr, result->fattr); 1706e4f93234SChuck Lever if (unlikely(error)) 1707e4f93234SChuck Lever goto out; 1708e4f93234SChuck Lever if (status != NFS3_OK) 1709e4f93234SChuck Lever goto out_status; 1710bf269551SChuck Lever error = decode_write3resok(xdr, result); 1711e4f93234SChuck Lever out: 1712e4f93234SChuck Lever return error; 1713e4f93234SChuck Lever out_status: 17145e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1715e4f93234SChuck Lever } 1716e4f93234SChuck Lever 1717e4f93234SChuck Lever /* 1718e4f93234SChuck Lever * 3.3.8 CREATE3res 1719e4f93234SChuck Lever * 1720e4f93234SChuck Lever * struct CREATE3resok { 1721e4f93234SChuck Lever * post_op_fh3 obj; 1722e4f93234SChuck Lever * post_op_attr obj_attributes; 1723e4f93234SChuck Lever * wcc_data dir_wcc; 1724e4f93234SChuck Lever * }; 1725e4f93234SChuck Lever * 1726e4f93234SChuck Lever * struct CREATE3resfail { 1727e4f93234SChuck Lever * wcc_data dir_wcc; 1728e4f93234SChuck Lever * }; 1729e4f93234SChuck Lever * 1730e4f93234SChuck Lever * union CREATE3res switch (nfsstat3 status) { 1731e4f93234SChuck Lever * case NFS3_OK: 1732e4f93234SChuck Lever * CREATE3resok resok; 1733e4f93234SChuck Lever * default: 1734e4f93234SChuck Lever * CREATE3resfail resfail; 1735e4f93234SChuck Lever * }; 1736e4f93234SChuck Lever */ 1737e4f93234SChuck Lever static int decode_create3resok(struct xdr_stream *xdr, 1738e4f93234SChuck Lever struct nfs3_diropres *result) 1739e4f93234SChuck Lever { 1740e4f93234SChuck Lever int error; 1741e4f93234SChuck Lever 1742e4f93234SChuck Lever error = decode_post_op_fh3(xdr, result->fh); 1743e4f93234SChuck Lever if (unlikely(error)) 1744e4f93234SChuck Lever goto out; 1745e4f93234SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1746e4f93234SChuck Lever if (unlikely(error)) 1747e4f93234SChuck Lever goto out; 1748e4f93234SChuck Lever /* The server isn't required to return a file handle. 1749e4f93234SChuck Lever * If it didn't, force the client to perform a LOOKUP 1750e4f93234SChuck Lever * to determine the correct file handle and attribute 1751e4f93234SChuck Lever * values for the new object. */ 1752e4f93234SChuck Lever if (result->fh->size == 0) 1753e4f93234SChuck Lever result->fattr->valid = 0; 1754e4f93234SChuck Lever error = decode_wcc_data(xdr, result->dir_attr); 1755e4f93234SChuck Lever out: 1756e4f93234SChuck Lever return error; 1757e4f93234SChuck Lever } 1758e4f93234SChuck Lever 1759bf269551SChuck Lever static int nfs3_xdr_dec_create3res(struct rpc_rqst *req, 1760bf269551SChuck Lever struct xdr_stream *xdr, 1761e4f93234SChuck Lever struct nfs3_diropres *result) 1762e4f93234SChuck Lever { 1763e4f93234SChuck Lever enum nfs_stat status; 1764e4f93234SChuck Lever int error; 1765e4f93234SChuck Lever 1766bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1767e4f93234SChuck Lever if (unlikely(error)) 1768e4f93234SChuck Lever goto out; 1769e4f93234SChuck Lever if (status != NFS3_OK) 1770e4f93234SChuck Lever goto out_default; 1771bf269551SChuck Lever error = decode_create3resok(xdr, result); 1772e4f93234SChuck Lever out: 1773e4f93234SChuck Lever return error; 1774e4f93234SChuck Lever out_default: 1775bf269551SChuck Lever error = decode_wcc_data(xdr, result->dir_attr); 1776e4f93234SChuck Lever if (unlikely(error)) 1777e4f93234SChuck Lever goto out; 17785e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1779e4f93234SChuck Lever } 1780e4f93234SChuck Lever 1781e4f93234SChuck Lever /* 1782e4f93234SChuck Lever * 3.3.12 REMOVE3res 1783e4f93234SChuck Lever * 1784e4f93234SChuck Lever * struct REMOVE3resok { 1785e4f93234SChuck Lever * wcc_data dir_wcc; 1786e4f93234SChuck Lever * }; 1787e4f93234SChuck Lever * 1788e4f93234SChuck Lever * struct REMOVE3resfail { 1789e4f93234SChuck Lever * wcc_data dir_wcc; 1790e4f93234SChuck Lever * }; 1791e4f93234SChuck Lever * 1792e4f93234SChuck Lever * union REMOVE3res switch (nfsstat3 status) { 1793e4f93234SChuck Lever * case NFS3_OK: 1794e4f93234SChuck Lever * REMOVE3resok resok; 1795e4f93234SChuck Lever * default: 1796e4f93234SChuck Lever * REMOVE3resfail resfail; 1797e4f93234SChuck Lever * }; 1798e4f93234SChuck Lever */ 1799bf269551SChuck Lever static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req, 1800bf269551SChuck Lever struct xdr_stream *xdr, 1801e4f93234SChuck Lever struct nfs_removeres *result) 1802e4f93234SChuck Lever { 1803e4f93234SChuck Lever enum nfs_stat status; 1804e4f93234SChuck Lever int error; 1805e4f93234SChuck Lever 1806bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1807e4f93234SChuck Lever if (unlikely(error)) 1808e4f93234SChuck Lever goto out; 1809bf269551SChuck Lever error = decode_wcc_data(xdr, result->dir_attr); 1810e4f93234SChuck Lever if (unlikely(error)) 1811e4f93234SChuck Lever goto out; 1812e4f93234SChuck Lever if (status != NFS3_OK) 1813e4f93234SChuck Lever goto out_status; 1814e4f93234SChuck Lever out: 1815e4f93234SChuck Lever return error; 1816e4f93234SChuck Lever out_status: 18175e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1818e4f93234SChuck Lever } 1819e4f93234SChuck Lever 1820e4f93234SChuck Lever /* 1821e4f93234SChuck Lever * 3.3.14 RENAME3res 1822e4f93234SChuck Lever * 1823e4f93234SChuck Lever * struct RENAME3resok { 1824e4f93234SChuck Lever * wcc_data fromdir_wcc; 1825e4f93234SChuck Lever * wcc_data todir_wcc; 1826e4f93234SChuck Lever * }; 1827e4f93234SChuck Lever * 1828e4f93234SChuck Lever * struct RENAME3resfail { 1829e4f93234SChuck Lever * wcc_data fromdir_wcc; 1830e4f93234SChuck Lever * wcc_data todir_wcc; 1831e4f93234SChuck Lever * }; 1832e4f93234SChuck Lever * 1833e4f93234SChuck Lever * union RENAME3res switch (nfsstat3 status) { 1834e4f93234SChuck Lever * case NFS3_OK: 1835e4f93234SChuck Lever * RENAME3resok resok; 1836e4f93234SChuck Lever * default: 1837e4f93234SChuck Lever * RENAME3resfail resfail; 1838e4f93234SChuck Lever * }; 1839e4f93234SChuck Lever */ 1840bf269551SChuck Lever static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req, 1841bf269551SChuck Lever struct xdr_stream *xdr, 1842e4f93234SChuck Lever struct nfs_renameres *result) 1843e4f93234SChuck Lever { 1844e4f93234SChuck Lever enum nfs_stat status; 1845e4f93234SChuck Lever int error; 1846e4f93234SChuck Lever 1847bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1848e4f93234SChuck Lever if (unlikely(error)) 1849e4f93234SChuck Lever goto out; 1850bf269551SChuck Lever error = decode_wcc_data(xdr, result->old_fattr); 1851e4f93234SChuck Lever if (unlikely(error)) 1852e4f93234SChuck Lever goto out; 1853bf269551SChuck Lever error = decode_wcc_data(xdr, result->new_fattr); 1854e4f93234SChuck Lever if (unlikely(error)) 1855e4f93234SChuck Lever goto out; 1856e4f93234SChuck Lever if (status != NFS3_OK) 1857e4f93234SChuck Lever goto out_status; 1858e4f93234SChuck Lever out: 1859e4f93234SChuck Lever return error; 1860e4f93234SChuck Lever out_status: 18615e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1862e4f93234SChuck Lever } 1863e4f93234SChuck Lever 1864e4f93234SChuck Lever /* 1865e4f93234SChuck Lever * 3.3.15 LINK3res 1866e4f93234SChuck Lever * 1867e4f93234SChuck Lever * struct LINK3resok { 1868e4f93234SChuck Lever * post_op_attr file_attributes; 1869e4f93234SChuck Lever * wcc_data linkdir_wcc; 1870e4f93234SChuck Lever * }; 1871e4f93234SChuck Lever * 1872e4f93234SChuck Lever * struct LINK3resfail { 1873e4f93234SChuck Lever * post_op_attr file_attributes; 1874e4f93234SChuck Lever * wcc_data linkdir_wcc; 1875e4f93234SChuck Lever * }; 1876e4f93234SChuck Lever * 1877e4f93234SChuck Lever * union LINK3res switch (nfsstat3 status) { 1878e4f93234SChuck Lever * case NFS3_OK: 1879e4f93234SChuck Lever * LINK3resok resok; 1880e4f93234SChuck Lever * default: 1881e4f93234SChuck Lever * LINK3resfail resfail; 1882e4f93234SChuck Lever * }; 1883e4f93234SChuck Lever */ 1884bf269551SChuck Lever static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr, 1885e4f93234SChuck Lever struct nfs3_linkres *result) 1886e4f93234SChuck Lever { 1887e4f93234SChuck Lever enum nfs_stat status; 1888e4f93234SChuck Lever int error; 1889e4f93234SChuck Lever 1890bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 1891e4f93234SChuck Lever if (unlikely(error)) 1892e4f93234SChuck Lever goto out; 1893bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 1894e4f93234SChuck Lever if (unlikely(error)) 1895e4f93234SChuck Lever goto out; 1896bf269551SChuck Lever error = decode_wcc_data(xdr, result->dir_attr); 1897e4f93234SChuck Lever if (unlikely(error)) 1898e4f93234SChuck Lever goto out; 1899e4f93234SChuck Lever if (status != NFS3_OK) 1900e4f93234SChuck Lever goto out_status; 1901e4f93234SChuck Lever out: 1902e4f93234SChuck Lever return error; 1903e4f93234SChuck Lever out_status: 19045e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 1905e4f93234SChuck Lever } 1906e4f93234SChuck Lever 1907e4f93234SChuck Lever /** 1908e4f93234SChuck Lever * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in 1909e4f93234SChuck Lever * the local page cache 1910e4f93234SChuck Lever * @xdr: XDR stream where entry resides 1911e4f93234SChuck Lever * @entry: buffer to fill in with entry data 1912e4f93234SChuck Lever * @plus: boolean indicating whether this should be a readdirplus entry 1913e4f93234SChuck Lever * 1914573c4e1eSChuck Lever * Returns zero if successful, otherwise a negative errno value is 1915573c4e1eSChuck Lever * returned. 1916e4f93234SChuck Lever * 1917e4f93234SChuck Lever * This function is not invoked during READDIR reply decoding, but 1918e4f93234SChuck Lever * rather whenever an application invokes the getdents(2) system call 1919e4f93234SChuck Lever * on a directory already in our cache. 1920e4f93234SChuck Lever * 1921e4f93234SChuck Lever * 3.3.16 entry3 1922e4f93234SChuck Lever * 1923e4f93234SChuck Lever * struct entry3 { 1924e4f93234SChuck Lever * fileid3 fileid; 1925e4f93234SChuck Lever * filename3 name; 1926e4f93234SChuck Lever * cookie3 cookie; 1927e4f93234SChuck Lever * fhandle3 filehandle; 1928e4f93234SChuck Lever * post_op_attr3 attributes; 1929e4f93234SChuck Lever * entry3 *nextentry; 1930e4f93234SChuck Lever * }; 1931e4f93234SChuck Lever * 1932e4f93234SChuck Lever * 3.3.17 entryplus3 1933e4f93234SChuck Lever * struct entryplus3 { 1934e4f93234SChuck Lever * fileid3 fileid; 1935e4f93234SChuck Lever * filename3 name; 1936e4f93234SChuck Lever * cookie3 cookie; 1937e4f93234SChuck Lever * post_op_attr name_attributes; 1938e4f93234SChuck Lever * post_op_fh3 name_handle; 1939e4f93234SChuck Lever * entryplus3 *nextentry; 1940e4f93234SChuck Lever * }; 1941e4f93234SChuck Lever */ 1942573c4e1eSChuck Lever int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, 1943573c4e1eSChuck Lever int plus) 1944e4f93234SChuck Lever { 1945e4f93234SChuck Lever struct nfs_entry old = *entry; 1946e4f93234SChuck Lever __be32 *p; 1947e4f93234SChuck Lever int error; 1948e4f93234SChuck Lever 1949e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 1950e4f93234SChuck Lever if (unlikely(p == NULL)) 1951e4f93234SChuck Lever goto out_overflow; 1952e4f93234SChuck Lever if (*p == xdr_zero) { 1953e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 1954e4f93234SChuck Lever if (unlikely(p == NULL)) 1955e4f93234SChuck Lever goto out_overflow; 1956e4f93234SChuck Lever if (*p == xdr_zero) 1957573c4e1eSChuck Lever return -EAGAIN; 1958e4f93234SChuck Lever entry->eof = 1; 1959573c4e1eSChuck Lever return -EBADCOOKIE; 1960e4f93234SChuck Lever } 1961e4f93234SChuck Lever 1962e4f93234SChuck Lever error = decode_fileid3(xdr, &entry->ino); 1963e4f93234SChuck Lever if (unlikely(error)) 1964573c4e1eSChuck Lever return error; 1965e4f93234SChuck Lever 1966e4f93234SChuck Lever error = decode_inline_filename3(xdr, &entry->name, &entry->len); 1967e4f93234SChuck Lever if (unlikely(error)) 1968573c4e1eSChuck Lever return error; 1969e4f93234SChuck Lever 1970e4f93234SChuck Lever entry->prev_cookie = entry->cookie; 1971e4f93234SChuck Lever error = decode_cookie3(xdr, &entry->cookie); 1972e4f93234SChuck Lever if (unlikely(error)) 1973573c4e1eSChuck Lever return error; 1974e4f93234SChuck Lever 1975e4f93234SChuck Lever entry->d_type = DT_UNKNOWN; 1976e4f93234SChuck Lever 1977e4f93234SChuck Lever if (plus) { 1978e4f93234SChuck Lever entry->fattr->valid = 0; 1979e4f93234SChuck Lever error = decode_post_op_attr(xdr, entry->fattr); 1980e4f93234SChuck Lever if (unlikely(error)) 1981573c4e1eSChuck Lever return error; 1982e4f93234SChuck Lever if (entry->fattr->valid & NFS_ATTR_FATTR_V3) 1983e4f93234SChuck Lever entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); 1984e4f93234SChuck Lever 1985e4f93234SChuck Lever /* In fact, a post_op_fh3: */ 1986e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4); 1987e4f93234SChuck Lever if (unlikely(p == NULL)) 1988e4f93234SChuck Lever goto out_overflow; 1989e4f93234SChuck Lever if (*p != xdr_zero) { 1990e4f93234SChuck Lever error = decode_nfs_fh3(xdr, entry->fh); 1991e4f93234SChuck Lever if (unlikely(error)) { 1992e4f93234SChuck Lever if (error == -E2BIG) 1993e4f93234SChuck Lever goto out_truncated; 1994573c4e1eSChuck Lever return error; 1995e4f93234SChuck Lever } 1996e4f93234SChuck Lever } else 1997e4f93234SChuck Lever zero_nfs_fh3(entry->fh); 1998e4f93234SChuck Lever } 1999e4f93234SChuck Lever 2000573c4e1eSChuck Lever return 0; 2001e4f93234SChuck Lever 2002e4f93234SChuck Lever out_overflow: 2003e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2004573c4e1eSChuck Lever return -EAGAIN; 2005e4f93234SChuck Lever out_truncated: 2006e4f93234SChuck Lever dprintk("NFS: directory entry contains invalid file handle\n"); 2007e4f93234SChuck Lever *entry = old; 2008573c4e1eSChuck Lever return -EAGAIN; 2009e4f93234SChuck Lever } 2010e4f93234SChuck Lever 2011e4f93234SChuck Lever /* 2012e4f93234SChuck Lever * 3.3.16 READDIR3res 2013e4f93234SChuck Lever * 2014e4f93234SChuck Lever * struct dirlist3 { 2015e4f93234SChuck Lever * entry3 *entries; 2016e4f93234SChuck Lever * bool eof; 2017e4f93234SChuck Lever * }; 2018e4f93234SChuck Lever * 2019e4f93234SChuck Lever * struct READDIR3resok { 2020e4f93234SChuck Lever * post_op_attr dir_attributes; 2021e4f93234SChuck Lever * cookieverf3 cookieverf; 2022e4f93234SChuck Lever * dirlist3 reply; 2023e4f93234SChuck Lever * }; 2024e4f93234SChuck Lever * 2025e4f93234SChuck Lever * struct READDIR3resfail { 2026e4f93234SChuck Lever * post_op_attr dir_attributes; 2027e4f93234SChuck Lever * }; 2028e4f93234SChuck Lever * 2029e4f93234SChuck Lever * union READDIR3res switch (nfsstat3 status) { 2030e4f93234SChuck Lever * case NFS3_OK: 2031e4f93234SChuck Lever * READDIR3resok resok; 2032e4f93234SChuck Lever * default: 2033e4f93234SChuck Lever * READDIR3resfail resfail; 2034e4f93234SChuck Lever * }; 2035e4f93234SChuck Lever * 2036e4f93234SChuck Lever * Read the directory contents into the page cache, but otherwise 2037e4f93234SChuck Lever * don't touch them. The actual decoding is done by nfs3_decode_entry() 2038e4f93234SChuck Lever * during subsequent nfs_readdir() calls. 2039e4f93234SChuck Lever */ 2040e4f93234SChuck Lever static int decode_dirlist3(struct xdr_stream *xdr) 2041e4f93234SChuck Lever { 2042e4f93234SChuck Lever u32 recvd, pglen; 2043e4f93234SChuck Lever size_t hdrlen; 2044e4f93234SChuck Lever 2045e4f93234SChuck Lever pglen = xdr->buf->page_len; 2046e4f93234SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 2047e4f93234SChuck Lever recvd = xdr->buf->len - hdrlen; 2048e4f93234SChuck Lever if (unlikely(pglen > recvd)) 2049e4f93234SChuck Lever goto out_cheating; 2050e4f93234SChuck Lever out: 2051e4f93234SChuck Lever xdr_read_pages(xdr, pglen); 2052e4f93234SChuck Lever return pglen; 2053e4f93234SChuck Lever out_cheating: 2054e4f93234SChuck Lever dprintk("NFS: server cheating in readdir result: " 2055e4f93234SChuck Lever "pglen %u > recvd %u\n", pglen, recvd); 2056e4f93234SChuck Lever pglen = recvd; 2057e4f93234SChuck Lever goto out; 2058e4f93234SChuck Lever } 2059e4f93234SChuck Lever 2060e4f93234SChuck Lever static int decode_readdir3resok(struct xdr_stream *xdr, 2061e4f93234SChuck Lever struct nfs3_readdirres *result) 2062e4f93234SChuck Lever { 2063e4f93234SChuck Lever int error; 2064e4f93234SChuck Lever 2065e4f93234SChuck Lever error = decode_post_op_attr(xdr, result->dir_attr); 2066e4f93234SChuck Lever if (unlikely(error)) 2067e4f93234SChuck Lever goto out; 2068e4f93234SChuck Lever /* XXX: do we need to check if result->verf != NULL ? */ 2069e4f93234SChuck Lever error = decode_cookieverf3(xdr, result->verf); 2070e4f93234SChuck Lever if (unlikely(error)) 2071e4f93234SChuck Lever goto out; 2072e4f93234SChuck Lever error = decode_dirlist3(xdr); 2073e4f93234SChuck Lever out: 2074e4f93234SChuck Lever return error; 2075e4f93234SChuck Lever } 2076e4f93234SChuck Lever 2077bf269551SChuck Lever static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req, 2078bf269551SChuck Lever struct xdr_stream *xdr, 2079e4f93234SChuck Lever struct nfs3_readdirres *result) 2080e4f93234SChuck Lever { 2081e4f93234SChuck Lever enum nfs_stat status; 2082e4f93234SChuck Lever int error; 2083e4f93234SChuck Lever 2084bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2085e4f93234SChuck Lever if (unlikely(error)) 2086e4f93234SChuck Lever goto out; 2087e4f93234SChuck Lever if (status != NFS3_OK) 2088e4f93234SChuck Lever goto out_default; 2089bf269551SChuck Lever error = decode_readdir3resok(xdr, result); 2090e4f93234SChuck Lever out: 2091e4f93234SChuck Lever return error; 2092e4f93234SChuck Lever out_default: 2093bf269551SChuck Lever error = decode_post_op_attr(xdr, result->dir_attr); 2094e4f93234SChuck Lever if (unlikely(error)) 2095e4f93234SChuck Lever goto out; 20965e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2097e4f93234SChuck Lever } 2098e4f93234SChuck Lever 2099e4f93234SChuck Lever /* 2100e4f93234SChuck Lever * 3.3.18 FSSTAT3res 2101e4f93234SChuck Lever * 2102e4f93234SChuck Lever * struct FSSTAT3resok { 2103e4f93234SChuck Lever * post_op_attr obj_attributes; 2104e4f93234SChuck Lever * size3 tbytes; 2105e4f93234SChuck Lever * size3 fbytes; 2106e4f93234SChuck Lever * size3 abytes; 2107e4f93234SChuck Lever * size3 tfiles; 2108e4f93234SChuck Lever * size3 ffiles; 2109e4f93234SChuck Lever * size3 afiles; 2110e4f93234SChuck Lever * uint32 invarsec; 2111e4f93234SChuck Lever * }; 2112e4f93234SChuck Lever * 2113e4f93234SChuck Lever * struct FSSTAT3resfail { 2114e4f93234SChuck Lever * post_op_attr obj_attributes; 2115e4f93234SChuck Lever * }; 2116e4f93234SChuck Lever * 2117e4f93234SChuck Lever * union FSSTAT3res switch (nfsstat3 status) { 2118e4f93234SChuck Lever * case NFS3_OK: 2119e4f93234SChuck Lever * FSSTAT3resok resok; 2120e4f93234SChuck Lever * default: 2121e4f93234SChuck Lever * FSSTAT3resfail resfail; 2122e4f93234SChuck Lever * }; 2123e4f93234SChuck Lever */ 2124e4f93234SChuck Lever static int decode_fsstat3resok(struct xdr_stream *xdr, 2125e4f93234SChuck Lever struct nfs_fsstat *result) 2126e4f93234SChuck Lever { 2127e4f93234SChuck Lever __be32 *p; 2128e4f93234SChuck Lever 2129e4f93234SChuck Lever p = xdr_inline_decode(xdr, 8 * 6 + 4); 2130e4f93234SChuck Lever if (unlikely(p == NULL)) 2131e4f93234SChuck Lever goto out_overflow; 2132e4f93234SChuck Lever p = xdr_decode_size3(p, &result->tbytes); 2133e4f93234SChuck Lever p = xdr_decode_size3(p, &result->fbytes); 2134e4f93234SChuck Lever p = xdr_decode_size3(p, &result->abytes); 2135e4f93234SChuck Lever p = xdr_decode_size3(p, &result->tfiles); 2136e4f93234SChuck Lever p = xdr_decode_size3(p, &result->ffiles); 2137e4f93234SChuck Lever xdr_decode_size3(p, &result->afiles); 2138e4f93234SChuck Lever /* ignore invarsec */ 2139e4f93234SChuck Lever return 0; 2140e4f93234SChuck Lever out_overflow: 2141e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2142e4f93234SChuck Lever return -EIO; 2143e4f93234SChuck Lever } 2144e4f93234SChuck Lever 2145bf269551SChuck Lever static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req, 2146bf269551SChuck Lever struct xdr_stream *xdr, 2147e4f93234SChuck Lever struct nfs_fsstat *result) 2148e4f93234SChuck Lever { 2149e4f93234SChuck Lever enum nfs_stat status; 2150e4f93234SChuck Lever int error; 2151e4f93234SChuck Lever 2152bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2153e4f93234SChuck Lever if (unlikely(error)) 2154e4f93234SChuck Lever goto out; 2155bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2156e4f93234SChuck Lever if (unlikely(error)) 2157e4f93234SChuck Lever goto out; 2158e4f93234SChuck Lever if (status != NFS3_OK) 2159e4f93234SChuck Lever goto out_status; 2160bf269551SChuck Lever error = decode_fsstat3resok(xdr, result); 2161e4f93234SChuck Lever out: 2162e4f93234SChuck Lever return error; 2163e4f93234SChuck Lever out_status: 21645e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2165e4f93234SChuck Lever } 2166e4f93234SChuck Lever 2167e4f93234SChuck Lever /* 2168e4f93234SChuck Lever * 3.3.19 FSINFO3res 2169e4f93234SChuck Lever * 2170e4f93234SChuck Lever * struct FSINFO3resok { 2171e4f93234SChuck Lever * post_op_attr obj_attributes; 2172e4f93234SChuck Lever * uint32 rtmax; 2173e4f93234SChuck Lever * uint32 rtpref; 2174e4f93234SChuck Lever * uint32 rtmult; 2175e4f93234SChuck Lever * uint32 wtmax; 2176e4f93234SChuck Lever * uint32 wtpref; 2177e4f93234SChuck Lever * uint32 wtmult; 2178e4f93234SChuck Lever * uint32 dtpref; 2179e4f93234SChuck Lever * size3 maxfilesize; 2180e4f93234SChuck Lever * nfstime3 time_delta; 2181e4f93234SChuck Lever * uint32 properties; 2182e4f93234SChuck Lever * }; 2183e4f93234SChuck Lever * 2184e4f93234SChuck Lever * struct FSINFO3resfail { 2185e4f93234SChuck Lever * post_op_attr obj_attributes; 2186e4f93234SChuck Lever * }; 2187e4f93234SChuck Lever * 2188e4f93234SChuck Lever * union FSINFO3res switch (nfsstat3 status) { 2189e4f93234SChuck Lever * case NFS3_OK: 2190e4f93234SChuck Lever * FSINFO3resok resok; 2191e4f93234SChuck Lever * default: 2192e4f93234SChuck Lever * FSINFO3resfail resfail; 2193e4f93234SChuck Lever * }; 2194e4f93234SChuck Lever */ 2195e4f93234SChuck Lever static int decode_fsinfo3resok(struct xdr_stream *xdr, 2196e4f93234SChuck Lever struct nfs_fsinfo *result) 2197e4f93234SChuck Lever { 2198e4f93234SChuck Lever __be32 *p; 2199e4f93234SChuck Lever 2200e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4); 2201e4f93234SChuck Lever if (unlikely(p == NULL)) 2202e4f93234SChuck Lever goto out_overflow; 2203e4f93234SChuck Lever result->rtmax = be32_to_cpup(p++); 2204e4f93234SChuck Lever result->rtpref = be32_to_cpup(p++); 2205e4f93234SChuck Lever result->rtmult = be32_to_cpup(p++); 2206e4f93234SChuck Lever result->wtmax = be32_to_cpup(p++); 2207e4f93234SChuck Lever result->wtpref = be32_to_cpup(p++); 2208e4f93234SChuck Lever result->wtmult = be32_to_cpup(p++); 2209e4f93234SChuck Lever result->dtpref = be32_to_cpup(p++); 2210e4f93234SChuck Lever p = xdr_decode_size3(p, &result->maxfilesize); 2211f6048709SChuck Lever xdr_decode_nfstime3(p, &result->time_delta); 2212e4f93234SChuck Lever 2213e4f93234SChuck Lever /* ignore properties */ 2214e4f93234SChuck Lever result->lease_time = 0; 2215e4f93234SChuck Lever return 0; 2216e4f93234SChuck Lever out_overflow: 2217e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2218e4f93234SChuck Lever return -EIO; 2219e4f93234SChuck Lever } 2220e4f93234SChuck Lever 2221bf269551SChuck Lever static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req, 2222bf269551SChuck Lever struct xdr_stream *xdr, 2223e4f93234SChuck Lever struct nfs_fsinfo *result) 2224e4f93234SChuck Lever { 2225e4f93234SChuck Lever enum nfs_stat status; 2226e4f93234SChuck Lever int error; 2227e4f93234SChuck Lever 2228bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2229e4f93234SChuck Lever if (unlikely(error)) 2230e4f93234SChuck Lever goto out; 2231bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2232e4f93234SChuck Lever if (unlikely(error)) 2233e4f93234SChuck Lever goto out; 2234e4f93234SChuck Lever if (status != NFS3_OK) 2235e4f93234SChuck Lever goto out_status; 2236bf269551SChuck Lever error = decode_fsinfo3resok(xdr, result); 2237e4f93234SChuck Lever out: 2238e4f93234SChuck Lever return error; 2239e4f93234SChuck Lever out_status: 22405e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2241e4f93234SChuck Lever } 2242e4f93234SChuck Lever 2243e4f93234SChuck Lever /* 2244e4f93234SChuck Lever * 3.3.20 PATHCONF3res 2245e4f93234SChuck Lever * 2246e4f93234SChuck Lever * struct PATHCONF3resok { 2247e4f93234SChuck Lever * post_op_attr obj_attributes; 2248e4f93234SChuck Lever * uint32 linkmax; 2249e4f93234SChuck Lever * uint32 name_max; 2250e4f93234SChuck Lever * bool no_trunc; 2251e4f93234SChuck Lever * bool chown_restricted; 2252e4f93234SChuck Lever * bool case_insensitive; 2253e4f93234SChuck Lever * bool case_preserving; 2254e4f93234SChuck Lever * }; 2255e4f93234SChuck Lever * 2256e4f93234SChuck Lever * struct PATHCONF3resfail { 2257e4f93234SChuck Lever * post_op_attr obj_attributes; 2258e4f93234SChuck Lever * }; 2259e4f93234SChuck Lever * 2260e4f93234SChuck Lever * union PATHCONF3res switch (nfsstat3 status) { 2261e4f93234SChuck Lever * case NFS3_OK: 2262e4f93234SChuck Lever * PATHCONF3resok resok; 2263e4f93234SChuck Lever * default: 2264e4f93234SChuck Lever * PATHCONF3resfail resfail; 2265e4f93234SChuck Lever * }; 2266e4f93234SChuck Lever */ 2267e4f93234SChuck Lever static int decode_pathconf3resok(struct xdr_stream *xdr, 2268e4f93234SChuck Lever struct nfs_pathconf *result) 2269e4f93234SChuck Lever { 2270e4f93234SChuck Lever __be32 *p; 2271e4f93234SChuck Lever 2272e4f93234SChuck Lever p = xdr_inline_decode(xdr, 4 * 6); 2273e4f93234SChuck Lever if (unlikely(p == NULL)) 2274e4f93234SChuck Lever goto out_overflow; 2275e4f93234SChuck Lever result->max_link = be32_to_cpup(p++); 2276e4f93234SChuck Lever result->max_namelen = be32_to_cpup(p); 2277e4f93234SChuck Lever /* ignore remaining fields */ 2278e4f93234SChuck Lever return 0; 2279e4f93234SChuck Lever out_overflow: 2280e4f93234SChuck Lever print_overflow_msg(__func__, xdr); 2281e4f93234SChuck Lever return -EIO; 2282e4f93234SChuck Lever } 2283e4f93234SChuck Lever 2284bf269551SChuck Lever static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req, 2285bf269551SChuck Lever struct xdr_stream *xdr, 2286e4f93234SChuck Lever struct nfs_pathconf *result) 2287e4f93234SChuck Lever { 2288e4f93234SChuck Lever enum nfs_stat status; 2289e4f93234SChuck Lever int error; 2290e4f93234SChuck Lever 2291bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2292e4f93234SChuck Lever if (unlikely(error)) 2293e4f93234SChuck Lever goto out; 2294bf269551SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2295e4f93234SChuck Lever if (unlikely(error)) 2296e4f93234SChuck Lever goto out; 2297e4f93234SChuck Lever if (status != NFS3_OK) 2298e4f93234SChuck Lever goto out_status; 2299bf269551SChuck Lever error = decode_pathconf3resok(xdr, result); 2300e4f93234SChuck Lever out: 2301e4f93234SChuck Lever return error; 2302e4f93234SChuck Lever out_status: 23035e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2304e4f93234SChuck Lever } 2305e4f93234SChuck Lever 2306e4f93234SChuck Lever /* 2307e4f93234SChuck Lever * 3.3.21 COMMIT3res 2308e4f93234SChuck Lever * 2309e4f93234SChuck Lever * struct COMMIT3resok { 2310e4f93234SChuck Lever * wcc_data file_wcc; 2311e4f93234SChuck Lever * writeverf3 verf; 2312e4f93234SChuck Lever * }; 2313e4f93234SChuck Lever * 2314e4f93234SChuck Lever * struct COMMIT3resfail { 2315e4f93234SChuck Lever * wcc_data file_wcc; 2316e4f93234SChuck Lever * }; 2317e4f93234SChuck Lever * 2318e4f93234SChuck Lever * union COMMIT3res switch (nfsstat3 status) { 2319e4f93234SChuck Lever * case NFS3_OK: 2320e4f93234SChuck Lever * COMMIT3resok resok; 2321e4f93234SChuck Lever * default: 2322e4f93234SChuck Lever * COMMIT3resfail resfail; 2323e4f93234SChuck Lever * }; 2324e4f93234SChuck Lever */ 2325bf269551SChuck Lever static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, 2326bf269551SChuck Lever struct xdr_stream *xdr, 23270b7c0153SFred Isaman struct nfs_commitres *result) 2328e4f93234SChuck Lever { 2329e4f93234SChuck Lever enum nfs_stat status; 2330e4f93234SChuck Lever int error; 2331e4f93234SChuck Lever 2332bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2333e4f93234SChuck Lever if (unlikely(error)) 2334e4f93234SChuck Lever goto out; 2335bf269551SChuck Lever error = decode_wcc_data(xdr, result->fattr); 2336e4f93234SChuck Lever if (unlikely(error)) 2337e4f93234SChuck Lever goto out; 2338e4f93234SChuck Lever if (status != NFS3_OK) 2339e4f93234SChuck Lever goto out_status; 2340bf269551SChuck Lever error = decode_writeverf3(xdr, result->verf->verifier); 2341e4f93234SChuck Lever out: 2342e4f93234SChuck Lever return error; 2343e4f93234SChuck Lever out_status: 23445e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2345e4f93234SChuck Lever } 2346e4f93234SChuck Lever 2347b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 2348b7fa0554SAndreas Gruenbacher 2349e4f93234SChuck Lever static inline int decode_getacl3resok(struct xdr_stream *xdr, 2350e4f93234SChuck Lever struct nfs3_getaclres *result) 2351e4f93234SChuck Lever { 2352e4f93234SChuck Lever struct posix_acl **acl; 2353e4f93234SChuck Lever unsigned int *aclcnt; 2354e4f93234SChuck Lever size_t hdrlen; 2355e4f93234SChuck Lever int error; 2356e4f93234SChuck Lever 2357e4f93234SChuck Lever error = decode_post_op_attr(xdr, result->fattr); 2358e4f93234SChuck Lever if (unlikely(error)) 2359e4f93234SChuck Lever goto out; 2360e4f93234SChuck Lever error = decode_uint32(xdr, &result->mask); 2361e4f93234SChuck Lever if (unlikely(error)) 2362e4f93234SChuck Lever goto out; 2363e4f93234SChuck Lever error = -EINVAL; 2364e4f93234SChuck Lever if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 2365e4f93234SChuck Lever goto out; 2366e4f93234SChuck Lever 2367e4f93234SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 2368e4f93234SChuck Lever 2369e4f93234SChuck Lever acl = NULL; 2370e4f93234SChuck Lever if (result->mask & NFS_ACL) 2371e4f93234SChuck Lever acl = &result->acl_access; 2372e4f93234SChuck Lever aclcnt = NULL; 2373e4f93234SChuck Lever if (result->mask & NFS_ACLCNT) 2374e4f93234SChuck Lever aclcnt = &result->acl_access_count; 2375e4f93234SChuck Lever error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl); 2376e4f93234SChuck Lever if (unlikely(error <= 0)) 2377e4f93234SChuck Lever goto out; 2378e4f93234SChuck Lever 2379e4f93234SChuck Lever acl = NULL; 2380e4f93234SChuck Lever if (result->mask & NFS_DFACL) 2381e4f93234SChuck Lever acl = &result->acl_default; 2382e4f93234SChuck Lever aclcnt = NULL; 2383e4f93234SChuck Lever if (result->mask & NFS_DFACLCNT) 2384e4f93234SChuck Lever aclcnt = &result->acl_default_count; 2385e4f93234SChuck Lever error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl); 2386e4f93234SChuck Lever if (unlikely(error <= 0)) 2387e4f93234SChuck Lever return error; 2388e4f93234SChuck Lever error = 0; 2389e4f93234SChuck Lever out: 2390e4f93234SChuck Lever return error; 2391e4f93234SChuck Lever } 2392e4f93234SChuck Lever 2393bf269551SChuck Lever static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req, 2394bf269551SChuck Lever struct xdr_stream *xdr, 2395e4f93234SChuck Lever struct nfs3_getaclres *result) 2396e4f93234SChuck Lever { 2397e4f93234SChuck Lever enum nfs_stat status; 2398e4f93234SChuck Lever int error; 2399e4f93234SChuck Lever 2400bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2401e4f93234SChuck Lever if (unlikely(error)) 2402e4f93234SChuck Lever goto out; 2403e4f93234SChuck Lever if (status != NFS3_OK) 2404e4f93234SChuck Lever goto out_default; 2405bf269551SChuck Lever error = decode_getacl3resok(xdr, result); 2406e4f93234SChuck Lever out: 2407e4f93234SChuck Lever return error; 2408e4f93234SChuck Lever out_default: 24095e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2410e4f93234SChuck Lever } 2411e4f93234SChuck Lever 2412bf269551SChuck Lever static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req, 2413bf269551SChuck Lever struct xdr_stream *xdr, 2414e4f93234SChuck Lever struct nfs_fattr *result) 2415e4f93234SChuck Lever { 2416e4f93234SChuck Lever enum nfs_stat status; 2417e4f93234SChuck Lever int error; 2418e4f93234SChuck Lever 2419bf269551SChuck Lever error = decode_nfsstat3(xdr, &status); 2420e4f93234SChuck Lever if (unlikely(error)) 2421e4f93234SChuck Lever goto out; 2422e4f93234SChuck Lever if (status != NFS3_OK) 2423e4f93234SChuck Lever goto out_default; 2424bf269551SChuck Lever error = decode_post_op_attr(xdr, result); 2425e4f93234SChuck Lever out: 2426e4f93234SChuck Lever return error; 2427e4f93234SChuck Lever out_default: 24285e7e5a0dSBryan Schumaker return nfs3_stat_to_errno(status); 2429e4f93234SChuck Lever } 2430e4f93234SChuck Lever 2431b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 2432b7fa0554SAndreas Gruenbacher 24335e7e5a0dSBryan Schumaker 24345e7e5a0dSBryan Schumaker /* 24355e7e5a0dSBryan Schumaker * We need to translate between nfs status return values and 24365e7e5a0dSBryan Schumaker * the local errno values which may not be the same. 24375e7e5a0dSBryan Schumaker */ 24385e7e5a0dSBryan Schumaker static const struct { 24395e7e5a0dSBryan Schumaker int stat; 24405e7e5a0dSBryan Schumaker int errno; 24415e7e5a0dSBryan Schumaker } nfs_errtbl[] = { 24425e7e5a0dSBryan Schumaker { NFS_OK, 0 }, 24435e7e5a0dSBryan Schumaker { NFSERR_PERM, -EPERM }, 24445e7e5a0dSBryan Schumaker { NFSERR_NOENT, -ENOENT }, 24455e7e5a0dSBryan Schumaker { NFSERR_IO, -errno_NFSERR_IO}, 24465e7e5a0dSBryan Schumaker { NFSERR_NXIO, -ENXIO }, 24475e7e5a0dSBryan Schumaker /* { NFSERR_EAGAIN, -EAGAIN }, */ 24485e7e5a0dSBryan Schumaker { NFSERR_ACCES, -EACCES }, 24495e7e5a0dSBryan Schumaker { NFSERR_EXIST, -EEXIST }, 24505e7e5a0dSBryan Schumaker { NFSERR_XDEV, -EXDEV }, 24515e7e5a0dSBryan Schumaker { NFSERR_NODEV, -ENODEV }, 24525e7e5a0dSBryan Schumaker { NFSERR_NOTDIR, -ENOTDIR }, 24535e7e5a0dSBryan Schumaker { NFSERR_ISDIR, -EISDIR }, 24545e7e5a0dSBryan Schumaker { NFSERR_INVAL, -EINVAL }, 24555e7e5a0dSBryan Schumaker { NFSERR_FBIG, -EFBIG }, 24565e7e5a0dSBryan Schumaker { NFSERR_NOSPC, -ENOSPC }, 24575e7e5a0dSBryan Schumaker { NFSERR_ROFS, -EROFS }, 24585e7e5a0dSBryan Schumaker { NFSERR_MLINK, -EMLINK }, 24595e7e5a0dSBryan Schumaker { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, 24605e7e5a0dSBryan Schumaker { NFSERR_NOTEMPTY, -ENOTEMPTY }, 24615e7e5a0dSBryan Schumaker { NFSERR_DQUOT, -EDQUOT }, 24625e7e5a0dSBryan Schumaker { NFSERR_STALE, -ESTALE }, 24635e7e5a0dSBryan Schumaker { NFSERR_REMOTE, -EREMOTE }, 24645e7e5a0dSBryan Schumaker #ifdef EWFLUSH 24655e7e5a0dSBryan Schumaker { NFSERR_WFLUSH, -EWFLUSH }, 24665e7e5a0dSBryan Schumaker #endif 24675e7e5a0dSBryan Schumaker { NFSERR_BADHANDLE, -EBADHANDLE }, 24685e7e5a0dSBryan Schumaker { NFSERR_NOT_SYNC, -ENOTSYNC }, 24695e7e5a0dSBryan Schumaker { NFSERR_BAD_COOKIE, -EBADCOOKIE }, 24705e7e5a0dSBryan Schumaker { NFSERR_NOTSUPP, -ENOTSUPP }, 24715e7e5a0dSBryan Schumaker { NFSERR_TOOSMALL, -ETOOSMALL }, 24725e7e5a0dSBryan Schumaker { NFSERR_SERVERFAULT, -EREMOTEIO }, 24735e7e5a0dSBryan Schumaker { NFSERR_BADTYPE, -EBADTYPE }, 24745e7e5a0dSBryan Schumaker { NFSERR_JUKEBOX, -EJUKEBOX }, 24755e7e5a0dSBryan Schumaker { -1, -EIO } 24765e7e5a0dSBryan Schumaker }; 24775e7e5a0dSBryan Schumaker 24785e7e5a0dSBryan Schumaker /** 24795e7e5a0dSBryan Schumaker * nfs3_stat_to_errno - convert an NFS status code to a local errno 24805e7e5a0dSBryan Schumaker * @status: NFS status code to convert 24815e7e5a0dSBryan Schumaker * 24825e7e5a0dSBryan Schumaker * Returns a local errno value, or -EIO if the NFS status code is 24835e7e5a0dSBryan Schumaker * not recognized. This function is used jointly by NFSv2 and NFSv3. 24845e7e5a0dSBryan Schumaker */ 24855e7e5a0dSBryan Schumaker static int nfs3_stat_to_errno(enum nfs_stat status) 24865e7e5a0dSBryan Schumaker { 24875e7e5a0dSBryan Schumaker int i; 24885e7e5a0dSBryan Schumaker 24895e7e5a0dSBryan Schumaker for (i = 0; nfs_errtbl[i].stat != -1; i++) { 24905e7e5a0dSBryan Schumaker if (nfs_errtbl[i].stat == (int)status) 24915e7e5a0dSBryan Schumaker return nfs_errtbl[i].errno; 24925e7e5a0dSBryan Schumaker } 24935e7e5a0dSBryan Schumaker dprintk("NFS: Unrecognized nfs status value: %u\n", status); 24945e7e5a0dSBryan Schumaker return nfs_errtbl[i].errno; 24955e7e5a0dSBryan Schumaker } 24965e7e5a0dSBryan Schumaker 24975e7e5a0dSBryan Schumaker 24981da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer) \ 24991da177e4SLinus Torvalds [NFS3PROC_##proc] = { \ 25001da177e4SLinus Torvalds .p_proc = NFS3PROC_##proc, \ 25019f06c719SChuck Lever .p_encode = (kxdreproc_t)nfs3_xdr_enc_##argtype##3args, \ 2502bf269551SChuck Lever .p_decode = (kxdrdproc_t)nfs3_xdr_dec_##restype##3res, \ 2503ad96b5b5SChuck Lever .p_arglen = NFS3_##argtype##args_sz, \ 2504f5fc3c50SChuck Lever .p_replen = NFS3_##restype##res_sz, \ 2505cc0175c1SChuck Lever .p_timer = timer, \ 2506cc0175c1SChuck Lever .p_statidx = NFS3PROC_##proc, \ 2507cc0175c1SChuck Lever .p_name = #proc, \ 25081da177e4SLinus Torvalds } 25091da177e4SLinus Torvalds 25101da177e4SLinus Torvalds struct rpc_procinfo nfs3_procedures[] = { 2511f5fc3c50SChuck Lever PROC(GETATTR, getattr, getattr, 1), 2512f5fc3c50SChuck Lever PROC(SETATTR, setattr, setattr, 0), 2513f5fc3c50SChuck Lever PROC(LOOKUP, lookup, lookup, 2), 2514f5fc3c50SChuck Lever PROC(ACCESS, access, access, 1), 2515f5fc3c50SChuck Lever PROC(READLINK, readlink, readlink, 3), 2516f5fc3c50SChuck Lever PROC(READ, read, read, 3), 2517f5fc3c50SChuck Lever PROC(WRITE, write, write, 4), 2518f5fc3c50SChuck Lever PROC(CREATE, create, create, 0), 2519f5fc3c50SChuck Lever PROC(MKDIR, mkdir, create, 0), 2520f5fc3c50SChuck Lever PROC(SYMLINK, symlink, create, 0), 2521f5fc3c50SChuck Lever PROC(MKNOD, mknod, create, 0), 2522f5fc3c50SChuck Lever PROC(REMOVE, remove, remove, 0), 2523f5fc3c50SChuck Lever PROC(RMDIR, lookup, setattr, 0), 2524f5fc3c50SChuck Lever PROC(RENAME, rename, rename, 0), 2525f5fc3c50SChuck Lever PROC(LINK, link, link, 0), 2526f5fc3c50SChuck Lever PROC(READDIR, readdir, readdir, 3), 2527f5fc3c50SChuck Lever PROC(READDIRPLUS, readdirplus, readdir, 3), 2528f5fc3c50SChuck Lever PROC(FSSTAT, getattr, fsstat, 0), 2529f5fc3c50SChuck Lever PROC(FSINFO, getattr, fsinfo, 0), 2530f5fc3c50SChuck Lever PROC(PATHCONF, getattr, pathconf, 0), 2531f5fc3c50SChuck Lever PROC(COMMIT, commit, commit, 5), 25321da177e4SLinus Torvalds }; 25331da177e4SLinus Torvalds 2534a613fa16STrond Myklebust const struct rpc_version nfs_version3 = { 25351da177e4SLinus Torvalds .number = 3, 2536e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nfs3_procedures), 25371da177e4SLinus Torvalds .procs = nfs3_procedures 25381da177e4SLinus Torvalds }; 25391da177e4SLinus Torvalds 2540b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL 2541b7fa0554SAndreas Gruenbacher static struct rpc_procinfo nfs3_acl_procedures[] = { 2542b7fa0554SAndreas Gruenbacher [ACLPROC3_GETACL] = { 2543b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_GETACL, 25449f06c719SChuck Lever .p_encode = (kxdreproc_t)nfs3_xdr_enc_getacl3args, 2545bf269551SChuck Lever .p_decode = (kxdrdproc_t)nfs3_xdr_dec_getacl3res, 25462bea90d4SChuck Lever .p_arglen = ACL3_getaclargs_sz, 25472bea90d4SChuck Lever .p_replen = ACL3_getaclres_sz, 2548b7fa0554SAndreas Gruenbacher .p_timer = 1, 2549cc0175c1SChuck Lever .p_name = "GETACL", 2550b7fa0554SAndreas Gruenbacher }, 2551b7fa0554SAndreas Gruenbacher [ACLPROC3_SETACL] = { 2552b7fa0554SAndreas Gruenbacher .p_proc = ACLPROC3_SETACL, 25539f06c719SChuck Lever .p_encode = (kxdreproc_t)nfs3_xdr_enc_setacl3args, 2554bf269551SChuck Lever .p_decode = (kxdrdproc_t)nfs3_xdr_dec_setacl3res, 25552bea90d4SChuck Lever .p_arglen = ACL3_setaclargs_sz, 25562bea90d4SChuck Lever .p_replen = ACL3_setaclres_sz, 2557b7fa0554SAndreas Gruenbacher .p_timer = 0, 2558cc0175c1SChuck Lever .p_name = "SETACL", 2559b7fa0554SAndreas Gruenbacher }, 2560b7fa0554SAndreas Gruenbacher }; 2561b7fa0554SAndreas Gruenbacher 2562a613fa16STrond Myklebust const struct rpc_version nfsacl_version3 = { 2563b7fa0554SAndreas Gruenbacher .number = 3, 2564b7fa0554SAndreas Gruenbacher .nrprocs = sizeof(nfs3_acl_procedures)/ 2565b7fa0554SAndreas Gruenbacher sizeof(nfs3_acl_procedures[0]), 2566b7fa0554SAndreas Gruenbacher .procs = nfs3_acl_procedures, 2567b7fa0554SAndreas Gruenbacher }; 2568b7fa0554SAndreas Gruenbacher #endif /* CONFIG_NFS_V3_ACL */ 2569