11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/nfs/nfs2xdr.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * XDR functions to encode/decode NFS RPC arguments and results. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1992, 1993, 1994 Rick Sladkey 71da177e4SLinus Torvalds * Copyright (C) 1996 Olaf Kirch 81da177e4SLinus Torvalds * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu> 91da177e4SLinus Torvalds * FIFO's need special handling in NFSv2 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/param.h> 131da177e4SLinus Torvalds #include <linux/time.h> 141da177e4SLinus Torvalds #include <linux/mm.h> 151da177e4SLinus Torvalds #include <linux/errno.h> 161da177e4SLinus Torvalds #include <linux/string.h> 171da177e4SLinus Torvalds #include <linux/in.h> 181da177e4SLinus Torvalds #include <linux/pagemap.h> 191da177e4SLinus Torvalds #include <linux/proc_fs.h> 201da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 211da177e4SLinus Torvalds #include <linux/nfs.h> 221da177e4SLinus Torvalds #include <linux/nfs2.h> 231da177e4SLinus Torvalds #include <linux/nfs_fs.h> 24816724e6STrond Myklebust #include "internal.h" 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #define NFSDBG_FACILITY NFSDBG_XDR 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */ 291da177e4SLinus Torvalds #define errno_NFSERR_IO EIO 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds /* 321da177e4SLinus Torvalds * Declare the space requirements for NFS arguments and replies as 331da177e4SLinus Torvalds * number of 32bit-words 341da177e4SLinus Torvalds */ 351da177e4SLinus Torvalds #define NFS_fhandle_sz (8) 361da177e4SLinus Torvalds #define NFS_sattr_sz (8) 371da177e4SLinus Torvalds #define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2)) 381da177e4SLinus Torvalds #define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2)) 391da177e4SLinus Torvalds #define NFS_fattr_sz (17) 401da177e4SLinus Torvalds #define NFS_info_sz (5) 411da177e4SLinus Torvalds #define NFS_entry_sz (NFS_filename_sz+3) 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds #define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz) 444fdc17b2STrond Myklebust #define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz) 451da177e4SLinus Torvalds #define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz) 461da177e4SLinus Torvalds #define NFS_readlinkargs_sz (NFS_fhandle_sz) 471da177e4SLinus Torvalds #define NFS_readargs_sz (NFS_fhandle_sz+3) 481da177e4SLinus Torvalds #define NFS_writeargs_sz (NFS_fhandle_sz+4) 491da177e4SLinus Torvalds #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) 501da177e4SLinus Torvalds #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) 511da177e4SLinus Torvalds #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) 5294a6d753SChuck Lever #define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz) 531da177e4SLinus Torvalds #define NFS_readdirargs_sz (NFS_fhandle_sz+2) 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds #define NFS_attrstat_sz (1+NFS_fattr_sz) 561da177e4SLinus Torvalds #define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz) 571da177e4SLinus Torvalds #define NFS_readlinkres_sz (2) 581da177e4SLinus Torvalds #define NFS_readres_sz (1+NFS_fattr_sz+1) 591da177e4SLinus Torvalds #define NFS_writeres_sz (NFS_attrstat_sz) 601da177e4SLinus Torvalds #define NFS_stat_sz (1) 611da177e4SLinus Torvalds #define NFS_readdirres_sz (1) 621da177e4SLinus Torvalds #define NFS_statfsres_sz (1+NFS_info_sz) 631da177e4SLinus Torvalds 6425a0866cSChuck Lever 6525a0866cSChuck Lever /* 6625a0866cSChuck Lever * While encoding arguments, set up the reply buffer in advance to 6725a0866cSChuck Lever * receive reply data directly into the page cache. 6825a0866cSChuck Lever */ 6925a0866cSChuck Lever static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages, 7025a0866cSChuck Lever unsigned int base, unsigned int len, 7125a0866cSChuck Lever unsigned int bufsize) 7225a0866cSChuck Lever { 7325a0866cSChuck Lever struct rpc_auth *auth = req->rq_cred->cr_auth; 7425a0866cSChuck Lever unsigned int replen; 7525a0866cSChuck Lever 7625a0866cSChuck Lever replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize; 7725a0866cSChuck Lever xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len); 7825a0866cSChuck Lever } 7925a0866cSChuck Lever 80f796f8b3SChuck Lever /* 81f796f8b3SChuck Lever * Handle decode buffer overflows out-of-line. 82f796f8b3SChuck Lever */ 83f796f8b3SChuck Lever static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 84f796f8b3SChuck Lever { 85f796f8b3SChuck Lever dprintk("NFS: %s prematurely hit the end of our receive buffer. " 86f796f8b3SChuck Lever "Remaining buffer length is %tu words.\n", 87f796f8b3SChuck Lever func, xdr->end - xdr->p); 88f796f8b3SChuck Lever } 89f796f8b3SChuck Lever 9025a0866cSChuck Lever 911da177e4SLinus Torvalds /* 9225a0866cSChuck Lever * Encode/decode NFSv2 basic data types 9325a0866cSChuck Lever * 9425a0866cSChuck Lever * Basic NFSv2 data types are defined in section 2.3 of RFC 1094: 9525a0866cSChuck Lever * "NFS: Network File System Protocol Specification". 9625a0866cSChuck Lever * 9725a0866cSChuck Lever * Not all basic data types have their own encoding and decoding 9825a0866cSChuck Lever * functions. For run-time efficiency, some data types are encoded 9925a0866cSChuck Lever * or decoded inline. 10025a0866cSChuck Lever */ 10125a0866cSChuck Lever 10225a0866cSChuck Lever /* 103f796f8b3SChuck Lever * typedef opaque nfsdata<>; 104f796f8b3SChuck Lever */ 105f796f8b3SChuck Lever static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result) 106f796f8b3SChuck Lever { 107f796f8b3SChuck Lever u32 recvd, count; 108f796f8b3SChuck Lever size_t hdrlen; 109f796f8b3SChuck Lever __be32 *p; 110f796f8b3SChuck Lever 111f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 112f796f8b3SChuck Lever if (unlikely(p == NULL)) 113f796f8b3SChuck Lever goto out_overflow; 114f796f8b3SChuck Lever count = be32_to_cpup(p); 115f796f8b3SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 116f796f8b3SChuck Lever recvd = xdr->buf->len - hdrlen; 117f796f8b3SChuck Lever if (unlikely(count > recvd)) 118f796f8b3SChuck Lever goto out_cheating; 119f796f8b3SChuck Lever out: 120f796f8b3SChuck Lever xdr_read_pages(xdr, count); 121f796f8b3SChuck Lever result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */ 122f796f8b3SChuck Lever result->count = count; 123f796f8b3SChuck Lever return count; 124f796f8b3SChuck Lever out_cheating: 125f796f8b3SChuck Lever dprintk("NFS: server cheating in read result: " 126f796f8b3SChuck Lever "count %u > recvd %u\n", count, recvd); 127f796f8b3SChuck Lever count = recvd; 128f796f8b3SChuck Lever goto out; 129f796f8b3SChuck Lever out_overflow: 130f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 131f796f8b3SChuck Lever return -EIO; 132f796f8b3SChuck Lever } 133f796f8b3SChuck Lever 134f796f8b3SChuck Lever /* 135f796f8b3SChuck Lever * enum stat { 136f796f8b3SChuck Lever * NFS_OK = 0, 137f796f8b3SChuck Lever * NFSERR_PERM = 1, 138f796f8b3SChuck Lever * NFSERR_NOENT = 2, 139f796f8b3SChuck Lever * NFSERR_IO = 5, 140f796f8b3SChuck Lever * NFSERR_NXIO = 6, 141f796f8b3SChuck Lever * NFSERR_ACCES = 13, 142f796f8b3SChuck Lever * NFSERR_EXIST = 17, 143f796f8b3SChuck Lever * NFSERR_NODEV = 19, 144f796f8b3SChuck Lever * NFSERR_NOTDIR = 20, 145f796f8b3SChuck Lever * NFSERR_ISDIR = 21, 146f796f8b3SChuck Lever * NFSERR_FBIG = 27, 147f796f8b3SChuck Lever * NFSERR_NOSPC = 28, 148f796f8b3SChuck Lever * NFSERR_ROFS = 30, 149f796f8b3SChuck Lever * NFSERR_NAMETOOLONG = 63, 150f796f8b3SChuck Lever * NFSERR_NOTEMPTY = 66, 151f796f8b3SChuck Lever * NFSERR_DQUOT = 69, 152f796f8b3SChuck Lever * NFSERR_STALE = 70, 153f796f8b3SChuck Lever * NFSERR_WFLUSH = 99 154f796f8b3SChuck Lever * }; 155f796f8b3SChuck Lever */ 156f796f8b3SChuck Lever static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status) 157f796f8b3SChuck Lever { 158f796f8b3SChuck Lever __be32 *p; 159f796f8b3SChuck Lever 160f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 161f796f8b3SChuck Lever if (unlikely(p == NULL)) 162f796f8b3SChuck Lever goto out_overflow; 163f796f8b3SChuck Lever *status = be32_to_cpup(p); 164f796f8b3SChuck Lever return 0; 165f796f8b3SChuck Lever out_overflow: 166f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 167f796f8b3SChuck Lever return -EIO; 168f796f8b3SChuck Lever } 169f796f8b3SChuck Lever 170f796f8b3SChuck Lever /* 1715f96e5e3SChuck Lever * 2.3.2. ftype 1725f96e5e3SChuck Lever * 1735f96e5e3SChuck Lever * enum ftype { 1745f96e5e3SChuck Lever * NFNON = 0, 1755f96e5e3SChuck Lever * NFREG = 1, 1765f96e5e3SChuck Lever * NFDIR = 2, 1775f96e5e3SChuck Lever * NFBLK = 3, 1785f96e5e3SChuck Lever * NFCHR = 4, 1795f96e5e3SChuck Lever * NFLNK = 5 1805f96e5e3SChuck Lever * }; 1815f96e5e3SChuck Lever * 1825f96e5e3SChuck Lever */ 1835f96e5e3SChuck Lever static __be32 *xdr_decode_ftype(__be32 *p, u32 *type) 1845f96e5e3SChuck Lever { 1855f96e5e3SChuck Lever *type = be32_to_cpup(p++); 1865f96e5e3SChuck Lever if (unlikely(*type > NF2FIFO)) 1875f96e5e3SChuck Lever *type = NFBAD; 1885f96e5e3SChuck Lever return p; 1895f96e5e3SChuck Lever } 1905f96e5e3SChuck Lever 1915f96e5e3SChuck Lever /* 19225a0866cSChuck Lever * 2.3.3. fhandle 19325a0866cSChuck Lever * 19425a0866cSChuck Lever * typedef opaque fhandle[FHSIZE]; 19525a0866cSChuck Lever */ 19625a0866cSChuck Lever static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh) 19725a0866cSChuck Lever { 19825a0866cSChuck Lever __be32 *p; 19925a0866cSChuck Lever 20025a0866cSChuck Lever BUG_ON(fh->size != NFS2_FHSIZE); 20125a0866cSChuck Lever p = xdr_reserve_space(xdr, NFS2_FHSIZE); 20225a0866cSChuck Lever memcpy(p, fh->data, NFS2_FHSIZE); 20325a0866cSChuck Lever } 20425a0866cSChuck Lever 205f796f8b3SChuck Lever static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) 206f796f8b3SChuck Lever { 207f796f8b3SChuck Lever __be32 *p; 208f796f8b3SChuck Lever 209f796f8b3SChuck Lever p = xdr_inline_decode(xdr, NFS2_FHSIZE); 210f796f8b3SChuck Lever if (unlikely(p == NULL)) 211f796f8b3SChuck Lever goto out_overflow; 212f796f8b3SChuck Lever fh->size = NFS2_FHSIZE; 213f796f8b3SChuck Lever memcpy(fh->data, p, NFS2_FHSIZE); 214f796f8b3SChuck Lever return 0; 215f796f8b3SChuck Lever out_overflow: 216f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 217f796f8b3SChuck Lever return -EIO; 218f796f8b3SChuck Lever } 219f796f8b3SChuck Lever 22025a0866cSChuck Lever /* 221282ac2a5SChuck Lever * 2.3.4. timeval 222282ac2a5SChuck Lever * 223282ac2a5SChuck Lever * struct timeval { 224282ac2a5SChuck Lever * unsigned int seconds; 225282ac2a5SChuck Lever * unsigned int useconds; 226282ac2a5SChuck Lever * }; 227282ac2a5SChuck Lever */ 228282ac2a5SChuck Lever static __be32 *xdr_encode_time(__be32 *p, const struct timespec *timep) 229282ac2a5SChuck Lever { 230282ac2a5SChuck Lever *p++ = cpu_to_be32(timep->tv_sec); 231282ac2a5SChuck Lever if (timep->tv_nsec != 0) 232282ac2a5SChuck Lever *p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC); 233282ac2a5SChuck Lever else 234282ac2a5SChuck Lever *p++ = cpu_to_be32(0); 235282ac2a5SChuck Lever return p; 236282ac2a5SChuck Lever } 237282ac2a5SChuck Lever 238282ac2a5SChuck Lever /* 239282ac2a5SChuck Lever * Passing the invalid value useconds=1000000 is a Sun convention for 240282ac2a5SChuck Lever * "set to current server time". It's needed to make permissions checks 241282ac2a5SChuck Lever * for the "touch" program across v2 mounts to Solaris and Irix servers 242282ac2a5SChuck Lever * work correctly. See description of sattr in section 6.1 of "NFS 243282ac2a5SChuck Lever * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5. 244282ac2a5SChuck Lever */ 245282ac2a5SChuck Lever static __be32 *xdr_encode_current_server_time(__be32 *p, 246282ac2a5SChuck Lever const struct timespec *timep) 247282ac2a5SChuck Lever { 248282ac2a5SChuck Lever *p++ = cpu_to_be32(timep->tv_sec); 249282ac2a5SChuck Lever *p++ = cpu_to_be32(1000000); 250282ac2a5SChuck Lever return p; 251282ac2a5SChuck Lever } 252282ac2a5SChuck Lever 2535f96e5e3SChuck Lever static __be32 *xdr_decode_time(__be32 *p, struct timespec *timep) 2545f96e5e3SChuck Lever { 2555f96e5e3SChuck Lever timep->tv_sec = be32_to_cpup(p++); 2565f96e5e3SChuck Lever timep->tv_nsec = be32_to_cpup(p++) * NSEC_PER_USEC; 2575f96e5e3SChuck Lever return p; 2585f96e5e3SChuck Lever } 2595f96e5e3SChuck Lever 260282ac2a5SChuck Lever /* 261f796f8b3SChuck Lever * 2.3.5. fattr 262f796f8b3SChuck Lever * 263f796f8b3SChuck Lever * struct fattr { 264f796f8b3SChuck Lever * ftype type; 265f796f8b3SChuck Lever * unsigned int mode; 266f796f8b3SChuck Lever * unsigned int nlink; 267f796f8b3SChuck Lever * unsigned int uid; 268f796f8b3SChuck Lever * unsigned int gid; 269f796f8b3SChuck Lever * unsigned int size; 270f796f8b3SChuck Lever * unsigned int blocksize; 271f796f8b3SChuck Lever * unsigned int rdev; 272f796f8b3SChuck Lever * unsigned int blocks; 273f796f8b3SChuck Lever * unsigned int fsid; 274f796f8b3SChuck Lever * unsigned int fileid; 275f796f8b3SChuck Lever * timeval atime; 276f796f8b3SChuck Lever * timeval mtime; 277f796f8b3SChuck Lever * timeval ctime; 278f796f8b3SChuck Lever * }; 279f796f8b3SChuck Lever * 280f796f8b3SChuck Lever */ 281f796f8b3SChuck Lever static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 282f796f8b3SChuck Lever { 2835f96e5e3SChuck Lever u32 rdev, type; 284f796f8b3SChuck Lever __be32 *p; 285f796f8b3SChuck Lever 286f796f8b3SChuck Lever p = xdr_inline_decode(xdr, NFS_fattr_sz << 2); 287f796f8b3SChuck Lever if (unlikely(p == NULL)) 288f796f8b3SChuck Lever goto out_overflow; 2895f96e5e3SChuck Lever 2905f96e5e3SChuck Lever fattr->valid |= NFS_ATTR_FATTR_V2; 2915f96e5e3SChuck Lever 2925f96e5e3SChuck Lever p = xdr_decode_ftype(p, &type); 2935f96e5e3SChuck Lever 2945f96e5e3SChuck Lever fattr->mode = be32_to_cpup(p++); 2955f96e5e3SChuck Lever fattr->nlink = be32_to_cpup(p++); 2965f96e5e3SChuck Lever fattr->uid = be32_to_cpup(p++); 2975f96e5e3SChuck Lever fattr->gid = be32_to_cpup(p++); 2985f96e5e3SChuck Lever fattr->size = be32_to_cpup(p++); 2995f96e5e3SChuck Lever fattr->du.nfs2.blocksize = be32_to_cpup(p++); 3005f96e5e3SChuck Lever 3015f96e5e3SChuck Lever rdev = be32_to_cpup(p++); 3025f96e5e3SChuck Lever fattr->rdev = new_decode_dev(rdev); 3035f96e5e3SChuck Lever if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) { 3045f96e5e3SChuck Lever fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; 3055f96e5e3SChuck Lever fattr->rdev = 0; 3065f96e5e3SChuck Lever } 3075f96e5e3SChuck Lever 3085f96e5e3SChuck Lever fattr->du.nfs2.blocks = be32_to_cpup(p++); 3095f96e5e3SChuck Lever fattr->fsid.major = be32_to_cpup(p++); 3105f96e5e3SChuck Lever fattr->fsid.minor = 0; 3115f96e5e3SChuck Lever fattr->fileid = be32_to_cpup(p++); 3125f96e5e3SChuck Lever 3135f96e5e3SChuck Lever p = xdr_decode_time(p, &fattr->atime); 3145f96e5e3SChuck Lever p = xdr_decode_time(p, &fattr->mtime); 3155f96e5e3SChuck Lever xdr_decode_time(p, &fattr->ctime); 316f796f8b3SChuck Lever return 0; 317f796f8b3SChuck Lever out_overflow: 318f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 319f796f8b3SChuck Lever return -EIO; 320f796f8b3SChuck Lever } 321f796f8b3SChuck Lever 322f796f8b3SChuck Lever /* 32325a0866cSChuck Lever * 2.3.6. sattr 32425a0866cSChuck Lever * 32525a0866cSChuck Lever * struct sattr { 32625a0866cSChuck Lever * unsigned int mode; 32725a0866cSChuck Lever * unsigned int uid; 32825a0866cSChuck Lever * unsigned int gid; 32925a0866cSChuck Lever * unsigned int size; 33025a0866cSChuck Lever * timeval atime; 33125a0866cSChuck Lever * timeval mtime; 33225a0866cSChuck Lever * }; 33325a0866cSChuck Lever */ 33425a0866cSChuck Lever 33525a0866cSChuck Lever #define NFS2_SATTR_NOT_SET (0xffffffff) 33625a0866cSChuck Lever 33725a0866cSChuck Lever static __be32 *xdr_time_not_set(__be32 *p) 33825a0866cSChuck Lever { 33925a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 34025a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 34125a0866cSChuck Lever return p; 34225a0866cSChuck Lever } 34325a0866cSChuck Lever 34425a0866cSChuck Lever static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr) 34525a0866cSChuck Lever { 34625a0866cSChuck Lever __be32 *p; 34725a0866cSChuck Lever 34825a0866cSChuck Lever p = xdr_reserve_space(xdr, NFS_sattr_sz << 2); 34925a0866cSChuck Lever 35025a0866cSChuck Lever if (attr->ia_valid & ATTR_MODE) 35125a0866cSChuck Lever *p++ = cpu_to_be32(attr->ia_mode); 35225a0866cSChuck Lever else 35325a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 35425a0866cSChuck Lever if (attr->ia_valid & ATTR_UID) 35525a0866cSChuck Lever *p++ = cpu_to_be32(attr->ia_uid); 35625a0866cSChuck Lever else 35725a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 35825a0866cSChuck Lever if (attr->ia_valid & ATTR_GID) 35925a0866cSChuck Lever *p++ = cpu_to_be32(attr->ia_gid); 36025a0866cSChuck Lever else 36125a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 36225a0866cSChuck Lever if (attr->ia_valid & ATTR_SIZE) 36325a0866cSChuck Lever *p++ = cpu_to_be32((u32)attr->ia_size); 36425a0866cSChuck Lever else 36525a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 36625a0866cSChuck Lever 36725a0866cSChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) 36825a0866cSChuck Lever p = xdr_encode_time(p, &attr->ia_atime); 36925a0866cSChuck Lever else if (attr->ia_valid & ATTR_ATIME) 37025a0866cSChuck Lever p = xdr_encode_current_server_time(p, &attr->ia_atime); 37125a0866cSChuck Lever else 37225a0866cSChuck Lever p = xdr_time_not_set(p); 37325a0866cSChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) 37425a0866cSChuck Lever xdr_encode_time(p, &attr->ia_mtime); 37525a0866cSChuck Lever else if (attr->ia_valid & ATTR_MTIME) 37625a0866cSChuck Lever xdr_encode_current_server_time(p, &attr->ia_mtime); 37725a0866cSChuck Lever else 37825a0866cSChuck Lever xdr_time_not_set(p); 37925a0866cSChuck Lever } 38025a0866cSChuck Lever 38125a0866cSChuck Lever /* 38225a0866cSChuck Lever * 2.3.7. filename 38325a0866cSChuck Lever * 38425a0866cSChuck Lever * typedef string filename<MAXNAMLEN>; 38525a0866cSChuck Lever */ 38625a0866cSChuck Lever static void encode_filename(struct xdr_stream *xdr, 38725a0866cSChuck Lever const char *name, u32 length) 38825a0866cSChuck Lever { 38925a0866cSChuck Lever __be32 *p; 39025a0866cSChuck Lever 39125a0866cSChuck Lever BUG_ON(length > NFS2_MAXNAMLEN); 39225a0866cSChuck Lever p = xdr_reserve_space(xdr, 4 + length); 39325a0866cSChuck Lever xdr_encode_opaque(p, name, length); 39425a0866cSChuck Lever } 39525a0866cSChuck Lever 396f796f8b3SChuck Lever static int decode_filename_inline(struct xdr_stream *xdr, 397f796f8b3SChuck Lever const char **name, u32 *length) 398f796f8b3SChuck Lever { 399f796f8b3SChuck Lever __be32 *p; 400f796f8b3SChuck Lever u32 count; 401f796f8b3SChuck Lever 402f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 403f796f8b3SChuck Lever if (unlikely(p == NULL)) 404f796f8b3SChuck Lever goto out_overflow; 405f796f8b3SChuck Lever count = be32_to_cpup(p); 406f796f8b3SChuck Lever if (count > NFS3_MAXNAMLEN) 407f796f8b3SChuck Lever goto out_nametoolong; 408f796f8b3SChuck Lever p = xdr_inline_decode(xdr, count); 409f796f8b3SChuck Lever if (unlikely(p == NULL)) 410f796f8b3SChuck Lever goto out_overflow; 411f796f8b3SChuck Lever *name = (const char *)p; 412f796f8b3SChuck Lever *length = count; 413f796f8b3SChuck Lever return 0; 414f796f8b3SChuck Lever out_nametoolong: 415f796f8b3SChuck Lever dprintk("NFS: returned filename too long: %u\n", count); 416f796f8b3SChuck Lever return -ENAMETOOLONG; 417f796f8b3SChuck Lever out_overflow: 418f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 419f796f8b3SChuck Lever return -EIO; 420f796f8b3SChuck Lever } 421f796f8b3SChuck Lever 42225a0866cSChuck Lever /* 42325a0866cSChuck Lever * 2.3.8. path 42425a0866cSChuck Lever * 42525a0866cSChuck Lever * typedef string path<MAXPATHLEN>; 42625a0866cSChuck Lever */ 42725a0866cSChuck Lever static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length) 42825a0866cSChuck Lever { 42925a0866cSChuck Lever __be32 *p; 43025a0866cSChuck Lever 43125a0866cSChuck Lever BUG_ON(length > NFS2_MAXPATHLEN); 43225a0866cSChuck Lever p = xdr_reserve_space(xdr, 4); 43325a0866cSChuck Lever *p = cpu_to_be32(length); 43425a0866cSChuck Lever xdr_write_pages(xdr, pages, 0, length); 43525a0866cSChuck Lever } 43625a0866cSChuck Lever 437f796f8b3SChuck Lever static int decode_path(struct xdr_stream *xdr) 438f796f8b3SChuck Lever { 439f796f8b3SChuck Lever u32 length, recvd; 440f796f8b3SChuck Lever size_t hdrlen; 441f796f8b3SChuck Lever __be32 *p; 442f796f8b3SChuck Lever 443f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 444f796f8b3SChuck Lever if (unlikely(p == NULL)) 445f796f8b3SChuck Lever goto out_overflow; 446f796f8b3SChuck Lever length = be32_to_cpup(p); 447f796f8b3SChuck Lever if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN)) 448f796f8b3SChuck Lever goto out_size; 449f796f8b3SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 450f796f8b3SChuck Lever recvd = xdr->buf->len - hdrlen; 451f796f8b3SChuck Lever if (unlikely(length > recvd)) 452f796f8b3SChuck Lever goto out_cheating; 453f796f8b3SChuck Lever 454f796f8b3SChuck Lever xdr_read_pages(xdr, length); 455f796f8b3SChuck Lever xdr_terminate_string(xdr->buf, length); 456f796f8b3SChuck Lever return 0; 457f796f8b3SChuck Lever out_size: 458f796f8b3SChuck Lever dprintk("NFS: returned pathname too long: %u\n", length); 459f796f8b3SChuck Lever return -ENAMETOOLONG; 460f796f8b3SChuck Lever out_cheating: 461f796f8b3SChuck Lever dprintk("NFS: server cheating in pathname result: " 462f796f8b3SChuck Lever "length %u > received %u\n", length, recvd); 463f796f8b3SChuck Lever return -EIO; 464f796f8b3SChuck Lever out_overflow: 465f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 466f796f8b3SChuck Lever return -EIO; 467f796f8b3SChuck Lever } 468f796f8b3SChuck Lever 469f796f8b3SChuck Lever /* 470f796f8b3SChuck Lever * 2.3.9. attrstat 471f796f8b3SChuck Lever * 472f796f8b3SChuck Lever * union attrstat switch (stat status) { 473f796f8b3SChuck Lever * case NFS_OK: 474f796f8b3SChuck Lever * fattr attributes; 475f796f8b3SChuck Lever * default: 476f796f8b3SChuck Lever * void; 477f796f8b3SChuck Lever * }; 478f796f8b3SChuck Lever */ 479f796f8b3SChuck Lever static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result) 480f796f8b3SChuck Lever { 481f796f8b3SChuck Lever enum nfs_stat status; 482f796f8b3SChuck Lever int error; 483f796f8b3SChuck Lever 484f796f8b3SChuck Lever error = decode_stat(xdr, &status); 485f796f8b3SChuck Lever if (unlikely(error)) 486f796f8b3SChuck Lever goto out; 487f796f8b3SChuck Lever if (status != NFS_OK) 488f796f8b3SChuck Lever goto out_default; 489f796f8b3SChuck Lever error = decode_fattr(xdr, result); 490f796f8b3SChuck Lever out: 491f796f8b3SChuck Lever return error; 492f796f8b3SChuck Lever out_default: 493f796f8b3SChuck Lever return nfs_stat_to_errno(status); 494f796f8b3SChuck Lever } 495f796f8b3SChuck Lever 49625a0866cSChuck Lever /* 49725a0866cSChuck Lever * 2.3.10. diropargs 49825a0866cSChuck Lever * 49925a0866cSChuck Lever * struct diropargs { 50025a0866cSChuck Lever * fhandle dir; 50125a0866cSChuck Lever * filename name; 50225a0866cSChuck Lever * }; 50325a0866cSChuck Lever */ 50425a0866cSChuck Lever static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh, 50525a0866cSChuck Lever const char *name, u32 length) 50625a0866cSChuck Lever { 50725a0866cSChuck Lever encode_fhandle(xdr, fh); 50825a0866cSChuck Lever encode_filename(xdr, name, length); 50925a0866cSChuck Lever } 51025a0866cSChuck Lever 511f796f8b3SChuck Lever /* 512f796f8b3SChuck Lever * 2.3.11. diropres 513f796f8b3SChuck Lever * 514f796f8b3SChuck Lever * union diropres switch (stat status) { 515f796f8b3SChuck Lever * case NFS_OK: 516f796f8b3SChuck Lever * struct { 517f796f8b3SChuck Lever * fhandle file; 518f796f8b3SChuck Lever * fattr attributes; 519f796f8b3SChuck Lever * } diropok; 520f796f8b3SChuck Lever * default: 521f796f8b3SChuck Lever * void; 522f796f8b3SChuck Lever * }; 523f796f8b3SChuck Lever */ 524f796f8b3SChuck Lever static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result) 525f796f8b3SChuck Lever { 526f796f8b3SChuck Lever int error; 527f796f8b3SChuck Lever 528f796f8b3SChuck Lever error = decode_fhandle(xdr, result->fh); 529f796f8b3SChuck Lever if (unlikely(error)) 530f796f8b3SChuck Lever goto out; 531f796f8b3SChuck Lever error = decode_fattr(xdr, result->fattr); 532f796f8b3SChuck Lever out: 533f796f8b3SChuck Lever return error; 534f796f8b3SChuck Lever } 535f796f8b3SChuck Lever 536f796f8b3SChuck Lever static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result) 537f796f8b3SChuck Lever { 538f796f8b3SChuck Lever enum nfs_stat status; 539f796f8b3SChuck Lever int error; 540f796f8b3SChuck Lever 541f796f8b3SChuck Lever error = decode_stat(xdr, &status); 542f796f8b3SChuck Lever if (unlikely(error)) 543f796f8b3SChuck Lever goto out; 544f796f8b3SChuck Lever if (status != NFS_OK) 545f796f8b3SChuck Lever goto out_default; 546f796f8b3SChuck Lever error = decode_diropok(xdr, result); 547f796f8b3SChuck Lever out: 548f796f8b3SChuck Lever return error; 549f796f8b3SChuck Lever out_default: 550f796f8b3SChuck Lever return nfs_stat_to_errno(status); 551f796f8b3SChuck Lever } 552f796f8b3SChuck Lever 55325a0866cSChuck Lever 55425a0866cSChuck Lever /* 5552d70f533SChuck Lever * NFSv2 XDR encode functions 5562d70f533SChuck Lever * 5572d70f533SChuck Lever * NFSv2 argument types are defined in section 2.2 of RFC 1094: 5582d70f533SChuck Lever * "NFS: Network File System Protocol Specification". 5591da177e4SLinus Torvalds */ 5601da177e4SLinus Torvalds 5619f06c719SChuck Lever static void nfs2_xdr_enc_fhandle(struct rpc_rqst *req, 5629f06c719SChuck Lever struct xdr_stream *xdr, 56325a0866cSChuck Lever const struct nfs_fh *fh) 56425a0866cSChuck Lever { 5659f06c719SChuck Lever encode_fhandle(xdr, fh); 56625a0866cSChuck Lever } 56725a0866cSChuck Lever 5681da177e4SLinus Torvalds /* 56925a0866cSChuck Lever * 2.2.3. sattrargs 57025a0866cSChuck Lever * 57125a0866cSChuck Lever * struct sattrargs { 57225a0866cSChuck Lever * fhandle file; 57325a0866cSChuck Lever * sattr attributes; 57425a0866cSChuck Lever * }; 57525a0866cSChuck Lever */ 5769f06c719SChuck Lever static void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req, 5779f06c719SChuck Lever struct xdr_stream *xdr, 57825a0866cSChuck Lever const struct nfs_sattrargs *args) 57925a0866cSChuck Lever { 5809f06c719SChuck Lever encode_fhandle(xdr, args->fh); 5819f06c719SChuck Lever encode_sattr(xdr, args->sattr); 58225a0866cSChuck Lever } 58325a0866cSChuck Lever 5849f06c719SChuck Lever static void nfs2_xdr_enc_diropargs(struct rpc_rqst *req, 5859f06c719SChuck Lever struct xdr_stream *xdr, 58625a0866cSChuck Lever const struct nfs_diropargs *args) 58725a0866cSChuck Lever { 5889f06c719SChuck Lever encode_diropargs(xdr, args->fh, args->name, args->len); 58925a0866cSChuck Lever } 59025a0866cSChuck Lever 5919f06c719SChuck Lever static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, 5929f06c719SChuck Lever struct xdr_stream *xdr, 59325a0866cSChuck Lever const struct nfs_readlinkargs *args) 59425a0866cSChuck Lever { 5959f06c719SChuck Lever encode_fhandle(xdr, args->fh); 59625a0866cSChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 59725a0866cSChuck Lever args->pglen, NFS_readlinkres_sz); 59825a0866cSChuck Lever } 59925a0866cSChuck Lever 6004fdc17b2STrond Myklebust /* 60125a0866cSChuck Lever * 2.2.7. readargs 60225a0866cSChuck Lever * 60325a0866cSChuck Lever * struct readargs { 60425a0866cSChuck Lever * fhandle file; 60525a0866cSChuck Lever * unsigned offset; 60625a0866cSChuck Lever * unsigned count; 60725a0866cSChuck Lever * unsigned totalcount; 60825a0866cSChuck Lever * }; 60925a0866cSChuck Lever */ 61025a0866cSChuck Lever static void encode_readargs(struct xdr_stream *xdr, 61125a0866cSChuck Lever const struct nfs_readargs *args) 61225a0866cSChuck Lever { 61325a0866cSChuck Lever u32 offset = args->offset; 61425a0866cSChuck Lever u32 count = args->count; 61525a0866cSChuck Lever __be32 *p; 61625a0866cSChuck Lever 61725a0866cSChuck Lever encode_fhandle(xdr, args->fh); 61825a0866cSChuck Lever 61925a0866cSChuck Lever p = xdr_reserve_space(xdr, 4 + 4 + 4); 62025a0866cSChuck Lever *p++ = cpu_to_be32(offset); 62125a0866cSChuck Lever *p++ = cpu_to_be32(count); 62225a0866cSChuck Lever *p = cpu_to_be32(count); 62325a0866cSChuck Lever } 62425a0866cSChuck Lever 6259f06c719SChuck Lever static void nfs2_xdr_enc_readargs(struct rpc_rqst *req, 6269f06c719SChuck Lever struct xdr_stream *xdr, 62725a0866cSChuck Lever const struct nfs_readargs *args) 62825a0866cSChuck Lever { 6299f06c719SChuck Lever encode_readargs(xdr, args); 63025a0866cSChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 63125a0866cSChuck Lever args->count, NFS_readres_sz); 63225a0866cSChuck Lever req->rq_rcv_buf.flags |= XDRBUF_READ; 63325a0866cSChuck Lever } 63425a0866cSChuck Lever 63525a0866cSChuck Lever /* 63625a0866cSChuck Lever * 2.2.9. writeargs 63725a0866cSChuck Lever * 63825a0866cSChuck Lever * struct writeargs { 63925a0866cSChuck Lever * fhandle file; 64025a0866cSChuck Lever * unsigned beginoffset; 64125a0866cSChuck Lever * unsigned offset; 64225a0866cSChuck Lever * unsigned totalcount; 64325a0866cSChuck Lever * nfsdata data; 64425a0866cSChuck Lever * }; 64525a0866cSChuck Lever */ 64625a0866cSChuck Lever static void encode_writeargs(struct xdr_stream *xdr, 64725a0866cSChuck Lever const struct nfs_writeargs *args) 64825a0866cSChuck Lever { 64925a0866cSChuck Lever u32 offset = args->offset; 65025a0866cSChuck Lever u32 count = args->count; 65125a0866cSChuck Lever __be32 *p; 65225a0866cSChuck Lever 65325a0866cSChuck Lever encode_fhandle(xdr, args->fh); 65425a0866cSChuck Lever 65525a0866cSChuck Lever p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4); 65625a0866cSChuck Lever *p++ = cpu_to_be32(offset); 65725a0866cSChuck Lever *p++ = cpu_to_be32(offset); 65825a0866cSChuck Lever *p++ = cpu_to_be32(count); 65925a0866cSChuck Lever 66025a0866cSChuck Lever /* nfsdata */ 66125a0866cSChuck Lever *p = cpu_to_be32(count); 66225a0866cSChuck Lever xdr_write_pages(xdr, args->pages, args->pgbase, count); 66325a0866cSChuck Lever } 66425a0866cSChuck Lever 6659f06c719SChuck Lever static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req, 6669f06c719SChuck Lever struct xdr_stream *xdr, 66725a0866cSChuck Lever const struct nfs_writeargs *args) 66825a0866cSChuck Lever { 6699f06c719SChuck Lever encode_writeargs(xdr, args); 6709f06c719SChuck Lever xdr->buf->flags |= XDRBUF_WRITE; 67125a0866cSChuck Lever } 67225a0866cSChuck Lever 67325a0866cSChuck Lever /* 67425a0866cSChuck Lever * 2.2.10. createargs 67525a0866cSChuck Lever * 67625a0866cSChuck Lever * struct createargs { 67725a0866cSChuck Lever * diropargs where; 67825a0866cSChuck Lever * sattr attributes; 67925a0866cSChuck Lever * }; 68025a0866cSChuck Lever */ 6819f06c719SChuck Lever static void nfs2_xdr_enc_createargs(struct rpc_rqst *req, 6829f06c719SChuck Lever struct xdr_stream *xdr, 68325a0866cSChuck Lever const struct nfs_createargs *args) 68425a0866cSChuck Lever { 6859f06c719SChuck Lever encode_diropargs(xdr, args->fh, args->name, args->len); 6869f06c719SChuck Lever encode_sattr(xdr, args->sattr); 68725a0866cSChuck Lever } 68825a0866cSChuck Lever 6899f06c719SChuck Lever static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req, 6909f06c719SChuck Lever struct xdr_stream *xdr, 69125a0866cSChuck Lever const struct nfs_removeargs *args) 69225a0866cSChuck Lever { 6939f06c719SChuck Lever encode_diropargs(xdr, args->fh, args->name.name, args->name.len); 69425a0866cSChuck Lever } 69525a0866cSChuck Lever 69625a0866cSChuck Lever /* 69725a0866cSChuck Lever * 2.2.12. renameargs 69825a0866cSChuck Lever * 69925a0866cSChuck Lever * struct renameargs { 70025a0866cSChuck Lever * diropargs from; 70125a0866cSChuck Lever * diropargs to; 70225a0866cSChuck Lever * }; 70325a0866cSChuck Lever */ 7049f06c719SChuck Lever static void nfs2_xdr_enc_renameargs(struct rpc_rqst *req, 7059f06c719SChuck Lever struct xdr_stream *xdr, 70625a0866cSChuck Lever const struct nfs_renameargs *args) 70725a0866cSChuck Lever { 70825a0866cSChuck Lever const struct qstr *old = args->old_name; 70925a0866cSChuck Lever const struct qstr *new = args->new_name; 71025a0866cSChuck Lever 7119f06c719SChuck Lever encode_diropargs(xdr, args->old_dir, old->name, old->len); 7129f06c719SChuck Lever encode_diropargs(xdr, args->new_dir, new->name, new->len); 71325a0866cSChuck Lever } 71425a0866cSChuck Lever 71525a0866cSChuck Lever /* 71625a0866cSChuck Lever * 2.2.13. linkargs 71725a0866cSChuck Lever * 71825a0866cSChuck Lever * struct linkargs { 71925a0866cSChuck Lever * fhandle from; 72025a0866cSChuck Lever * diropargs to; 72125a0866cSChuck Lever * }; 72225a0866cSChuck Lever */ 7239f06c719SChuck Lever static void nfs2_xdr_enc_linkargs(struct rpc_rqst *req, 7249f06c719SChuck Lever struct xdr_stream *xdr, 72525a0866cSChuck Lever const struct nfs_linkargs *args) 72625a0866cSChuck Lever { 7279f06c719SChuck Lever encode_fhandle(xdr, args->fromfh); 7289f06c719SChuck Lever encode_diropargs(xdr, args->tofh, args->toname, args->tolen); 72925a0866cSChuck Lever } 73025a0866cSChuck Lever 73125a0866cSChuck Lever /* 73225a0866cSChuck Lever * 2.2.14. symlinkargs 73325a0866cSChuck Lever * 73425a0866cSChuck Lever * struct symlinkargs { 73525a0866cSChuck Lever * diropargs from; 73625a0866cSChuck Lever * path to; 73725a0866cSChuck Lever * sattr attributes; 73825a0866cSChuck Lever * }; 73925a0866cSChuck Lever */ 7409f06c719SChuck Lever static void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req, 7419f06c719SChuck Lever struct xdr_stream *xdr, 74225a0866cSChuck Lever const struct nfs_symlinkargs *args) 74325a0866cSChuck Lever { 7449f06c719SChuck Lever encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen); 7459f06c719SChuck Lever encode_path(xdr, args->pages, args->pathlen); 7469f06c719SChuck Lever encode_sattr(xdr, args->sattr); 74725a0866cSChuck Lever } 74825a0866cSChuck Lever 74925a0866cSChuck Lever /* 75025a0866cSChuck Lever * 2.2.17. readdirargs 75125a0866cSChuck Lever * 75225a0866cSChuck Lever * struct readdirargs { 75325a0866cSChuck Lever * fhandle dir; 75425a0866cSChuck Lever * nfscookie cookie; 75525a0866cSChuck Lever * unsigned count; 75625a0866cSChuck Lever * }; 75725a0866cSChuck Lever */ 75825a0866cSChuck Lever static void encode_readdirargs(struct xdr_stream *xdr, 75925a0866cSChuck Lever const struct nfs_readdirargs *args) 76025a0866cSChuck Lever { 76125a0866cSChuck Lever __be32 *p; 76225a0866cSChuck Lever 76325a0866cSChuck Lever encode_fhandle(xdr, args->fh); 76425a0866cSChuck Lever 76525a0866cSChuck Lever p = xdr_reserve_space(xdr, 4 + 4); 76625a0866cSChuck Lever *p++ = cpu_to_be32(args->cookie); 76725a0866cSChuck Lever *p = cpu_to_be32(args->count); 76825a0866cSChuck Lever } 76925a0866cSChuck Lever 7709f06c719SChuck Lever static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, 7719f06c719SChuck Lever struct xdr_stream *xdr, 77225a0866cSChuck Lever const struct nfs_readdirargs *args) 77325a0866cSChuck Lever { 7749f06c719SChuck Lever encode_readdirargs(xdr, args); 77525a0866cSChuck Lever prepare_reply_buffer(req, args->pages, 0, 77625a0866cSChuck Lever args->count, NFS_readdirres_sz); 77725a0866cSChuck Lever } 77825a0866cSChuck Lever 77925a0866cSChuck Lever /* 780661ad423SChuck Lever * NFSv2 XDR decode functions 781661ad423SChuck Lever * 782661ad423SChuck Lever * NFSv2 result types are defined in section 2.2 of RFC 1094: 783661ad423SChuck Lever * "NFS: Network File System Protocol Specification". 7841da177e4SLinus Torvalds */ 7851da177e4SLinus Torvalds 786bf269551SChuck Lever static int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr, 787f796f8b3SChuck Lever void *__unused) 788f796f8b3SChuck Lever { 789f796f8b3SChuck Lever enum nfs_stat status; 790f796f8b3SChuck Lever int error; 791f796f8b3SChuck Lever 792bf269551SChuck Lever error = decode_stat(xdr, &status); 793f796f8b3SChuck Lever if (unlikely(error)) 794f796f8b3SChuck Lever goto out; 795f796f8b3SChuck Lever if (status != NFS_OK) 796f796f8b3SChuck Lever goto out_default; 797f796f8b3SChuck Lever out: 798f796f8b3SChuck Lever return error; 799f796f8b3SChuck Lever out_default: 800f796f8b3SChuck Lever return nfs_stat_to_errno(status); 801f796f8b3SChuck Lever } 802f796f8b3SChuck Lever 803bf269551SChuck Lever static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr, 804f796f8b3SChuck Lever struct nfs_fattr *result) 805f796f8b3SChuck Lever { 806bf269551SChuck Lever return decode_attrstat(xdr, result); 807f796f8b3SChuck Lever } 808f796f8b3SChuck Lever 809bf269551SChuck Lever static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr, 810f796f8b3SChuck Lever struct nfs_diropok *result) 811f796f8b3SChuck Lever { 812bf269551SChuck Lever return decode_diropres(xdr, result); 813f796f8b3SChuck Lever } 814f796f8b3SChuck Lever 8151da177e4SLinus Torvalds /* 816f796f8b3SChuck Lever * 2.2.6. readlinkres 817f796f8b3SChuck Lever * 818f796f8b3SChuck Lever * union readlinkres switch (stat status) { 819f796f8b3SChuck Lever * case NFS_OK: 820f796f8b3SChuck Lever * path data; 821f796f8b3SChuck Lever * default: 822f796f8b3SChuck Lever * void; 823f796f8b3SChuck Lever * }; 824f796f8b3SChuck Lever */ 825bf269551SChuck Lever static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req, 826bf269551SChuck Lever struct xdr_stream *xdr, void *__unused) 827f796f8b3SChuck Lever { 828f796f8b3SChuck Lever enum nfs_stat status; 829f796f8b3SChuck Lever int error; 830f796f8b3SChuck Lever 831bf269551SChuck Lever error = decode_stat(xdr, &status); 832f796f8b3SChuck Lever if (unlikely(error)) 833f796f8b3SChuck Lever goto out; 834f796f8b3SChuck Lever if (status != NFS_OK) 835f796f8b3SChuck Lever goto out_default; 836bf269551SChuck Lever error = decode_path(xdr); 837f796f8b3SChuck Lever out: 838f796f8b3SChuck Lever return error; 839f796f8b3SChuck Lever out_default: 840f796f8b3SChuck Lever return nfs_stat_to_errno(status); 841f796f8b3SChuck Lever } 842f796f8b3SChuck Lever 843f796f8b3SChuck Lever /* 844f796f8b3SChuck Lever * 2.2.7. readres 845f796f8b3SChuck Lever * 846f796f8b3SChuck Lever * union readres switch (stat status) { 847f796f8b3SChuck Lever * case NFS_OK: 848f796f8b3SChuck Lever * fattr attributes; 849f796f8b3SChuck Lever * nfsdata data; 850f796f8b3SChuck Lever * default: 851f796f8b3SChuck Lever * void; 852f796f8b3SChuck Lever * }; 853f796f8b3SChuck Lever */ 854bf269551SChuck Lever static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr, 855f796f8b3SChuck Lever struct nfs_readres *result) 856f796f8b3SChuck Lever { 857f796f8b3SChuck Lever enum nfs_stat status; 858f796f8b3SChuck Lever int error; 859f796f8b3SChuck Lever 860bf269551SChuck Lever error = decode_stat(xdr, &status); 861f796f8b3SChuck Lever if (unlikely(error)) 862f796f8b3SChuck Lever goto out; 863f796f8b3SChuck Lever if (status != NFS_OK) 864f796f8b3SChuck Lever goto out_default; 865bf269551SChuck Lever error = decode_fattr(xdr, result->fattr); 866f796f8b3SChuck Lever if (unlikely(error)) 867f796f8b3SChuck Lever goto out; 868bf269551SChuck Lever error = decode_nfsdata(xdr, result); 869f796f8b3SChuck Lever out: 870f796f8b3SChuck Lever return error; 871f796f8b3SChuck Lever out_default: 872f796f8b3SChuck Lever return nfs_stat_to_errno(status); 873f796f8b3SChuck Lever } 874f796f8b3SChuck Lever 875bf269551SChuck Lever static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr, 876f796f8b3SChuck Lever struct nfs_writeres *result) 877f796f8b3SChuck Lever { 878f796f8b3SChuck Lever /* All NFSv2 writes are "file sync" writes */ 879f796f8b3SChuck Lever result->verf->committed = NFS_FILE_SYNC; 880bf269551SChuck Lever return decode_attrstat(xdr, result->fattr); 881f796f8b3SChuck Lever } 882f796f8b3SChuck Lever 883f796f8b3SChuck Lever /** 884f796f8b3SChuck Lever * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in 885f796f8b3SChuck Lever * the local page cache. 886f796f8b3SChuck Lever * @xdr: XDR stream where entry resides 887f796f8b3SChuck Lever * @entry: buffer to fill in with entry data 888f796f8b3SChuck Lever * @plus: boolean indicating whether this should be a readdirplus entry 889f796f8b3SChuck Lever * 890573c4e1eSChuck Lever * Returns zero if successful, otherwise a negative errno value is 891573c4e1eSChuck Lever * returned. 892f796f8b3SChuck Lever * 893f796f8b3SChuck Lever * This function is not invoked during READDIR reply decoding, but 894f796f8b3SChuck Lever * rather whenever an application invokes the getdents(2) system call 895f796f8b3SChuck Lever * on a directory already in our cache. 896f796f8b3SChuck Lever * 897f796f8b3SChuck Lever * 2.2.17. entry 898f796f8b3SChuck Lever * 899f796f8b3SChuck Lever * struct entry { 900f796f8b3SChuck Lever * unsigned fileid; 901f796f8b3SChuck Lever * filename name; 902f796f8b3SChuck Lever * nfscookie cookie; 903f796f8b3SChuck Lever * entry *nextentry; 904f796f8b3SChuck Lever * }; 905f796f8b3SChuck Lever */ 906573c4e1eSChuck Lever int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, 907573c4e1eSChuck Lever int plus) 908f796f8b3SChuck Lever { 909f796f8b3SChuck Lever __be32 *p; 910f796f8b3SChuck Lever int error; 911f796f8b3SChuck Lever 912f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 913f796f8b3SChuck Lever if (unlikely(p == NULL)) 914f796f8b3SChuck Lever goto out_overflow; 915f796f8b3SChuck Lever if (*p++ == xdr_zero) { 916f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 917f796f8b3SChuck Lever if (unlikely(p == NULL)) 918f796f8b3SChuck Lever goto out_overflow; 919f796f8b3SChuck Lever if (*p++ == xdr_zero) 920573c4e1eSChuck Lever return -EAGAIN; 921f796f8b3SChuck Lever entry->eof = 1; 922573c4e1eSChuck Lever return -EBADCOOKIE; 923f796f8b3SChuck Lever } 924f796f8b3SChuck Lever 925f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 926f796f8b3SChuck Lever if (unlikely(p == NULL)) 927f796f8b3SChuck Lever goto out_overflow; 928f796f8b3SChuck Lever entry->ino = be32_to_cpup(p); 929f796f8b3SChuck Lever 930f796f8b3SChuck Lever error = decode_filename_inline(xdr, &entry->name, &entry->len); 931f796f8b3SChuck Lever if (unlikely(error)) 932573c4e1eSChuck Lever return error; 933f796f8b3SChuck Lever 934f796f8b3SChuck Lever /* 935f796f8b3SChuck Lever * The type (size and byte order) of nfscookie isn't defined in 936f796f8b3SChuck Lever * RFC 1094. This implementation assumes that it's an XDR uint32. 937f796f8b3SChuck Lever */ 938f796f8b3SChuck Lever entry->prev_cookie = entry->cookie; 939f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 940f796f8b3SChuck Lever if (unlikely(p == NULL)) 941f796f8b3SChuck Lever goto out_overflow; 942f796f8b3SChuck Lever entry->cookie = be32_to_cpup(p); 943f796f8b3SChuck Lever 944f796f8b3SChuck Lever entry->d_type = DT_UNKNOWN; 945f796f8b3SChuck Lever 946573c4e1eSChuck Lever return 0; 947f796f8b3SChuck Lever 948f796f8b3SChuck Lever out_overflow: 949f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 950573c4e1eSChuck Lever return -EAGAIN; 951f796f8b3SChuck Lever } 952f796f8b3SChuck Lever 953f796f8b3SChuck Lever /* 954f796f8b3SChuck Lever * 2.2.17. readdirres 955f796f8b3SChuck Lever * 956f796f8b3SChuck Lever * union readdirres switch (stat status) { 957f796f8b3SChuck Lever * case NFS_OK: 958f796f8b3SChuck Lever * struct { 959f796f8b3SChuck Lever * entry *entries; 960f796f8b3SChuck Lever * bool eof; 961f796f8b3SChuck Lever * } readdirok; 962f796f8b3SChuck Lever * default: 963f796f8b3SChuck Lever * void; 964f796f8b3SChuck Lever * }; 965f796f8b3SChuck Lever * 966f796f8b3SChuck Lever * Read the directory contents into the page cache, but don't 967f796f8b3SChuck Lever * touch them. The actual decoding is done by nfs2_decode_dirent() 968f796f8b3SChuck Lever * during subsequent nfs_readdir() calls. 969f796f8b3SChuck Lever */ 970f796f8b3SChuck Lever static int decode_readdirok(struct xdr_stream *xdr) 971f796f8b3SChuck Lever { 972f796f8b3SChuck Lever u32 recvd, pglen; 973f796f8b3SChuck Lever size_t hdrlen; 974f796f8b3SChuck Lever 975f796f8b3SChuck Lever pglen = xdr->buf->page_len; 976f796f8b3SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 977f796f8b3SChuck Lever recvd = xdr->buf->len - hdrlen; 978f796f8b3SChuck Lever if (unlikely(pglen > recvd)) 979f796f8b3SChuck Lever goto out_cheating; 980f796f8b3SChuck Lever out: 981f796f8b3SChuck Lever xdr_read_pages(xdr, pglen); 982f796f8b3SChuck Lever return pglen; 983f796f8b3SChuck Lever out_cheating: 984f796f8b3SChuck Lever dprintk("NFS: server cheating in readdir result: " 985f796f8b3SChuck Lever "pglen %u > recvd %u\n", pglen, recvd); 986f796f8b3SChuck Lever pglen = recvd; 987f796f8b3SChuck Lever goto out; 988f796f8b3SChuck Lever } 989f796f8b3SChuck Lever 990bf269551SChuck Lever static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, 991bf269551SChuck Lever struct xdr_stream *xdr, void *__unused) 992f796f8b3SChuck Lever { 993f796f8b3SChuck Lever enum nfs_stat status; 994f796f8b3SChuck Lever int error; 995f796f8b3SChuck Lever 996bf269551SChuck Lever error = decode_stat(xdr, &status); 997f796f8b3SChuck Lever if (unlikely(error)) 998f796f8b3SChuck Lever goto out; 999f796f8b3SChuck Lever if (status != NFS_OK) 1000f796f8b3SChuck Lever goto out_default; 1001bf269551SChuck Lever error = decode_readdirok(xdr); 1002f796f8b3SChuck Lever out: 1003f796f8b3SChuck Lever return error; 1004f796f8b3SChuck Lever out_default: 1005f796f8b3SChuck Lever return nfs_stat_to_errno(status); 1006f796f8b3SChuck Lever } 1007f796f8b3SChuck Lever 10081da177e4SLinus Torvalds /* 1009f796f8b3SChuck Lever * 2.2.18. statfsres 1010f796f8b3SChuck Lever * 1011f796f8b3SChuck Lever * union statfsres (stat status) { 1012f796f8b3SChuck Lever * case NFS_OK: 1013f796f8b3SChuck Lever * struct { 1014f796f8b3SChuck Lever * unsigned tsize; 1015f796f8b3SChuck Lever * unsigned bsize; 1016f796f8b3SChuck Lever * unsigned blocks; 1017f796f8b3SChuck Lever * unsigned bfree; 1018f796f8b3SChuck Lever * unsigned bavail; 1019f796f8b3SChuck Lever * } info; 1020f796f8b3SChuck Lever * default: 1021f796f8b3SChuck Lever * void; 1022f796f8b3SChuck Lever * }; 1023f796f8b3SChuck Lever */ 1024f796f8b3SChuck Lever static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result) 1025f796f8b3SChuck Lever { 1026f796f8b3SChuck Lever __be32 *p; 1027f796f8b3SChuck Lever 1028f796f8b3SChuck Lever p = xdr_inline_decode(xdr, NFS_info_sz << 2); 1029f796f8b3SChuck Lever if (unlikely(p == NULL)) 1030f796f8b3SChuck Lever goto out_overflow; 1031f796f8b3SChuck Lever result->tsize = be32_to_cpup(p++); 1032f796f8b3SChuck Lever result->bsize = be32_to_cpup(p++); 1033f796f8b3SChuck Lever result->blocks = be32_to_cpup(p++); 1034f796f8b3SChuck Lever result->bfree = be32_to_cpup(p++); 1035f796f8b3SChuck Lever result->bavail = be32_to_cpup(p); 1036f796f8b3SChuck Lever return 0; 1037f796f8b3SChuck Lever out_overflow: 1038f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 1039f796f8b3SChuck Lever return -EIO; 1040f796f8b3SChuck Lever } 1041f796f8b3SChuck Lever 1042bf269551SChuck Lever static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr, 1043f796f8b3SChuck Lever struct nfs2_fsstat *result) 1044f796f8b3SChuck Lever { 1045f796f8b3SChuck Lever enum nfs_stat status; 1046f796f8b3SChuck Lever int error; 1047f796f8b3SChuck Lever 1048bf269551SChuck Lever error = decode_stat(xdr, &status); 1049f796f8b3SChuck Lever if (unlikely(error)) 1050f796f8b3SChuck Lever goto out; 1051f796f8b3SChuck Lever if (status != NFS_OK) 1052f796f8b3SChuck Lever goto out_default; 1053bf269551SChuck Lever error = decode_info(xdr, result); 1054f796f8b3SChuck Lever out: 1055f796f8b3SChuck Lever return error; 1056f796f8b3SChuck Lever out_default: 1057f796f8b3SChuck Lever return nfs_stat_to_errno(status); 1058f796f8b3SChuck Lever } 1059f796f8b3SChuck Lever 1060f796f8b3SChuck Lever 1061f796f8b3SChuck Lever /* 10621da177e4SLinus Torvalds * We need to translate between nfs status return values and 10631da177e4SLinus Torvalds * the local errno values which may not be the same. 10641da177e4SLinus Torvalds */ 106585828493SChuck Lever static const struct { 10661da177e4SLinus Torvalds int stat; 10671da177e4SLinus Torvalds int errno; 10681da177e4SLinus Torvalds } nfs_errtbl[] = { 10691da177e4SLinus Torvalds { NFS_OK, 0 }, 1070856dff3dSBenny Halevy { NFSERR_PERM, -EPERM }, 1071856dff3dSBenny Halevy { NFSERR_NOENT, -ENOENT }, 1072856dff3dSBenny Halevy { NFSERR_IO, -errno_NFSERR_IO}, 1073856dff3dSBenny Halevy { NFSERR_NXIO, -ENXIO }, 1074856dff3dSBenny Halevy /* { NFSERR_EAGAIN, -EAGAIN }, */ 1075856dff3dSBenny Halevy { NFSERR_ACCES, -EACCES }, 1076856dff3dSBenny Halevy { NFSERR_EXIST, -EEXIST }, 1077856dff3dSBenny Halevy { NFSERR_XDEV, -EXDEV }, 1078856dff3dSBenny Halevy { NFSERR_NODEV, -ENODEV }, 1079856dff3dSBenny Halevy { NFSERR_NOTDIR, -ENOTDIR }, 1080856dff3dSBenny Halevy { NFSERR_ISDIR, -EISDIR }, 1081856dff3dSBenny Halevy { NFSERR_INVAL, -EINVAL }, 1082856dff3dSBenny Halevy { NFSERR_FBIG, -EFBIG }, 1083856dff3dSBenny Halevy { NFSERR_NOSPC, -ENOSPC }, 1084856dff3dSBenny Halevy { NFSERR_ROFS, -EROFS }, 1085856dff3dSBenny Halevy { NFSERR_MLINK, -EMLINK }, 1086856dff3dSBenny Halevy { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, 1087856dff3dSBenny Halevy { NFSERR_NOTEMPTY, -ENOTEMPTY }, 1088856dff3dSBenny Halevy { NFSERR_DQUOT, -EDQUOT }, 1089856dff3dSBenny Halevy { NFSERR_STALE, -ESTALE }, 1090856dff3dSBenny Halevy { NFSERR_REMOTE, -EREMOTE }, 10911da177e4SLinus Torvalds #ifdef EWFLUSH 1092856dff3dSBenny Halevy { NFSERR_WFLUSH, -EWFLUSH }, 10931da177e4SLinus Torvalds #endif 1094856dff3dSBenny Halevy { NFSERR_BADHANDLE, -EBADHANDLE }, 1095856dff3dSBenny Halevy { NFSERR_NOT_SYNC, -ENOTSYNC }, 1096856dff3dSBenny Halevy { NFSERR_BAD_COOKIE, -EBADCOOKIE }, 1097856dff3dSBenny Halevy { NFSERR_NOTSUPP, -ENOTSUPP }, 1098856dff3dSBenny Halevy { NFSERR_TOOSMALL, -ETOOSMALL }, 1099fdcb4577STrond Myklebust { NFSERR_SERVERFAULT, -EREMOTEIO }, 1100856dff3dSBenny Halevy { NFSERR_BADTYPE, -EBADTYPE }, 1101856dff3dSBenny Halevy { NFSERR_JUKEBOX, -EJUKEBOX }, 1102856dff3dSBenny Halevy { -1, -EIO } 11031da177e4SLinus Torvalds }; 11041da177e4SLinus Torvalds 110585828493SChuck Lever /** 110685828493SChuck Lever * nfs_stat_to_errno - convert an NFS status code to a local errno 110785828493SChuck Lever * @status: NFS status code to convert 110885828493SChuck Lever * 110985828493SChuck Lever * Returns a local errno value, or -EIO if the NFS status code is 111085828493SChuck Lever * not recognized. This function is used jointly by NFSv2 and NFSv3. 11111da177e4SLinus Torvalds */ 111285828493SChuck Lever int nfs_stat_to_errno(enum nfs_stat status) 11131da177e4SLinus Torvalds { 11141da177e4SLinus Torvalds int i; 11151da177e4SLinus Torvalds 11161da177e4SLinus Torvalds for (i = 0; nfs_errtbl[i].stat != -1; i++) { 111785828493SChuck Lever if (nfs_errtbl[i].stat == (int)status) 11181da177e4SLinus Torvalds return nfs_errtbl[i].errno; 11191da177e4SLinus Torvalds } 112085828493SChuck Lever dprintk("NFS: Unrecognized nfs status value: %u\n", status); 11211da177e4SLinus Torvalds return nfs_errtbl[i].errno; 11221da177e4SLinus Torvalds } 11231da177e4SLinus Torvalds 11241da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer) \ 11251da177e4SLinus Torvalds [NFSPROC_##proc] = { \ 11261da177e4SLinus Torvalds .p_proc = NFSPROC_##proc, \ 11279f06c719SChuck Lever .p_encode = (kxdreproc_t)nfs2_xdr_enc_##argtype, \ 1128bf269551SChuck Lever .p_decode = (kxdrdproc_t)nfs2_xdr_dec_##restype, \ 11292bea90d4SChuck Lever .p_arglen = NFS_##argtype##_sz, \ 11302bea90d4SChuck Lever .p_replen = NFS_##restype##_sz, \ 1131cc0175c1SChuck Lever .p_timer = timer, \ 1132cc0175c1SChuck Lever .p_statidx = NFSPROC_##proc, \ 1133cc0175c1SChuck Lever .p_name = #proc, \ 11341da177e4SLinus Torvalds } 11351da177e4SLinus Torvalds struct rpc_procinfo nfs_procedures[] = { 11361da177e4SLinus Torvalds PROC(GETATTR, fhandle, attrstat, 1), 11371da177e4SLinus Torvalds PROC(SETATTR, sattrargs, attrstat, 0), 11381da177e4SLinus Torvalds PROC(LOOKUP, diropargs, diropres, 2), 11391da177e4SLinus Torvalds PROC(READLINK, readlinkargs, readlinkres, 3), 11401da177e4SLinus Torvalds PROC(READ, readargs, readres, 3), 11411da177e4SLinus Torvalds PROC(WRITE, writeargs, writeres, 4), 11421da177e4SLinus Torvalds PROC(CREATE, createargs, diropres, 0), 11434fdc17b2STrond Myklebust PROC(REMOVE, removeargs, stat, 0), 11441da177e4SLinus Torvalds PROC(RENAME, renameargs, stat, 0), 11451da177e4SLinus Torvalds PROC(LINK, linkargs, stat, 0), 11461da177e4SLinus Torvalds PROC(SYMLINK, symlinkargs, stat, 0), 11471da177e4SLinus Torvalds PROC(MKDIR, createargs, diropres, 0), 11481da177e4SLinus Torvalds PROC(RMDIR, diropargs, stat, 0), 11491da177e4SLinus Torvalds PROC(READDIR, readdirargs, readdirres, 3), 11501da177e4SLinus Torvalds PROC(STATFS, fhandle, statfsres, 0), 11511da177e4SLinus Torvalds }; 11521da177e4SLinus Torvalds 1153a613fa16STrond Myklebust const struct rpc_version nfs_version2 = { 11541da177e4SLinus Torvalds .number = 2, 1155e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nfs_procedures), 11561da177e4SLinus Torvalds .procs = nfs_procedures 11571da177e4SLinus Torvalds }; 1158