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 /* 921da177e4SLinus Torvalds * Common NFS XDR functions as inlines 931da177e4SLinus Torvalds */ 949d787a75SAl Viro static inline __be32 * 959d787a75SAl Viro xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle) 961da177e4SLinus Torvalds { 971da177e4SLinus Torvalds /* NFSv2 handles have a fixed length */ 981da177e4SLinus Torvalds fhandle->size = NFS2_FHSIZE; 991da177e4SLinus Torvalds memcpy(fhandle->data, p, NFS2_FHSIZE); 1001da177e4SLinus Torvalds return p + XDR_QUADLEN(NFS2_FHSIZE); 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1039d787a75SAl Viro static inline __be32* 1049d787a75SAl Viro xdr_decode_time(__be32 *p, struct timespec *timep) 1051da177e4SLinus Torvalds { 1061da177e4SLinus Torvalds timep->tv_sec = ntohl(*p++); 1071da177e4SLinus Torvalds /* Convert microseconds into nanoseconds */ 1081da177e4SLinus Torvalds timep->tv_nsec = ntohl(*p++) * 1000; 1091da177e4SLinus Torvalds return p; 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 1129d787a75SAl Viro static __be32 * 1139d787a75SAl Viro xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) 1141da177e4SLinus Torvalds { 115bca79478STrond Myklebust u32 rdev, type; 116bca79478STrond Myklebust type = ntohl(*p++); 1171da177e4SLinus Torvalds fattr->mode = ntohl(*p++); 1181da177e4SLinus Torvalds fattr->nlink = ntohl(*p++); 1191da177e4SLinus Torvalds fattr->uid = ntohl(*p++); 1201da177e4SLinus Torvalds fattr->gid = ntohl(*p++); 1211da177e4SLinus Torvalds fattr->size = ntohl(*p++); 1221da177e4SLinus Torvalds fattr->du.nfs2.blocksize = ntohl(*p++); 1231da177e4SLinus Torvalds rdev = ntohl(*p++); 1241da177e4SLinus Torvalds fattr->du.nfs2.blocks = ntohl(*p++); 1258b4bdcf8STrond Myklebust fattr->fsid.major = ntohl(*p++); 1268b4bdcf8STrond Myklebust fattr->fsid.minor = 0; 1271da177e4SLinus Torvalds fattr->fileid = ntohl(*p++); 1281da177e4SLinus Torvalds p = xdr_decode_time(p, &fattr->atime); 1291da177e4SLinus Torvalds p = xdr_decode_time(p, &fattr->mtime); 1301da177e4SLinus Torvalds p = xdr_decode_time(p, &fattr->ctime); 1319e6e70f8STrond Myklebust fattr->valid |= NFS_ATTR_FATTR_V2; 1321da177e4SLinus Torvalds fattr->rdev = new_decode_dev(rdev); 133bca79478STrond Myklebust if (type == NFCHR && rdev == NFS2_FIFO_DEV) { 1341da177e4SLinus Torvalds fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; 1351da177e4SLinus Torvalds fattr->rdev = 0; 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds return p; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds /* 14125a0866cSChuck Lever * Encode/decode NFSv2 basic data types 14225a0866cSChuck Lever * 14325a0866cSChuck Lever * Basic NFSv2 data types are defined in section 2.3 of RFC 1094: 14425a0866cSChuck Lever * "NFS: Network File System Protocol Specification". 14525a0866cSChuck Lever * 14625a0866cSChuck Lever * Not all basic data types have their own encoding and decoding 14725a0866cSChuck Lever * functions. For run-time efficiency, some data types are encoded 14825a0866cSChuck Lever * or decoded inline. 14925a0866cSChuck Lever */ 15025a0866cSChuck Lever 15125a0866cSChuck Lever /* 152f796f8b3SChuck Lever * typedef opaque nfsdata<>; 153f796f8b3SChuck Lever */ 154f796f8b3SChuck Lever static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result) 155f796f8b3SChuck Lever { 156f796f8b3SChuck Lever u32 recvd, count; 157f796f8b3SChuck Lever size_t hdrlen; 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 count = be32_to_cpup(p); 164f796f8b3SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 165f796f8b3SChuck Lever recvd = xdr->buf->len - hdrlen; 166f796f8b3SChuck Lever if (unlikely(count > recvd)) 167f796f8b3SChuck Lever goto out_cheating; 168f796f8b3SChuck Lever out: 169f796f8b3SChuck Lever xdr_read_pages(xdr, count); 170f796f8b3SChuck Lever result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */ 171f796f8b3SChuck Lever result->count = count; 172f796f8b3SChuck Lever return count; 173f796f8b3SChuck Lever out_cheating: 174f796f8b3SChuck Lever dprintk("NFS: server cheating in read result: " 175f796f8b3SChuck Lever "count %u > recvd %u\n", count, recvd); 176f796f8b3SChuck Lever count = recvd; 177f796f8b3SChuck Lever goto out; 178f796f8b3SChuck Lever out_overflow: 179f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 180f796f8b3SChuck Lever return -EIO; 181f796f8b3SChuck Lever } 182f796f8b3SChuck Lever 183f796f8b3SChuck Lever /* 184f796f8b3SChuck Lever * enum stat { 185f796f8b3SChuck Lever * NFS_OK = 0, 186f796f8b3SChuck Lever * NFSERR_PERM = 1, 187f796f8b3SChuck Lever * NFSERR_NOENT = 2, 188f796f8b3SChuck Lever * NFSERR_IO = 5, 189f796f8b3SChuck Lever * NFSERR_NXIO = 6, 190f796f8b3SChuck Lever * NFSERR_ACCES = 13, 191f796f8b3SChuck Lever * NFSERR_EXIST = 17, 192f796f8b3SChuck Lever * NFSERR_NODEV = 19, 193f796f8b3SChuck Lever * NFSERR_NOTDIR = 20, 194f796f8b3SChuck Lever * NFSERR_ISDIR = 21, 195f796f8b3SChuck Lever * NFSERR_FBIG = 27, 196f796f8b3SChuck Lever * NFSERR_NOSPC = 28, 197f796f8b3SChuck Lever * NFSERR_ROFS = 30, 198f796f8b3SChuck Lever * NFSERR_NAMETOOLONG = 63, 199f796f8b3SChuck Lever * NFSERR_NOTEMPTY = 66, 200f796f8b3SChuck Lever * NFSERR_DQUOT = 69, 201f796f8b3SChuck Lever * NFSERR_STALE = 70, 202f796f8b3SChuck Lever * NFSERR_WFLUSH = 99 203f796f8b3SChuck Lever * }; 204f796f8b3SChuck Lever */ 205f796f8b3SChuck Lever static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status) 206f796f8b3SChuck Lever { 207f796f8b3SChuck Lever __be32 *p; 208f796f8b3SChuck Lever 209f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 210f796f8b3SChuck Lever if (unlikely(p == NULL)) 211f796f8b3SChuck Lever goto out_overflow; 212f796f8b3SChuck Lever *status = be32_to_cpup(p); 213f796f8b3SChuck Lever return 0; 214f796f8b3SChuck Lever out_overflow: 215f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 216f796f8b3SChuck Lever return -EIO; 217f796f8b3SChuck Lever } 218f796f8b3SChuck Lever 219f796f8b3SChuck Lever /* 22025a0866cSChuck Lever * 2.3.3. fhandle 22125a0866cSChuck Lever * 22225a0866cSChuck Lever * typedef opaque fhandle[FHSIZE]; 22325a0866cSChuck Lever */ 22425a0866cSChuck Lever static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh) 22525a0866cSChuck Lever { 22625a0866cSChuck Lever __be32 *p; 22725a0866cSChuck Lever 22825a0866cSChuck Lever BUG_ON(fh->size != NFS2_FHSIZE); 22925a0866cSChuck Lever p = xdr_reserve_space(xdr, NFS2_FHSIZE); 23025a0866cSChuck Lever memcpy(p, fh->data, NFS2_FHSIZE); 23125a0866cSChuck Lever } 23225a0866cSChuck Lever 233f796f8b3SChuck Lever static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) 234f796f8b3SChuck Lever { 235f796f8b3SChuck Lever __be32 *p; 236f796f8b3SChuck Lever 237f796f8b3SChuck Lever p = xdr_inline_decode(xdr, NFS2_FHSIZE); 238f796f8b3SChuck Lever if (unlikely(p == NULL)) 239f796f8b3SChuck Lever goto out_overflow; 240f796f8b3SChuck Lever fh->size = NFS2_FHSIZE; 241f796f8b3SChuck Lever memcpy(fh->data, p, NFS2_FHSIZE); 242f796f8b3SChuck Lever return 0; 243f796f8b3SChuck Lever out_overflow: 244f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 245f796f8b3SChuck Lever return -EIO; 246f796f8b3SChuck Lever } 247f796f8b3SChuck Lever 24825a0866cSChuck Lever /* 249282ac2a5SChuck Lever * 2.3.4. timeval 250282ac2a5SChuck Lever * 251282ac2a5SChuck Lever * struct timeval { 252282ac2a5SChuck Lever * unsigned int seconds; 253282ac2a5SChuck Lever * unsigned int useconds; 254282ac2a5SChuck Lever * }; 255282ac2a5SChuck Lever */ 256282ac2a5SChuck Lever static __be32 *xdr_encode_time(__be32 *p, const struct timespec *timep) 257282ac2a5SChuck Lever { 258282ac2a5SChuck Lever *p++ = cpu_to_be32(timep->tv_sec); 259282ac2a5SChuck Lever if (timep->tv_nsec != 0) 260282ac2a5SChuck Lever *p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC); 261282ac2a5SChuck Lever else 262282ac2a5SChuck Lever *p++ = cpu_to_be32(0); 263282ac2a5SChuck Lever return p; 264282ac2a5SChuck Lever } 265282ac2a5SChuck Lever 266282ac2a5SChuck Lever /* 267282ac2a5SChuck Lever * Passing the invalid value useconds=1000000 is a Sun convention for 268282ac2a5SChuck Lever * "set to current server time". It's needed to make permissions checks 269282ac2a5SChuck Lever * for the "touch" program across v2 mounts to Solaris and Irix servers 270282ac2a5SChuck Lever * work correctly. See description of sattr in section 6.1 of "NFS 271282ac2a5SChuck Lever * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5. 272282ac2a5SChuck Lever */ 273282ac2a5SChuck Lever static __be32 *xdr_encode_current_server_time(__be32 *p, 274282ac2a5SChuck Lever const struct timespec *timep) 275282ac2a5SChuck Lever { 276282ac2a5SChuck Lever *p++ = cpu_to_be32(timep->tv_sec); 277282ac2a5SChuck Lever *p++ = cpu_to_be32(1000000); 278282ac2a5SChuck Lever return p; 279282ac2a5SChuck Lever } 280282ac2a5SChuck Lever 281282ac2a5SChuck Lever /* 282f796f8b3SChuck Lever * 2.3.5. fattr 283f796f8b3SChuck Lever * 284f796f8b3SChuck Lever * struct fattr { 285f796f8b3SChuck Lever * ftype type; 286f796f8b3SChuck Lever * unsigned int mode; 287f796f8b3SChuck Lever * unsigned int nlink; 288f796f8b3SChuck Lever * unsigned int uid; 289f796f8b3SChuck Lever * unsigned int gid; 290f796f8b3SChuck Lever * unsigned int size; 291f796f8b3SChuck Lever * unsigned int blocksize; 292f796f8b3SChuck Lever * unsigned int rdev; 293f796f8b3SChuck Lever * unsigned int blocks; 294f796f8b3SChuck Lever * unsigned int fsid; 295f796f8b3SChuck Lever * unsigned int fileid; 296f796f8b3SChuck Lever * timeval atime; 297f796f8b3SChuck Lever * timeval mtime; 298f796f8b3SChuck Lever * timeval ctime; 299f796f8b3SChuck Lever * }; 300f796f8b3SChuck Lever * 301f796f8b3SChuck Lever */ 302f796f8b3SChuck Lever static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr) 303f796f8b3SChuck Lever { 304f796f8b3SChuck Lever __be32 *p; 305f796f8b3SChuck Lever 306f796f8b3SChuck Lever p = xdr_inline_decode(xdr, NFS_fattr_sz << 2); 307f796f8b3SChuck Lever if (unlikely(p == NULL)) 308f796f8b3SChuck Lever goto out_overflow; 309f796f8b3SChuck Lever xdr_decode_fattr(p, fattr); 310f796f8b3SChuck Lever return 0; 311f796f8b3SChuck Lever out_overflow: 312f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 313f796f8b3SChuck Lever return -EIO; 314f796f8b3SChuck Lever } 315f796f8b3SChuck Lever 316f796f8b3SChuck Lever /* 31725a0866cSChuck Lever * 2.3.6. sattr 31825a0866cSChuck Lever * 31925a0866cSChuck Lever * struct sattr { 32025a0866cSChuck Lever * unsigned int mode; 32125a0866cSChuck Lever * unsigned int uid; 32225a0866cSChuck Lever * unsigned int gid; 32325a0866cSChuck Lever * unsigned int size; 32425a0866cSChuck Lever * timeval atime; 32525a0866cSChuck Lever * timeval mtime; 32625a0866cSChuck Lever * }; 32725a0866cSChuck Lever */ 32825a0866cSChuck Lever 32925a0866cSChuck Lever #define NFS2_SATTR_NOT_SET (0xffffffff) 33025a0866cSChuck Lever 33125a0866cSChuck Lever static __be32 *xdr_time_not_set(__be32 *p) 33225a0866cSChuck Lever { 33325a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 33425a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 33525a0866cSChuck Lever return p; 33625a0866cSChuck Lever } 33725a0866cSChuck Lever 33825a0866cSChuck Lever static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr) 33925a0866cSChuck Lever { 34025a0866cSChuck Lever __be32 *p; 34125a0866cSChuck Lever 34225a0866cSChuck Lever p = xdr_reserve_space(xdr, NFS_sattr_sz << 2); 34325a0866cSChuck Lever 34425a0866cSChuck Lever if (attr->ia_valid & ATTR_MODE) 34525a0866cSChuck Lever *p++ = cpu_to_be32(attr->ia_mode); 34625a0866cSChuck Lever else 34725a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 34825a0866cSChuck Lever if (attr->ia_valid & ATTR_UID) 34925a0866cSChuck Lever *p++ = cpu_to_be32(attr->ia_uid); 35025a0866cSChuck Lever else 35125a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 35225a0866cSChuck Lever if (attr->ia_valid & ATTR_GID) 35325a0866cSChuck Lever *p++ = cpu_to_be32(attr->ia_gid); 35425a0866cSChuck Lever else 35525a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 35625a0866cSChuck Lever if (attr->ia_valid & ATTR_SIZE) 35725a0866cSChuck Lever *p++ = cpu_to_be32((u32)attr->ia_size); 35825a0866cSChuck Lever else 35925a0866cSChuck Lever *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); 36025a0866cSChuck Lever 36125a0866cSChuck Lever if (attr->ia_valid & ATTR_ATIME_SET) 36225a0866cSChuck Lever p = xdr_encode_time(p, &attr->ia_atime); 36325a0866cSChuck Lever else if (attr->ia_valid & ATTR_ATIME) 36425a0866cSChuck Lever p = xdr_encode_current_server_time(p, &attr->ia_atime); 36525a0866cSChuck Lever else 36625a0866cSChuck Lever p = xdr_time_not_set(p); 36725a0866cSChuck Lever if (attr->ia_valid & ATTR_MTIME_SET) 36825a0866cSChuck Lever xdr_encode_time(p, &attr->ia_mtime); 36925a0866cSChuck Lever else if (attr->ia_valid & ATTR_MTIME) 37025a0866cSChuck Lever xdr_encode_current_server_time(p, &attr->ia_mtime); 37125a0866cSChuck Lever else 37225a0866cSChuck Lever xdr_time_not_set(p); 37325a0866cSChuck Lever } 37425a0866cSChuck Lever 37525a0866cSChuck Lever /* 37625a0866cSChuck Lever * 2.3.7. filename 37725a0866cSChuck Lever * 37825a0866cSChuck Lever * typedef string filename<MAXNAMLEN>; 37925a0866cSChuck Lever */ 38025a0866cSChuck Lever static void encode_filename(struct xdr_stream *xdr, 38125a0866cSChuck Lever const char *name, u32 length) 38225a0866cSChuck Lever { 38325a0866cSChuck Lever __be32 *p; 38425a0866cSChuck Lever 38525a0866cSChuck Lever BUG_ON(length > NFS2_MAXNAMLEN); 38625a0866cSChuck Lever p = xdr_reserve_space(xdr, 4 + length); 38725a0866cSChuck Lever xdr_encode_opaque(p, name, length); 38825a0866cSChuck Lever } 38925a0866cSChuck Lever 390f796f8b3SChuck Lever static int decode_filename_inline(struct xdr_stream *xdr, 391f796f8b3SChuck Lever const char **name, u32 *length) 392f796f8b3SChuck Lever { 393f796f8b3SChuck Lever __be32 *p; 394f796f8b3SChuck Lever u32 count; 395f796f8b3SChuck Lever 396f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 397f796f8b3SChuck Lever if (unlikely(p == NULL)) 398f796f8b3SChuck Lever goto out_overflow; 399f796f8b3SChuck Lever count = be32_to_cpup(p); 400f796f8b3SChuck Lever if (count > NFS3_MAXNAMLEN) 401f796f8b3SChuck Lever goto out_nametoolong; 402f796f8b3SChuck Lever p = xdr_inline_decode(xdr, count); 403f796f8b3SChuck Lever if (unlikely(p == NULL)) 404f796f8b3SChuck Lever goto out_overflow; 405f796f8b3SChuck Lever *name = (const char *)p; 406f796f8b3SChuck Lever *length = count; 407f796f8b3SChuck Lever return 0; 408f796f8b3SChuck Lever out_nametoolong: 409f796f8b3SChuck Lever dprintk("NFS: returned filename too long: %u\n", count); 410f796f8b3SChuck Lever return -ENAMETOOLONG; 411f796f8b3SChuck Lever out_overflow: 412f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 413f796f8b3SChuck Lever return -EIO; 414f796f8b3SChuck Lever } 415f796f8b3SChuck Lever 41625a0866cSChuck Lever /* 41725a0866cSChuck Lever * 2.3.8. path 41825a0866cSChuck Lever * 41925a0866cSChuck Lever * typedef string path<MAXPATHLEN>; 42025a0866cSChuck Lever */ 42125a0866cSChuck Lever static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length) 42225a0866cSChuck Lever { 42325a0866cSChuck Lever __be32 *p; 42425a0866cSChuck Lever 42525a0866cSChuck Lever BUG_ON(length > NFS2_MAXPATHLEN); 42625a0866cSChuck Lever p = xdr_reserve_space(xdr, 4); 42725a0866cSChuck Lever *p = cpu_to_be32(length); 42825a0866cSChuck Lever xdr_write_pages(xdr, pages, 0, length); 42925a0866cSChuck Lever } 43025a0866cSChuck Lever 431f796f8b3SChuck Lever static int decode_path(struct xdr_stream *xdr) 432f796f8b3SChuck Lever { 433f796f8b3SChuck Lever u32 length, recvd; 434f796f8b3SChuck Lever size_t hdrlen; 435f796f8b3SChuck Lever __be32 *p; 436f796f8b3SChuck Lever 437f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 438f796f8b3SChuck Lever if (unlikely(p == NULL)) 439f796f8b3SChuck Lever goto out_overflow; 440f796f8b3SChuck Lever length = be32_to_cpup(p); 441f796f8b3SChuck Lever if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN)) 442f796f8b3SChuck Lever goto out_size; 443f796f8b3SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 444f796f8b3SChuck Lever recvd = xdr->buf->len - hdrlen; 445f796f8b3SChuck Lever if (unlikely(length > recvd)) 446f796f8b3SChuck Lever goto out_cheating; 447f796f8b3SChuck Lever 448f796f8b3SChuck Lever xdr_read_pages(xdr, length); 449f796f8b3SChuck Lever xdr_terminate_string(xdr->buf, length); 450f796f8b3SChuck Lever return 0; 451f796f8b3SChuck Lever out_size: 452f796f8b3SChuck Lever dprintk("NFS: returned pathname too long: %u\n", length); 453f796f8b3SChuck Lever return -ENAMETOOLONG; 454f796f8b3SChuck Lever out_cheating: 455f796f8b3SChuck Lever dprintk("NFS: server cheating in pathname result: " 456f796f8b3SChuck Lever "length %u > received %u\n", length, recvd); 457f796f8b3SChuck Lever return -EIO; 458f796f8b3SChuck Lever out_overflow: 459f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 460f796f8b3SChuck Lever return -EIO; 461f796f8b3SChuck Lever } 462f796f8b3SChuck Lever 463f796f8b3SChuck Lever /* 464f796f8b3SChuck Lever * 2.3.9. attrstat 465f796f8b3SChuck Lever * 466f796f8b3SChuck Lever * union attrstat switch (stat status) { 467f796f8b3SChuck Lever * case NFS_OK: 468f796f8b3SChuck Lever * fattr attributes; 469f796f8b3SChuck Lever * default: 470f796f8b3SChuck Lever * void; 471f796f8b3SChuck Lever * }; 472f796f8b3SChuck Lever */ 473f796f8b3SChuck Lever static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result) 474f796f8b3SChuck Lever { 475f796f8b3SChuck Lever enum nfs_stat status; 476f796f8b3SChuck Lever int error; 477f796f8b3SChuck Lever 478f796f8b3SChuck Lever error = decode_stat(xdr, &status); 479f796f8b3SChuck Lever if (unlikely(error)) 480f796f8b3SChuck Lever goto out; 481f796f8b3SChuck Lever if (status != NFS_OK) 482f796f8b3SChuck Lever goto out_default; 483f796f8b3SChuck Lever error = decode_fattr(xdr, result); 484f796f8b3SChuck Lever out: 485f796f8b3SChuck Lever return error; 486f796f8b3SChuck Lever out_default: 487f796f8b3SChuck Lever return nfs_stat_to_errno(status); 488f796f8b3SChuck Lever } 489f796f8b3SChuck Lever 49025a0866cSChuck Lever /* 49125a0866cSChuck Lever * 2.3.10. diropargs 49225a0866cSChuck Lever * 49325a0866cSChuck Lever * struct diropargs { 49425a0866cSChuck Lever * fhandle dir; 49525a0866cSChuck Lever * filename name; 49625a0866cSChuck Lever * }; 49725a0866cSChuck Lever */ 49825a0866cSChuck Lever static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh, 49925a0866cSChuck Lever const char *name, u32 length) 50025a0866cSChuck Lever { 50125a0866cSChuck Lever encode_fhandle(xdr, fh); 50225a0866cSChuck Lever encode_filename(xdr, name, length); 50325a0866cSChuck Lever } 50425a0866cSChuck Lever 505f796f8b3SChuck Lever /* 506f796f8b3SChuck Lever * 2.3.11. diropres 507f796f8b3SChuck Lever * 508f796f8b3SChuck Lever * union diropres switch (stat status) { 509f796f8b3SChuck Lever * case NFS_OK: 510f796f8b3SChuck Lever * struct { 511f796f8b3SChuck Lever * fhandle file; 512f796f8b3SChuck Lever * fattr attributes; 513f796f8b3SChuck Lever * } diropok; 514f796f8b3SChuck Lever * default: 515f796f8b3SChuck Lever * void; 516f796f8b3SChuck Lever * }; 517f796f8b3SChuck Lever */ 518f796f8b3SChuck Lever static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result) 519f796f8b3SChuck Lever { 520f796f8b3SChuck Lever int error; 521f796f8b3SChuck Lever 522f796f8b3SChuck Lever error = decode_fhandle(xdr, result->fh); 523f796f8b3SChuck Lever if (unlikely(error)) 524f796f8b3SChuck Lever goto out; 525f796f8b3SChuck Lever error = decode_fattr(xdr, result->fattr); 526f796f8b3SChuck Lever out: 527f796f8b3SChuck Lever return error; 528f796f8b3SChuck Lever } 529f796f8b3SChuck Lever 530f796f8b3SChuck Lever static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result) 531f796f8b3SChuck Lever { 532f796f8b3SChuck Lever enum nfs_stat status; 533f796f8b3SChuck Lever int error; 534f796f8b3SChuck Lever 535f796f8b3SChuck Lever error = decode_stat(xdr, &status); 536f796f8b3SChuck Lever if (unlikely(error)) 537f796f8b3SChuck Lever goto out; 538f796f8b3SChuck Lever if (status != NFS_OK) 539f796f8b3SChuck Lever goto out_default; 540f796f8b3SChuck Lever error = decode_diropok(xdr, result); 541f796f8b3SChuck Lever out: 542f796f8b3SChuck Lever return error; 543f796f8b3SChuck Lever out_default: 544f796f8b3SChuck Lever return nfs_stat_to_errno(status); 545f796f8b3SChuck Lever } 546f796f8b3SChuck Lever 54725a0866cSChuck Lever 54825a0866cSChuck Lever /* 5492d70f533SChuck Lever * NFSv2 XDR encode functions 5502d70f533SChuck Lever * 5512d70f533SChuck Lever * NFSv2 argument types are defined in section 2.2 of RFC 1094: 5522d70f533SChuck Lever * "NFS: Network File System Protocol Specification". 5531da177e4SLinus Torvalds */ 5541da177e4SLinus Torvalds 55525a0866cSChuck Lever static int nfs2_xdr_enc_fhandle(struct rpc_rqst *req, __be32 *p, 55625a0866cSChuck Lever const struct nfs_fh *fh) 55725a0866cSChuck Lever { 55825a0866cSChuck Lever struct xdr_stream xdr; 55925a0866cSChuck Lever 56025a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 56125a0866cSChuck Lever encode_fhandle(&xdr, fh); 56225a0866cSChuck Lever return 0; 56325a0866cSChuck Lever } 56425a0866cSChuck Lever 5651da177e4SLinus Torvalds /* 56625a0866cSChuck Lever * 2.2.3. sattrargs 56725a0866cSChuck Lever * 56825a0866cSChuck Lever * struct sattrargs { 56925a0866cSChuck Lever * fhandle file; 57025a0866cSChuck Lever * sattr attributes; 57125a0866cSChuck Lever * }; 57225a0866cSChuck Lever */ 57325a0866cSChuck Lever static int nfs2_xdr_enc_sattrargs(struct rpc_rqst *req, __be32 *p, 57425a0866cSChuck Lever const struct nfs_sattrargs *args) 57525a0866cSChuck Lever { 57625a0866cSChuck Lever struct xdr_stream xdr; 57725a0866cSChuck Lever 57825a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 57925a0866cSChuck Lever encode_fhandle(&xdr, args->fh); 58025a0866cSChuck Lever encode_sattr(&xdr, args->sattr); 58125a0866cSChuck Lever return 0; 58225a0866cSChuck Lever } 58325a0866cSChuck Lever 58425a0866cSChuck Lever static int nfs2_xdr_enc_diropargs(struct rpc_rqst *req, __be32 *p, 58525a0866cSChuck Lever const struct nfs_diropargs *args) 58625a0866cSChuck Lever { 58725a0866cSChuck Lever struct xdr_stream xdr; 58825a0866cSChuck Lever 58925a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 59025a0866cSChuck Lever encode_diropargs(&xdr, args->fh, args->name, args->len); 59125a0866cSChuck Lever return 0; 59225a0866cSChuck Lever } 59325a0866cSChuck Lever 59425a0866cSChuck Lever static int nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, __be32 *p, 59525a0866cSChuck Lever const struct nfs_readlinkargs *args) 59625a0866cSChuck Lever { 59725a0866cSChuck Lever struct xdr_stream xdr; 59825a0866cSChuck Lever 59925a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 60025a0866cSChuck Lever encode_fhandle(&xdr, args->fh); 60125a0866cSChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 60225a0866cSChuck Lever args->pglen, NFS_readlinkres_sz); 60325a0866cSChuck Lever return 0; 60425a0866cSChuck Lever } 60525a0866cSChuck Lever 6064fdc17b2STrond Myklebust /* 60725a0866cSChuck Lever * 2.2.7. readargs 60825a0866cSChuck Lever * 60925a0866cSChuck Lever * struct readargs { 61025a0866cSChuck Lever * fhandle file; 61125a0866cSChuck Lever * unsigned offset; 61225a0866cSChuck Lever * unsigned count; 61325a0866cSChuck Lever * unsigned totalcount; 61425a0866cSChuck Lever * }; 61525a0866cSChuck Lever */ 61625a0866cSChuck Lever static void encode_readargs(struct xdr_stream *xdr, 61725a0866cSChuck Lever const struct nfs_readargs *args) 61825a0866cSChuck Lever { 61925a0866cSChuck Lever u32 offset = args->offset; 62025a0866cSChuck Lever u32 count = args->count; 62125a0866cSChuck Lever __be32 *p; 62225a0866cSChuck Lever 62325a0866cSChuck Lever encode_fhandle(xdr, args->fh); 62425a0866cSChuck Lever 62525a0866cSChuck Lever p = xdr_reserve_space(xdr, 4 + 4 + 4); 62625a0866cSChuck Lever *p++ = cpu_to_be32(offset); 62725a0866cSChuck Lever *p++ = cpu_to_be32(count); 62825a0866cSChuck Lever *p = cpu_to_be32(count); 62925a0866cSChuck Lever } 63025a0866cSChuck Lever 63125a0866cSChuck Lever static int nfs2_xdr_enc_readargs(struct rpc_rqst *req, __be32 *p, 63225a0866cSChuck Lever const struct nfs_readargs *args) 63325a0866cSChuck Lever { 63425a0866cSChuck Lever struct xdr_stream xdr; 63525a0866cSChuck Lever 63625a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 63725a0866cSChuck Lever encode_readargs(&xdr, args); 63825a0866cSChuck Lever prepare_reply_buffer(req, args->pages, args->pgbase, 63925a0866cSChuck Lever args->count, NFS_readres_sz); 64025a0866cSChuck Lever req->rq_rcv_buf.flags |= XDRBUF_READ; 64125a0866cSChuck Lever return 0; 64225a0866cSChuck Lever } 64325a0866cSChuck Lever 64425a0866cSChuck Lever /* 6451da177e4SLinus Torvalds * Decode READ reply 6461da177e4SLinus Torvalds */ 6471da177e4SLinus Torvalds static int 6489d787a75SAl Viro nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) 6491da177e4SLinus Torvalds { 6501da177e4SLinus Torvalds struct kvec *iov = req->rq_rcv_buf.head; 6516232dbbcSChuck Lever size_t hdrlen; 6526232dbbcSChuck Lever u32 count, recvd; 6536232dbbcSChuck Lever int status; 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds if ((status = ntohl(*p++))) 656856dff3dSBenny Halevy return nfs_stat_to_errno(status); 6571da177e4SLinus Torvalds p = xdr_decode_fattr(p, res->fattr); 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds count = ntohl(*p++); 6601da177e4SLinus Torvalds res->eof = 0; 6611da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 6621da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 663fe82a183SChuck Lever dprintk("NFS: READ reply header overflowed:" 6646232dbbcSChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 6651da177e4SLinus Torvalds return -errno_NFSERR_IO; 6661da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 6671da177e4SLinus Torvalds dprintk("NFS: READ header is short. iovec will be shifted.\n"); 6681da177e4SLinus Torvalds xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds recvd = req->rq_rcv_buf.len - hdrlen; 6721da177e4SLinus Torvalds if (count > recvd) { 673fe82a183SChuck Lever dprintk("NFS: server cheating in read reply: " 6746232dbbcSChuck Lever "count %u > recvd %u\n", count, recvd); 6751da177e4SLinus Torvalds count = recvd; 6761da177e4SLinus Torvalds } 6771da177e4SLinus Torvalds 6786232dbbcSChuck Lever dprintk("RPC: readres OK count %u\n", count); 6791da177e4SLinus Torvalds if (count < res->count) 6801da177e4SLinus Torvalds res->count = count; 6811da177e4SLinus Torvalds 6821da177e4SLinus Torvalds return count; 6831da177e4SLinus Torvalds } 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds /* 68725a0866cSChuck Lever * 2.2.9. writeargs 68825a0866cSChuck Lever * 68925a0866cSChuck Lever * struct writeargs { 69025a0866cSChuck Lever * fhandle file; 69125a0866cSChuck Lever * unsigned beginoffset; 69225a0866cSChuck Lever * unsigned offset; 69325a0866cSChuck Lever * unsigned totalcount; 69425a0866cSChuck Lever * nfsdata data; 69525a0866cSChuck Lever * }; 69625a0866cSChuck Lever */ 69725a0866cSChuck Lever static void encode_writeargs(struct xdr_stream *xdr, 69825a0866cSChuck Lever const struct nfs_writeargs *args) 69925a0866cSChuck Lever { 70025a0866cSChuck Lever u32 offset = args->offset; 70125a0866cSChuck Lever u32 count = args->count; 70225a0866cSChuck Lever __be32 *p; 70325a0866cSChuck Lever 70425a0866cSChuck Lever encode_fhandle(xdr, args->fh); 70525a0866cSChuck Lever 70625a0866cSChuck Lever p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4); 70725a0866cSChuck Lever *p++ = cpu_to_be32(offset); 70825a0866cSChuck Lever *p++ = cpu_to_be32(offset); 70925a0866cSChuck Lever *p++ = cpu_to_be32(count); 71025a0866cSChuck Lever 71125a0866cSChuck Lever /* nfsdata */ 71225a0866cSChuck Lever *p = cpu_to_be32(count); 71325a0866cSChuck Lever xdr_write_pages(xdr, args->pages, args->pgbase, count); 71425a0866cSChuck Lever } 71525a0866cSChuck Lever 71625a0866cSChuck Lever static int nfs2_xdr_enc_writeargs(struct rpc_rqst *req, __be32 *p, 71725a0866cSChuck Lever const struct nfs_writeargs *args) 71825a0866cSChuck Lever { 71925a0866cSChuck Lever struct xdr_stream xdr; 72025a0866cSChuck Lever 72125a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 72225a0866cSChuck Lever encode_writeargs(&xdr, args); 72325a0866cSChuck Lever xdr.buf->flags |= XDRBUF_WRITE; 72425a0866cSChuck Lever return 0; 72525a0866cSChuck Lever } 72625a0866cSChuck Lever 72725a0866cSChuck Lever /* 72825a0866cSChuck Lever * 2.2.10. createargs 72925a0866cSChuck Lever * 73025a0866cSChuck Lever * struct createargs { 73125a0866cSChuck Lever * diropargs where; 73225a0866cSChuck Lever * sattr attributes; 73325a0866cSChuck Lever * }; 73425a0866cSChuck Lever */ 73525a0866cSChuck Lever static int nfs2_xdr_enc_createargs(struct rpc_rqst *req, __be32 *p, 73625a0866cSChuck Lever const struct nfs_createargs *args) 73725a0866cSChuck Lever { 73825a0866cSChuck Lever struct xdr_stream xdr; 73925a0866cSChuck Lever 74025a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 74125a0866cSChuck Lever encode_diropargs(&xdr, args->fh, args->name, args->len); 74225a0866cSChuck Lever encode_sattr(&xdr, args->sattr); 74325a0866cSChuck Lever return 0; 74425a0866cSChuck Lever } 74525a0866cSChuck Lever 74625a0866cSChuck Lever static int nfs2_xdr_enc_removeargs(struct rpc_rqst *req, __be32 *p, 74725a0866cSChuck Lever const struct nfs_removeargs *args) 74825a0866cSChuck Lever { 74925a0866cSChuck Lever struct xdr_stream xdr; 75025a0866cSChuck Lever 75125a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 75225a0866cSChuck Lever encode_diropargs(&xdr, args->fh, args->name.name, args->name.len); 75325a0866cSChuck Lever return 0; 75425a0866cSChuck Lever } 75525a0866cSChuck Lever 75625a0866cSChuck Lever /* 75725a0866cSChuck Lever * 2.2.12. renameargs 75825a0866cSChuck Lever * 75925a0866cSChuck Lever * struct renameargs { 76025a0866cSChuck Lever * diropargs from; 76125a0866cSChuck Lever * diropargs to; 76225a0866cSChuck Lever * }; 76325a0866cSChuck Lever */ 76425a0866cSChuck Lever static int nfs2_xdr_enc_renameargs(struct rpc_rqst *req, __be32 *p, 76525a0866cSChuck Lever const struct nfs_renameargs *args) 76625a0866cSChuck Lever { 76725a0866cSChuck Lever const struct qstr *old = args->old_name; 76825a0866cSChuck Lever const struct qstr *new = args->new_name; 76925a0866cSChuck Lever struct xdr_stream xdr; 77025a0866cSChuck Lever 77125a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 77225a0866cSChuck Lever encode_diropargs(&xdr, args->old_dir, old->name, old->len); 77325a0866cSChuck Lever encode_diropargs(&xdr, args->new_dir, new->name, new->len); 77425a0866cSChuck Lever return 0; 77525a0866cSChuck Lever } 77625a0866cSChuck Lever 77725a0866cSChuck Lever /* 77825a0866cSChuck Lever * 2.2.13. linkargs 77925a0866cSChuck Lever * 78025a0866cSChuck Lever * struct linkargs { 78125a0866cSChuck Lever * fhandle from; 78225a0866cSChuck Lever * diropargs to; 78325a0866cSChuck Lever * }; 78425a0866cSChuck Lever */ 78525a0866cSChuck Lever static int nfs2_xdr_enc_linkargs(struct rpc_rqst *req, __be32 *p, 78625a0866cSChuck Lever const struct nfs_linkargs *args) 78725a0866cSChuck Lever { 78825a0866cSChuck Lever struct xdr_stream xdr; 78925a0866cSChuck Lever 79025a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 79125a0866cSChuck Lever encode_fhandle(&xdr, args->fromfh); 79225a0866cSChuck Lever encode_diropargs(&xdr, args->tofh, args->toname, args->tolen); 79325a0866cSChuck Lever return 0; 79425a0866cSChuck Lever } 79525a0866cSChuck Lever 79625a0866cSChuck Lever /* 79725a0866cSChuck Lever * 2.2.14. symlinkargs 79825a0866cSChuck Lever * 79925a0866cSChuck Lever * struct symlinkargs { 80025a0866cSChuck Lever * diropargs from; 80125a0866cSChuck Lever * path to; 80225a0866cSChuck Lever * sattr attributes; 80325a0866cSChuck Lever * }; 80425a0866cSChuck Lever */ 80525a0866cSChuck Lever static int nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req, __be32 *p, 80625a0866cSChuck Lever const struct nfs_symlinkargs *args) 80725a0866cSChuck Lever { 80825a0866cSChuck Lever struct xdr_stream xdr; 80925a0866cSChuck Lever 81025a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 81125a0866cSChuck Lever encode_diropargs(&xdr, args->fromfh, args->fromname, args->fromlen); 81225a0866cSChuck Lever encode_path(&xdr, args->pages, args->pathlen); 81325a0866cSChuck Lever encode_sattr(&xdr, args->sattr); 81425a0866cSChuck Lever return 0; 81525a0866cSChuck Lever } 81625a0866cSChuck Lever 81725a0866cSChuck Lever /* 81825a0866cSChuck Lever * 2.2.17. readdirargs 81925a0866cSChuck Lever * 82025a0866cSChuck Lever * struct readdirargs { 82125a0866cSChuck Lever * fhandle dir; 82225a0866cSChuck Lever * nfscookie cookie; 82325a0866cSChuck Lever * unsigned count; 82425a0866cSChuck Lever * }; 82525a0866cSChuck Lever */ 82625a0866cSChuck Lever static void encode_readdirargs(struct xdr_stream *xdr, 82725a0866cSChuck Lever const struct nfs_readdirargs *args) 82825a0866cSChuck Lever { 82925a0866cSChuck Lever __be32 *p; 83025a0866cSChuck Lever 83125a0866cSChuck Lever encode_fhandle(xdr, args->fh); 83225a0866cSChuck Lever 83325a0866cSChuck Lever p = xdr_reserve_space(xdr, 4 + 4); 83425a0866cSChuck Lever *p++ = cpu_to_be32(args->cookie); 83525a0866cSChuck Lever *p = cpu_to_be32(args->count); 83625a0866cSChuck Lever } 83725a0866cSChuck Lever 83825a0866cSChuck Lever static int nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, __be32 *p, 83925a0866cSChuck Lever const struct nfs_readdirargs *args) 84025a0866cSChuck Lever { 84125a0866cSChuck Lever struct xdr_stream xdr; 84225a0866cSChuck Lever 84325a0866cSChuck Lever xdr_init_encode(&xdr, &req->rq_snd_buf, p); 84425a0866cSChuck Lever encode_readdirargs(&xdr, args); 84525a0866cSChuck Lever prepare_reply_buffer(req, args->pages, 0, 84625a0866cSChuck Lever args->count, NFS_readdirres_sz); 84725a0866cSChuck Lever return 0; 84825a0866cSChuck Lever } 84925a0866cSChuck Lever 85025a0866cSChuck Lever /* 8511da177e4SLinus Torvalds * Decode the result of a readdir call. 8521da177e4SLinus Torvalds * We're not really decoding anymore, we just leave the buffer untouched 8531da177e4SLinus Torvalds * and only check that it is syntactically correct. 8541da177e4SLinus Torvalds * The real decoding happens in nfs_decode_entry below, called directly 8551da177e4SLinus Torvalds * from nfs_readdir for each entry. 8561da177e4SLinus Torvalds */ 8571da177e4SLinus Torvalds static int 8589d787a75SAl Viro nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) 8591da177e4SLinus Torvalds { 8601da177e4SLinus Torvalds struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 8611da177e4SLinus Torvalds struct kvec *iov = rcvbuf->head; 8621da177e4SLinus Torvalds struct page **page; 8636232dbbcSChuck Lever size_t hdrlen; 8646232dbbcSChuck Lever unsigned int pglen, recvd; 865ac396128STrond Myklebust int status; 8661da177e4SLinus Torvalds 8671da177e4SLinus Torvalds if ((status = ntohl(*p++))) 868856dff3dSBenny Halevy return nfs_stat_to_errno(status); 8691da177e4SLinus Torvalds 8701da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 8711da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 872fe82a183SChuck Lever dprintk("NFS: READDIR reply header overflowed:" 8736232dbbcSChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 8741da177e4SLinus Torvalds return -errno_NFSERR_IO; 8751da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 8761da177e4SLinus Torvalds dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); 8771da177e4SLinus Torvalds xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 8781da177e4SLinus Torvalds } 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds pglen = rcvbuf->page_len; 8811da177e4SLinus Torvalds recvd = rcvbuf->len - hdrlen; 8821da177e4SLinus Torvalds if (pglen > recvd) 8831da177e4SLinus Torvalds pglen = recvd; 8841da177e4SLinus Torvalds page = rcvbuf->pages; 885ac396128STrond Myklebust return pglen; 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds 888babddc72SBryan Schumaker __be32 * 88982f2e547SBryan Schumaker nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus) 890babddc72SBryan Schumaker { 891babddc72SBryan Schumaker __be32 *p; 892babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 893babddc72SBryan Schumaker if (unlikely(!p)) 894babddc72SBryan Schumaker goto out_overflow; 895babddc72SBryan Schumaker if (!ntohl(*p++)) { 896babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 4); 897babddc72SBryan Schumaker if (unlikely(!p)) 898babddc72SBryan Schumaker goto out_overflow; 899babddc72SBryan Schumaker if (!ntohl(*p++)) 9001da177e4SLinus Torvalds return ERR_PTR(-EAGAIN); 9011da177e4SLinus Torvalds entry->eof = 1; 9021da177e4SLinus Torvalds return ERR_PTR(-EBADCOOKIE); 9031da177e4SLinus Torvalds } 9041da177e4SLinus Torvalds 905babddc72SBryan Schumaker p = xdr_inline_decode(xdr, 8); 906babddc72SBryan Schumaker if (unlikely(!p)) 907babddc72SBryan Schumaker goto out_overflow; 908babddc72SBryan Schumaker 9091da177e4SLinus Torvalds entry->ino = ntohl(*p++); 9101da177e4SLinus Torvalds entry->len = ntohl(*p++); 911babddc72SBryan Schumaker 912babddc72SBryan Schumaker p = xdr_inline_decode(xdr, entry->len + 4); 913babddc72SBryan Schumaker if (unlikely(!p)) 914babddc72SBryan Schumaker goto out_overflow; 9151da177e4SLinus Torvalds entry->name = (const char *) p; 9161da177e4SLinus Torvalds p += XDR_QUADLEN(entry->len); 9171da177e4SLinus Torvalds entry->prev_cookie = entry->cookie; 9181da177e4SLinus Torvalds entry->cookie = ntohl(*p++); 919babddc72SBryan Schumaker 9200b26a0bfSTrond Myklebust entry->d_type = DT_UNKNOWN; 9210b26a0bfSTrond Myklebust 922babddc72SBryan Schumaker p = xdr_inline_peek(xdr, 8); 923babddc72SBryan Schumaker if (p != NULL) 9241da177e4SLinus Torvalds entry->eof = !p[0] && p[1]; 925babddc72SBryan Schumaker else 926babddc72SBryan Schumaker entry->eof = 0; 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds return p; 929babddc72SBryan Schumaker 930babddc72SBryan Schumaker out_overflow: 931babddc72SBryan Schumaker print_overflow_msg(__func__, xdr); 932463a376eSTrond Myklebust return ERR_PTR(-EAGAIN); 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds /* 9361da177e4SLinus Torvalds * NFS XDR decode functions 9371da177e4SLinus Torvalds */ 9381da177e4SLinus Torvalds /* 9391da177e4SLinus Torvalds * Decode simple status reply 9401da177e4SLinus Torvalds */ 9411da177e4SLinus Torvalds static int 9429d787a75SAl Viro nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy) 9431da177e4SLinus Torvalds { 9441da177e4SLinus Torvalds int status; 9451da177e4SLinus Torvalds 9461da177e4SLinus Torvalds if ((status = ntohl(*p++)) != 0) 947856dff3dSBenny Halevy status = nfs_stat_to_errno(status); 9481da177e4SLinus Torvalds return status; 9491da177e4SLinus Torvalds } 9501da177e4SLinus Torvalds 951f796f8b3SChuck Lever static int nfs2_xdr_dec_stat(struct rpc_rqst *req, __be32 *p, 952f796f8b3SChuck Lever void *__unused) 953f796f8b3SChuck Lever { 954f796f8b3SChuck Lever struct xdr_stream xdr; 955f796f8b3SChuck Lever enum nfs_stat status; 956f796f8b3SChuck Lever int error; 957f796f8b3SChuck Lever 958f796f8b3SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 959f796f8b3SChuck Lever error = decode_stat(&xdr, &status); 960f796f8b3SChuck Lever if (unlikely(error)) 961f796f8b3SChuck Lever goto out; 962f796f8b3SChuck Lever if (status != NFS_OK) 963f796f8b3SChuck Lever goto out_default; 964f796f8b3SChuck Lever out: 965f796f8b3SChuck Lever return error; 966f796f8b3SChuck Lever out_default: 967f796f8b3SChuck Lever return nfs_stat_to_errno(status); 968f796f8b3SChuck Lever } 969f796f8b3SChuck Lever 9701da177e4SLinus Torvalds /* 9711da177e4SLinus Torvalds * Decode attrstat reply 9721da177e4SLinus Torvalds * GETATTR, SETATTR, WRITE 9731da177e4SLinus Torvalds */ 9741da177e4SLinus Torvalds static int 9759d787a75SAl Viro nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) 9761da177e4SLinus Torvalds { 9771da177e4SLinus Torvalds int status; 9781da177e4SLinus Torvalds 9791da177e4SLinus Torvalds if ((status = ntohl(*p++))) 980856dff3dSBenny Halevy return nfs_stat_to_errno(status); 9811da177e4SLinus Torvalds xdr_decode_fattr(p, fattr); 9821da177e4SLinus Torvalds return 0; 9831da177e4SLinus Torvalds } 9841da177e4SLinus Torvalds 985f796f8b3SChuck Lever static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, __be32 *p, 986f796f8b3SChuck Lever struct nfs_fattr *result) 987f796f8b3SChuck Lever { 988f796f8b3SChuck Lever struct xdr_stream xdr; 989f796f8b3SChuck Lever 990f796f8b3SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 991f796f8b3SChuck Lever return decode_attrstat(&xdr, result); 992f796f8b3SChuck Lever } 993f796f8b3SChuck Lever 9941da177e4SLinus Torvalds /* 9951da177e4SLinus Torvalds * Decode diropres reply 9961da177e4SLinus Torvalds * LOOKUP, CREATE, MKDIR 9971da177e4SLinus Torvalds */ 9981da177e4SLinus Torvalds static int 9999d787a75SAl Viro nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) 10001da177e4SLinus Torvalds { 10011da177e4SLinus Torvalds int status; 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds if ((status = ntohl(*p++))) 1004856dff3dSBenny Halevy return nfs_stat_to_errno(status); 10051da177e4SLinus Torvalds p = xdr_decode_fhandle(p, res->fh); 10061da177e4SLinus Torvalds xdr_decode_fattr(p, res->fattr); 10071da177e4SLinus Torvalds return 0; 10081da177e4SLinus Torvalds } 10091da177e4SLinus Torvalds 1010f796f8b3SChuck Lever static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, __be32 *p, 1011f796f8b3SChuck Lever struct nfs_diropok *result) 1012f796f8b3SChuck Lever { 1013f796f8b3SChuck Lever struct xdr_stream xdr; 1014f796f8b3SChuck Lever 1015f796f8b3SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1016f796f8b3SChuck Lever return decode_diropres(&xdr, result); 1017f796f8b3SChuck Lever } 1018f796f8b3SChuck Lever 10191da177e4SLinus Torvalds /* 10201da177e4SLinus Torvalds * Decode READLINK reply 10211da177e4SLinus Torvalds */ 10221da177e4SLinus Torvalds static int 10239d787a75SAl Viro nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) 10241da177e4SLinus Torvalds { 10251da177e4SLinus Torvalds struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 10261da177e4SLinus Torvalds struct kvec *iov = rcvbuf->head; 10276232dbbcSChuck Lever size_t hdrlen; 10286232dbbcSChuck Lever u32 len, recvd; 10291da177e4SLinus Torvalds int status; 10301da177e4SLinus Torvalds 10311da177e4SLinus Torvalds if ((status = ntohl(*p++))) 1032856dff3dSBenny Halevy return nfs_stat_to_errno(status); 10331da177e4SLinus Torvalds /* Convert length of symlink */ 10341da177e4SLinus Torvalds len = ntohl(*p++); 10356232dbbcSChuck Lever if (len >= rcvbuf->page_len) { 1036fe82a183SChuck Lever dprintk("nfs: server returned giant symlink!\n"); 10371da177e4SLinus Torvalds return -ENAMETOOLONG; 10381da177e4SLinus Torvalds } 10391da177e4SLinus Torvalds hdrlen = (u8 *) p - (u8 *) iov->iov_base; 10401da177e4SLinus Torvalds if (iov->iov_len < hdrlen) { 1041fe82a183SChuck Lever dprintk("NFS: READLINK reply header overflowed:" 10426232dbbcSChuck Lever "length %Zu > %Zu\n", hdrlen, iov->iov_len); 10431da177e4SLinus Torvalds return -errno_NFSERR_IO; 10441da177e4SLinus Torvalds } else if (iov->iov_len != hdrlen) { 10451da177e4SLinus Torvalds dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); 10461da177e4SLinus Torvalds xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds recvd = req->rq_rcv_buf.len - hdrlen; 10491da177e4SLinus Torvalds if (recvd < len) { 1050fe82a183SChuck Lever dprintk("NFS: server cheating in readlink reply: " 10511da177e4SLinus Torvalds "count %u > recvd %u\n", len, recvd); 10521da177e4SLinus Torvalds return -EIO; 10531da177e4SLinus Torvalds } 10541da177e4SLinus Torvalds 1055b4687da7SChuck Lever xdr_terminate_string(rcvbuf, len); 10561da177e4SLinus Torvalds return 0; 10571da177e4SLinus Torvalds } 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds /* 1060f796f8b3SChuck Lever * 2.2.6. readlinkres 1061f796f8b3SChuck Lever * 1062f796f8b3SChuck Lever * union readlinkres switch (stat status) { 1063f796f8b3SChuck Lever * case NFS_OK: 1064f796f8b3SChuck Lever * path data; 1065f796f8b3SChuck Lever * default: 1066f796f8b3SChuck Lever * void; 1067f796f8b3SChuck Lever * }; 1068f796f8b3SChuck Lever */ 1069f796f8b3SChuck Lever static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req, __be32 *p, 1070f796f8b3SChuck Lever void *__unused) 1071f796f8b3SChuck Lever { 1072f796f8b3SChuck Lever struct xdr_stream xdr; 1073f796f8b3SChuck Lever enum nfs_stat status; 1074f796f8b3SChuck Lever int error; 1075f796f8b3SChuck Lever 1076f796f8b3SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1077f796f8b3SChuck Lever error = decode_stat(&xdr, &status); 1078f796f8b3SChuck Lever if (unlikely(error)) 1079f796f8b3SChuck Lever goto out; 1080f796f8b3SChuck Lever if (status != NFS_OK) 1081f796f8b3SChuck Lever goto out_default; 1082f796f8b3SChuck Lever error = decode_path(&xdr); 1083f796f8b3SChuck Lever out: 1084f796f8b3SChuck Lever return error; 1085f796f8b3SChuck Lever out_default: 1086f796f8b3SChuck Lever return nfs_stat_to_errno(status); 1087f796f8b3SChuck Lever } 1088f796f8b3SChuck Lever 1089f796f8b3SChuck Lever /* 1090f796f8b3SChuck Lever * 2.2.7. readres 1091f796f8b3SChuck Lever * 1092f796f8b3SChuck Lever * union readres switch (stat status) { 1093f796f8b3SChuck Lever * case NFS_OK: 1094f796f8b3SChuck Lever * fattr attributes; 1095f796f8b3SChuck Lever * nfsdata data; 1096f796f8b3SChuck Lever * default: 1097f796f8b3SChuck Lever * void; 1098f796f8b3SChuck Lever * }; 1099f796f8b3SChuck Lever */ 1100f796f8b3SChuck Lever static int nfs2_xdr_dec_readres(struct rpc_rqst *req, __be32 *p, 1101f796f8b3SChuck Lever struct nfs_readres *result) 1102f796f8b3SChuck Lever { 1103f796f8b3SChuck Lever struct xdr_stream xdr; 1104f796f8b3SChuck Lever enum nfs_stat status; 1105f796f8b3SChuck Lever int error; 1106f796f8b3SChuck Lever 1107f796f8b3SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1108f796f8b3SChuck Lever error = decode_stat(&xdr, &status); 1109f796f8b3SChuck Lever if (unlikely(error)) 1110f796f8b3SChuck Lever goto out; 1111f796f8b3SChuck Lever if (status != NFS_OK) 1112f796f8b3SChuck Lever goto out_default; 1113f796f8b3SChuck Lever error = decode_fattr(&xdr, result->fattr); 1114f796f8b3SChuck Lever if (unlikely(error)) 1115f796f8b3SChuck Lever goto out; 1116f796f8b3SChuck Lever error = decode_nfsdata(&xdr, result); 1117f796f8b3SChuck Lever out: 1118f796f8b3SChuck Lever return error; 1119f796f8b3SChuck Lever out_default: 1120f796f8b3SChuck Lever return nfs_stat_to_errno(status); 1121f796f8b3SChuck Lever } 1122f796f8b3SChuck Lever 1123f796f8b3SChuck Lever /* 11241da177e4SLinus Torvalds * Decode WRITE reply 11251da177e4SLinus Torvalds */ 11261da177e4SLinus Torvalds static int 11279d787a75SAl Viro nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) 11281da177e4SLinus Torvalds { 11291da177e4SLinus Torvalds res->verf->committed = NFS_FILE_SYNC; 11301da177e4SLinus Torvalds return nfs_xdr_attrstat(req, p, res->fattr); 11311da177e4SLinus Torvalds } 11321da177e4SLinus Torvalds 1133f796f8b3SChuck Lever static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, __be32 *p, 1134f796f8b3SChuck Lever struct nfs_writeres *result) 1135f796f8b3SChuck Lever { 1136f796f8b3SChuck Lever struct xdr_stream xdr; 1137f796f8b3SChuck Lever 1138f796f8b3SChuck Lever /* All NFSv2 writes are "file sync" writes */ 1139f796f8b3SChuck Lever result->verf->committed = NFS_FILE_SYNC; 1140f796f8b3SChuck Lever 1141f796f8b3SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1142f796f8b3SChuck Lever return decode_attrstat(&xdr, result->fattr); 1143f796f8b3SChuck Lever } 1144f796f8b3SChuck Lever 1145f796f8b3SChuck Lever /** 1146f796f8b3SChuck Lever * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in 1147f796f8b3SChuck Lever * the local page cache. 1148f796f8b3SChuck Lever * @xdr: XDR stream where entry resides 1149f796f8b3SChuck Lever * @entry: buffer to fill in with entry data 1150f796f8b3SChuck Lever * @server: nfs_server data for this directory 1151f796f8b3SChuck Lever * @plus: boolean indicating whether this should be a readdirplus entry 1152f796f8b3SChuck Lever * 1153f796f8b3SChuck Lever * Returns the position of the next item in the buffer, or an ERR_PTR. 1154f796f8b3SChuck Lever * 1155f796f8b3SChuck Lever * This function is not invoked during READDIR reply decoding, but 1156f796f8b3SChuck Lever * rather whenever an application invokes the getdents(2) system call 1157f796f8b3SChuck Lever * on a directory already in our cache. 1158f796f8b3SChuck Lever * 1159f796f8b3SChuck Lever * 2.2.17. entry 1160f796f8b3SChuck Lever * 1161f796f8b3SChuck Lever * struct entry { 1162f796f8b3SChuck Lever * unsigned fileid; 1163f796f8b3SChuck Lever * filename name; 1164f796f8b3SChuck Lever * nfscookie cookie; 1165f796f8b3SChuck Lever * entry *nextentry; 1166f796f8b3SChuck Lever * }; 1167f796f8b3SChuck Lever */ 1168f796f8b3SChuck Lever __be32 *nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, 1169f796f8b3SChuck Lever struct nfs_server *server, int plus) 1170f796f8b3SChuck Lever { 1171f796f8b3SChuck Lever __be32 *p; 1172f796f8b3SChuck Lever int error; 1173f796f8b3SChuck Lever 1174f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 1175f796f8b3SChuck Lever if (unlikely(p == NULL)) 1176f796f8b3SChuck Lever goto out_overflow; 1177f796f8b3SChuck Lever if (*p++ == xdr_zero) { 1178f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 1179f796f8b3SChuck Lever if (unlikely(p == NULL)) 1180f796f8b3SChuck Lever goto out_overflow; 1181f796f8b3SChuck Lever if (*p++ == xdr_zero) 1182f796f8b3SChuck Lever return ERR_PTR(-EAGAIN); 1183f796f8b3SChuck Lever entry->eof = 1; 1184f796f8b3SChuck Lever return ERR_PTR(-EBADCOOKIE); 1185f796f8b3SChuck Lever } 1186f796f8b3SChuck Lever 1187f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 1188f796f8b3SChuck Lever if (unlikely(p == NULL)) 1189f796f8b3SChuck Lever goto out_overflow; 1190f796f8b3SChuck Lever entry->ino = be32_to_cpup(p); 1191f796f8b3SChuck Lever 1192f796f8b3SChuck Lever error = decode_filename_inline(xdr, &entry->name, &entry->len); 1193f796f8b3SChuck Lever if (unlikely(error)) 1194f796f8b3SChuck Lever return ERR_PTR(error); 1195f796f8b3SChuck Lever 1196f796f8b3SChuck Lever /* 1197f796f8b3SChuck Lever * The type (size and byte order) of nfscookie isn't defined in 1198f796f8b3SChuck Lever * RFC 1094. This implementation assumes that it's an XDR uint32. 1199f796f8b3SChuck Lever */ 1200f796f8b3SChuck Lever entry->prev_cookie = entry->cookie; 1201f796f8b3SChuck Lever p = xdr_inline_decode(xdr, 4); 1202f796f8b3SChuck Lever if (unlikely(p == NULL)) 1203f796f8b3SChuck Lever goto out_overflow; 1204f796f8b3SChuck Lever entry->cookie = be32_to_cpup(p); 1205f796f8b3SChuck Lever 1206f796f8b3SChuck Lever entry->d_type = DT_UNKNOWN; 1207f796f8b3SChuck Lever 1208f796f8b3SChuck Lever /* Peek at the next entry to see if we're at EOD */ 1209f796f8b3SChuck Lever p = xdr_inline_peek(xdr, 4 + 4); 1210f796f8b3SChuck Lever entry->eof = 0; 1211f796f8b3SChuck Lever if (p != NULL) 1212f796f8b3SChuck Lever entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero); 1213f796f8b3SChuck Lever return p; 1214f796f8b3SChuck Lever 1215f796f8b3SChuck Lever out_overflow: 1216f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 1217f796f8b3SChuck Lever return ERR_PTR(-EAGAIN); 1218f796f8b3SChuck Lever } 1219f796f8b3SChuck Lever 1220f796f8b3SChuck Lever /* 1221f796f8b3SChuck Lever * 2.2.17. readdirres 1222f796f8b3SChuck Lever * 1223f796f8b3SChuck Lever * union readdirres switch (stat status) { 1224f796f8b3SChuck Lever * case NFS_OK: 1225f796f8b3SChuck Lever * struct { 1226f796f8b3SChuck Lever * entry *entries; 1227f796f8b3SChuck Lever * bool eof; 1228f796f8b3SChuck Lever * } readdirok; 1229f796f8b3SChuck Lever * default: 1230f796f8b3SChuck Lever * void; 1231f796f8b3SChuck Lever * }; 1232f796f8b3SChuck Lever * 1233f796f8b3SChuck Lever * Read the directory contents into the page cache, but don't 1234f796f8b3SChuck Lever * touch them. The actual decoding is done by nfs2_decode_dirent() 1235f796f8b3SChuck Lever * during subsequent nfs_readdir() calls. 1236f796f8b3SChuck Lever */ 1237f796f8b3SChuck Lever static int decode_readdirok(struct xdr_stream *xdr) 1238f796f8b3SChuck Lever { 1239f796f8b3SChuck Lever u32 recvd, pglen; 1240f796f8b3SChuck Lever size_t hdrlen; 1241f796f8b3SChuck Lever 1242f796f8b3SChuck Lever pglen = xdr->buf->page_len; 1243f796f8b3SChuck Lever hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 1244f796f8b3SChuck Lever recvd = xdr->buf->len - hdrlen; 1245f796f8b3SChuck Lever if (unlikely(pglen > recvd)) 1246f796f8b3SChuck Lever goto out_cheating; 1247f796f8b3SChuck Lever out: 1248f796f8b3SChuck Lever xdr_read_pages(xdr, pglen); 1249f796f8b3SChuck Lever return pglen; 1250f796f8b3SChuck Lever out_cheating: 1251f796f8b3SChuck Lever dprintk("NFS: server cheating in readdir result: " 1252f796f8b3SChuck Lever "pglen %u > recvd %u\n", pglen, recvd); 1253f796f8b3SChuck Lever pglen = recvd; 1254f796f8b3SChuck Lever goto out; 1255f796f8b3SChuck Lever } 1256f796f8b3SChuck Lever 1257f796f8b3SChuck Lever static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, __be32 *p, 1258f796f8b3SChuck Lever void *__unused) 1259f796f8b3SChuck Lever { 1260f796f8b3SChuck Lever struct xdr_stream xdr; 1261f796f8b3SChuck Lever enum nfs_stat status; 1262f796f8b3SChuck Lever int error; 1263f796f8b3SChuck Lever 1264f796f8b3SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1265f796f8b3SChuck Lever error = decode_stat(&xdr, &status); 1266f796f8b3SChuck Lever if (unlikely(error)) 1267f796f8b3SChuck Lever goto out; 1268f796f8b3SChuck Lever if (status != NFS_OK) 1269f796f8b3SChuck Lever goto out_default; 1270f796f8b3SChuck Lever error = decode_readdirok(&xdr); 1271f796f8b3SChuck Lever out: 1272f796f8b3SChuck Lever return error; 1273f796f8b3SChuck Lever out_default: 1274f796f8b3SChuck Lever return nfs_stat_to_errno(status); 1275f796f8b3SChuck Lever } 1276f796f8b3SChuck Lever 12771da177e4SLinus Torvalds /* 12781da177e4SLinus Torvalds * Decode STATFS reply 12791da177e4SLinus Torvalds */ 12801da177e4SLinus Torvalds static int 12819d787a75SAl Viro nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res) 12821da177e4SLinus Torvalds { 12831da177e4SLinus Torvalds int status; 12841da177e4SLinus Torvalds 12851da177e4SLinus Torvalds if ((status = ntohl(*p++))) 1286856dff3dSBenny Halevy return nfs_stat_to_errno(status); 12871da177e4SLinus Torvalds 12881da177e4SLinus Torvalds res->tsize = ntohl(*p++); 12891da177e4SLinus Torvalds res->bsize = ntohl(*p++); 12901da177e4SLinus Torvalds res->blocks = ntohl(*p++); 12911da177e4SLinus Torvalds res->bfree = ntohl(*p++); 12921da177e4SLinus Torvalds res->bavail = ntohl(*p++); 12931da177e4SLinus Torvalds return 0; 12941da177e4SLinus Torvalds } 12951da177e4SLinus Torvalds 12961da177e4SLinus Torvalds /* 1297f796f8b3SChuck Lever * 2.2.18. statfsres 1298f796f8b3SChuck Lever * 1299f796f8b3SChuck Lever * union statfsres (stat status) { 1300f796f8b3SChuck Lever * case NFS_OK: 1301f796f8b3SChuck Lever * struct { 1302f796f8b3SChuck Lever * unsigned tsize; 1303f796f8b3SChuck Lever * unsigned bsize; 1304f796f8b3SChuck Lever * unsigned blocks; 1305f796f8b3SChuck Lever * unsigned bfree; 1306f796f8b3SChuck Lever * unsigned bavail; 1307f796f8b3SChuck Lever * } info; 1308f796f8b3SChuck Lever * default: 1309f796f8b3SChuck Lever * void; 1310f796f8b3SChuck Lever * }; 1311f796f8b3SChuck Lever */ 1312f796f8b3SChuck Lever static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result) 1313f796f8b3SChuck Lever { 1314f796f8b3SChuck Lever __be32 *p; 1315f796f8b3SChuck Lever 1316f796f8b3SChuck Lever p = xdr_inline_decode(xdr, NFS_info_sz << 2); 1317f796f8b3SChuck Lever if (unlikely(p == NULL)) 1318f796f8b3SChuck Lever goto out_overflow; 1319f796f8b3SChuck Lever result->tsize = be32_to_cpup(p++); 1320f796f8b3SChuck Lever result->bsize = be32_to_cpup(p++); 1321f796f8b3SChuck Lever result->blocks = be32_to_cpup(p++); 1322f796f8b3SChuck Lever result->bfree = be32_to_cpup(p++); 1323f796f8b3SChuck Lever result->bavail = be32_to_cpup(p); 1324f796f8b3SChuck Lever return 0; 1325f796f8b3SChuck Lever out_overflow: 1326f796f8b3SChuck Lever print_overflow_msg(__func__, xdr); 1327f796f8b3SChuck Lever return -EIO; 1328f796f8b3SChuck Lever } 1329f796f8b3SChuck Lever 1330f796f8b3SChuck Lever static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, __be32 *p, 1331f796f8b3SChuck Lever struct nfs2_fsstat *result) 1332f796f8b3SChuck Lever { 1333f796f8b3SChuck Lever struct xdr_stream xdr; 1334f796f8b3SChuck Lever enum nfs_stat status; 1335f796f8b3SChuck Lever int error; 1336f796f8b3SChuck Lever 1337f796f8b3SChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 1338f796f8b3SChuck Lever error = decode_stat(&xdr, &status); 1339f796f8b3SChuck Lever if (unlikely(error)) 1340f796f8b3SChuck Lever goto out; 1341f796f8b3SChuck Lever if (status != NFS_OK) 1342f796f8b3SChuck Lever goto out_default; 1343f796f8b3SChuck Lever error = decode_info(&xdr, result); 1344f796f8b3SChuck Lever out: 1345f796f8b3SChuck Lever return error; 1346f796f8b3SChuck Lever out_default: 1347f796f8b3SChuck Lever return nfs_stat_to_errno(status); 1348f796f8b3SChuck Lever } 1349f796f8b3SChuck Lever 1350f796f8b3SChuck Lever 1351f796f8b3SChuck Lever /* 13521da177e4SLinus Torvalds * We need to translate between nfs status return values and 13531da177e4SLinus Torvalds * the local errno values which may not be the same. 13541da177e4SLinus Torvalds */ 135585828493SChuck Lever static const struct { 13561da177e4SLinus Torvalds int stat; 13571da177e4SLinus Torvalds int errno; 13581da177e4SLinus Torvalds } nfs_errtbl[] = { 13591da177e4SLinus Torvalds { NFS_OK, 0 }, 1360856dff3dSBenny Halevy { NFSERR_PERM, -EPERM }, 1361856dff3dSBenny Halevy { NFSERR_NOENT, -ENOENT }, 1362856dff3dSBenny Halevy { NFSERR_IO, -errno_NFSERR_IO}, 1363856dff3dSBenny Halevy { NFSERR_NXIO, -ENXIO }, 1364856dff3dSBenny Halevy /* { NFSERR_EAGAIN, -EAGAIN }, */ 1365856dff3dSBenny Halevy { NFSERR_ACCES, -EACCES }, 1366856dff3dSBenny Halevy { NFSERR_EXIST, -EEXIST }, 1367856dff3dSBenny Halevy { NFSERR_XDEV, -EXDEV }, 1368856dff3dSBenny Halevy { NFSERR_NODEV, -ENODEV }, 1369856dff3dSBenny Halevy { NFSERR_NOTDIR, -ENOTDIR }, 1370856dff3dSBenny Halevy { NFSERR_ISDIR, -EISDIR }, 1371856dff3dSBenny Halevy { NFSERR_INVAL, -EINVAL }, 1372856dff3dSBenny Halevy { NFSERR_FBIG, -EFBIG }, 1373856dff3dSBenny Halevy { NFSERR_NOSPC, -ENOSPC }, 1374856dff3dSBenny Halevy { NFSERR_ROFS, -EROFS }, 1375856dff3dSBenny Halevy { NFSERR_MLINK, -EMLINK }, 1376856dff3dSBenny Halevy { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, 1377856dff3dSBenny Halevy { NFSERR_NOTEMPTY, -ENOTEMPTY }, 1378856dff3dSBenny Halevy { NFSERR_DQUOT, -EDQUOT }, 1379856dff3dSBenny Halevy { NFSERR_STALE, -ESTALE }, 1380856dff3dSBenny Halevy { NFSERR_REMOTE, -EREMOTE }, 13811da177e4SLinus Torvalds #ifdef EWFLUSH 1382856dff3dSBenny Halevy { NFSERR_WFLUSH, -EWFLUSH }, 13831da177e4SLinus Torvalds #endif 1384856dff3dSBenny Halevy { NFSERR_BADHANDLE, -EBADHANDLE }, 1385856dff3dSBenny Halevy { NFSERR_NOT_SYNC, -ENOTSYNC }, 1386856dff3dSBenny Halevy { NFSERR_BAD_COOKIE, -EBADCOOKIE }, 1387856dff3dSBenny Halevy { NFSERR_NOTSUPP, -ENOTSUPP }, 1388856dff3dSBenny Halevy { NFSERR_TOOSMALL, -ETOOSMALL }, 1389fdcb4577STrond Myklebust { NFSERR_SERVERFAULT, -EREMOTEIO }, 1390856dff3dSBenny Halevy { NFSERR_BADTYPE, -EBADTYPE }, 1391856dff3dSBenny Halevy { NFSERR_JUKEBOX, -EJUKEBOX }, 1392856dff3dSBenny Halevy { -1, -EIO } 13931da177e4SLinus Torvalds }; 13941da177e4SLinus Torvalds 139585828493SChuck Lever /** 139685828493SChuck Lever * nfs_stat_to_errno - convert an NFS status code to a local errno 139785828493SChuck Lever * @status: NFS status code to convert 139885828493SChuck Lever * 139985828493SChuck Lever * Returns a local errno value, or -EIO if the NFS status code is 140085828493SChuck Lever * not recognized. This function is used jointly by NFSv2 and NFSv3. 14011da177e4SLinus Torvalds */ 140285828493SChuck Lever int nfs_stat_to_errno(enum nfs_stat status) 14031da177e4SLinus Torvalds { 14041da177e4SLinus Torvalds int i; 14051da177e4SLinus Torvalds 14061da177e4SLinus Torvalds for (i = 0; nfs_errtbl[i].stat != -1; i++) { 140785828493SChuck Lever if (nfs_errtbl[i].stat == (int)status) 14081da177e4SLinus Torvalds return nfs_errtbl[i].errno; 14091da177e4SLinus Torvalds } 141085828493SChuck Lever dprintk("NFS: Unrecognized nfs status value: %u\n", status); 14111da177e4SLinus Torvalds return nfs_errtbl[i].errno; 14121da177e4SLinus Torvalds } 14131da177e4SLinus Torvalds 14141da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer) \ 14151da177e4SLinus Torvalds [NFSPROC_##proc] = { \ 14161da177e4SLinus Torvalds .p_proc = NFSPROC_##proc, \ 141725a0866cSChuck Lever .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \ 1418f796f8b3SChuck Lever .p_decode = (kxdrproc_t)nfs2_xdr_dec_##restype, \ 14192bea90d4SChuck Lever .p_arglen = NFS_##argtype##_sz, \ 14202bea90d4SChuck Lever .p_replen = NFS_##restype##_sz, \ 1421cc0175c1SChuck Lever .p_timer = timer, \ 1422cc0175c1SChuck Lever .p_statidx = NFSPROC_##proc, \ 1423cc0175c1SChuck Lever .p_name = #proc, \ 14241da177e4SLinus Torvalds } 14251da177e4SLinus Torvalds struct rpc_procinfo nfs_procedures[] = { 14261da177e4SLinus Torvalds PROC(GETATTR, fhandle, attrstat, 1), 14271da177e4SLinus Torvalds PROC(SETATTR, sattrargs, attrstat, 0), 14281da177e4SLinus Torvalds PROC(LOOKUP, diropargs, diropres, 2), 14291da177e4SLinus Torvalds PROC(READLINK, readlinkargs, readlinkres, 3), 14301da177e4SLinus Torvalds PROC(READ, readargs, readres, 3), 14311da177e4SLinus Torvalds PROC(WRITE, writeargs, writeres, 4), 14321da177e4SLinus Torvalds PROC(CREATE, createargs, diropres, 0), 14334fdc17b2STrond Myklebust PROC(REMOVE, removeargs, stat, 0), 14341da177e4SLinus Torvalds PROC(RENAME, renameargs, stat, 0), 14351da177e4SLinus Torvalds PROC(LINK, linkargs, stat, 0), 14361da177e4SLinus Torvalds PROC(SYMLINK, symlinkargs, stat, 0), 14371da177e4SLinus Torvalds PROC(MKDIR, createargs, diropres, 0), 14381da177e4SLinus Torvalds PROC(RMDIR, diropargs, stat, 0), 14391da177e4SLinus Torvalds PROC(READDIR, readdirargs, readdirres, 3), 14401da177e4SLinus Torvalds PROC(STATFS, fhandle, statfsres, 0), 14411da177e4SLinus Torvalds }; 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds struct rpc_version nfs_version2 = { 14441da177e4SLinus Torvalds .number = 2, 1445e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nfs_procedures), 14461da177e4SLinus Torvalds .procs = nfs_procedures 14471da177e4SLinus Torvalds }; 1448