11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Server-side XDR for NFSv4 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2002 The Regents of the University of Michigan. 51da177e4SLinus Torvalds * All rights reserved. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Kendrick Smith <kmsmith@umich.edu> 81da177e4SLinus Torvalds * Andy Adamson <andros@umich.edu> 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or without 111da177e4SLinus Torvalds * modification, are permitted provided that the following conditions 121da177e4SLinus Torvalds * are met: 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * 1. Redistributions of source code must retain the above copyright 151da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer. 161da177e4SLinus Torvalds * 2. Redistributions in binary form must reproduce the above copyright 171da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer in the 181da177e4SLinus Torvalds * documentation and/or other materials provided with the distribution. 191da177e4SLinus Torvalds * 3. Neither the name of the University nor the names of its 201da177e4SLinus Torvalds * contributors may be used to endorse or promote products derived 211da177e4SLinus Torvalds * from this software without specific prior written permission. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 241da177e4SLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 251da177e4SLinus Torvalds * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 261da177e4SLinus Torvalds * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 271da177e4SLinus Torvalds * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 281da177e4SLinus Torvalds * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 291da177e4SLinus Torvalds * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 301da177e4SLinus Torvalds * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 311da177e4SLinus Torvalds * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 321da177e4SLinus Torvalds * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 331da177e4SLinus Torvalds * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 341da177e4SLinus Torvalds * 351da177e4SLinus Torvalds * TODO: Neil Brown made the following observation: We currently 361da177e4SLinus Torvalds * initially reserve NFSD_BUFSIZE space on the transmit queue and 371da177e4SLinus Torvalds * never release any of that until the request is complete. 381da177e4SLinus Torvalds * It would be good to calculate a new maximum response size while 391da177e4SLinus Torvalds * decoding the COMPOUND, and call svc_reserve with this number 401da177e4SLinus Torvalds * at the end of nfs4svc_decode_compoundargs. 411da177e4SLinus Torvalds */ 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds #include <linux/param.h> 441da177e4SLinus Torvalds #include <linux/smp.h> 451da177e4SLinus Torvalds #include <linux/fs.h> 461da177e4SLinus Torvalds #include <linux/namei.h> 471da177e4SLinus Torvalds #include <linux/vfs.h> 480733d213SAndy Adamson #include <linux/utsname.h> 491da177e4SLinus Torvalds #include <linux/sunrpc/xdr.h> 501da177e4SLinus Torvalds #include <linux/sunrpc/svc.h> 511da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 521da177e4SLinus Torvalds #include <linux/nfsd/nfsd.h> 531da177e4SLinus Torvalds #include <linux/nfsd/state.h> 541da177e4SLinus Torvalds #include <linux/nfsd/xdr4.h> 551da177e4SLinus Torvalds #include <linux/nfsd_idmap.h> 561da177e4SLinus Torvalds #include <linux/nfs4.h> 571da177e4SLinus Torvalds #include <linux/nfs4_acl.h> 58dcb488a3SAndy Adamson #include <linux/sunrpc/gss_api.h> 594796f457SJ. Bruce Fields #include <linux/sunrpc/svcauth_gss.h> 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_XDR 621da177e4SLinus Torvalds 6342ca0993SJ.Bruce Fields /* 6442ca0993SJ.Bruce Fields * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing 6542ca0993SJ.Bruce Fields * directory in order to indicate to the client that a filesystem boundary is present 6642ca0993SJ.Bruce Fields * We use a fixed fsid for a referral 6742ca0993SJ.Bruce Fields */ 6842ca0993SJ.Bruce Fields #define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL 6942ca0993SJ.Bruce Fields #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL 7042ca0993SJ.Bruce Fields 71b37ad28bSAl Viro static __be32 72b37ad28bSAl Viro check_filename(char *str, int len, __be32 err) 731da177e4SLinus Torvalds { 741da177e4SLinus Torvalds int i; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds if (len == 0) 771da177e4SLinus Torvalds return nfserr_inval; 781da177e4SLinus Torvalds if (isdotent(str, len)) 791da177e4SLinus Torvalds return err; 801da177e4SLinus Torvalds for (i = 0; i < len; i++) 811da177e4SLinus Torvalds if (str[i] == '/') 821da177e4SLinus Torvalds return err; 831da177e4SLinus Torvalds return 0; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* 871da177e4SLinus Torvalds * START OF "GENERIC" DECODE ROUTINES. 881da177e4SLinus Torvalds * These may look a little ugly since they are imported from a "generic" 891da177e4SLinus Torvalds * set of XDR encode/decode routines which are intended to be shared by 901da177e4SLinus Torvalds * all of our NFSv4 implementations (OpenBSD, MacOS X...). 911da177e4SLinus Torvalds * 921da177e4SLinus Torvalds * If the pain of reading these is too great, it should be a straightforward 931da177e4SLinus Torvalds * task to translate them into Linux-specific versions which are more 941da177e4SLinus Torvalds * consistent with the style used in NFSv2/v3... 951da177e4SLinus Torvalds */ 961da177e4SLinus Torvalds #define DECODE_HEAD \ 972ebbc012SAl Viro __be32 *p; \ 98b37ad28bSAl Viro __be32 status 991da177e4SLinus Torvalds #define DECODE_TAIL \ 1001da177e4SLinus Torvalds status = 0; \ 1011da177e4SLinus Torvalds out: \ 1021da177e4SLinus Torvalds return status; \ 1031da177e4SLinus Torvalds xdr_error: \ 104817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 105817cb9d4SChuck Lever __FILE__, __LINE__); \ 1061da177e4SLinus Torvalds status = nfserr_bad_xdr; \ 1071da177e4SLinus Torvalds goto out 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds #define READ32(x) (x) = ntohl(*p++) 1101da177e4SLinus Torvalds #define READ64(x) do { \ 1111da177e4SLinus Torvalds (x) = (u64)ntohl(*p++) << 32; \ 1121da177e4SLinus Torvalds (x) |= ntohl(*p++); \ 1131da177e4SLinus Torvalds } while (0) 1141da177e4SLinus Torvalds #define READTIME(x) do { \ 1151da177e4SLinus Torvalds p++; \ 1161da177e4SLinus Torvalds (x) = ntohl(*p++); \ 1171da177e4SLinus Torvalds p++; \ 1181da177e4SLinus Torvalds } while (0) 1191da177e4SLinus Torvalds #define READMEM(x,nbytes) do { \ 1201da177e4SLinus Torvalds x = (char *)p; \ 1211da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1221da177e4SLinus Torvalds } while (0) 1231da177e4SLinus Torvalds #define SAVEMEM(x,nbytes) do { \ 1241da177e4SLinus Torvalds if (!(x = (p==argp->tmp || p == argp->tmpp) ? \ 1251da177e4SLinus Torvalds savemem(argp, p, nbytes) : \ 1261da177e4SLinus Torvalds (char *)p)) { \ 127817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 128817cb9d4SChuck Lever __FILE__, __LINE__); \ 1291da177e4SLinus Torvalds goto xdr_error; \ 1301da177e4SLinus Torvalds } \ 1311da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1321da177e4SLinus Torvalds } while (0) 1331da177e4SLinus Torvalds #define COPYMEM(x,nbytes) do { \ 1341da177e4SLinus Torvalds memcpy((x), p, nbytes); \ 1351da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1361da177e4SLinus Torvalds } while (0) 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds /* READ_BUF, read_buf(): nbytes must be <= PAGE_SIZE */ 1391da177e4SLinus Torvalds #define READ_BUF(nbytes) do { \ 1401da177e4SLinus Torvalds if (nbytes <= (u32)((char *)argp->end - (char *)argp->p)) { \ 1411da177e4SLinus Torvalds p = argp->p; \ 1421da177e4SLinus Torvalds argp->p += XDR_QUADLEN(nbytes); \ 1431da177e4SLinus Torvalds } else if (!(p = read_buf(argp, nbytes))) { \ 144817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 145817cb9d4SChuck Lever __FILE__, __LINE__); \ 1461da177e4SLinus Torvalds goto xdr_error; \ 1471da177e4SLinus Torvalds } \ 1481da177e4SLinus Torvalds } while (0) 1491da177e4SLinus Torvalds 150ca2a05aaSJ. Bruce Fields static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) 1511da177e4SLinus Torvalds { 1521da177e4SLinus Torvalds /* We want more bytes than seem to be available. 1531da177e4SLinus Torvalds * Maybe we need a new page, maybe we have just run out 1541da177e4SLinus Torvalds */ 155ca2a05aaSJ. Bruce Fields unsigned int avail = (char *)argp->end - (char *)argp->p; 1562ebbc012SAl Viro __be32 *p; 1571da177e4SLinus Torvalds if (avail + argp->pagelen < nbytes) 1581da177e4SLinus Torvalds return NULL; 1591da177e4SLinus Torvalds if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */ 1601da177e4SLinus Torvalds return NULL; 1611da177e4SLinus Torvalds /* ok, we can do it with the current plus the next page */ 1621da177e4SLinus Torvalds if (nbytes <= sizeof(argp->tmp)) 1631da177e4SLinus Torvalds p = argp->tmp; 1641da177e4SLinus Torvalds else { 1651da177e4SLinus Torvalds kfree(argp->tmpp); 1661da177e4SLinus Torvalds p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL); 1671da177e4SLinus Torvalds if (!p) 1681da177e4SLinus Torvalds return NULL; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds } 171ca2a05aaSJ. Bruce Fields /* 172ca2a05aaSJ. Bruce Fields * The following memcpy is safe because read_buf is always 173ca2a05aaSJ. Bruce Fields * called with nbytes > avail, and the two cases above both 174ca2a05aaSJ. Bruce Fields * guarantee p points to at least nbytes bytes. 175ca2a05aaSJ. Bruce Fields */ 1761da177e4SLinus Torvalds memcpy(p, argp->p, avail); 1771da177e4SLinus Torvalds /* step to next page */ 1781da177e4SLinus Torvalds argp->p = page_address(argp->pagelist[0]); 1791da177e4SLinus Torvalds argp->pagelist++; 1801da177e4SLinus Torvalds if (argp->pagelen < PAGE_SIZE) { 1811da177e4SLinus Torvalds argp->end = p + (argp->pagelen>>2); 1821da177e4SLinus Torvalds argp->pagelen = 0; 1831da177e4SLinus Torvalds } else { 1841da177e4SLinus Torvalds argp->end = p + (PAGE_SIZE>>2); 1851da177e4SLinus Torvalds argp->pagelen -= PAGE_SIZE; 1861da177e4SLinus Torvalds } 1871da177e4SLinus Torvalds memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); 1881da177e4SLinus Torvalds argp->p += XDR_QUADLEN(nbytes - avail); 1891da177e4SLinus Torvalds return p; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 19260adfc50SAndy Adamson static int zero_clientid(clientid_t *clid) 19360adfc50SAndy Adamson { 19460adfc50SAndy Adamson return (clid->cl_boot == 0) && (clid->cl_id == 0); 19560adfc50SAndy Adamson } 19660adfc50SAndy Adamson 1971da177e4SLinus Torvalds static int 1981da177e4SLinus Torvalds defer_free(struct nfsd4_compoundargs *argp, 1991da177e4SLinus Torvalds void (*release)(const void *), void *p) 2001da177e4SLinus Torvalds { 2011da177e4SLinus Torvalds struct tmpbuf *tb; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds tb = kmalloc(sizeof(*tb), GFP_KERNEL); 2041da177e4SLinus Torvalds if (!tb) 2051da177e4SLinus Torvalds return -ENOMEM; 2061da177e4SLinus Torvalds tb->buf = p; 2071da177e4SLinus Torvalds tb->release = release; 2081da177e4SLinus Torvalds tb->next = argp->to_free; 2091da177e4SLinus Torvalds argp->to_free = tb; 2101da177e4SLinus Torvalds return 0; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 2132ebbc012SAl Viro static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) 2141da177e4SLinus Torvalds { 2151da177e4SLinus Torvalds if (p == argp->tmp) { 216a4db5fe5SJ. Bruce Fields p = kmalloc(nbytes, GFP_KERNEL); 217a4db5fe5SJ. Bruce Fields if (!p) 218a4db5fe5SJ. Bruce Fields return NULL; 2191da177e4SLinus Torvalds memcpy(p, argp->tmp, nbytes); 2201da177e4SLinus Torvalds } else { 22173dff8beSEric Sesterhenn BUG_ON(p != argp->tmpp); 2221da177e4SLinus Torvalds argp->tmpp = NULL; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds if (defer_free(argp, kfree, p)) { 225a4db5fe5SJ. Bruce Fields kfree(p); 2261da177e4SLinus Torvalds return NULL; 2271da177e4SLinus Torvalds } else 2281da177e4SLinus Torvalds return (char *)p; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 231b37ad28bSAl Viro static __be32 2321da177e4SLinus Torvalds nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) 2331da177e4SLinus Torvalds { 2341da177e4SLinus Torvalds u32 bmlen; 2351da177e4SLinus Torvalds DECODE_HEAD; 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds bmval[0] = 0; 2381da177e4SLinus Torvalds bmval[1] = 0; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds READ_BUF(4); 2411da177e4SLinus Torvalds READ32(bmlen); 2421da177e4SLinus Torvalds if (bmlen > 1000) 2431da177e4SLinus Torvalds goto xdr_error; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds READ_BUF(bmlen << 2); 2461da177e4SLinus Torvalds if (bmlen > 0) 2471da177e4SLinus Torvalds READ32(bmval[0]); 2481da177e4SLinus Torvalds if (bmlen > 1) 2491da177e4SLinus Torvalds READ32(bmval[1]); 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds DECODE_TAIL; 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 254*c0d6fc8aSBenny Halevy static u32 nfsd_attrmask[] = { 255*c0d6fc8aSBenny Halevy NFSD_WRITEABLE_ATTRS_WORD0, 256*c0d6fc8aSBenny Halevy NFSD_WRITEABLE_ATTRS_WORD1 257*c0d6fc8aSBenny Halevy }; 258*c0d6fc8aSBenny Halevy 259b37ad28bSAl Viro static __be32 260*c0d6fc8aSBenny Halevy nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, 261*c0d6fc8aSBenny Halevy struct iattr *iattr, struct nfs4_acl **acl) 2621da177e4SLinus Torvalds { 2631da177e4SLinus Torvalds int expected_len, len = 0; 2641da177e4SLinus Torvalds u32 dummy32; 2651da177e4SLinus Torvalds char *buf; 266b8dd7b9aSAl Viro int host_err; 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds DECODE_HEAD; 2691da177e4SLinus Torvalds iattr->ia_valid = 0; 2701da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, bmval))) 2711da177e4SLinus Torvalds return status; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds /* 274f34f9242SJ. Bruce Fields * According to spec, unsupported attributes return ERR_ATTRNOTSUPP; 2751da177e4SLinus Torvalds * read-only attributes return ERR_INVAL. 2761da177e4SLinus Torvalds */ 2771da177e4SLinus Torvalds if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) || (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1)) 2781da177e4SLinus Torvalds return nfserr_attrnotsupp; 279*c0d6fc8aSBenny Halevy if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1])) 2801da177e4SLinus Torvalds return nfserr_inval; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds READ_BUF(4); 2831da177e4SLinus Torvalds READ32(expected_len); 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds if (bmval[0] & FATTR4_WORD0_SIZE) { 2861da177e4SLinus Torvalds READ_BUF(8); 2871da177e4SLinus Torvalds len += 8; 2881da177e4SLinus Torvalds READ64(iattr->ia_size); 2891da177e4SLinus Torvalds iattr->ia_valid |= ATTR_SIZE; 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds if (bmval[0] & FATTR4_WORD0_ACL) { 29228e05dd8SJ. Bruce Fields int nace; 29328e05dd8SJ. Bruce Fields struct nfs4_ace *ace; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds READ_BUF(4); len += 4; 2961da177e4SLinus Torvalds READ32(nace); 2971da177e4SLinus Torvalds 29828e05dd8SJ. Bruce Fields if (nace > NFS4_ACL_MAX) 29928e05dd8SJ. Bruce Fields return nfserr_resource; 30028e05dd8SJ. Bruce Fields 30128e05dd8SJ. Bruce Fields *acl = nfs4_acl_new(nace); 3021da177e4SLinus Torvalds if (*acl == NULL) { 303b8dd7b9aSAl Viro host_err = -ENOMEM; 3041da177e4SLinus Torvalds goto out_nfserr; 3051da177e4SLinus Torvalds } 30628e05dd8SJ. Bruce Fields defer_free(argp, kfree, *acl); 3071da177e4SLinus Torvalds 30828e05dd8SJ. Bruce Fields (*acl)->naces = nace; 30928e05dd8SJ. Bruce Fields for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { 3101da177e4SLinus Torvalds READ_BUF(16); len += 16; 31128e05dd8SJ. Bruce Fields READ32(ace->type); 31228e05dd8SJ. Bruce Fields READ32(ace->flag); 31328e05dd8SJ. Bruce Fields READ32(ace->access_mask); 3141da177e4SLinus Torvalds READ32(dummy32); 3151da177e4SLinus Torvalds READ_BUF(dummy32); 3161da177e4SLinus Torvalds len += XDR_QUADLEN(dummy32) << 2; 3171da177e4SLinus Torvalds READMEM(buf, dummy32); 31828e05dd8SJ. Bruce Fields ace->whotype = nfs4_acl_get_whotype(buf, dummy32); 319b8dd7b9aSAl Viro host_err = 0; 32028e05dd8SJ. Bruce Fields if (ace->whotype != NFS4_ACL_WHO_NAMED) 32128e05dd8SJ. Bruce Fields ace->who = 0; 32228e05dd8SJ. Bruce Fields else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) 323b8dd7b9aSAl Viro host_err = nfsd_map_name_to_gid(argp->rqstp, 32428e05dd8SJ. Bruce Fields buf, dummy32, &ace->who); 3251da177e4SLinus Torvalds else 326b8dd7b9aSAl Viro host_err = nfsd_map_name_to_uid(argp->rqstp, 32728e05dd8SJ. Bruce Fields buf, dummy32, &ace->who); 328b8dd7b9aSAl Viro if (host_err) 3291da177e4SLinus Torvalds goto out_nfserr; 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds } else 3321da177e4SLinus Torvalds *acl = NULL; 3331da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_MODE) { 3341da177e4SLinus Torvalds READ_BUF(4); 3351da177e4SLinus Torvalds len += 4; 3361da177e4SLinus Torvalds READ32(iattr->ia_mode); 3371da177e4SLinus Torvalds iattr->ia_mode &= (S_IFMT | S_IALLUGO); 3381da177e4SLinus Torvalds iattr->ia_valid |= ATTR_MODE; 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_OWNER) { 3411da177e4SLinus Torvalds READ_BUF(4); 3421da177e4SLinus Torvalds len += 4; 3431da177e4SLinus Torvalds READ32(dummy32); 3441da177e4SLinus Torvalds READ_BUF(dummy32); 3451da177e4SLinus Torvalds len += (XDR_QUADLEN(dummy32) << 2); 3461da177e4SLinus Torvalds READMEM(buf, dummy32); 347b8dd7b9aSAl Viro if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) 3481da177e4SLinus Torvalds goto out_nfserr; 3491da177e4SLinus Torvalds iattr->ia_valid |= ATTR_UID; 3501da177e4SLinus Torvalds } 3511da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) { 3521da177e4SLinus Torvalds READ_BUF(4); 3531da177e4SLinus Torvalds len += 4; 3541da177e4SLinus Torvalds READ32(dummy32); 3551da177e4SLinus Torvalds READ_BUF(dummy32); 3561da177e4SLinus Torvalds len += (XDR_QUADLEN(dummy32) << 2); 3571da177e4SLinus Torvalds READMEM(buf, dummy32); 358b8dd7b9aSAl Viro if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) 3591da177e4SLinus Torvalds goto out_nfserr; 3601da177e4SLinus Torvalds iattr->ia_valid |= ATTR_GID; 3611da177e4SLinus Torvalds } 3621da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) { 3631da177e4SLinus Torvalds READ_BUF(4); 3641da177e4SLinus Torvalds len += 4; 3651da177e4SLinus Torvalds READ32(dummy32); 3661da177e4SLinus Torvalds switch (dummy32) { 3671da177e4SLinus Torvalds case NFS4_SET_TO_CLIENT_TIME: 3681da177e4SLinus Torvalds /* We require the high 32 bits of 'seconds' to be 0, and we ignore 3691da177e4SLinus Torvalds all 32 bits of 'nseconds'. */ 3701da177e4SLinus Torvalds READ_BUF(12); 3711da177e4SLinus Torvalds len += 12; 3721da177e4SLinus Torvalds READ32(dummy32); 3731da177e4SLinus Torvalds if (dummy32) 3741da177e4SLinus Torvalds return nfserr_inval; 3751da177e4SLinus Torvalds READ32(iattr->ia_atime.tv_sec); 3761da177e4SLinus Torvalds READ32(iattr->ia_atime.tv_nsec); 3771da177e4SLinus Torvalds if (iattr->ia_atime.tv_nsec >= (u32)1000000000) 3781da177e4SLinus Torvalds return nfserr_inval; 3791da177e4SLinus Torvalds iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); 3801da177e4SLinus Torvalds break; 3811da177e4SLinus Torvalds case NFS4_SET_TO_SERVER_TIME: 3821da177e4SLinus Torvalds iattr->ia_valid |= ATTR_ATIME; 3831da177e4SLinus Torvalds break; 3841da177e4SLinus Torvalds default: 3851da177e4SLinus Torvalds goto xdr_error; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { 3891da177e4SLinus Torvalds READ_BUF(4); 3901da177e4SLinus Torvalds len += 4; 3911da177e4SLinus Torvalds READ32(dummy32); 3921da177e4SLinus Torvalds switch (dummy32) { 3931da177e4SLinus Torvalds case NFS4_SET_TO_CLIENT_TIME: 3941da177e4SLinus Torvalds /* We require the high 32 bits of 'seconds' to be 0, and we ignore 3951da177e4SLinus Torvalds all 32 bits of 'nseconds'. */ 3961da177e4SLinus Torvalds READ_BUF(12); 3971da177e4SLinus Torvalds len += 12; 3981da177e4SLinus Torvalds READ32(dummy32); 3991da177e4SLinus Torvalds if (dummy32) 4001da177e4SLinus Torvalds return nfserr_inval; 4011da177e4SLinus Torvalds READ32(iattr->ia_mtime.tv_sec); 4021da177e4SLinus Torvalds READ32(iattr->ia_mtime.tv_nsec); 4031da177e4SLinus Torvalds if (iattr->ia_mtime.tv_nsec >= (u32)1000000000) 4041da177e4SLinus Torvalds return nfserr_inval; 4051da177e4SLinus Torvalds iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); 4061da177e4SLinus Torvalds break; 4071da177e4SLinus Torvalds case NFS4_SET_TO_SERVER_TIME: 4081da177e4SLinus Torvalds iattr->ia_valid |= ATTR_MTIME; 4091da177e4SLinus Torvalds break; 4101da177e4SLinus Torvalds default: 4111da177e4SLinus Torvalds goto xdr_error; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds if (len != expected_len) 4151da177e4SLinus Torvalds goto xdr_error; 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds DECODE_TAIL; 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds out_nfserr: 420b8dd7b9aSAl Viro status = nfserrno(host_err); 4211da177e4SLinus Torvalds goto out; 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds 424b37ad28bSAl Viro static __be32 425e31a1b66SBenny Halevy nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid) 426e31a1b66SBenny Halevy { 427e31a1b66SBenny Halevy DECODE_HEAD; 428e31a1b66SBenny Halevy 429e31a1b66SBenny Halevy READ_BUF(sizeof(stateid_t)); 430e31a1b66SBenny Halevy READ32(sid->si_generation); 431e31a1b66SBenny Halevy COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); 432e31a1b66SBenny Halevy 433e31a1b66SBenny Halevy DECODE_TAIL; 434e31a1b66SBenny Halevy } 435e31a1b66SBenny Halevy 436e31a1b66SBenny Halevy static __be32 4371da177e4SLinus Torvalds nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access) 4381da177e4SLinus Torvalds { 4391da177e4SLinus Torvalds DECODE_HEAD; 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds READ_BUF(4); 4421da177e4SLinus Torvalds READ32(access->ac_req_access); 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds DECODE_TAIL; 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds 447b37ad28bSAl Viro static __be32 4481da177e4SLinus Torvalds nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) 4491da177e4SLinus Torvalds { 4501da177e4SLinus Torvalds DECODE_HEAD; 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds close->cl_stateowner = NULL; 453e31a1b66SBenny Halevy READ_BUF(4); 4541da177e4SLinus Torvalds READ32(close->cl_seqid); 455e31a1b66SBenny Halevy return nfsd4_decode_stateid(argp, &close->cl_stateid); 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds DECODE_TAIL; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds 461b37ad28bSAl Viro static __be32 4621da177e4SLinus Torvalds nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit) 4631da177e4SLinus Torvalds { 4641da177e4SLinus Torvalds DECODE_HEAD; 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds READ_BUF(12); 4671da177e4SLinus Torvalds READ64(commit->co_offset); 4681da177e4SLinus Torvalds READ32(commit->co_count); 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds DECODE_TAIL; 4711da177e4SLinus Torvalds } 4721da177e4SLinus Torvalds 473b37ad28bSAl Viro static __be32 4741da177e4SLinus Torvalds nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create) 4751da177e4SLinus Torvalds { 4761da177e4SLinus Torvalds DECODE_HEAD; 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds READ_BUF(4); 4791da177e4SLinus Torvalds READ32(create->cr_type); 4801da177e4SLinus Torvalds switch (create->cr_type) { 4811da177e4SLinus Torvalds case NF4LNK: 4821da177e4SLinus Torvalds READ_BUF(4); 4831da177e4SLinus Torvalds READ32(create->cr_linklen); 4841da177e4SLinus Torvalds READ_BUF(create->cr_linklen); 4851da177e4SLinus Torvalds SAVEMEM(create->cr_linkname, create->cr_linklen); 4861da177e4SLinus Torvalds break; 4871da177e4SLinus Torvalds case NF4BLK: 4881da177e4SLinus Torvalds case NF4CHR: 4891da177e4SLinus Torvalds READ_BUF(8); 4901da177e4SLinus Torvalds READ32(create->cr_specdata1); 4911da177e4SLinus Torvalds READ32(create->cr_specdata2); 4921da177e4SLinus Torvalds break; 4931da177e4SLinus Torvalds case NF4SOCK: 4941da177e4SLinus Torvalds case NF4FIFO: 4951da177e4SLinus Torvalds case NF4DIR: 4961da177e4SLinus Torvalds default: 4971da177e4SLinus Torvalds break; 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds READ_BUF(4); 5011da177e4SLinus Torvalds READ32(create->cr_namelen); 5021da177e4SLinus Torvalds READ_BUF(create->cr_namelen); 5031da177e4SLinus Torvalds SAVEMEM(create->cr_name, create->cr_namelen); 5041da177e4SLinus Torvalds if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) 5051da177e4SLinus Torvalds return status; 5061da177e4SLinus Torvalds 507*c0d6fc8aSBenny Halevy status = nfsd4_decode_fattr(argp, create->cr_bmval, nfsd_attrmask, 508*c0d6fc8aSBenny Halevy &create->cr_iattr, &create->cr_acl); 509*c0d6fc8aSBenny Halevy if (status) 5101da177e4SLinus Torvalds goto out; 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds DECODE_TAIL; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 515b37ad28bSAl Viro static inline __be32 5161da177e4SLinus Torvalds nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr) 5171da177e4SLinus Torvalds { 518e31a1b66SBenny Halevy return nfsd4_decode_stateid(argp, &dr->dr_stateid); 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 521b37ad28bSAl Viro static inline __be32 5221da177e4SLinus Torvalds nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) 5231da177e4SLinus Torvalds { 5241da177e4SLinus Torvalds return nfsd4_decode_bitmap(argp, getattr->ga_bmval); 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds 527b37ad28bSAl Viro static __be32 5281da177e4SLinus Torvalds nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) 5291da177e4SLinus Torvalds { 5301da177e4SLinus Torvalds DECODE_HEAD; 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds READ_BUF(4); 5331da177e4SLinus Torvalds READ32(link->li_namelen); 5341da177e4SLinus Torvalds READ_BUF(link->li_namelen); 5351da177e4SLinus Torvalds SAVEMEM(link->li_name, link->li_namelen); 5361da177e4SLinus Torvalds if ((status = check_filename(link->li_name, link->li_namelen, nfserr_inval))) 5371da177e4SLinus Torvalds return status; 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds DECODE_TAIL; 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds 542b37ad28bSAl Viro static __be32 5431da177e4SLinus Torvalds nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) 5441da177e4SLinus Torvalds { 5451da177e4SLinus Torvalds DECODE_HEAD; 5461da177e4SLinus Torvalds 5473a65588aSJ. Bruce Fields lock->lk_replay_owner = NULL; 5481da177e4SLinus Torvalds /* 5491da177e4SLinus Torvalds * type, reclaim(boolean), offset, length, new_lock_owner(boolean) 5501da177e4SLinus Torvalds */ 5511da177e4SLinus Torvalds READ_BUF(28); 5521da177e4SLinus Torvalds READ32(lock->lk_type); 5531da177e4SLinus Torvalds if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT)) 5541da177e4SLinus Torvalds goto xdr_error; 5551da177e4SLinus Torvalds READ32(lock->lk_reclaim); 5561da177e4SLinus Torvalds READ64(lock->lk_offset); 5571da177e4SLinus Torvalds READ64(lock->lk_length); 5581da177e4SLinus Torvalds READ32(lock->lk_is_new); 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds if (lock->lk_is_new) { 561e31a1b66SBenny Halevy READ_BUF(4); 5621da177e4SLinus Torvalds READ32(lock->lk_new_open_seqid); 563e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid); 564e31a1b66SBenny Halevy if (status) 565e31a1b66SBenny Halevy return status; 566e31a1b66SBenny Halevy READ_BUF(8 + sizeof(clientid_t)); 5671da177e4SLinus Torvalds READ32(lock->lk_new_lock_seqid); 5681da177e4SLinus Torvalds COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t)); 5691da177e4SLinus Torvalds READ32(lock->lk_new_owner.len); 5701da177e4SLinus Torvalds READ_BUF(lock->lk_new_owner.len); 5711da177e4SLinus Torvalds READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len); 5721da177e4SLinus Torvalds } else { 573e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid); 574e31a1b66SBenny Halevy if (status) 575e31a1b66SBenny Halevy return status; 576e31a1b66SBenny Halevy READ_BUF(4); 5771da177e4SLinus Torvalds READ32(lock->lk_old_lock_seqid); 5781da177e4SLinus Torvalds } 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds DECODE_TAIL; 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds 583b37ad28bSAl Viro static __be32 5841da177e4SLinus Torvalds nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) 5851da177e4SLinus Torvalds { 5861da177e4SLinus Torvalds DECODE_HEAD; 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds READ_BUF(32); 5891da177e4SLinus Torvalds READ32(lockt->lt_type); 5901da177e4SLinus Torvalds if((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT)) 5911da177e4SLinus Torvalds goto xdr_error; 5921da177e4SLinus Torvalds READ64(lockt->lt_offset); 5931da177e4SLinus Torvalds READ64(lockt->lt_length); 5941da177e4SLinus Torvalds COPYMEM(&lockt->lt_clientid, 8); 5951da177e4SLinus Torvalds READ32(lockt->lt_owner.len); 5961da177e4SLinus Torvalds READ_BUF(lockt->lt_owner.len); 5971da177e4SLinus Torvalds READMEM(lockt->lt_owner.data, lockt->lt_owner.len); 5981da177e4SLinus Torvalds 59960adfc50SAndy Adamson if (argp->minorversion && !zero_clientid(&lockt->lt_clientid)) 60060adfc50SAndy Adamson return nfserr_inval; 6011da177e4SLinus Torvalds DECODE_TAIL; 6021da177e4SLinus Torvalds } 6031da177e4SLinus Torvalds 604b37ad28bSAl Viro static __be32 6051da177e4SLinus Torvalds nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) 6061da177e4SLinus Torvalds { 6071da177e4SLinus Torvalds DECODE_HEAD; 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds locku->lu_stateowner = NULL; 610e31a1b66SBenny Halevy READ_BUF(8); 6111da177e4SLinus Torvalds READ32(locku->lu_type); 6121da177e4SLinus Torvalds if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT)) 6131da177e4SLinus Torvalds goto xdr_error; 6141da177e4SLinus Torvalds READ32(locku->lu_seqid); 615e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &locku->lu_stateid); 616e31a1b66SBenny Halevy if (status) 617e31a1b66SBenny Halevy return status; 618e31a1b66SBenny Halevy READ_BUF(16); 6191da177e4SLinus Torvalds READ64(locku->lu_offset); 6201da177e4SLinus Torvalds READ64(locku->lu_length); 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds DECODE_TAIL; 6231da177e4SLinus Torvalds } 6241da177e4SLinus Torvalds 625b37ad28bSAl Viro static __be32 6261da177e4SLinus Torvalds nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) 6271da177e4SLinus Torvalds { 6281da177e4SLinus Torvalds DECODE_HEAD; 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds READ_BUF(4); 6311da177e4SLinus Torvalds READ32(lookup->lo_len); 6321da177e4SLinus Torvalds READ_BUF(lookup->lo_len); 6331da177e4SLinus Torvalds SAVEMEM(lookup->lo_name, lookup->lo_len); 6341da177e4SLinus Torvalds if ((status = check_filename(lookup->lo_name, lookup->lo_len, nfserr_noent))) 6351da177e4SLinus Torvalds return status; 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds DECODE_TAIL; 6381da177e4SLinus Torvalds } 6391da177e4SLinus Torvalds 640b37ad28bSAl Viro static __be32 6411da177e4SLinus Torvalds nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) 6421da177e4SLinus Torvalds { 6431da177e4SLinus Torvalds DECODE_HEAD; 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds memset(open->op_bmval, 0, sizeof(open->op_bmval)); 6461da177e4SLinus Torvalds open->op_iattr.ia_valid = 0; 6471da177e4SLinus Torvalds open->op_stateowner = NULL; 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds /* seqid, share_access, share_deny, clientid, ownerlen */ 6501da177e4SLinus Torvalds READ_BUF(16 + sizeof(clientid_t)); 6511da177e4SLinus Torvalds READ32(open->op_seqid); 6521da177e4SLinus Torvalds READ32(open->op_share_access); 6531da177e4SLinus Torvalds READ32(open->op_share_deny); 6541da177e4SLinus Torvalds COPYMEM(&open->op_clientid, sizeof(clientid_t)); 6551da177e4SLinus Torvalds READ32(open->op_owner.len); 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds /* owner, open_flag */ 6581da177e4SLinus Torvalds READ_BUF(open->op_owner.len + 4); 6591da177e4SLinus Torvalds SAVEMEM(open->op_owner.data, open->op_owner.len); 6601da177e4SLinus Torvalds READ32(open->op_create); 6611da177e4SLinus Torvalds switch (open->op_create) { 6621da177e4SLinus Torvalds case NFS4_OPEN_NOCREATE: 6631da177e4SLinus Torvalds break; 6641da177e4SLinus Torvalds case NFS4_OPEN_CREATE: 6651da177e4SLinus Torvalds READ_BUF(4); 6661da177e4SLinus Torvalds READ32(open->op_createmode); 6671da177e4SLinus Torvalds switch (open->op_createmode) { 6681da177e4SLinus Torvalds case NFS4_CREATE_UNCHECKED: 6691da177e4SLinus Torvalds case NFS4_CREATE_GUARDED: 670*c0d6fc8aSBenny Halevy status = nfsd4_decode_fattr(argp, open->op_bmval, 671*c0d6fc8aSBenny Halevy nfsd_attrmask, &open->op_iattr, &open->op_acl); 672*c0d6fc8aSBenny Halevy if (status) 6731da177e4SLinus Torvalds goto out; 6741da177e4SLinus Torvalds break; 6751da177e4SLinus Torvalds case NFS4_CREATE_EXCLUSIVE: 6761da177e4SLinus Torvalds READ_BUF(8); 6771da177e4SLinus Torvalds COPYMEM(open->op_verf.data, 8); 6781da177e4SLinus Torvalds break; 6791da177e4SLinus Torvalds default: 6801da177e4SLinus Torvalds goto xdr_error; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds break; 6831da177e4SLinus Torvalds default: 6841da177e4SLinus Torvalds goto xdr_error; 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds /* open_claim */ 6881da177e4SLinus Torvalds READ_BUF(4); 6891da177e4SLinus Torvalds READ32(open->op_claim_type); 6901da177e4SLinus Torvalds switch (open->op_claim_type) { 6911da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_NULL: 6921da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_PREV: 6931da177e4SLinus Torvalds READ_BUF(4); 6941da177e4SLinus Torvalds READ32(open->op_fname.len); 6951da177e4SLinus Torvalds READ_BUF(open->op_fname.len); 6961da177e4SLinus Torvalds SAVEMEM(open->op_fname.data, open->op_fname.len); 6971da177e4SLinus Torvalds if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) 6981da177e4SLinus Torvalds return status; 6991da177e4SLinus Torvalds break; 7001da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_PREVIOUS: 7011da177e4SLinus Torvalds READ_BUF(4); 7021da177e4SLinus Torvalds READ32(open->op_delegate_type); 7031da177e4SLinus Torvalds break; 7041da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_CUR: 705e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); 706e31a1b66SBenny Halevy if (status) 707e31a1b66SBenny Halevy return status; 708e31a1b66SBenny Halevy READ_BUF(4); 7091da177e4SLinus Torvalds READ32(open->op_fname.len); 7101da177e4SLinus Torvalds READ_BUF(open->op_fname.len); 7111da177e4SLinus Torvalds SAVEMEM(open->op_fname.data, open->op_fname.len); 7121da177e4SLinus Torvalds if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) 7131da177e4SLinus Torvalds return status; 7141da177e4SLinus Torvalds break; 7151da177e4SLinus Torvalds default: 7161da177e4SLinus Torvalds goto xdr_error; 7171da177e4SLinus Torvalds } 7181da177e4SLinus Torvalds 7191da177e4SLinus Torvalds DECODE_TAIL; 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds 722b37ad28bSAl Viro static __be32 7231da177e4SLinus Torvalds nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) 7241da177e4SLinus Torvalds { 7251da177e4SLinus Torvalds DECODE_HEAD; 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds open_conf->oc_stateowner = NULL; 728e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); 729e31a1b66SBenny Halevy if (status) 730e31a1b66SBenny Halevy return status; 731e31a1b66SBenny Halevy READ_BUF(4); 7321da177e4SLinus Torvalds READ32(open_conf->oc_seqid); 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds DECODE_TAIL; 7351da177e4SLinus Torvalds } 7361da177e4SLinus Torvalds 737b37ad28bSAl Viro static __be32 7381da177e4SLinus Torvalds nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down) 7391da177e4SLinus Torvalds { 7401da177e4SLinus Torvalds DECODE_HEAD; 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds open_down->od_stateowner = NULL; 743e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open_down->od_stateid); 744e31a1b66SBenny Halevy if (status) 745e31a1b66SBenny Halevy return status; 746e31a1b66SBenny Halevy READ_BUF(12); 7471da177e4SLinus Torvalds READ32(open_down->od_seqid); 7481da177e4SLinus Torvalds READ32(open_down->od_share_access); 7491da177e4SLinus Torvalds READ32(open_down->od_share_deny); 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds DECODE_TAIL; 7521da177e4SLinus Torvalds } 7531da177e4SLinus Torvalds 754b37ad28bSAl Viro static __be32 7551da177e4SLinus Torvalds nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) 7561da177e4SLinus Torvalds { 7571da177e4SLinus Torvalds DECODE_HEAD; 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds READ_BUF(4); 7601da177e4SLinus Torvalds READ32(putfh->pf_fhlen); 7611da177e4SLinus Torvalds if (putfh->pf_fhlen > NFS4_FHSIZE) 7621da177e4SLinus Torvalds goto xdr_error; 7631da177e4SLinus Torvalds READ_BUF(putfh->pf_fhlen); 7641da177e4SLinus Torvalds SAVEMEM(putfh->pf_fhval, putfh->pf_fhlen); 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds DECODE_TAIL; 7671da177e4SLinus Torvalds } 7681da177e4SLinus Torvalds 769b37ad28bSAl Viro static __be32 7701da177e4SLinus Torvalds nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) 7711da177e4SLinus Torvalds { 7721da177e4SLinus Torvalds DECODE_HEAD; 7731da177e4SLinus Torvalds 774e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &read->rd_stateid); 775e31a1b66SBenny Halevy if (status) 776e31a1b66SBenny Halevy return status; 777e31a1b66SBenny Halevy READ_BUF(12); 7781da177e4SLinus Torvalds READ64(read->rd_offset); 7791da177e4SLinus Torvalds READ32(read->rd_length); 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds DECODE_TAIL; 7821da177e4SLinus Torvalds } 7831da177e4SLinus Torvalds 784b37ad28bSAl Viro static __be32 7851da177e4SLinus Torvalds nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir) 7861da177e4SLinus Torvalds { 7871da177e4SLinus Torvalds DECODE_HEAD; 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds READ_BUF(24); 7901da177e4SLinus Torvalds READ64(readdir->rd_cookie); 7911da177e4SLinus Torvalds COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data)); 7921da177e4SLinus Torvalds READ32(readdir->rd_dircount); /* just in case you needed a useless field... */ 7931da177e4SLinus Torvalds READ32(readdir->rd_maxcount); 7941da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval))) 7951da177e4SLinus Torvalds goto out; 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds DECODE_TAIL; 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds 800b37ad28bSAl Viro static __be32 8011da177e4SLinus Torvalds nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove) 8021da177e4SLinus Torvalds { 8031da177e4SLinus Torvalds DECODE_HEAD; 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds READ_BUF(4); 8061da177e4SLinus Torvalds READ32(remove->rm_namelen); 8071da177e4SLinus Torvalds READ_BUF(remove->rm_namelen); 8081da177e4SLinus Torvalds SAVEMEM(remove->rm_name, remove->rm_namelen); 8091da177e4SLinus Torvalds if ((status = check_filename(remove->rm_name, remove->rm_namelen, nfserr_noent))) 8101da177e4SLinus Torvalds return status; 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds DECODE_TAIL; 8131da177e4SLinus Torvalds } 8141da177e4SLinus Torvalds 815b37ad28bSAl Viro static __be32 8161da177e4SLinus Torvalds nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename) 8171da177e4SLinus Torvalds { 8181da177e4SLinus Torvalds DECODE_HEAD; 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds READ_BUF(4); 8211da177e4SLinus Torvalds READ32(rename->rn_snamelen); 8221da177e4SLinus Torvalds READ_BUF(rename->rn_snamelen + 4); 8231da177e4SLinus Torvalds SAVEMEM(rename->rn_sname, rename->rn_snamelen); 8241da177e4SLinus Torvalds READ32(rename->rn_tnamelen); 8251da177e4SLinus Torvalds READ_BUF(rename->rn_tnamelen); 8261da177e4SLinus Torvalds SAVEMEM(rename->rn_tname, rename->rn_tnamelen); 8271da177e4SLinus Torvalds if ((status = check_filename(rename->rn_sname, rename->rn_snamelen, nfserr_noent))) 8281da177e4SLinus Torvalds return status; 8291da177e4SLinus Torvalds if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen, nfserr_inval))) 8301da177e4SLinus Torvalds return status; 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds DECODE_TAIL; 8331da177e4SLinus Torvalds } 8341da177e4SLinus Torvalds 835b37ad28bSAl Viro static __be32 8361da177e4SLinus Torvalds nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) 8371da177e4SLinus Torvalds { 8381da177e4SLinus Torvalds DECODE_HEAD; 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds READ_BUF(sizeof(clientid_t)); 8411da177e4SLinus Torvalds COPYMEM(clientid, sizeof(clientid_t)); 8421da177e4SLinus Torvalds 8431da177e4SLinus Torvalds DECODE_TAIL; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds 846b37ad28bSAl Viro static __be32 847dcb488a3SAndy Adamson nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, 848dcb488a3SAndy Adamson struct nfsd4_secinfo *secinfo) 849dcb488a3SAndy Adamson { 850dcb488a3SAndy Adamson DECODE_HEAD; 851dcb488a3SAndy Adamson 852dcb488a3SAndy Adamson READ_BUF(4); 853dcb488a3SAndy Adamson READ32(secinfo->si_namelen); 854dcb488a3SAndy Adamson READ_BUF(secinfo->si_namelen); 855dcb488a3SAndy Adamson SAVEMEM(secinfo->si_name, secinfo->si_namelen); 856dcb488a3SAndy Adamson status = check_filename(secinfo->si_name, secinfo->si_namelen, 857dcb488a3SAndy Adamson nfserr_noent); 858dcb488a3SAndy Adamson if (status) 859dcb488a3SAndy Adamson return status; 860dcb488a3SAndy Adamson DECODE_TAIL; 861dcb488a3SAndy Adamson } 862dcb488a3SAndy Adamson 863dcb488a3SAndy Adamson static __be32 8641da177e4SLinus Torvalds nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) 8651da177e4SLinus Torvalds { 866e31a1b66SBenny Halevy __be32 status; 8671da177e4SLinus Torvalds 868e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); 869e31a1b66SBenny Halevy if (status) 870e31a1b66SBenny Halevy return status; 871*c0d6fc8aSBenny Halevy return nfsd4_decode_fattr(argp, setattr->sa_bmval, nfsd_attrmask, 872e31a1b66SBenny Halevy &setattr->sa_iattr, &setattr->sa_acl); 8731da177e4SLinus Torvalds } 8741da177e4SLinus Torvalds 875b37ad28bSAl Viro static __be32 8761da177e4SLinus Torvalds nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid) 8771da177e4SLinus Torvalds { 8781da177e4SLinus Torvalds DECODE_HEAD; 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds READ_BUF(12); 8811da177e4SLinus Torvalds COPYMEM(setclientid->se_verf.data, 8); 8821da177e4SLinus Torvalds READ32(setclientid->se_namelen); 8831da177e4SLinus Torvalds 8841da177e4SLinus Torvalds READ_BUF(setclientid->se_namelen + 8); 8851da177e4SLinus Torvalds SAVEMEM(setclientid->se_name, setclientid->se_namelen); 8861da177e4SLinus Torvalds READ32(setclientid->se_callback_prog); 8871da177e4SLinus Torvalds READ32(setclientid->se_callback_netid_len); 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds READ_BUF(setclientid->se_callback_netid_len + 4); 8901da177e4SLinus Torvalds SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len); 8911da177e4SLinus Torvalds READ32(setclientid->se_callback_addr_len); 8921da177e4SLinus Torvalds 8931da177e4SLinus Torvalds READ_BUF(setclientid->se_callback_addr_len + 4); 8941da177e4SLinus Torvalds SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len); 8951da177e4SLinus Torvalds READ32(setclientid->se_callback_ident); 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds DECODE_TAIL; 8981da177e4SLinus Torvalds } 8991da177e4SLinus Torvalds 900b37ad28bSAl Viro static __be32 9011da177e4SLinus Torvalds nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c) 9021da177e4SLinus Torvalds { 9031da177e4SLinus Torvalds DECODE_HEAD; 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds READ_BUF(8 + sizeof(nfs4_verifier)); 9061da177e4SLinus Torvalds COPYMEM(&scd_c->sc_clientid, 8); 9071da177e4SLinus Torvalds COPYMEM(&scd_c->sc_confirm, sizeof(nfs4_verifier)); 9081da177e4SLinus Torvalds 9091da177e4SLinus Torvalds DECODE_TAIL; 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds /* Also used for NVERIFY */ 913b37ad28bSAl Viro static __be32 9141da177e4SLinus Torvalds nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) 9151da177e4SLinus Torvalds { 9161da177e4SLinus Torvalds #if 0 9171da177e4SLinus Torvalds struct nfsd4_compoundargs save = { 9181da177e4SLinus Torvalds .p = argp->p, 9191da177e4SLinus Torvalds .end = argp->end, 9201da177e4SLinus Torvalds .rqstp = argp->rqstp, 9211da177e4SLinus Torvalds }; 9221da177e4SLinus Torvalds u32 ve_bmval[2]; 9231da177e4SLinus Torvalds struct iattr ve_iattr; /* request */ 9241da177e4SLinus Torvalds struct nfs4_acl *ve_acl; /* request */ 9251da177e4SLinus Torvalds #endif 9261da177e4SLinus Torvalds DECODE_HEAD; 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) 9291da177e4SLinus Torvalds goto out; 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds /* For convenience's sake, we compare raw xdr'd attributes in 9321da177e4SLinus Torvalds * nfsd4_proc_verify; however we still decode here just to return 9331da177e4SLinus Torvalds * correct error in case of bad xdr. */ 9341da177e4SLinus Torvalds #if 0 9351da177e4SLinus Torvalds status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl); 9361da177e4SLinus Torvalds if (status == nfserr_inval) { 9371da177e4SLinus Torvalds status = nfserrno(status); 9381da177e4SLinus Torvalds goto out; 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds #endif 9411da177e4SLinus Torvalds READ_BUF(4); 9421da177e4SLinus Torvalds READ32(verify->ve_attrlen); 9431da177e4SLinus Torvalds READ_BUF(verify->ve_attrlen); 9441da177e4SLinus Torvalds SAVEMEM(verify->ve_attrval, verify->ve_attrlen); 9451da177e4SLinus Torvalds 9461da177e4SLinus Torvalds DECODE_TAIL; 9471da177e4SLinus Torvalds } 9481da177e4SLinus Torvalds 949b37ad28bSAl Viro static __be32 9501da177e4SLinus Torvalds nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) 9511da177e4SLinus Torvalds { 9521da177e4SLinus Torvalds int avail; 9531da177e4SLinus Torvalds int v; 9541da177e4SLinus Torvalds int len; 9551da177e4SLinus Torvalds DECODE_HEAD; 9561da177e4SLinus Torvalds 957e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &write->wr_stateid); 958e31a1b66SBenny Halevy if (status) 959e31a1b66SBenny Halevy return status; 960e31a1b66SBenny Halevy READ_BUF(16); 9611da177e4SLinus Torvalds READ64(write->wr_offset); 9621da177e4SLinus Torvalds READ32(write->wr_stable_how); 9631da177e4SLinus Torvalds if (write->wr_stable_how > 2) 9641da177e4SLinus Torvalds goto xdr_error; 9651da177e4SLinus Torvalds READ32(write->wr_buflen); 9661da177e4SLinus Torvalds 9671da177e4SLinus Torvalds /* Sorry .. no magic macros for this.. * 9681da177e4SLinus Torvalds * READ_BUF(write->wr_buflen); 9691da177e4SLinus Torvalds * SAVEMEM(write->wr_buf, write->wr_buflen); 9701da177e4SLinus Torvalds */ 9711da177e4SLinus Torvalds avail = (char*)argp->end - (char*)argp->p; 9721da177e4SLinus Torvalds if (avail + argp->pagelen < write->wr_buflen) { 973817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", 974817cb9d4SChuck Lever __FILE__, __LINE__); 9751da177e4SLinus Torvalds goto xdr_error; 9761da177e4SLinus Torvalds } 9773cc03b16SNeilBrown argp->rqstp->rq_vec[0].iov_base = p; 9783cc03b16SNeilBrown argp->rqstp->rq_vec[0].iov_len = avail; 9791da177e4SLinus Torvalds v = 0; 9801da177e4SLinus Torvalds len = write->wr_buflen; 9813cc03b16SNeilBrown while (len > argp->rqstp->rq_vec[v].iov_len) { 9823cc03b16SNeilBrown len -= argp->rqstp->rq_vec[v].iov_len; 9831da177e4SLinus Torvalds v++; 9843cc03b16SNeilBrown argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]); 9851da177e4SLinus Torvalds argp->pagelist++; 9861da177e4SLinus Torvalds if (argp->pagelen >= PAGE_SIZE) { 9873cc03b16SNeilBrown argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE; 9881da177e4SLinus Torvalds argp->pagelen -= PAGE_SIZE; 9891da177e4SLinus Torvalds } else { 9903cc03b16SNeilBrown argp->rqstp->rq_vec[v].iov_len = argp->pagelen; 9911da177e4SLinus Torvalds argp->pagelen -= len; 9921da177e4SLinus Torvalds } 9931da177e4SLinus Torvalds } 9942ebbc012SAl Viro argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len); 9952ebbc012SAl Viro argp->p = (__be32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); 9963cc03b16SNeilBrown argp->rqstp->rq_vec[v].iov_len = len; 9971da177e4SLinus Torvalds write->wr_vlen = v+1; 9981da177e4SLinus Torvalds 9991da177e4SLinus Torvalds DECODE_TAIL; 10001da177e4SLinus Torvalds } 10011da177e4SLinus Torvalds 1002b37ad28bSAl Viro static __be32 10031da177e4SLinus Torvalds nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner) 10041da177e4SLinus Torvalds { 10051da177e4SLinus Torvalds DECODE_HEAD; 10061da177e4SLinus Torvalds 10071da177e4SLinus Torvalds READ_BUF(12); 10081da177e4SLinus Torvalds COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); 10091da177e4SLinus Torvalds READ32(rlockowner->rl_owner.len); 10101da177e4SLinus Torvalds READ_BUF(rlockowner->rl_owner.len); 10111da177e4SLinus Torvalds READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len); 10121da177e4SLinus Torvalds 101360adfc50SAndy Adamson if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid)) 101460adfc50SAndy Adamson return nfserr_inval; 10151da177e4SLinus Torvalds DECODE_TAIL; 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds 1018b37ad28bSAl Viro static __be32 10192db134ebSAndy Adamson nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, 10200733d213SAndy Adamson struct nfsd4_exchange_id *exid) 10212db134ebSAndy Adamson { 10220733d213SAndy Adamson int dummy; 10230733d213SAndy Adamson DECODE_HEAD; 10240733d213SAndy Adamson 10250733d213SAndy Adamson READ_BUF(NFS4_VERIFIER_SIZE); 10260733d213SAndy Adamson COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE); 10270733d213SAndy Adamson 10280733d213SAndy Adamson READ_BUF(4); 10290733d213SAndy Adamson READ32(exid->clname.len); 10300733d213SAndy Adamson 10310733d213SAndy Adamson READ_BUF(exid->clname.len); 10320733d213SAndy Adamson SAVEMEM(exid->clname.data, exid->clname.len); 10330733d213SAndy Adamson 10340733d213SAndy Adamson READ_BUF(4); 10350733d213SAndy Adamson READ32(exid->flags); 10360733d213SAndy Adamson 10370733d213SAndy Adamson /* Ignore state_protect4_a */ 10380733d213SAndy Adamson READ_BUF(4); 10390733d213SAndy Adamson READ32(exid->spa_how); 10400733d213SAndy Adamson switch (exid->spa_how) { 10410733d213SAndy Adamson case SP4_NONE: 10420733d213SAndy Adamson break; 10430733d213SAndy Adamson case SP4_MACH_CRED: 10440733d213SAndy Adamson /* spo_must_enforce */ 10450733d213SAndy Adamson READ_BUF(4); 10460733d213SAndy Adamson READ32(dummy); 10470733d213SAndy Adamson READ_BUF(dummy * 4); 10480733d213SAndy Adamson p += dummy; 10490733d213SAndy Adamson 10500733d213SAndy Adamson /* spo_must_allow */ 10510733d213SAndy Adamson READ_BUF(4); 10520733d213SAndy Adamson READ32(dummy); 10530733d213SAndy Adamson READ_BUF(dummy * 4); 10540733d213SAndy Adamson p += dummy; 10550733d213SAndy Adamson break; 10560733d213SAndy Adamson case SP4_SSV: 10570733d213SAndy Adamson /* ssp_ops */ 10580733d213SAndy Adamson READ_BUF(4); 10590733d213SAndy Adamson READ32(dummy); 10600733d213SAndy Adamson READ_BUF(dummy * 4); 10610733d213SAndy Adamson p += dummy; 10620733d213SAndy Adamson 10630733d213SAndy Adamson READ_BUF(4); 10640733d213SAndy Adamson READ32(dummy); 10650733d213SAndy Adamson READ_BUF(dummy * 4); 10660733d213SAndy Adamson p += dummy; 10670733d213SAndy Adamson 10680733d213SAndy Adamson /* ssp_hash_algs<> */ 10690733d213SAndy Adamson READ_BUF(4); 10700733d213SAndy Adamson READ32(dummy); 10710733d213SAndy Adamson READ_BUF(dummy); 10720733d213SAndy Adamson p += XDR_QUADLEN(dummy); 10730733d213SAndy Adamson 10740733d213SAndy Adamson /* ssp_encr_algs<> */ 10750733d213SAndy Adamson READ_BUF(4); 10760733d213SAndy Adamson READ32(dummy); 10770733d213SAndy Adamson READ_BUF(dummy); 10780733d213SAndy Adamson p += XDR_QUADLEN(dummy); 10790733d213SAndy Adamson 10800733d213SAndy Adamson /* ssp_window and ssp_num_gss_handles */ 10810733d213SAndy Adamson READ_BUF(8); 10820733d213SAndy Adamson READ32(dummy); 10830733d213SAndy Adamson READ32(dummy); 10840733d213SAndy Adamson break; 10850733d213SAndy Adamson default: 10860733d213SAndy Adamson goto xdr_error; 10870733d213SAndy Adamson } 10880733d213SAndy Adamson 10890733d213SAndy Adamson /* Ignore Implementation ID */ 10900733d213SAndy Adamson READ_BUF(4); /* nfs_impl_id4 array length */ 10910733d213SAndy Adamson READ32(dummy); 10920733d213SAndy Adamson 10930733d213SAndy Adamson if (dummy > 1) 10940733d213SAndy Adamson goto xdr_error; 10950733d213SAndy Adamson 10960733d213SAndy Adamson if (dummy == 1) { 10970733d213SAndy Adamson /* nii_domain */ 10980733d213SAndy Adamson READ_BUF(4); 10990733d213SAndy Adamson READ32(dummy); 11000733d213SAndy Adamson READ_BUF(dummy); 11010733d213SAndy Adamson p += XDR_QUADLEN(dummy); 11020733d213SAndy Adamson 11030733d213SAndy Adamson /* nii_name */ 11040733d213SAndy Adamson READ_BUF(4); 11050733d213SAndy Adamson READ32(dummy); 11060733d213SAndy Adamson READ_BUF(dummy); 11070733d213SAndy Adamson p += XDR_QUADLEN(dummy); 11080733d213SAndy Adamson 11090733d213SAndy Adamson /* nii_date */ 11100733d213SAndy Adamson READ_BUF(12); 11110733d213SAndy Adamson p += 3; 11120733d213SAndy Adamson } 11130733d213SAndy Adamson DECODE_TAIL; 11142db134ebSAndy Adamson } 11152db134ebSAndy Adamson 11162db134ebSAndy Adamson static __be32 11172db134ebSAndy Adamson nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, 11182db134ebSAndy Adamson struct nfsd4_create_session *sess) 11192db134ebSAndy Adamson { 1120ec6b5d7bSAndy Adamson DECODE_HEAD; 1121ec6b5d7bSAndy Adamson 1122ec6b5d7bSAndy Adamson u32 dummy; 1123ec6b5d7bSAndy Adamson char *machine_name; 1124ec6b5d7bSAndy Adamson int i; 1125ec6b5d7bSAndy Adamson int nr_secflavs; 1126ec6b5d7bSAndy Adamson 1127ec6b5d7bSAndy Adamson READ_BUF(16); 1128ec6b5d7bSAndy Adamson COPYMEM(&sess->clientid, 8); 1129ec6b5d7bSAndy Adamson READ32(sess->seqid); 1130ec6b5d7bSAndy Adamson READ32(sess->flags); 1131ec6b5d7bSAndy Adamson 1132ec6b5d7bSAndy Adamson /* Fore channel attrs */ 1133ec6b5d7bSAndy Adamson READ_BUF(28); 1134ec6b5d7bSAndy Adamson READ32(dummy); /* headerpadsz is always 0 */ 1135ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxreq_sz); 1136ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxresp_sz); 1137ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxresp_cached); 1138ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxops); 1139ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxreqs); 1140ec6b5d7bSAndy Adamson READ32(sess->fore_channel.nr_rdma_attrs); 1141ec6b5d7bSAndy Adamson if (sess->fore_channel.nr_rdma_attrs == 1) { 1142ec6b5d7bSAndy Adamson READ_BUF(4); 1143ec6b5d7bSAndy Adamson READ32(sess->fore_channel.rdma_attrs); 1144ec6b5d7bSAndy Adamson } else if (sess->fore_channel.nr_rdma_attrs > 1) { 1145ec6b5d7bSAndy Adamson dprintk("Too many fore channel attr bitmaps!\n"); 1146ec6b5d7bSAndy Adamson goto xdr_error; 1147ec6b5d7bSAndy Adamson } 1148ec6b5d7bSAndy Adamson 1149ec6b5d7bSAndy Adamson /* Back channel attrs */ 1150ec6b5d7bSAndy Adamson READ_BUF(28); 1151ec6b5d7bSAndy Adamson READ32(dummy); /* headerpadsz is always 0 */ 1152ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxreq_sz); 1153ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxresp_sz); 1154ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxresp_cached); 1155ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxops); 1156ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxreqs); 1157ec6b5d7bSAndy Adamson READ32(sess->back_channel.nr_rdma_attrs); 1158ec6b5d7bSAndy Adamson if (sess->back_channel.nr_rdma_attrs == 1) { 1159ec6b5d7bSAndy Adamson READ_BUF(4); 1160ec6b5d7bSAndy Adamson READ32(sess->back_channel.rdma_attrs); 1161ec6b5d7bSAndy Adamson } else if (sess->back_channel.nr_rdma_attrs > 1) { 1162ec6b5d7bSAndy Adamson dprintk("Too many back channel attr bitmaps!\n"); 1163ec6b5d7bSAndy Adamson goto xdr_error; 1164ec6b5d7bSAndy Adamson } 1165ec6b5d7bSAndy Adamson 1166ec6b5d7bSAndy Adamson READ_BUF(8); 1167ec6b5d7bSAndy Adamson READ32(sess->callback_prog); 1168ec6b5d7bSAndy Adamson 1169ec6b5d7bSAndy Adamson /* callback_sec_params4 */ 1170ec6b5d7bSAndy Adamson READ32(nr_secflavs); 1171ec6b5d7bSAndy Adamson for (i = 0; i < nr_secflavs; ++i) { 1172ec6b5d7bSAndy Adamson READ_BUF(4); 1173ec6b5d7bSAndy Adamson READ32(dummy); 1174ec6b5d7bSAndy Adamson switch (dummy) { 1175ec6b5d7bSAndy Adamson case RPC_AUTH_NULL: 1176ec6b5d7bSAndy Adamson /* Nothing to read */ 1177ec6b5d7bSAndy Adamson break; 1178ec6b5d7bSAndy Adamson case RPC_AUTH_UNIX: 1179ec6b5d7bSAndy Adamson READ_BUF(8); 1180ec6b5d7bSAndy Adamson /* stamp */ 1181ec6b5d7bSAndy Adamson READ32(dummy); 1182ec6b5d7bSAndy Adamson 1183ec6b5d7bSAndy Adamson /* machine name */ 1184ec6b5d7bSAndy Adamson READ32(dummy); 1185ec6b5d7bSAndy Adamson READ_BUF(dummy); 1186ec6b5d7bSAndy Adamson SAVEMEM(machine_name, dummy); 1187ec6b5d7bSAndy Adamson 1188ec6b5d7bSAndy Adamson /* uid, gid */ 1189ec6b5d7bSAndy Adamson READ_BUF(8); 1190ec6b5d7bSAndy Adamson READ32(sess->uid); 1191ec6b5d7bSAndy Adamson READ32(sess->gid); 1192ec6b5d7bSAndy Adamson 1193ec6b5d7bSAndy Adamson /* more gids */ 1194ec6b5d7bSAndy Adamson READ_BUF(4); 1195ec6b5d7bSAndy Adamson READ32(dummy); 1196ec6b5d7bSAndy Adamson READ_BUF(dummy * 4); 1197ec6b5d7bSAndy Adamson for (i = 0; i < dummy; ++i) 1198ec6b5d7bSAndy Adamson READ32(dummy); 1199ec6b5d7bSAndy Adamson break; 1200ec6b5d7bSAndy Adamson case RPC_AUTH_GSS: 1201ec6b5d7bSAndy Adamson dprintk("RPC_AUTH_GSS callback secflavor " 1202ec6b5d7bSAndy Adamson "not supported!\n"); 1203ec6b5d7bSAndy Adamson READ_BUF(8); 1204ec6b5d7bSAndy Adamson /* gcbp_service */ 1205ec6b5d7bSAndy Adamson READ32(dummy); 1206ec6b5d7bSAndy Adamson /* gcbp_handle_from_server */ 1207ec6b5d7bSAndy Adamson READ32(dummy); 1208ec6b5d7bSAndy Adamson READ_BUF(dummy); 1209ec6b5d7bSAndy Adamson p += XDR_QUADLEN(dummy); 1210ec6b5d7bSAndy Adamson /* gcbp_handle_from_client */ 1211ec6b5d7bSAndy Adamson READ_BUF(4); 1212ec6b5d7bSAndy Adamson READ32(dummy); 1213ec6b5d7bSAndy Adamson READ_BUF(dummy); 1214ec6b5d7bSAndy Adamson p += XDR_QUADLEN(dummy); 1215ec6b5d7bSAndy Adamson break; 1216ec6b5d7bSAndy Adamson default: 1217ec6b5d7bSAndy Adamson dprintk("Illegal callback secflavor\n"); 1218ec6b5d7bSAndy Adamson return nfserr_inval; 1219ec6b5d7bSAndy Adamson } 1220ec6b5d7bSAndy Adamson } 1221ec6b5d7bSAndy Adamson DECODE_TAIL; 12222db134ebSAndy Adamson } 12232db134ebSAndy Adamson 12242db134ebSAndy Adamson static __be32 12252db134ebSAndy Adamson nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp, 12262db134ebSAndy Adamson struct nfsd4_destroy_session *destroy_session) 12272db134ebSAndy Adamson { 1228e10e0cfcSBenny Halevy DECODE_HEAD; 1229e10e0cfcSBenny Halevy READ_BUF(NFS4_MAX_SESSIONID_LEN); 1230e10e0cfcSBenny Halevy COPYMEM(destroy_session->sessionid.data, NFS4_MAX_SESSIONID_LEN); 1231e10e0cfcSBenny Halevy 1232e10e0cfcSBenny Halevy DECODE_TAIL; 12332db134ebSAndy Adamson } 12342db134ebSAndy Adamson 12352db134ebSAndy Adamson static __be32 12362db134ebSAndy Adamson nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, 12372db134ebSAndy Adamson struct nfsd4_sequence *seq) 12382db134ebSAndy Adamson { 1239b85d4c01SBenny Halevy DECODE_HEAD; 1240b85d4c01SBenny Halevy 1241b85d4c01SBenny Halevy READ_BUF(NFS4_MAX_SESSIONID_LEN + 16); 1242b85d4c01SBenny Halevy COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); 1243b85d4c01SBenny Halevy READ32(seq->seqid); 1244b85d4c01SBenny Halevy READ32(seq->slotid); 1245b85d4c01SBenny Halevy READ32(seq->maxslots); 1246b85d4c01SBenny Halevy READ32(seq->cachethis); 1247b85d4c01SBenny Halevy 1248b85d4c01SBenny Halevy DECODE_TAIL; 12492db134ebSAndy Adamson } 12502db134ebSAndy Adamson 12512db134ebSAndy Adamson static __be32 1252347e0ad9SBenny Halevy nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p) 1253347e0ad9SBenny Halevy { 1254347e0ad9SBenny Halevy return nfs_ok; 1255347e0ad9SBenny Halevy } 1256347e0ad9SBenny Halevy 12573c375c6fSBenny Halevy static __be32 12583c375c6fSBenny Halevy nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p) 12593c375c6fSBenny Halevy { 12601e685ec2SBenny Halevy return nfserr_notsupp; 12613c375c6fSBenny Halevy } 12623c375c6fSBenny Halevy 1263347e0ad9SBenny Halevy typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *); 1264347e0ad9SBenny Halevy 1265347e0ad9SBenny Halevy static nfsd4_dec nfsd4_dec_ops[] = { 1266ad1060c8SJ. Bruce Fields [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, 1267ad1060c8SJ. Bruce Fields [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, 1268ad1060c8SJ. Bruce Fields [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, 1269ad1060c8SJ. Bruce Fields [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, 1270ad1060c8SJ. Bruce Fields [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, 1271ad1060c8SJ. Bruce Fields [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, 1272ad1060c8SJ. Bruce Fields [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, 1273ad1060c8SJ. Bruce Fields [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, 1274ad1060c8SJ. Bruce Fields [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, 1275ad1060c8SJ. Bruce Fields [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, 1276ad1060c8SJ. Bruce Fields [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, 1277ad1060c8SJ. Bruce Fields [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, 1278ad1060c8SJ. Bruce Fields [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, 1279ad1060c8SJ. Bruce Fields [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, 1280ad1060c8SJ. Bruce Fields [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, 1281ad1060c8SJ. Bruce Fields [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, 1282ad1060c8SJ. Bruce Fields [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, 1283ad1060c8SJ. Bruce Fields [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, 1284ad1060c8SJ. Bruce Fields [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, 1285ad1060c8SJ. Bruce Fields [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, 1286a1c8c4d1SJ. Bruce Fields [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_noop, 1287ad1060c8SJ. Bruce Fields [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, 1288ad1060c8SJ. Bruce Fields [OP_READ] = (nfsd4_dec)nfsd4_decode_read, 1289ad1060c8SJ. Bruce Fields [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, 1290ad1060c8SJ. Bruce Fields [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, 1291ad1060c8SJ. Bruce Fields [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, 1292ad1060c8SJ. Bruce Fields [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, 1293ad1060c8SJ. Bruce Fields [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew, 1294ad1060c8SJ. Bruce Fields [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, 1295ad1060c8SJ. Bruce Fields [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, 1296ad1060c8SJ. Bruce Fields [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, 1297ad1060c8SJ. Bruce Fields [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, 1298ad1060c8SJ. Bruce Fields [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid, 1299ad1060c8SJ. Bruce Fields [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm, 1300ad1060c8SJ. Bruce Fields [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, 1301ad1060c8SJ. Bruce Fields [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, 1302ad1060c8SJ. Bruce Fields [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, 1303347e0ad9SBenny Halevy }; 1304347e0ad9SBenny Halevy 13052db134ebSAndy Adamson static nfsd4_dec nfsd41_dec_ops[] = { 13062db134ebSAndy Adamson [OP_ACCESS] (nfsd4_dec)nfsd4_decode_access, 13072db134ebSAndy Adamson [OP_CLOSE] (nfsd4_dec)nfsd4_decode_close, 13082db134ebSAndy Adamson [OP_COMMIT] (nfsd4_dec)nfsd4_decode_commit, 13092db134ebSAndy Adamson [OP_CREATE] (nfsd4_dec)nfsd4_decode_create, 13102db134ebSAndy Adamson [OP_DELEGPURGE] (nfsd4_dec)nfsd4_decode_notsupp, 13112db134ebSAndy Adamson [OP_DELEGRETURN] (nfsd4_dec)nfsd4_decode_delegreturn, 13122db134ebSAndy Adamson [OP_GETATTR] (nfsd4_dec)nfsd4_decode_getattr, 13132db134ebSAndy Adamson [OP_GETFH] (nfsd4_dec)nfsd4_decode_noop, 13142db134ebSAndy Adamson [OP_LINK] (nfsd4_dec)nfsd4_decode_link, 13152db134ebSAndy Adamson [OP_LOCK] (nfsd4_dec)nfsd4_decode_lock, 13162db134ebSAndy Adamson [OP_LOCKT] (nfsd4_dec)nfsd4_decode_lockt, 13172db134ebSAndy Adamson [OP_LOCKU] (nfsd4_dec)nfsd4_decode_locku, 13182db134ebSAndy Adamson [OP_LOOKUP] (nfsd4_dec)nfsd4_decode_lookup, 13192db134ebSAndy Adamson [OP_LOOKUPP] (nfsd4_dec)nfsd4_decode_noop, 13202db134ebSAndy Adamson [OP_NVERIFY] (nfsd4_dec)nfsd4_decode_verify, 13212db134ebSAndy Adamson [OP_OPEN] (nfsd4_dec)nfsd4_decode_open, 13222db134ebSAndy Adamson [OP_OPENATTR] (nfsd4_dec)nfsd4_decode_notsupp, 13232db134ebSAndy Adamson [OP_OPEN_CONFIRM] (nfsd4_dec)nfsd4_decode_notsupp, 13242db134ebSAndy Adamson [OP_OPEN_DOWNGRADE] (nfsd4_dec)nfsd4_decode_open_downgrade, 13252db134ebSAndy Adamson [OP_PUTFH] (nfsd4_dec)nfsd4_decode_putfh, 13262db134ebSAndy Adamson [OP_PUTPUBFH] (nfsd4_dec)nfsd4_decode_notsupp, 13272db134ebSAndy Adamson [OP_PUTROOTFH] (nfsd4_dec)nfsd4_decode_noop, 13282db134ebSAndy Adamson [OP_READ] (nfsd4_dec)nfsd4_decode_read, 13292db134ebSAndy Adamson [OP_READDIR] (nfsd4_dec)nfsd4_decode_readdir, 13302db134ebSAndy Adamson [OP_READLINK] (nfsd4_dec)nfsd4_decode_noop, 13312db134ebSAndy Adamson [OP_REMOVE] (nfsd4_dec)nfsd4_decode_remove, 13322db134ebSAndy Adamson [OP_RENAME] (nfsd4_dec)nfsd4_decode_rename, 13332db134ebSAndy Adamson [OP_RENEW] (nfsd4_dec)nfsd4_decode_notsupp, 13342db134ebSAndy Adamson [OP_RESTOREFH] (nfsd4_dec)nfsd4_decode_noop, 13352db134ebSAndy Adamson [OP_SAVEFH] (nfsd4_dec)nfsd4_decode_noop, 13362db134ebSAndy Adamson [OP_SECINFO] (nfsd4_dec)nfsd4_decode_secinfo, 13372db134ebSAndy Adamson [OP_SETATTR] (nfsd4_dec)nfsd4_decode_setattr, 13382db134ebSAndy Adamson [OP_SETCLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, 13392db134ebSAndy Adamson [OP_SETCLIENTID_CONFIRM](nfsd4_dec)nfsd4_decode_notsupp, 13402db134ebSAndy Adamson [OP_VERIFY] (nfsd4_dec)nfsd4_decode_verify, 13412db134ebSAndy Adamson [OP_WRITE] (nfsd4_dec)nfsd4_decode_write, 13422db134ebSAndy Adamson [OP_RELEASE_LOCKOWNER] (nfsd4_dec)nfsd4_decode_notsupp, 13432db134ebSAndy Adamson 13442db134ebSAndy Adamson /* new operations for NFSv4.1 */ 13452db134ebSAndy Adamson [OP_BACKCHANNEL_CTL] (nfsd4_dec)nfsd4_decode_notsupp, 13462db134ebSAndy Adamson [OP_BIND_CONN_TO_SESSION](nfsd4_dec)nfsd4_decode_notsupp, 13472db134ebSAndy Adamson [OP_EXCHANGE_ID] (nfsd4_dec)nfsd4_decode_exchange_id, 13482db134ebSAndy Adamson [OP_CREATE_SESSION] (nfsd4_dec)nfsd4_decode_create_session, 13492db134ebSAndy Adamson [OP_DESTROY_SESSION] (nfsd4_dec)nfsd4_decode_destroy_session, 13502db134ebSAndy Adamson [OP_FREE_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, 13512db134ebSAndy Adamson [OP_GET_DIR_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, 13522db134ebSAndy Adamson [OP_GETDEVICEINFO] (nfsd4_dec)nfsd4_decode_notsupp, 13532db134ebSAndy Adamson [OP_GETDEVICELIST] (nfsd4_dec)nfsd4_decode_notsupp, 13542db134ebSAndy Adamson [OP_LAYOUTCOMMIT] (nfsd4_dec)nfsd4_decode_notsupp, 13552db134ebSAndy Adamson [OP_LAYOUTGET] (nfsd4_dec)nfsd4_decode_notsupp, 13562db134ebSAndy Adamson [OP_LAYOUTRETURN] (nfsd4_dec)nfsd4_decode_notsupp, 13572db134ebSAndy Adamson [OP_SECINFO_NO_NAME] (nfsd4_dec)nfsd4_decode_notsupp, 13582db134ebSAndy Adamson [OP_SEQUENCE] (nfsd4_dec)nfsd4_decode_sequence, 13592db134ebSAndy Adamson [OP_SET_SSV] (nfsd4_dec)nfsd4_decode_notsupp, 13602db134ebSAndy Adamson [OP_TEST_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, 13612db134ebSAndy Adamson [OP_WANT_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, 13622db134ebSAndy Adamson [OP_DESTROY_CLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, 13632db134ebSAndy Adamson [OP_RECLAIM_COMPLETE] (nfsd4_dec)nfsd4_decode_notsupp, 13642db134ebSAndy Adamson }; 13652db134ebSAndy Adamson 1366f2feb96bSBenny Halevy struct nfsd4_minorversion_ops { 1367f2feb96bSBenny Halevy nfsd4_dec *decoders; 1368f2feb96bSBenny Halevy int nops; 1369f2feb96bSBenny Halevy }; 1370f2feb96bSBenny Halevy 1371f2feb96bSBenny Halevy static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { 1372ad1060c8SJ. Bruce Fields [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, 13732db134ebSAndy Adamson [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, 1374f2feb96bSBenny Halevy }; 1375f2feb96bSBenny Halevy 1376347e0ad9SBenny Halevy static __be32 13771da177e4SLinus Torvalds nfsd4_decode_compound(struct nfsd4_compoundargs *argp) 13781da177e4SLinus Torvalds { 13791da177e4SLinus Torvalds DECODE_HEAD; 13801da177e4SLinus Torvalds struct nfsd4_op *op; 1381f2feb96bSBenny Halevy struct nfsd4_minorversion_ops *ops; 13821da177e4SLinus Torvalds int i; 13831da177e4SLinus Torvalds 13841da177e4SLinus Torvalds /* 13851da177e4SLinus Torvalds * XXX: According to spec, we should check the tag 13861da177e4SLinus Torvalds * for UTF-8 compliance. I'm postponing this for 13871da177e4SLinus Torvalds * now because it seems that some clients do use 13881da177e4SLinus Torvalds * binary tags. 13891da177e4SLinus Torvalds */ 13901da177e4SLinus Torvalds READ_BUF(4); 13911da177e4SLinus Torvalds READ32(argp->taglen); 13921da177e4SLinus Torvalds READ_BUF(argp->taglen + 8); 13931da177e4SLinus Torvalds SAVEMEM(argp->tag, argp->taglen); 13941da177e4SLinus Torvalds READ32(argp->minorversion); 13951da177e4SLinus Torvalds READ32(argp->opcnt); 13961da177e4SLinus Torvalds 13971da177e4SLinus Torvalds if (argp->taglen > NFSD4_MAX_TAGLEN) 13981da177e4SLinus Torvalds goto xdr_error; 13991da177e4SLinus Torvalds if (argp->opcnt > 100) 14001da177e4SLinus Torvalds goto xdr_error; 14011da177e4SLinus Torvalds 1402e8c96f8cSTobias Klauser if (argp->opcnt > ARRAY_SIZE(argp->iops)) { 14031da177e4SLinus Torvalds argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); 14041da177e4SLinus Torvalds if (!argp->ops) { 14051da177e4SLinus Torvalds argp->ops = argp->iops; 1406817cb9d4SChuck Lever dprintk("nfsd: couldn't allocate room for COMPOUND\n"); 14071da177e4SLinus Torvalds goto xdr_error; 14081da177e4SLinus Torvalds } 14091da177e4SLinus Torvalds } 14101da177e4SLinus Torvalds 1411f2feb96bSBenny Halevy if (argp->minorversion >= ARRAY_SIZE(nfsd4_minorversion)) 141230cff1ffSBenny Halevy argp->opcnt = 0; 141330cff1ffSBenny Halevy 1414f2feb96bSBenny Halevy ops = &nfsd4_minorversion[argp->minorversion]; 14151da177e4SLinus Torvalds for (i = 0; i < argp->opcnt; i++) { 14161da177e4SLinus Torvalds op = &argp->ops[i]; 14171da177e4SLinus Torvalds op->replay = NULL; 14181da177e4SLinus Torvalds 14191da177e4SLinus Torvalds /* 14201da177e4SLinus Torvalds * We can't use READ_BUF() here because we need to handle 14211da177e4SLinus Torvalds * a missing opcode as an OP_WRITE + 1. So we need to check 14221da177e4SLinus Torvalds * to see if we're truly at the end of our buffer or if there 14231da177e4SLinus Torvalds * is another page we need to flip to. 14241da177e4SLinus Torvalds */ 14251da177e4SLinus Torvalds 14261da177e4SLinus Torvalds if (argp->p == argp->end) { 14271da177e4SLinus Torvalds if (argp->pagelen < 4) { 14281da177e4SLinus Torvalds /* There isn't an opcode still on the wire */ 14291da177e4SLinus Torvalds op->opnum = OP_WRITE + 1; 14301da177e4SLinus Torvalds op->status = nfserr_bad_xdr; 14311da177e4SLinus Torvalds argp->opcnt = i+1; 14321da177e4SLinus Torvalds break; 14331da177e4SLinus Torvalds } 14341da177e4SLinus Torvalds 14351da177e4SLinus Torvalds /* 14361da177e4SLinus Torvalds * False alarm. We just hit a page boundary, but there 14371da177e4SLinus Torvalds * is still data available. Move pointer across page 14381da177e4SLinus Torvalds * boundary. *snip from READ_BUF* 14391da177e4SLinus Torvalds */ 14401da177e4SLinus Torvalds argp->p = page_address(argp->pagelist[0]); 14411da177e4SLinus Torvalds argp->pagelist++; 14421da177e4SLinus Torvalds if (argp->pagelen < PAGE_SIZE) { 14431da177e4SLinus Torvalds argp->end = p + (argp->pagelen>>2); 14441da177e4SLinus Torvalds argp->pagelen = 0; 14451da177e4SLinus Torvalds } else { 14461da177e4SLinus Torvalds argp->end = p + (PAGE_SIZE>>2); 14471da177e4SLinus Torvalds argp->pagelen -= PAGE_SIZE; 14481da177e4SLinus Torvalds } 14491da177e4SLinus Torvalds } 14501da177e4SLinus Torvalds op->opnum = ntohl(*argp->p++); 14511da177e4SLinus Torvalds 1452f2feb96bSBenny Halevy if (op->opnum >= OP_ACCESS && op->opnum < ops->nops) 1453f2feb96bSBenny Halevy op->status = ops->decoders[op->opnum](argp, &op->u); 1454347e0ad9SBenny Halevy else { 14551da177e4SLinus Torvalds op->opnum = OP_ILLEGAL; 14561da177e4SLinus Torvalds op->status = nfserr_op_illegal; 14571da177e4SLinus Torvalds } 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds if (op->status) { 14601da177e4SLinus Torvalds argp->opcnt = i+1; 14611da177e4SLinus Torvalds break; 14621da177e4SLinus Torvalds } 14631da177e4SLinus Torvalds } 14641da177e4SLinus Torvalds 14651da177e4SLinus Torvalds DECODE_TAIL; 14661da177e4SLinus Torvalds } 14671da177e4SLinus Torvalds /* 14681da177e4SLinus Torvalds * END OF "GENERIC" DECODE ROUTINES. 14691da177e4SLinus Torvalds */ 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds /* 14721da177e4SLinus Torvalds * START OF "GENERIC" ENCODE ROUTINES. 14731da177e4SLinus Torvalds * These may look a little ugly since they are imported from a "generic" 14741da177e4SLinus Torvalds * set of XDR encode/decode routines which are intended to be shared by 14751da177e4SLinus Torvalds * all of our NFSv4 implementations (OpenBSD, MacOS X...). 14761da177e4SLinus Torvalds * 14771da177e4SLinus Torvalds * If the pain of reading these is too great, it should be a straightforward 14781da177e4SLinus Torvalds * task to translate them into Linux-specific versions which are more 14791da177e4SLinus Torvalds * consistent with the style used in NFSv2/v3... 14801da177e4SLinus Torvalds */ 14812ebbc012SAl Viro #define ENCODE_HEAD __be32 *p 14821da177e4SLinus Torvalds 14831da177e4SLinus Torvalds #define WRITE32(n) *p++ = htonl(n) 14841da177e4SLinus Torvalds #define WRITE64(n) do { \ 14851da177e4SLinus Torvalds *p++ = htonl((u32)((n) >> 32)); \ 14861da177e4SLinus Torvalds *p++ = htonl((u32)(n)); \ 14871da177e4SLinus Torvalds } while (0) 14885108b276SHarvey Harrison #define WRITEMEM(ptr,nbytes) do { if (nbytes > 0) { \ 14891da177e4SLinus Torvalds *(p + XDR_QUADLEN(nbytes) -1) = 0; \ 14901da177e4SLinus Torvalds memcpy(p, ptr, nbytes); \ 14911da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 14925108b276SHarvey Harrison }} while (0) 14931da177e4SLinus Torvalds #define WRITECINFO(c) do { \ 14941da177e4SLinus Torvalds *p++ = htonl(c.atomic); \ 14951da177e4SLinus Torvalds *p++ = htonl(c.before_ctime_sec); \ 14961da177e4SLinus Torvalds *p++ = htonl(c.before_ctime_nsec); \ 14971da177e4SLinus Torvalds *p++ = htonl(c.after_ctime_sec); \ 14981da177e4SLinus Torvalds *p++ = htonl(c.after_ctime_nsec); \ 14991da177e4SLinus Torvalds } while (0) 15001da177e4SLinus Torvalds 15011da177e4SLinus Torvalds #define RESERVE_SPACE(nbytes) do { \ 15021da177e4SLinus Torvalds p = resp->p; \ 15031da177e4SLinus Torvalds BUG_ON(p + XDR_QUADLEN(nbytes) > resp->end); \ 15041da177e4SLinus Torvalds } while (0) 15051da177e4SLinus Torvalds #define ADJUST_ARGS() resp->p = p 15061da177e4SLinus Torvalds 15071da177e4SLinus Torvalds /* 15081da177e4SLinus Torvalds * Header routine to setup seqid operation replay cache 15091da177e4SLinus Torvalds */ 15101da177e4SLinus Torvalds #define ENCODE_SEQID_OP_HEAD \ 15112ebbc012SAl Viro __be32 *save; \ 15121da177e4SLinus Torvalds \ 15131da177e4SLinus Torvalds save = resp->p; 15141da177e4SLinus Torvalds 15151da177e4SLinus Torvalds /* 15167fb64ceeSNeilBrown * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This 15177fb64ceeSNeilBrown * is where sequence id's are incremented, and the replay cache is filled. 15187fb64ceeSNeilBrown * Note that we increment sequence id's here, at the last moment, so we're sure 15197fb64ceeSNeilBrown * we know whether the error to be returned is a sequence id mutating error. 15201da177e4SLinus Torvalds */ 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvalds #define ENCODE_SEQID_OP_TAIL(stateowner) do { \ 15231da177e4SLinus Torvalds if (seqid_mutating_err(nfserr) && stateowner) { \ 15241da177e4SLinus Torvalds stateowner->so_seqid++; \ 15251da177e4SLinus Torvalds stateowner->so_replay.rp_status = nfserr; \ 15261da177e4SLinus Torvalds stateowner->so_replay.rp_buflen = \ 15271da177e4SLinus Torvalds (((char *)(resp)->p - (char *)save)); \ 15281da177e4SLinus Torvalds memcpy(stateowner->so_replay.rp_buf, save, \ 15291da177e4SLinus Torvalds stateowner->so_replay.rp_buflen); \ 15301da177e4SLinus Torvalds } } while (0); 15311da177e4SLinus Torvalds 153281c3f413SJ.Bruce Fields /* Encode as an array of strings the string given with components 153381c3f413SJ.Bruce Fields * seperated @sep. 153481c3f413SJ.Bruce Fields */ 1535b37ad28bSAl Viro static __be32 nfsd4_encode_components(char sep, char *components, 15362ebbc012SAl Viro __be32 **pp, int *buflen) 153781c3f413SJ.Bruce Fields { 15382ebbc012SAl Viro __be32 *p = *pp; 15392ebbc012SAl Viro __be32 *countp = p; 154081c3f413SJ.Bruce Fields int strlen, count=0; 154181c3f413SJ.Bruce Fields char *str, *end; 154281c3f413SJ.Bruce Fields 154381c3f413SJ.Bruce Fields dprintk("nfsd4_encode_components(%s)\n", components); 154481c3f413SJ.Bruce Fields if ((*buflen -= 4) < 0) 154581c3f413SJ.Bruce Fields return nfserr_resource; 154681c3f413SJ.Bruce Fields WRITE32(0); /* We will fill this in with @count later */ 154781c3f413SJ.Bruce Fields end = str = components; 154881c3f413SJ.Bruce Fields while (*end) { 154981c3f413SJ.Bruce Fields for (; *end && (*end != sep); end++) 155081c3f413SJ.Bruce Fields ; /* Point to end of component */ 155181c3f413SJ.Bruce Fields strlen = end - str; 155281c3f413SJ.Bruce Fields if (strlen) { 155381c3f413SJ.Bruce Fields if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) 155481c3f413SJ.Bruce Fields return nfserr_resource; 155581c3f413SJ.Bruce Fields WRITE32(strlen); 155681c3f413SJ.Bruce Fields WRITEMEM(str, strlen); 155781c3f413SJ.Bruce Fields count++; 155881c3f413SJ.Bruce Fields } 155981c3f413SJ.Bruce Fields else 156081c3f413SJ.Bruce Fields end++; 156181c3f413SJ.Bruce Fields str = end; 156281c3f413SJ.Bruce Fields } 156381c3f413SJ.Bruce Fields *pp = p; 156481c3f413SJ.Bruce Fields p = countp; 156581c3f413SJ.Bruce Fields WRITE32(count); 156681c3f413SJ.Bruce Fields return 0; 156781c3f413SJ.Bruce Fields } 156881c3f413SJ.Bruce Fields 156981c3f413SJ.Bruce Fields /* 157081c3f413SJ.Bruce Fields * encode a location element of a fs_locations structure 157181c3f413SJ.Bruce Fields */ 1572b37ad28bSAl Viro static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, 15732ebbc012SAl Viro __be32 **pp, int *buflen) 157481c3f413SJ.Bruce Fields { 1575b37ad28bSAl Viro __be32 status; 15762ebbc012SAl Viro __be32 *p = *pp; 157781c3f413SJ.Bruce Fields 157881c3f413SJ.Bruce Fields status = nfsd4_encode_components(':', location->hosts, &p, buflen); 157981c3f413SJ.Bruce Fields if (status) 158081c3f413SJ.Bruce Fields return status; 158181c3f413SJ.Bruce Fields status = nfsd4_encode_components('/', location->path, &p, buflen); 158281c3f413SJ.Bruce Fields if (status) 158381c3f413SJ.Bruce Fields return status; 158481c3f413SJ.Bruce Fields *pp = p; 158581c3f413SJ.Bruce Fields return 0; 158681c3f413SJ.Bruce Fields } 158781c3f413SJ.Bruce Fields 158881c3f413SJ.Bruce Fields /* 158981c3f413SJ.Bruce Fields * Return the path to an export point in the pseudo filesystem namespace 159081c3f413SJ.Bruce Fields * Returned string is safe to use as long as the caller holds a reference 159181c3f413SJ.Bruce Fields * to @exp. 159281c3f413SJ.Bruce Fields */ 1593b37ad28bSAl Viro static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) 159481c3f413SJ.Bruce Fields { 159581c3f413SJ.Bruce Fields struct svc_fh tmp_fh; 159681c3f413SJ.Bruce Fields char *path, *rootpath; 159781c3f413SJ.Bruce Fields 159881c3f413SJ.Bruce Fields fh_init(&tmp_fh, NFS4_FHSIZE); 1599df547efbSJ. Bruce Fields *stat = exp_pseudoroot(rqstp, &tmp_fh); 1600cc45f017SAl Viro if (*stat) 1601cc45f017SAl Viro return NULL; 160254775491SJan Blunck rootpath = tmp_fh.fh_export->ex_pathname; 160381c3f413SJ.Bruce Fields 160454775491SJan Blunck path = exp->ex_pathname; 160581c3f413SJ.Bruce Fields 160681c3f413SJ.Bruce Fields if (strncmp(path, rootpath, strlen(rootpath))) { 1607817cb9d4SChuck Lever dprintk("nfsd: fs_locations failed;" 160881c3f413SJ.Bruce Fields "%s is not contained in %s\n", path, rootpath); 1609cc45f017SAl Viro *stat = nfserr_notsupp; 1610cc45f017SAl Viro return NULL; 161181c3f413SJ.Bruce Fields } 161281c3f413SJ.Bruce Fields 161381c3f413SJ.Bruce Fields return path + strlen(rootpath); 161481c3f413SJ.Bruce Fields } 161581c3f413SJ.Bruce Fields 161681c3f413SJ.Bruce Fields /* 161781c3f413SJ.Bruce Fields * encode a fs_locations structure 161881c3f413SJ.Bruce Fields */ 1619b37ad28bSAl Viro static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp, 162081c3f413SJ.Bruce Fields struct svc_export *exp, 16212ebbc012SAl Viro __be32 **pp, int *buflen) 162281c3f413SJ.Bruce Fields { 1623b37ad28bSAl Viro __be32 status; 1624cc45f017SAl Viro int i; 16252ebbc012SAl Viro __be32 *p = *pp; 162681c3f413SJ.Bruce Fields struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; 1627cc45f017SAl Viro char *root = nfsd4_path(rqstp, exp, &status); 162881c3f413SJ.Bruce Fields 1629cc45f017SAl Viro if (status) 1630cc45f017SAl Viro return status; 163181c3f413SJ.Bruce Fields status = nfsd4_encode_components('/', root, &p, buflen); 163281c3f413SJ.Bruce Fields if (status) 163381c3f413SJ.Bruce Fields return status; 163481c3f413SJ.Bruce Fields if ((*buflen -= 4) < 0) 163581c3f413SJ.Bruce Fields return nfserr_resource; 163681c3f413SJ.Bruce Fields WRITE32(fslocs->locations_count); 163781c3f413SJ.Bruce Fields for (i=0; i<fslocs->locations_count; i++) { 163881c3f413SJ.Bruce Fields status = nfsd4_encode_fs_location4(&fslocs->locations[i], 163981c3f413SJ.Bruce Fields &p, buflen); 164081c3f413SJ.Bruce Fields if (status) 164181c3f413SJ.Bruce Fields return status; 164281c3f413SJ.Bruce Fields } 164381c3f413SJ.Bruce Fields *pp = p; 164481c3f413SJ.Bruce Fields return 0; 164581c3f413SJ.Bruce Fields } 16461da177e4SLinus Torvalds 16471da177e4SLinus Torvalds static u32 nfs4_ftypes[16] = { 16481da177e4SLinus Torvalds NF4BAD, NF4FIFO, NF4CHR, NF4BAD, 16491da177e4SLinus Torvalds NF4DIR, NF4BAD, NF4BLK, NF4BAD, 16501da177e4SLinus Torvalds NF4REG, NF4BAD, NF4LNK, NF4BAD, 16511da177e4SLinus Torvalds NF4SOCK, NF4BAD, NF4LNK, NF4BAD, 16521da177e4SLinus Torvalds }; 16531da177e4SLinus Torvalds 1654b37ad28bSAl Viro static __be32 16551da177e4SLinus Torvalds nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, 16562ebbc012SAl Viro __be32 **p, int *buflen) 16571da177e4SLinus Torvalds { 16581da177e4SLinus Torvalds int status; 16591da177e4SLinus Torvalds 16601da177e4SLinus Torvalds if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4) 16611da177e4SLinus Torvalds return nfserr_resource; 16621da177e4SLinus Torvalds if (whotype != NFS4_ACL_WHO_NAMED) 16631da177e4SLinus Torvalds status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1)); 16641da177e4SLinus Torvalds else if (group) 16651da177e4SLinus Torvalds status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1)); 16661da177e4SLinus Torvalds else 16671da177e4SLinus Torvalds status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1)); 16681da177e4SLinus Torvalds if (status < 0) 16691da177e4SLinus Torvalds return nfserrno(status); 16701da177e4SLinus Torvalds *p = xdr_encode_opaque(*p, NULL, status); 16711da177e4SLinus Torvalds *buflen -= (XDR_QUADLEN(status) << 2) + 4; 16721da177e4SLinus Torvalds BUG_ON(*buflen < 0); 16731da177e4SLinus Torvalds return 0; 16741da177e4SLinus Torvalds } 16751da177e4SLinus Torvalds 1676b37ad28bSAl Viro static inline __be32 16772ebbc012SAl Viro nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen) 16781da177e4SLinus Torvalds { 16791da177e4SLinus Torvalds return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen); 16801da177e4SLinus Torvalds } 16811da177e4SLinus Torvalds 1682b37ad28bSAl Viro static inline __be32 16832ebbc012SAl Viro nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen) 16841da177e4SLinus Torvalds { 16851da177e4SLinus Torvalds return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen); 16861da177e4SLinus Torvalds } 16871da177e4SLinus Torvalds 1688b37ad28bSAl Viro static inline __be32 16891da177e4SLinus Torvalds nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, 16902ebbc012SAl Viro __be32 **p, int *buflen) 16911da177e4SLinus Torvalds { 16921da177e4SLinus Torvalds return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen); 16931da177e4SLinus Torvalds } 16941da177e4SLinus Torvalds 169542ca0993SJ.Bruce Fields #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ 169642ca0993SJ.Bruce Fields FATTR4_WORD0_RDATTR_ERROR) 169742ca0993SJ.Bruce Fields #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID 169842ca0993SJ.Bruce Fields 1699b37ad28bSAl Viro static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) 170042ca0993SJ.Bruce Fields { 170142ca0993SJ.Bruce Fields /* As per referral draft: */ 170242ca0993SJ.Bruce Fields if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS || 170342ca0993SJ.Bruce Fields *bmval1 & ~WORD1_ABSENT_FS_ATTRS) { 170442ca0993SJ.Bruce Fields if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR || 170542ca0993SJ.Bruce Fields *bmval0 & FATTR4_WORD0_FS_LOCATIONS) 170642ca0993SJ.Bruce Fields *rdattr_err = NFSERR_MOVED; 170742ca0993SJ.Bruce Fields else 170842ca0993SJ.Bruce Fields return nfserr_moved; 170942ca0993SJ.Bruce Fields } 171042ca0993SJ.Bruce Fields *bmval0 &= WORD0_ABSENT_FS_ATTRS; 171142ca0993SJ.Bruce Fields *bmval1 &= WORD1_ABSENT_FS_ATTRS; 171242ca0993SJ.Bruce Fields return 0; 171342ca0993SJ.Bruce Fields } 17141da177e4SLinus Torvalds 17151da177e4SLinus Torvalds /* 17161da177e4SLinus Torvalds * Note: @fhp can be NULL; in this case, we might have to compose the filehandle 17171da177e4SLinus Torvalds * ourselves. 17181da177e4SLinus Torvalds * 17191da177e4SLinus Torvalds * @countp is the buffer size in _words_; upon successful return this becomes 17201da177e4SLinus Torvalds * replaced with the number of words written. 17211da177e4SLinus Torvalds */ 1722b37ad28bSAl Viro __be32 17231da177e4SLinus Torvalds nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, 17242ebbc012SAl Viro struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, 1725406a7ea9SFrank Filz struct svc_rqst *rqstp, int ignore_crossmnt) 17261da177e4SLinus Torvalds { 17271da177e4SLinus Torvalds u32 bmval0 = bmval[0]; 17281da177e4SLinus Torvalds u32 bmval1 = bmval[1]; 17291da177e4SLinus Torvalds struct kstat stat; 17301da177e4SLinus Torvalds struct svc_fh tempfh; 17311da177e4SLinus Torvalds struct kstatfs statfs; 17321da177e4SLinus Torvalds int buflen = *countp << 2; 17332ebbc012SAl Viro __be32 *attrlenp; 17341da177e4SLinus Torvalds u32 dummy; 17351da177e4SLinus Torvalds u64 dummy64; 173642ca0993SJ.Bruce Fields u32 rdattr_err = 0; 17372ebbc012SAl Viro __be32 *p = buffer; 1738b37ad28bSAl Viro __be32 status; 1739b8dd7b9aSAl Viro int err; 17401da177e4SLinus Torvalds int aclsupport = 0; 17411da177e4SLinus Torvalds struct nfs4_acl *acl = NULL; 17421da177e4SLinus Torvalds 17431da177e4SLinus Torvalds BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); 17441da177e4SLinus Torvalds BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0); 17451da177e4SLinus Torvalds BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1); 17461da177e4SLinus Torvalds 174742ca0993SJ.Bruce Fields if (exp->ex_fslocs.migrated) { 174842ca0993SJ.Bruce Fields status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err); 174942ca0993SJ.Bruce Fields if (status) 175042ca0993SJ.Bruce Fields goto out; 175142ca0993SJ.Bruce Fields } 175242ca0993SJ.Bruce Fields 175354775491SJan Blunck err = vfs_getattr(exp->ex_path.mnt, dentry, &stat); 1754b8dd7b9aSAl Viro if (err) 17551da177e4SLinus Torvalds goto out_nfserr; 1756a16e92edSJ. Bruce Fields if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | 1757a16e92edSJ. Bruce Fields FATTR4_WORD0_MAXNAME)) || 17581da177e4SLinus Torvalds (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | 17591da177e4SLinus Torvalds FATTR4_WORD1_SPACE_TOTAL))) { 1760b8dd7b9aSAl Viro err = vfs_statfs(dentry, &statfs); 1761b8dd7b9aSAl Viro if (err) 17621da177e4SLinus Torvalds goto out_nfserr; 17631da177e4SLinus Torvalds } 17641da177e4SLinus Torvalds if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) { 17651da177e4SLinus Torvalds fh_init(&tempfh, NFS4_FHSIZE); 17661da177e4SLinus Torvalds status = fh_compose(&tempfh, exp, dentry, NULL); 17671da177e4SLinus Torvalds if (status) 17681da177e4SLinus Torvalds goto out; 17691da177e4SLinus Torvalds fhp = &tempfh; 17701da177e4SLinus Torvalds } 17711da177e4SLinus Torvalds if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT 17721da177e4SLinus Torvalds | FATTR4_WORD0_SUPPORTED_ATTRS)) { 1773b8dd7b9aSAl Viro err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); 1774b8dd7b9aSAl Viro aclsupport = (err == 0); 17751da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACL) { 1776b8dd7b9aSAl Viro if (err == -EOPNOTSUPP) 17771da177e4SLinus Torvalds bmval0 &= ~FATTR4_WORD0_ACL; 1778b8dd7b9aSAl Viro else if (err == -EINVAL) { 17791da177e4SLinus Torvalds status = nfserr_attrnotsupp; 17801da177e4SLinus Torvalds goto out; 1781b8dd7b9aSAl Viro } else if (err != 0) 17821da177e4SLinus Torvalds goto out_nfserr; 17831da177e4SLinus Torvalds } 17841da177e4SLinus Torvalds } 178581c3f413SJ.Bruce Fields if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { 178681c3f413SJ.Bruce Fields if (exp->ex_fslocs.locations == NULL) { 178781c3f413SJ.Bruce Fields bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS; 178881c3f413SJ.Bruce Fields } 178981c3f413SJ.Bruce Fields } 17901da177e4SLinus Torvalds if ((buflen -= 16) < 0) 17911da177e4SLinus Torvalds goto out_resource; 17921da177e4SLinus Torvalds 17931da177e4SLinus Torvalds WRITE32(2); 17941da177e4SLinus Torvalds WRITE32(bmval0); 17951da177e4SLinus Torvalds WRITE32(bmval1); 17961da177e4SLinus Torvalds attrlenp = p++; /* to be backfilled later */ 17971da177e4SLinus Torvalds 17981da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { 179942ca0993SJ.Bruce Fields u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0; 18001da177e4SLinus Torvalds if ((buflen -= 12) < 0) 18011da177e4SLinus Torvalds goto out_resource; 180242ca0993SJ.Bruce Fields if (!aclsupport) 180342ca0993SJ.Bruce Fields word0 &= ~FATTR4_WORD0_ACL; 180442ca0993SJ.Bruce Fields if (!exp->ex_fslocs.locations) 180542ca0993SJ.Bruce Fields word0 &= ~FATTR4_WORD0_FS_LOCATIONS; 18061da177e4SLinus Torvalds WRITE32(2); 180742ca0993SJ.Bruce Fields WRITE32(word0); 18081da177e4SLinus Torvalds WRITE32(NFSD_SUPPORTED_ATTRS_WORD1); 18091da177e4SLinus Torvalds } 18101da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_TYPE) { 18111da177e4SLinus Torvalds if ((buflen -= 4) < 0) 18121da177e4SLinus Torvalds goto out_resource; 18131da177e4SLinus Torvalds dummy = nfs4_ftypes[(stat.mode & S_IFMT) >> 12]; 18141da177e4SLinus Torvalds if (dummy == NF4BAD) 18151da177e4SLinus Torvalds goto out_serverfault; 18161da177e4SLinus Torvalds WRITE32(dummy); 18171da177e4SLinus Torvalds } 18181da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { 18191da177e4SLinus Torvalds if ((buflen -= 4) < 0) 18201da177e4SLinus Torvalds goto out_resource; 182149640001SNeilBrown if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) 1822e34ac862SNeilBrown WRITE32(NFS4_FH_PERSISTENT); 182349640001SNeilBrown else 1824e34ac862SNeilBrown WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); 18251da177e4SLinus Torvalds } 18261da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CHANGE) { 18271da177e4SLinus Torvalds /* 18281da177e4SLinus Torvalds * Note: This _must_ be consistent with the scheme for writing 18291da177e4SLinus Torvalds * change_info, so any changes made here must be reflected there 18301da177e4SLinus Torvalds * as well. (See xdr4.h:set_change_info() and the WRITECINFO() 18311da177e4SLinus Torvalds * macro above.) 18321da177e4SLinus Torvalds */ 18331da177e4SLinus Torvalds if ((buflen -= 8) < 0) 18341da177e4SLinus Torvalds goto out_resource; 18351da177e4SLinus Torvalds WRITE32(stat.ctime.tv_sec); 18361da177e4SLinus Torvalds WRITE32(stat.ctime.tv_nsec); 18371da177e4SLinus Torvalds } 18381da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SIZE) { 18391da177e4SLinus Torvalds if ((buflen -= 8) < 0) 18401da177e4SLinus Torvalds goto out_resource; 18411da177e4SLinus Torvalds WRITE64(stat.size); 18421da177e4SLinus Torvalds } 18431da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) { 18441da177e4SLinus Torvalds if ((buflen -= 4) < 0) 18451da177e4SLinus Torvalds goto out_resource; 18461da177e4SLinus Torvalds WRITE32(1); 18471da177e4SLinus Torvalds } 18481da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) { 18491da177e4SLinus Torvalds if ((buflen -= 4) < 0) 18501da177e4SLinus Torvalds goto out_resource; 18511da177e4SLinus Torvalds WRITE32(1); 18521da177e4SLinus Torvalds } 18531da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_NAMED_ATTR) { 18541da177e4SLinus Torvalds if ((buflen -= 4) < 0) 18551da177e4SLinus Torvalds goto out_resource; 18561da177e4SLinus Torvalds WRITE32(0); 18571da177e4SLinus Torvalds } 18581da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FSID) { 18591da177e4SLinus Torvalds if ((buflen -= 16) < 0) 18601da177e4SLinus Torvalds goto out_resource; 186142ca0993SJ.Bruce Fields if (exp->ex_fslocs.migrated) { 186242ca0993SJ.Bruce Fields WRITE64(NFS4_REFERRAL_FSID_MAJOR); 186342ca0993SJ.Bruce Fields WRITE64(NFS4_REFERRAL_FSID_MINOR); 1864af6a4e28SNeilBrown } else switch(fsid_source(fhp)) { 1865af6a4e28SNeilBrown case FSIDSOURCE_FSID: 18661da177e4SLinus Torvalds WRITE64((u64)exp->ex_fsid); 18671da177e4SLinus Torvalds WRITE64((u64)0); 1868af6a4e28SNeilBrown break; 1869af6a4e28SNeilBrown case FSIDSOURCE_DEV: 18701da177e4SLinus Torvalds WRITE32(0); 18711da177e4SLinus Torvalds WRITE32(MAJOR(stat.dev)); 18721da177e4SLinus Torvalds WRITE32(0); 18731da177e4SLinus Torvalds WRITE32(MINOR(stat.dev)); 1874af6a4e28SNeilBrown break; 1875af6a4e28SNeilBrown case FSIDSOURCE_UUID: 1876af6a4e28SNeilBrown WRITEMEM(exp->ex_uuid, 16); 1877af6a4e28SNeilBrown break; 18781da177e4SLinus Torvalds } 18791da177e4SLinus Torvalds } 18801da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { 18811da177e4SLinus Torvalds if ((buflen -= 4) < 0) 18821da177e4SLinus Torvalds goto out_resource; 18831da177e4SLinus Torvalds WRITE32(0); 18841da177e4SLinus Torvalds } 18851da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_LEASE_TIME) { 18861da177e4SLinus Torvalds if ((buflen -= 4) < 0) 18871da177e4SLinus Torvalds goto out_resource; 18881da177e4SLinus Torvalds WRITE32(NFSD_LEASE_TIME); 18891da177e4SLinus Torvalds } 18901da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { 18911da177e4SLinus Torvalds if ((buflen -= 4) < 0) 18921da177e4SLinus Torvalds goto out_resource; 189342ca0993SJ.Bruce Fields WRITE32(rdattr_err); 18941da177e4SLinus Torvalds } 18951da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACL) { 18961da177e4SLinus Torvalds struct nfs4_ace *ace; 18971da177e4SLinus Torvalds 18981da177e4SLinus Torvalds if (acl == NULL) { 18991da177e4SLinus Torvalds if ((buflen -= 4) < 0) 19001da177e4SLinus Torvalds goto out_resource; 19011da177e4SLinus Torvalds 19021da177e4SLinus Torvalds WRITE32(0); 19031da177e4SLinus Torvalds goto out_acl; 19041da177e4SLinus Torvalds } 19051da177e4SLinus Torvalds if ((buflen -= 4) < 0) 19061da177e4SLinus Torvalds goto out_resource; 19071da177e4SLinus Torvalds WRITE32(acl->naces); 19081da177e4SLinus Torvalds 190928e05dd8SJ. Bruce Fields for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { 19101da177e4SLinus Torvalds if ((buflen -= 4*3) < 0) 19111da177e4SLinus Torvalds goto out_resource; 19121da177e4SLinus Torvalds WRITE32(ace->type); 19131da177e4SLinus Torvalds WRITE32(ace->flag); 19141da177e4SLinus Torvalds WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL); 19151da177e4SLinus Torvalds status = nfsd4_encode_aclname(rqstp, ace->whotype, 19161da177e4SLinus Torvalds ace->who, ace->flag & NFS4_ACE_IDENTIFIER_GROUP, 19171da177e4SLinus Torvalds &p, &buflen); 19181da177e4SLinus Torvalds if (status == nfserr_resource) 19191da177e4SLinus Torvalds goto out_resource; 19201da177e4SLinus Torvalds if (status) 19211da177e4SLinus Torvalds goto out; 19221da177e4SLinus Torvalds } 19231da177e4SLinus Torvalds } 19241da177e4SLinus Torvalds out_acl: 19251da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACLSUPPORT) { 19261da177e4SLinus Torvalds if ((buflen -= 4) < 0) 19271da177e4SLinus Torvalds goto out_resource; 19281da177e4SLinus Torvalds WRITE32(aclsupport ? 19291da177e4SLinus Torvalds ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0); 19301da177e4SLinus Torvalds } 19311da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CANSETTIME) { 19321da177e4SLinus Torvalds if ((buflen -= 4) < 0) 19331da177e4SLinus Torvalds goto out_resource; 19341da177e4SLinus Torvalds WRITE32(1); 19351da177e4SLinus Torvalds } 19361da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { 19371da177e4SLinus Torvalds if ((buflen -= 4) < 0) 19381da177e4SLinus Torvalds goto out_resource; 19391da177e4SLinus Torvalds WRITE32(1); 19401da177e4SLinus Torvalds } 19411da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { 19421da177e4SLinus Torvalds if ((buflen -= 4) < 0) 19431da177e4SLinus Torvalds goto out_resource; 19441da177e4SLinus Torvalds WRITE32(1); 19451da177e4SLinus Torvalds } 19461da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) { 19471da177e4SLinus Torvalds if ((buflen -= 4) < 0) 19481da177e4SLinus Torvalds goto out_resource; 19491da177e4SLinus Torvalds WRITE32(1); 19501da177e4SLinus Torvalds } 19511da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILEHANDLE) { 19521da177e4SLinus Torvalds buflen -= (XDR_QUADLEN(fhp->fh_handle.fh_size) << 2) + 4; 19531da177e4SLinus Torvalds if (buflen < 0) 19541da177e4SLinus Torvalds goto out_resource; 19551da177e4SLinus Torvalds WRITE32(fhp->fh_handle.fh_size); 19561da177e4SLinus Torvalds WRITEMEM(&fhp->fh_handle.fh_base, fhp->fh_handle.fh_size); 19571da177e4SLinus Torvalds } 19581da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILEID) { 19591da177e4SLinus Torvalds if ((buflen -= 8) < 0) 19601da177e4SLinus Torvalds goto out_resource; 196140ee5dc6SPeter Staubach WRITE64(stat.ino); 19621da177e4SLinus Torvalds } 19631da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { 19641da177e4SLinus Torvalds if ((buflen -= 8) < 0) 19651da177e4SLinus Torvalds goto out_resource; 19661da177e4SLinus Torvalds WRITE64((u64) statfs.f_ffree); 19671da177e4SLinus Torvalds } 19681da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_FREE) { 19691da177e4SLinus Torvalds if ((buflen -= 8) < 0) 19701da177e4SLinus Torvalds goto out_resource; 19711da177e4SLinus Torvalds WRITE64((u64) statfs.f_ffree); 19721da177e4SLinus Torvalds } 19731da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { 19741da177e4SLinus Torvalds if ((buflen -= 8) < 0) 19751da177e4SLinus Torvalds goto out_resource; 19761da177e4SLinus Torvalds WRITE64((u64) statfs.f_files); 19771da177e4SLinus Torvalds } 197881c3f413SJ.Bruce Fields if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { 197981c3f413SJ.Bruce Fields status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen); 198081c3f413SJ.Bruce Fields if (status == nfserr_resource) 198181c3f413SJ.Bruce Fields goto out_resource; 198281c3f413SJ.Bruce Fields if (status) 198381c3f413SJ.Bruce Fields goto out; 198481c3f413SJ.Bruce Fields } 19851da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { 19861da177e4SLinus Torvalds if ((buflen -= 4) < 0) 19871da177e4SLinus Torvalds goto out_resource; 19881da177e4SLinus Torvalds WRITE32(1); 19891da177e4SLinus Torvalds } 19901da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { 19911da177e4SLinus Torvalds if ((buflen -= 8) < 0) 19921da177e4SLinus Torvalds goto out_resource; 19931da177e4SLinus Torvalds WRITE64(~(u64)0); 19941da177e4SLinus Torvalds } 19951da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXLINK) { 19961da177e4SLinus Torvalds if ((buflen -= 4) < 0) 19971da177e4SLinus Torvalds goto out_resource; 19981da177e4SLinus Torvalds WRITE32(255); 19991da177e4SLinus Torvalds } 20001da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXNAME) { 20011da177e4SLinus Torvalds if ((buflen -= 4) < 0) 20021da177e4SLinus Torvalds goto out_resource; 2003a16e92edSJ. Bruce Fields WRITE32(statfs.f_namelen); 20041da177e4SLinus Torvalds } 20051da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXREAD) { 20061da177e4SLinus Torvalds if ((buflen -= 8) < 0) 20071da177e4SLinus Torvalds goto out_resource; 20087adae489SGreg Banks WRITE64((u64) svc_max_payload(rqstp)); 20091da177e4SLinus Torvalds } 20101da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXWRITE) { 20111da177e4SLinus Torvalds if ((buflen -= 8) < 0) 20121da177e4SLinus Torvalds goto out_resource; 20137adae489SGreg Banks WRITE64((u64) svc_max_payload(rqstp)); 20141da177e4SLinus Torvalds } 20151da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_MODE) { 20161da177e4SLinus Torvalds if ((buflen -= 4) < 0) 20171da177e4SLinus Torvalds goto out_resource; 20181da177e4SLinus Torvalds WRITE32(stat.mode & S_IALLUGO); 20191da177e4SLinus Torvalds } 20201da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_NO_TRUNC) { 20211da177e4SLinus Torvalds if ((buflen -= 4) < 0) 20221da177e4SLinus Torvalds goto out_resource; 20231da177e4SLinus Torvalds WRITE32(1); 20241da177e4SLinus Torvalds } 20251da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_NUMLINKS) { 20261da177e4SLinus Torvalds if ((buflen -= 4) < 0) 20271da177e4SLinus Torvalds goto out_resource; 20281da177e4SLinus Torvalds WRITE32(stat.nlink); 20291da177e4SLinus Torvalds } 20301da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_OWNER) { 20311da177e4SLinus Torvalds status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen); 20321da177e4SLinus Torvalds if (status == nfserr_resource) 20331da177e4SLinus Torvalds goto out_resource; 20341da177e4SLinus Torvalds if (status) 20351da177e4SLinus Torvalds goto out; 20361da177e4SLinus Torvalds } 20371da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { 20381da177e4SLinus Torvalds status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen); 20391da177e4SLinus Torvalds if (status == nfserr_resource) 20401da177e4SLinus Torvalds goto out_resource; 20411da177e4SLinus Torvalds if (status) 20421da177e4SLinus Torvalds goto out; 20431da177e4SLinus Torvalds } 20441da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_RAWDEV) { 20451da177e4SLinus Torvalds if ((buflen -= 8) < 0) 20461da177e4SLinus Torvalds goto out_resource; 20471da177e4SLinus Torvalds WRITE32((u32) MAJOR(stat.rdev)); 20481da177e4SLinus Torvalds WRITE32((u32) MINOR(stat.rdev)); 20491da177e4SLinus Torvalds } 20501da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { 20511da177e4SLinus Torvalds if ((buflen -= 8) < 0) 20521da177e4SLinus Torvalds goto out_resource; 20531da177e4SLinus Torvalds dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize; 20541da177e4SLinus Torvalds WRITE64(dummy64); 20551da177e4SLinus Torvalds } 20561da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_FREE) { 20571da177e4SLinus Torvalds if ((buflen -= 8) < 0) 20581da177e4SLinus Torvalds goto out_resource; 20591da177e4SLinus Torvalds dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize; 20601da177e4SLinus Torvalds WRITE64(dummy64); 20611da177e4SLinus Torvalds } 20621da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { 20631da177e4SLinus Torvalds if ((buflen -= 8) < 0) 20641da177e4SLinus Torvalds goto out_resource; 20651da177e4SLinus Torvalds dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize; 20661da177e4SLinus Torvalds WRITE64(dummy64); 20671da177e4SLinus Torvalds } 20681da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_USED) { 20691da177e4SLinus Torvalds if ((buflen -= 8) < 0) 20701da177e4SLinus Torvalds goto out_resource; 20711da177e4SLinus Torvalds dummy64 = (u64)stat.blocks << 9; 20721da177e4SLinus Torvalds WRITE64(dummy64); 20731da177e4SLinus Torvalds } 20741da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { 20751da177e4SLinus Torvalds if ((buflen -= 12) < 0) 20761da177e4SLinus Torvalds goto out_resource; 20771da177e4SLinus Torvalds WRITE32(0); 20781da177e4SLinus Torvalds WRITE32(stat.atime.tv_sec); 20791da177e4SLinus Torvalds WRITE32(stat.atime.tv_nsec); 20801da177e4SLinus Torvalds } 20811da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_DELTA) { 20821da177e4SLinus Torvalds if ((buflen -= 12) < 0) 20831da177e4SLinus Torvalds goto out_resource; 20841da177e4SLinus Torvalds WRITE32(0); 20851da177e4SLinus Torvalds WRITE32(1); 20861da177e4SLinus Torvalds WRITE32(0); 20871da177e4SLinus Torvalds } 20881da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_METADATA) { 20891da177e4SLinus Torvalds if ((buflen -= 12) < 0) 20901da177e4SLinus Torvalds goto out_resource; 20911da177e4SLinus Torvalds WRITE32(0); 20921da177e4SLinus Torvalds WRITE32(stat.ctime.tv_sec); 20931da177e4SLinus Torvalds WRITE32(stat.ctime.tv_nsec); 20941da177e4SLinus Torvalds } 20951da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { 20961da177e4SLinus Torvalds if ((buflen -= 12) < 0) 20971da177e4SLinus Torvalds goto out_resource; 20981da177e4SLinus Torvalds WRITE32(0); 20991da177e4SLinus Torvalds WRITE32(stat.mtime.tv_sec); 21001da177e4SLinus Torvalds WRITE32(stat.mtime.tv_nsec); 21011da177e4SLinus Torvalds } 21021da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { 21031da177e4SLinus Torvalds if ((buflen -= 8) < 0) 21041da177e4SLinus Torvalds goto out_resource; 2105406a7ea9SFrank Filz /* 2106406a7ea9SFrank Filz * Get parent's attributes if not ignoring crossmount 2107406a7ea9SFrank Filz * and this is the root of a cross-mounted filesystem. 2108406a7ea9SFrank Filz */ 2109406a7ea9SFrank Filz if (ignore_crossmnt == 0 && 211054775491SJan Blunck exp->ex_path.mnt->mnt_root->d_inode == dentry->d_inode) { 211154775491SJan Blunck err = vfs_getattr(exp->ex_path.mnt->mnt_parent, 211254775491SJan Blunck exp->ex_path.mnt->mnt_mountpoint, &stat); 211340ee5dc6SPeter Staubach if (err) 211440ee5dc6SPeter Staubach goto out_nfserr; 211540ee5dc6SPeter Staubach } 211640ee5dc6SPeter Staubach WRITE64(stat.ino); 21171da177e4SLinus Torvalds } 21181da177e4SLinus Torvalds *attrlenp = htonl((char *)p - (char *)attrlenp - 4); 21191da177e4SLinus Torvalds *countp = p - buffer; 21201da177e4SLinus Torvalds status = nfs_ok; 21211da177e4SLinus Torvalds 21221da177e4SLinus Torvalds out: 212328e05dd8SJ. Bruce Fields kfree(acl); 21241da177e4SLinus Torvalds if (fhp == &tempfh) 21251da177e4SLinus Torvalds fh_put(&tempfh); 21261da177e4SLinus Torvalds return status; 21271da177e4SLinus Torvalds out_nfserr: 2128b8dd7b9aSAl Viro status = nfserrno(err); 21291da177e4SLinus Torvalds goto out; 21301da177e4SLinus Torvalds out_resource: 21311da177e4SLinus Torvalds *countp = 0; 21321da177e4SLinus Torvalds status = nfserr_resource; 21331da177e4SLinus Torvalds goto out; 21341da177e4SLinus Torvalds out_serverfault: 21351da177e4SLinus Torvalds status = nfserr_serverfault; 21361da177e4SLinus Torvalds goto out; 21371da177e4SLinus Torvalds } 21381da177e4SLinus Torvalds 2139c0ce6ec8SJ. Bruce Fields static inline int attributes_need_mount(u32 *bmval) 2140c0ce6ec8SJ. Bruce Fields { 2141c0ce6ec8SJ. Bruce Fields if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME)) 2142c0ce6ec8SJ. Bruce Fields return 1; 2143c0ce6ec8SJ. Bruce Fields if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) 2144c0ce6ec8SJ. Bruce Fields return 1; 2145c0ce6ec8SJ. Bruce Fields return 0; 2146c0ce6ec8SJ. Bruce Fields } 2147c0ce6ec8SJ. Bruce Fields 2148b37ad28bSAl Viro static __be32 21491da177e4SLinus Torvalds nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, 21502ebbc012SAl Viro const char *name, int namlen, __be32 *p, int *buflen) 21511da177e4SLinus Torvalds { 21521da177e4SLinus Torvalds struct svc_export *exp = cd->rd_fhp->fh_export; 21531da177e4SLinus Torvalds struct dentry *dentry; 2154b37ad28bSAl Viro __be32 nfserr; 2155406a7ea9SFrank Filz int ignore_crossmnt = 0; 21561da177e4SLinus Torvalds 21571da177e4SLinus Torvalds dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); 21581da177e4SLinus Torvalds if (IS_ERR(dentry)) 21591da177e4SLinus Torvalds return nfserrno(PTR_ERR(dentry)); 21601da177e4SLinus Torvalds 21611da177e4SLinus Torvalds exp_get(exp); 2162406a7ea9SFrank Filz /* 2163406a7ea9SFrank Filz * In the case of a mountpoint, the client may be asking for 2164406a7ea9SFrank Filz * attributes that are only properties of the underlying filesystem 2165406a7ea9SFrank Filz * as opposed to the cross-mounted file system. In such a case, 2166406a7ea9SFrank Filz * we will not follow the cross mount and will fill the attribtutes 2167406a7ea9SFrank Filz * directly from the mountpoint dentry. 2168406a7ea9SFrank Filz */ 2169c0ce6ec8SJ. Bruce Fields if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval)) 2170406a7ea9SFrank Filz ignore_crossmnt = 1; 2171406a7ea9SFrank Filz else if (d_mountpoint(dentry)) { 2172021d3a72SJ.Bruce Fields int err; 2173021d3a72SJ.Bruce Fields 2174dcb488a3SAndy Adamson /* 2175dcb488a3SAndy Adamson * Why the heck aren't we just using nfsd_lookup?? 2176dcb488a3SAndy Adamson * Different "."/".." handling? Something else? 2177dcb488a3SAndy Adamson * At least, add a comment here to explain.... 2178dcb488a3SAndy Adamson */ 2179021d3a72SJ.Bruce Fields err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); 2180021d3a72SJ.Bruce Fields if (err) { 2181021d3a72SJ.Bruce Fields nfserr = nfserrno(err); 21821da177e4SLinus Torvalds goto out_put; 21831da177e4SLinus Torvalds } 2184dcb488a3SAndy Adamson nfserr = check_nfsd_access(exp, cd->rd_rqstp); 2185dcb488a3SAndy Adamson if (nfserr) 2186dcb488a3SAndy Adamson goto out_put; 21871da177e4SLinus Torvalds 21881da177e4SLinus Torvalds } 21891da177e4SLinus Torvalds nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, 2190406a7ea9SFrank Filz cd->rd_rqstp, ignore_crossmnt); 21911da177e4SLinus Torvalds out_put: 21921da177e4SLinus Torvalds dput(dentry); 21931da177e4SLinus Torvalds exp_put(exp); 21941da177e4SLinus Torvalds return nfserr; 21951da177e4SLinus Torvalds } 21961da177e4SLinus Torvalds 21972ebbc012SAl Viro static __be32 * 2198b37ad28bSAl Viro nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr) 21991da177e4SLinus Torvalds { 22002ebbc012SAl Viro __be32 *attrlenp; 22011da177e4SLinus Torvalds 22021da177e4SLinus Torvalds if (buflen < 6) 22031da177e4SLinus Torvalds return NULL; 22041da177e4SLinus Torvalds *p++ = htonl(2); 22051da177e4SLinus Torvalds *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */ 22061da177e4SLinus Torvalds *p++ = htonl(0); /* bmval1 */ 22071da177e4SLinus Torvalds 22081da177e4SLinus Torvalds attrlenp = p++; 22091da177e4SLinus Torvalds *p++ = nfserr; /* no htonl */ 22101da177e4SLinus Torvalds *attrlenp = htonl((char *)p - (char *)attrlenp - 4); 22111da177e4SLinus Torvalds return p; 22121da177e4SLinus Torvalds } 22131da177e4SLinus Torvalds 22141da177e4SLinus Torvalds static int 2215a0ad13efSNeilBrown nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, 2216a0ad13efSNeilBrown loff_t offset, u64 ino, unsigned int d_type) 22171da177e4SLinus Torvalds { 2218a0ad13efSNeilBrown struct readdir_cd *ccd = ccdv; 22191da177e4SLinus Torvalds struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); 22201da177e4SLinus Torvalds int buflen; 22212ebbc012SAl Viro __be32 *p = cd->buffer; 2222b37ad28bSAl Viro __be32 nfserr = nfserr_toosmall; 22231da177e4SLinus Torvalds 22241da177e4SLinus Torvalds /* In nfsv4, "." and ".." never make it onto the wire.. */ 22251da177e4SLinus Torvalds if (name && isdotent(name, namlen)) { 22261da177e4SLinus Torvalds cd->common.err = nfs_ok; 22271da177e4SLinus Torvalds return 0; 22281da177e4SLinus Torvalds } 22291da177e4SLinus Torvalds 22301da177e4SLinus Torvalds if (cd->offset) 22311da177e4SLinus Torvalds xdr_encode_hyper(cd->offset, (u64) offset); 22321da177e4SLinus Torvalds 22331da177e4SLinus Torvalds buflen = cd->buflen - 4 - XDR_QUADLEN(namlen); 22341da177e4SLinus Torvalds if (buflen < 0) 22351da177e4SLinus Torvalds goto fail; 22361da177e4SLinus Torvalds 22371da177e4SLinus Torvalds *p++ = xdr_one; /* mark entry present */ 22381da177e4SLinus Torvalds cd->offset = p; /* remember pointer */ 22391da177e4SLinus Torvalds p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */ 22401da177e4SLinus Torvalds p = xdr_encode_array(p, name, namlen); /* name length & name */ 22411da177e4SLinus Torvalds 22421da177e4SLinus Torvalds nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, p, &buflen); 22431da177e4SLinus Torvalds switch (nfserr) { 22441da177e4SLinus Torvalds case nfs_ok: 22451da177e4SLinus Torvalds p += buflen; 22461da177e4SLinus Torvalds break; 22471da177e4SLinus Torvalds case nfserr_resource: 22481da177e4SLinus Torvalds nfserr = nfserr_toosmall; 22491da177e4SLinus Torvalds goto fail; 22501da177e4SLinus Torvalds case nfserr_dropit: 22511da177e4SLinus Torvalds goto fail; 22521da177e4SLinus Torvalds default: 22531da177e4SLinus Torvalds /* 22541da177e4SLinus Torvalds * If the client requested the RDATTR_ERROR attribute, 22551da177e4SLinus Torvalds * we stuff the error code into this attribute 22561da177e4SLinus Torvalds * and continue. If this attribute was not requested, 22571da177e4SLinus Torvalds * then in accordance with the spec, we fail the 22581da177e4SLinus Torvalds * entire READDIR operation(!) 22591da177e4SLinus Torvalds */ 22601da177e4SLinus Torvalds if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) 22611da177e4SLinus Torvalds goto fail; 22621da177e4SLinus Torvalds p = nfsd4_encode_rdattr_error(p, buflen, nfserr); 226334081efcSFred Isaman if (p == NULL) { 226434081efcSFred Isaman nfserr = nfserr_toosmall; 22651da177e4SLinus Torvalds goto fail; 22661da177e4SLinus Torvalds } 226734081efcSFred Isaman } 22681da177e4SLinus Torvalds cd->buflen -= (p - cd->buffer); 22691da177e4SLinus Torvalds cd->buffer = p; 22701da177e4SLinus Torvalds cd->common.err = nfs_ok; 22711da177e4SLinus Torvalds return 0; 22721da177e4SLinus Torvalds fail: 22731da177e4SLinus Torvalds cd->common.err = nfserr; 22741da177e4SLinus Torvalds return -EINVAL; 22751da177e4SLinus Torvalds } 22761da177e4SLinus Torvalds 2277e2f282b9SBenny Halevy static void 2278e2f282b9SBenny Halevy nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) 2279e2f282b9SBenny Halevy { 2280e2f282b9SBenny Halevy ENCODE_HEAD; 2281e2f282b9SBenny Halevy 2282e2f282b9SBenny Halevy RESERVE_SPACE(sizeof(stateid_t)); 2283e2f282b9SBenny Halevy WRITE32(sid->si_generation); 2284e2f282b9SBenny Halevy WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); 2285e2f282b9SBenny Halevy ADJUST_ARGS(); 2286e2f282b9SBenny Halevy } 2287e2f282b9SBenny Halevy 2288695e12f8SBenny Halevy static __be32 2289b37ad28bSAl Viro nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) 22901da177e4SLinus Torvalds { 22911da177e4SLinus Torvalds ENCODE_HEAD; 22921da177e4SLinus Torvalds 22931da177e4SLinus Torvalds if (!nfserr) { 22941da177e4SLinus Torvalds RESERVE_SPACE(8); 22951da177e4SLinus Torvalds WRITE32(access->ac_supported); 22961da177e4SLinus Torvalds WRITE32(access->ac_resp_access); 22971da177e4SLinus Torvalds ADJUST_ARGS(); 22981da177e4SLinus Torvalds } 2299695e12f8SBenny Halevy return nfserr; 23001da177e4SLinus Torvalds } 23011da177e4SLinus Torvalds 2302695e12f8SBenny Halevy static __be32 2303b37ad28bSAl Viro nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) 23041da177e4SLinus Torvalds { 23051da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 23061da177e4SLinus Torvalds 2307e2f282b9SBenny Halevy if (!nfserr) 2308e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &close->cl_stateid); 2309e2f282b9SBenny Halevy 23101da177e4SLinus Torvalds ENCODE_SEQID_OP_TAIL(close->cl_stateowner); 2311695e12f8SBenny Halevy return nfserr; 23121da177e4SLinus Torvalds } 23131da177e4SLinus Torvalds 23141da177e4SLinus Torvalds 2315695e12f8SBenny Halevy static __be32 2316b37ad28bSAl Viro nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) 23171da177e4SLinus Torvalds { 23181da177e4SLinus Torvalds ENCODE_HEAD; 23191da177e4SLinus Torvalds 23201da177e4SLinus Torvalds if (!nfserr) { 23211da177e4SLinus Torvalds RESERVE_SPACE(8); 23221da177e4SLinus Torvalds WRITEMEM(commit->co_verf.data, 8); 23231da177e4SLinus Torvalds ADJUST_ARGS(); 23241da177e4SLinus Torvalds } 2325695e12f8SBenny Halevy return nfserr; 23261da177e4SLinus Torvalds } 23271da177e4SLinus Torvalds 2328695e12f8SBenny Halevy static __be32 2329b37ad28bSAl Viro nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) 23301da177e4SLinus Torvalds { 23311da177e4SLinus Torvalds ENCODE_HEAD; 23321da177e4SLinus Torvalds 23331da177e4SLinus Torvalds if (!nfserr) { 23341da177e4SLinus Torvalds RESERVE_SPACE(32); 23351da177e4SLinus Torvalds WRITECINFO(create->cr_cinfo); 23361da177e4SLinus Torvalds WRITE32(2); 23371da177e4SLinus Torvalds WRITE32(create->cr_bmval[0]); 23381da177e4SLinus Torvalds WRITE32(create->cr_bmval[1]); 23391da177e4SLinus Torvalds ADJUST_ARGS(); 23401da177e4SLinus Torvalds } 2341695e12f8SBenny Halevy return nfserr; 23421da177e4SLinus Torvalds } 23431da177e4SLinus Torvalds 2344b37ad28bSAl Viro static __be32 2345b37ad28bSAl Viro nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr) 23461da177e4SLinus Torvalds { 23471da177e4SLinus Torvalds struct svc_fh *fhp = getattr->ga_fhp; 23481da177e4SLinus Torvalds int buflen; 23491da177e4SLinus Torvalds 23501da177e4SLinus Torvalds if (nfserr) 23511da177e4SLinus Torvalds return nfserr; 23521da177e4SLinus Torvalds 23531da177e4SLinus Torvalds buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2); 23541da177e4SLinus Torvalds nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry, 23551da177e4SLinus Torvalds resp->p, &buflen, getattr->ga_bmval, 2356406a7ea9SFrank Filz resp->rqstp, 0); 23571da177e4SLinus Torvalds if (!nfserr) 23581da177e4SLinus Torvalds resp->p += buflen; 23591da177e4SLinus Torvalds return nfserr; 23601da177e4SLinus Torvalds } 23611da177e4SLinus Torvalds 2362695e12f8SBenny Halevy static __be32 2363695e12f8SBenny Halevy nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp) 23641da177e4SLinus Torvalds { 2365695e12f8SBenny Halevy struct svc_fh *fhp = *fhpp; 23661da177e4SLinus Torvalds unsigned int len; 23671da177e4SLinus Torvalds ENCODE_HEAD; 23681da177e4SLinus Torvalds 23691da177e4SLinus Torvalds if (!nfserr) { 23701da177e4SLinus Torvalds len = fhp->fh_handle.fh_size; 23711da177e4SLinus Torvalds RESERVE_SPACE(len + 4); 23721da177e4SLinus Torvalds WRITE32(len); 23731da177e4SLinus Torvalds WRITEMEM(&fhp->fh_handle.fh_base, len); 23741da177e4SLinus Torvalds ADJUST_ARGS(); 23751da177e4SLinus Torvalds } 2376695e12f8SBenny Halevy return nfserr; 23771da177e4SLinus Torvalds } 23781da177e4SLinus Torvalds 23791da177e4SLinus Torvalds /* 23801da177e4SLinus Torvalds * Including all fields other than the name, a LOCK4denied structure requires 23811da177e4SLinus Torvalds * 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes. 23821da177e4SLinus Torvalds */ 23831da177e4SLinus Torvalds static void 23841da177e4SLinus Torvalds nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) 23851da177e4SLinus Torvalds { 23861da177e4SLinus Torvalds ENCODE_HEAD; 23871da177e4SLinus Torvalds 23881da177e4SLinus Torvalds RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); 23891da177e4SLinus Torvalds WRITE64(ld->ld_start); 23901da177e4SLinus Torvalds WRITE64(ld->ld_length); 23911da177e4SLinus Torvalds WRITE32(ld->ld_type); 23921da177e4SLinus Torvalds if (ld->ld_sop) { 23931da177e4SLinus Torvalds WRITEMEM(&ld->ld_clientid, 8); 23941da177e4SLinus Torvalds WRITE32(ld->ld_sop->so_owner.len); 23951da177e4SLinus Torvalds WRITEMEM(ld->ld_sop->so_owner.data, ld->ld_sop->so_owner.len); 23961da177e4SLinus Torvalds kref_put(&ld->ld_sop->so_ref, nfs4_free_stateowner); 23971da177e4SLinus Torvalds } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ 23981da177e4SLinus Torvalds WRITE64((u64)0); /* clientid */ 23991da177e4SLinus Torvalds WRITE32(0); /* length of owner name */ 24001da177e4SLinus Torvalds } 24011da177e4SLinus Torvalds ADJUST_ARGS(); 24021da177e4SLinus Torvalds } 24031da177e4SLinus Torvalds 2404695e12f8SBenny Halevy static __be32 2405b37ad28bSAl Viro nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) 24061da177e4SLinus Torvalds { 24071da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 24081da177e4SLinus Torvalds 2409e2f282b9SBenny Halevy if (!nfserr) 2410e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &lock->lk_resp_stateid); 2411e2f282b9SBenny Halevy else if (nfserr == nfserr_denied) 24121da177e4SLinus Torvalds nfsd4_encode_lock_denied(resp, &lock->lk_denied); 24131da177e4SLinus Torvalds 24143a65588aSJ. Bruce Fields ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner); 2415695e12f8SBenny Halevy return nfserr; 24161da177e4SLinus Torvalds } 24171da177e4SLinus Torvalds 2418695e12f8SBenny Halevy static __be32 2419b37ad28bSAl Viro nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) 24201da177e4SLinus Torvalds { 24211da177e4SLinus Torvalds if (nfserr == nfserr_denied) 24221da177e4SLinus Torvalds nfsd4_encode_lock_denied(resp, &lockt->lt_denied); 2423695e12f8SBenny Halevy return nfserr; 24241da177e4SLinus Torvalds } 24251da177e4SLinus Torvalds 2426695e12f8SBenny Halevy static __be32 2427b37ad28bSAl Viro nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) 24281da177e4SLinus Torvalds { 24291da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 24301da177e4SLinus Torvalds 2431e2f282b9SBenny Halevy if (!nfserr) 2432e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &locku->lu_stateid); 24331da177e4SLinus Torvalds 24341da177e4SLinus Torvalds ENCODE_SEQID_OP_TAIL(locku->lu_stateowner); 2435695e12f8SBenny Halevy return nfserr; 24361da177e4SLinus Torvalds } 24371da177e4SLinus Torvalds 24381da177e4SLinus Torvalds 2439695e12f8SBenny Halevy static __be32 2440b37ad28bSAl Viro nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) 24411da177e4SLinus Torvalds { 24421da177e4SLinus Torvalds ENCODE_HEAD; 24431da177e4SLinus Torvalds 24441da177e4SLinus Torvalds if (!nfserr) { 24451da177e4SLinus Torvalds RESERVE_SPACE(20); 24461da177e4SLinus Torvalds WRITECINFO(link->li_cinfo); 24471da177e4SLinus Torvalds ADJUST_ARGS(); 24481da177e4SLinus Torvalds } 2449695e12f8SBenny Halevy return nfserr; 24501da177e4SLinus Torvalds } 24511da177e4SLinus Torvalds 24521da177e4SLinus Torvalds 2453695e12f8SBenny Halevy static __be32 2454b37ad28bSAl Viro nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) 24551da177e4SLinus Torvalds { 24561b6b2257SBenny Halevy ENCODE_HEAD; 24571da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 24581da177e4SLinus Torvalds 24591da177e4SLinus Torvalds if (nfserr) 24601da177e4SLinus Torvalds goto out; 24611da177e4SLinus Torvalds 2462e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &open->op_stateid); 2463e2f282b9SBenny Halevy RESERVE_SPACE(40); 24641da177e4SLinus Torvalds WRITECINFO(open->op_cinfo); 24651da177e4SLinus Torvalds WRITE32(open->op_rflags); 24661da177e4SLinus Torvalds WRITE32(2); 24671da177e4SLinus Torvalds WRITE32(open->op_bmval[0]); 24681da177e4SLinus Torvalds WRITE32(open->op_bmval[1]); 24691da177e4SLinus Torvalds WRITE32(open->op_delegate_type); 24701da177e4SLinus Torvalds ADJUST_ARGS(); 24711da177e4SLinus Torvalds 24721da177e4SLinus Torvalds switch (open->op_delegate_type) { 24731da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_NONE: 24741da177e4SLinus Torvalds break; 24751da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_READ: 2476e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &open->op_delegate_stateid); 2477e2f282b9SBenny Halevy RESERVE_SPACE(20); 24787b190fecSNeilBrown WRITE32(open->op_recall); 24791da177e4SLinus Torvalds 24801da177e4SLinus Torvalds /* 24811da177e4SLinus Torvalds * TODO: ACE's in delegations 24821da177e4SLinus Torvalds */ 24831da177e4SLinus Torvalds WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); 24841da177e4SLinus Torvalds WRITE32(0); 24851da177e4SLinus Torvalds WRITE32(0); 24861da177e4SLinus Torvalds WRITE32(0); /* XXX: is NULL principal ok? */ 24871da177e4SLinus Torvalds ADJUST_ARGS(); 24881da177e4SLinus Torvalds break; 24891da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_WRITE: 2490e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &open->op_delegate_stateid); 2491e2f282b9SBenny Halevy RESERVE_SPACE(32); 24921da177e4SLinus Torvalds WRITE32(0); 24931da177e4SLinus Torvalds 24941da177e4SLinus Torvalds /* 24951da177e4SLinus Torvalds * TODO: space_limit's in delegations 24961da177e4SLinus Torvalds */ 24971da177e4SLinus Torvalds WRITE32(NFS4_LIMIT_SIZE); 24981da177e4SLinus Torvalds WRITE32(~(u32)0); 24991da177e4SLinus Torvalds WRITE32(~(u32)0); 25001da177e4SLinus Torvalds 25011da177e4SLinus Torvalds /* 25021da177e4SLinus Torvalds * TODO: ACE's in delegations 25031da177e4SLinus Torvalds */ 25041da177e4SLinus Torvalds WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); 25051da177e4SLinus Torvalds WRITE32(0); 25061da177e4SLinus Torvalds WRITE32(0); 25071da177e4SLinus Torvalds WRITE32(0); /* XXX: is NULL principal ok? */ 25081da177e4SLinus Torvalds ADJUST_ARGS(); 25091da177e4SLinus Torvalds break; 25101da177e4SLinus Torvalds default: 25111da177e4SLinus Torvalds BUG(); 25121da177e4SLinus Torvalds } 25131da177e4SLinus Torvalds /* XXX save filehandle here */ 25141da177e4SLinus Torvalds out: 25151da177e4SLinus Torvalds ENCODE_SEQID_OP_TAIL(open->op_stateowner); 2516695e12f8SBenny Halevy return nfserr; 25171da177e4SLinus Torvalds } 25181da177e4SLinus Torvalds 2519695e12f8SBenny Halevy static __be32 2520b37ad28bSAl Viro nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) 25211da177e4SLinus Torvalds { 25221da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 25231da177e4SLinus Torvalds 2524e2f282b9SBenny Halevy if (!nfserr) 2525e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &oc->oc_resp_stateid); 25261da177e4SLinus Torvalds 25271da177e4SLinus Torvalds ENCODE_SEQID_OP_TAIL(oc->oc_stateowner); 2528695e12f8SBenny Halevy return nfserr; 25291da177e4SLinus Torvalds } 25301da177e4SLinus Torvalds 2531695e12f8SBenny Halevy static __be32 2532b37ad28bSAl Viro nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) 25331da177e4SLinus Torvalds { 25341da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 25351da177e4SLinus Torvalds 2536e2f282b9SBenny Halevy if (!nfserr) 2537e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &od->od_stateid); 25381da177e4SLinus Torvalds 25391da177e4SLinus Torvalds ENCODE_SEQID_OP_TAIL(od->od_stateowner); 2540695e12f8SBenny Halevy return nfserr; 25411da177e4SLinus Torvalds } 25421da177e4SLinus Torvalds 2543b37ad28bSAl Viro static __be32 2544b37ad28bSAl Viro nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, 254544524359SNeilBrown struct nfsd4_read *read) 25461da177e4SLinus Torvalds { 25471da177e4SLinus Torvalds u32 eof; 25481da177e4SLinus Torvalds int v, pn; 25491da177e4SLinus Torvalds unsigned long maxcount; 25501da177e4SLinus Torvalds long len; 25511da177e4SLinus Torvalds ENCODE_HEAD; 25521da177e4SLinus Torvalds 25531da177e4SLinus Torvalds if (nfserr) 25541da177e4SLinus Torvalds return nfserr; 25551da177e4SLinus Torvalds if (resp->xbuf->page_len) 25561da177e4SLinus Torvalds return nfserr_resource; 25571da177e4SLinus Torvalds 25581da177e4SLinus Torvalds RESERVE_SPACE(8); /* eof flag and byte count */ 25591da177e4SLinus Torvalds 25607adae489SGreg Banks maxcount = svc_max_payload(resp->rqstp); 25611da177e4SLinus Torvalds if (maxcount > read->rd_length) 25621da177e4SLinus Torvalds maxcount = read->rd_length; 25631da177e4SLinus Torvalds 25641da177e4SLinus Torvalds len = maxcount; 25651da177e4SLinus Torvalds v = 0; 25661da177e4SLinus Torvalds while (len > 0) { 256744524359SNeilBrown pn = resp->rqstp->rq_resused++; 25683cc03b16SNeilBrown resp->rqstp->rq_vec[v].iov_base = 256944524359SNeilBrown page_address(resp->rqstp->rq_respages[pn]); 25703cc03b16SNeilBrown resp->rqstp->rq_vec[v].iov_len = 257144524359SNeilBrown len < PAGE_SIZE ? len : PAGE_SIZE; 25721da177e4SLinus Torvalds v++; 25731da177e4SLinus Torvalds len -= PAGE_SIZE; 25741da177e4SLinus Torvalds } 25751da177e4SLinus Torvalds read->rd_vlen = v; 25761da177e4SLinus Torvalds 25771da177e4SLinus Torvalds nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp, 25783cc03b16SNeilBrown read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, 25791da177e4SLinus Torvalds &maxcount); 25801da177e4SLinus Torvalds 25811da177e4SLinus Torvalds if (nfserr == nfserr_symlink) 25821da177e4SLinus Torvalds nfserr = nfserr_inval; 25831da177e4SLinus Torvalds if (nfserr) 25841da177e4SLinus Torvalds return nfserr; 258544524359SNeilBrown eof = (read->rd_offset + maxcount >= 258644524359SNeilBrown read->rd_fhp->fh_dentry->d_inode->i_size); 25871da177e4SLinus Torvalds 25881da177e4SLinus Torvalds WRITE32(eof); 25891da177e4SLinus Torvalds WRITE32(maxcount); 25901da177e4SLinus Torvalds ADJUST_ARGS(); 25916ed6deccSNeilBrown resp->xbuf->head[0].iov_len = (char*)p 25926ed6deccSNeilBrown - (char*)resp->xbuf->head[0].iov_base; 25931da177e4SLinus Torvalds resp->xbuf->page_len = maxcount; 25941da177e4SLinus Torvalds 25956ed6deccSNeilBrown /* Use rest of head for padding and remaining ops: */ 25966ed6deccSNeilBrown resp->xbuf->tail[0].iov_base = p; 25971da177e4SLinus Torvalds resp->xbuf->tail[0].iov_len = 0; 25981da177e4SLinus Torvalds if (maxcount&3) { 25996ed6deccSNeilBrown RESERVE_SPACE(4); 26006ed6deccSNeilBrown WRITE32(0); 26011da177e4SLinus Torvalds resp->xbuf->tail[0].iov_base += maxcount&3; 26021da177e4SLinus Torvalds resp->xbuf->tail[0].iov_len = 4 - (maxcount&3); 26036ed6deccSNeilBrown ADJUST_ARGS(); 26041da177e4SLinus Torvalds } 26051da177e4SLinus Torvalds return 0; 26061da177e4SLinus Torvalds } 26071da177e4SLinus Torvalds 2608b37ad28bSAl Viro static __be32 2609b37ad28bSAl Viro nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) 26101da177e4SLinus Torvalds { 26111da177e4SLinus Torvalds int maxcount; 26121da177e4SLinus Torvalds char *page; 26131da177e4SLinus Torvalds ENCODE_HEAD; 26141da177e4SLinus Torvalds 26151da177e4SLinus Torvalds if (nfserr) 26161da177e4SLinus Torvalds return nfserr; 26171da177e4SLinus Torvalds if (resp->xbuf->page_len) 26181da177e4SLinus Torvalds return nfserr_resource; 26191da177e4SLinus Torvalds 262044524359SNeilBrown page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); 26211da177e4SLinus Torvalds 26221da177e4SLinus Torvalds maxcount = PAGE_SIZE; 26231da177e4SLinus Torvalds RESERVE_SPACE(4); 26241da177e4SLinus Torvalds 26251da177e4SLinus Torvalds /* 26261da177e4SLinus Torvalds * XXX: By default, the ->readlink() VFS op will truncate symlinks 26271da177e4SLinus Torvalds * if they would overflow the buffer. Is this kosher in NFSv4? If 26281da177e4SLinus Torvalds * not, one easy fix is: if ->readlink() precisely fills the buffer, 26291da177e4SLinus Torvalds * assume that truncation occurred, and return NFS4ERR_RESOURCE. 26301da177e4SLinus Torvalds */ 26311da177e4SLinus Torvalds nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, page, &maxcount); 26321da177e4SLinus Torvalds if (nfserr == nfserr_isdir) 26331da177e4SLinus Torvalds return nfserr_inval; 26341da177e4SLinus Torvalds if (nfserr) 26351da177e4SLinus Torvalds return nfserr; 26361da177e4SLinus Torvalds 26371da177e4SLinus Torvalds WRITE32(maxcount); 26381da177e4SLinus Torvalds ADJUST_ARGS(); 26396ed6deccSNeilBrown resp->xbuf->head[0].iov_len = (char*)p 26406ed6deccSNeilBrown - (char*)resp->xbuf->head[0].iov_base; 26411da177e4SLinus Torvalds resp->xbuf->page_len = maxcount; 26426ed6deccSNeilBrown 26436ed6deccSNeilBrown /* Use rest of head for padding and remaining ops: */ 26446ed6deccSNeilBrown resp->xbuf->tail[0].iov_base = p; 26456ed6deccSNeilBrown resp->xbuf->tail[0].iov_len = 0; 26461da177e4SLinus Torvalds if (maxcount&3) { 26476ed6deccSNeilBrown RESERVE_SPACE(4); 26486ed6deccSNeilBrown WRITE32(0); 26491da177e4SLinus Torvalds resp->xbuf->tail[0].iov_base += maxcount&3; 26501da177e4SLinus Torvalds resp->xbuf->tail[0].iov_len = 4 - (maxcount&3); 26516ed6deccSNeilBrown ADJUST_ARGS(); 26521da177e4SLinus Torvalds } 26531da177e4SLinus Torvalds return 0; 26541da177e4SLinus Torvalds } 26551da177e4SLinus Torvalds 2656b37ad28bSAl Viro static __be32 2657b37ad28bSAl Viro nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir) 26581da177e4SLinus Torvalds { 26591da177e4SLinus Torvalds int maxcount; 26601da177e4SLinus Torvalds loff_t offset; 26612ebbc012SAl Viro __be32 *page, *savep, *tailbase; 26621da177e4SLinus Torvalds ENCODE_HEAD; 26631da177e4SLinus Torvalds 26641da177e4SLinus Torvalds if (nfserr) 26651da177e4SLinus Torvalds return nfserr; 26661da177e4SLinus Torvalds if (resp->xbuf->page_len) 26671da177e4SLinus Torvalds return nfserr_resource; 26681da177e4SLinus Torvalds 26691da177e4SLinus Torvalds RESERVE_SPACE(8); /* verifier */ 26701da177e4SLinus Torvalds savep = p; 26711da177e4SLinus Torvalds 26721da177e4SLinus Torvalds /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */ 26731da177e4SLinus Torvalds WRITE32(0); 26741da177e4SLinus Torvalds WRITE32(0); 26751da177e4SLinus Torvalds ADJUST_ARGS(); 26761da177e4SLinus Torvalds resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base; 2677bb6e8a9fSNeilBrown tailbase = p; 26781da177e4SLinus Torvalds 26791da177e4SLinus Torvalds maxcount = PAGE_SIZE; 26801da177e4SLinus Torvalds if (maxcount > readdir->rd_maxcount) 26811da177e4SLinus Torvalds maxcount = readdir->rd_maxcount; 26821da177e4SLinus Torvalds 26831da177e4SLinus Torvalds /* 26841da177e4SLinus Torvalds * Convert from bytes to words, account for the two words already 26851da177e4SLinus Torvalds * written, make sure to leave two words at the end for the next 26861da177e4SLinus Torvalds * pointer and eof field. 26871da177e4SLinus Torvalds */ 26881da177e4SLinus Torvalds maxcount = (maxcount >> 2) - 4; 26891da177e4SLinus Torvalds if (maxcount < 0) { 26901da177e4SLinus Torvalds nfserr = nfserr_toosmall; 26911da177e4SLinus Torvalds goto err_no_verf; 26921da177e4SLinus Torvalds } 26931da177e4SLinus Torvalds 269444524359SNeilBrown page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); 26951da177e4SLinus Torvalds readdir->common.err = 0; 26961da177e4SLinus Torvalds readdir->buflen = maxcount; 26971da177e4SLinus Torvalds readdir->buffer = page; 26981da177e4SLinus Torvalds readdir->offset = NULL; 26991da177e4SLinus Torvalds 27001da177e4SLinus Torvalds offset = readdir->rd_cookie; 27011da177e4SLinus Torvalds nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, 27021da177e4SLinus Torvalds &offset, 27031da177e4SLinus Torvalds &readdir->common, nfsd4_encode_dirent); 27041da177e4SLinus Torvalds if (nfserr == nfs_ok && 27051da177e4SLinus Torvalds readdir->common.err == nfserr_toosmall && 27061da177e4SLinus Torvalds readdir->buffer == page) 27071da177e4SLinus Torvalds nfserr = nfserr_toosmall; 27081da177e4SLinus Torvalds if (nfserr == nfserr_symlink) 27091da177e4SLinus Torvalds nfserr = nfserr_notdir; 27101da177e4SLinus Torvalds if (nfserr) 27111da177e4SLinus Torvalds goto err_no_verf; 27121da177e4SLinus Torvalds 27131da177e4SLinus Torvalds if (readdir->offset) 27141da177e4SLinus Torvalds xdr_encode_hyper(readdir->offset, offset); 27151da177e4SLinus Torvalds 27161da177e4SLinus Torvalds p = readdir->buffer; 27171da177e4SLinus Torvalds *p++ = 0; /* no more entries */ 27181da177e4SLinus Torvalds *p++ = htonl(readdir->common.err == nfserr_eof); 271944524359SNeilBrown resp->xbuf->page_len = ((char*)p) - (char*)page_address( 272044524359SNeilBrown resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); 27211da177e4SLinus Torvalds 2722bb6e8a9fSNeilBrown /* Use rest of head for padding and remaining ops: */ 2723bb6e8a9fSNeilBrown resp->xbuf->tail[0].iov_base = tailbase; 27241da177e4SLinus Torvalds resp->xbuf->tail[0].iov_len = 0; 27251da177e4SLinus Torvalds resp->p = resp->xbuf->tail[0].iov_base; 2726bb6e8a9fSNeilBrown resp->end = resp->p + (PAGE_SIZE - resp->xbuf->head[0].iov_len)/4; 27271da177e4SLinus Torvalds 27281da177e4SLinus Torvalds return 0; 27291da177e4SLinus Torvalds err_no_verf: 27301da177e4SLinus Torvalds p = savep; 27311da177e4SLinus Torvalds ADJUST_ARGS(); 27321da177e4SLinus Torvalds return nfserr; 27331da177e4SLinus Torvalds } 27341da177e4SLinus Torvalds 2735695e12f8SBenny Halevy static __be32 2736b37ad28bSAl Viro nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) 27371da177e4SLinus Torvalds { 27381da177e4SLinus Torvalds ENCODE_HEAD; 27391da177e4SLinus Torvalds 27401da177e4SLinus Torvalds if (!nfserr) { 27411da177e4SLinus Torvalds RESERVE_SPACE(20); 27421da177e4SLinus Torvalds WRITECINFO(remove->rm_cinfo); 27431da177e4SLinus Torvalds ADJUST_ARGS(); 27441da177e4SLinus Torvalds } 2745695e12f8SBenny Halevy return nfserr; 27461da177e4SLinus Torvalds } 27471da177e4SLinus Torvalds 2748695e12f8SBenny Halevy static __be32 2749b37ad28bSAl Viro nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) 27501da177e4SLinus Torvalds { 27511da177e4SLinus Torvalds ENCODE_HEAD; 27521da177e4SLinus Torvalds 27531da177e4SLinus Torvalds if (!nfserr) { 27541da177e4SLinus Torvalds RESERVE_SPACE(40); 27551da177e4SLinus Torvalds WRITECINFO(rename->rn_sinfo); 27561da177e4SLinus Torvalds WRITECINFO(rename->rn_tinfo); 27571da177e4SLinus Torvalds ADJUST_ARGS(); 27581da177e4SLinus Torvalds } 2759695e12f8SBenny Halevy return nfserr; 27601da177e4SLinus Torvalds } 27611da177e4SLinus Torvalds 2762695e12f8SBenny Halevy static __be32 2763ca5c8cdeSAl Viro nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, 2764dcb488a3SAndy Adamson struct nfsd4_secinfo *secinfo) 2765dcb488a3SAndy Adamson { 2766dcb488a3SAndy Adamson int i = 0; 2767dcb488a3SAndy Adamson struct svc_export *exp = secinfo->si_exp; 27684796f457SJ. Bruce Fields u32 nflavs; 27694796f457SJ. Bruce Fields struct exp_flavor_info *flavs; 27704796f457SJ. Bruce Fields struct exp_flavor_info def_flavs[2]; 2771dcb488a3SAndy Adamson ENCODE_HEAD; 2772dcb488a3SAndy Adamson 2773dcb488a3SAndy Adamson if (nfserr) 2774dcb488a3SAndy Adamson goto out; 27754796f457SJ. Bruce Fields if (exp->ex_nflavors) { 27764796f457SJ. Bruce Fields flavs = exp->ex_flavors; 27774796f457SJ. Bruce Fields nflavs = exp->ex_nflavors; 27784796f457SJ. Bruce Fields } else { /* Handling of some defaults in absence of real secinfo: */ 27794796f457SJ. Bruce Fields flavs = def_flavs; 27804796f457SJ. Bruce Fields if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) { 27814796f457SJ. Bruce Fields nflavs = 2; 27824796f457SJ. Bruce Fields flavs[0].pseudoflavor = RPC_AUTH_UNIX; 27834796f457SJ. Bruce Fields flavs[1].pseudoflavor = RPC_AUTH_NULL; 27844796f457SJ. Bruce Fields } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) { 27854796f457SJ. Bruce Fields nflavs = 1; 27864796f457SJ. Bruce Fields flavs[0].pseudoflavor 27874796f457SJ. Bruce Fields = svcauth_gss_flavor(exp->ex_client); 27884796f457SJ. Bruce Fields } else { 27894796f457SJ. Bruce Fields nflavs = 1; 27904796f457SJ. Bruce Fields flavs[0].pseudoflavor 27914796f457SJ. Bruce Fields = exp->ex_client->flavour->flavour; 27924796f457SJ. Bruce Fields } 27934796f457SJ. Bruce Fields } 27944796f457SJ. Bruce Fields 2795dcb488a3SAndy Adamson RESERVE_SPACE(4); 27964796f457SJ. Bruce Fields WRITE32(nflavs); 2797dcb488a3SAndy Adamson ADJUST_ARGS(); 27984796f457SJ. Bruce Fields for (i = 0; i < nflavs; i++) { 27994796f457SJ. Bruce Fields u32 flav = flavs[i].pseudoflavor; 2800dcb488a3SAndy Adamson struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav); 2801dcb488a3SAndy Adamson 2802dcb488a3SAndy Adamson if (gm) { 2803dcb488a3SAndy Adamson RESERVE_SPACE(4); 2804dcb488a3SAndy Adamson WRITE32(RPC_AUTH_GSS); 2805dcb488a3SAndy Adamson ADJUST_ARGS(); 2806dcb488a3SAndy Adamson RESERVE_SPACE(4 + gm->gm_oid.len); 2807dcb488a3SAndy Adamson WRITE32(gm->gm_oid.len); 2808dcb488a3SAndy Adamson WRITEMEM(gm->gm_oid.data, gm->gm_oid.len); 2809dcb488a3SAndy Adamson ADJUST_ARGS(); 2810dcb488a3SAndy Adamson RESERVE_SPACE(4); 2811dcb488a3SAndy Adamson WRITE32(0); /* qop */ 2812dcb488a3SAndy Adamson ADJUST_ARGS(); 2813dcb488a3SAndy Adamson RESERVE_SPACE(4); 2814dcb488a3SAndy Adamson WRITE32(gss_pseudoflavor_to_service(gm, flav)); 2815dcb488a3SAndy Adamson ADJUST_ARGS(); 2816dcb488a3SAndy Adamson gss_mech_put(gm); 2817dcb488a3SAndy Adamson } else { 2818dcb488a3SAndy Adamson RESERVE_SPACE(4); 2819dcb488a3SAndy Adamson WRITE32(flav); 2820dcb488a3SAndy Adamson ADJUST_ARGS(); 2821dcb488a3SAndy Adamson } 2822dcb488a3SAndy Adamson } 2823dcb488a3SAndy Adamson out: 2824dcb488a3SAndy Adamson if (exp) 2825dcb488a3SAndy Adamson exp_put(exp); 2826695e12f8SBenny Halevy return nfserr; 2827dcb488a3SAndy Adamson } 2828dcb488a3SAndy Adamson 28291da177e4SLinus Torvalds /* 28301da177e4SLinus Torvalds * The SETATTR encode routine is special -- it always encodes a bitmap, 28311da177e4SLinus Torvalds * regardless of the error status. 28321da177e4SLinus Torvalds */ 2833695e12f8SBenny Halevy static __be32 2834b37ad28bSAl Viro nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) 28351da177e4SLinus Torvalds { 28361da177e4SLinus Torvalds ENCODE_HEAD; 28371da177e4SLinus Torvalds 28381da177e4SLinus Torvalds RESERVE_SPACE(12); 28391da177e4SLinus Torvalds if (nfserr) { 28401da177e4SLinus Torvalds WRITE32(2); 28411da177e4SLinus Torvalds WRITE32(0); 28421da177e4SLinus Torvalds WRITE32(0); 28431da177e4SLinus Torvalds } 28441da177e4SLinus Torvalds else { 28451da177e4SLinus Torvalds WRITE32(2); 28461da177e4SLinus Torvalds WRITE32(setattr->sa_bmval[0]); 28471da177e4SLinus Torvalds WRITE32(setattr->sa_bmval[1]); 28481da177e4SLinus Torvalds } 28491da177e4SLinus Torvalds ADJUST_ARGS(); 2850695e12f8SBenny Halevy return nfserr; 28511da177e4SLinus Torvalds } 28521da177e4SLinus Torvalds 2853695e12f8SBenny Halevy static __be32 2854b37ad28bSAl Viro nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) 28551da177e4SLinus Torvalds { 28561da177e4SLinus Torvalds ENCODE_HEAD; 28571da177e4SLinus Torvalds 28581da177e4SLinus Torvalds if (!nfserr) { 28591da177e4SLinus Torvalds RESERVE_SPACE(8 + sizeof(nfs4_verifier)); 28601da177e4SLinus Torvalds WRITEMEM(&scd->se_clientid, 8); 28611da177e4SLinus Torvalds WRITEMEM(&scd->se_confirm, sizeof(nfs4_verifier)); 28621da177e4SLinus Torvalds ADJUST_ARGS(); 28631da177e4SLinus Torvalds } 28641da177e4SLinus Torvalds else if (nfserr == nfserr_clid_inuse) { 28651da177e4SLinus Torvalds RESERVE_SPACE(8); 28661da177e4SLinus Torvalds WRITE32(0); 28671da177e4SLinus Torvalds WRITE32(0); 28681da177e4SLinus Torvalds ADJUST_ARGS(); 28691da177e4SLinus Torvalds } 2870695e12f8SBenny Halevy return nfserr; 28711da177e4SLinus Torvalds } 28721da177e4SLinus Torvalds 2873695e12f8SBenny Halevy static __be32 2874b37ad28bSAl Viro nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) 28751da177e4SLinus Torvalds { 28761da177e4SLinus Torvalds ENCODE_HEAD; 28771da177e4SLinus Torvalds 28781da177e4SLinus Torvalds if (!nfserr) { 28791da177e4SLinus Torvalds RESERVE_SPACE(16); 28801da177e4SLinus Torvalds WRITE32(write->wr_bytes_written); 28811da177e4SLinus Torvalds WRITE32(write->wr_how_written); 28821da177e4SLinus Torvalds WRITEMEM(write->wr_verifier.data, 8); 28831da177e4SLinus Torvalds ADJUST_ARGS(); 28841da177e4SLinus Torvalds } 2885695e12f8SBenny Halevy return nfserr; 28861da177e4SLinus Torvalds } 28871da177e4SLinus Torvalds 2888695e12f8SBenny Halevy static __be32 28892db134ebSAndy Adamson nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, 28902db134ebSAndy Adamson struct nfsd4_exchange_id *exid) 28912db134ebSAndy Adamson { 28920733d213SAndy Adamson ENCODE_HEAD; 28930733d213SAndy Adamson char *major_id; 28940733d213SAndy Adamson char *server_scope; 28950733d213SAndy Adamson int major_id_sz; 28960733d213SAndy Adamson int server_scope_sz; 28970733d213SAndy Adamson uint64_t minor_id = 0; 28980733d213SAndy Adamson 28990733d213SAndy Adamson if (nfserr) 29002db134ebSAndy Adamson return nfserr; 29010733d213SAndy Adamson 29020733d213SAndy Adamson major_id = utsname()->nodename; 29030733d213SAndy Adamson major_id_sz = strlen(major_id); 29040733d213SAndy Adamson server_scope = utsname()->nodename; 29050733d213SAndy Adamson server_scope_sz = strlen(server_scope); 29060733d213SAndy Adamson 29070733d213SAndy Adamson RESERVE_SPACE( 29080733d213SAndy Adamson 8 /* eir_clientid */ + 29090733d213SAndy Adamson 4 /* eir_sequenceid */ + 29100733d213SAndy Adamson 4 /* eir_flags */ + 29110733d213SAndy Adamson 4 /* spr_how (SP4_NONE) */ + 29120733d213SAndy Adamson 8 /* so_minor_id */ + 29130733d213SAndy Adamson 4 /* so_major_id.len */ + 29140733d213SAndy Adamson (XDR_QUADLEN(major_id_sz) * 4) + 29150733d213SAndy Adamson 4 /* eir_server_scope.len */ + 29160733d213SAndy Adamson (XDR_QUADLEN(server_scope_sz) * 4) + 29170733d213SAndy Adamson 4 /* eir_server_impl_id.count (0) */); 29180733d213SAndy Adamson 29190733d213SAndy Adamson WRITEMEM(&exid->clientid, 8); 29200733d213SAndy Adamson WRITE32(exid->seqid); 29210733d213SAndy Adamson WRITE32(exid->flags); 29220733d213SAndy Adamson 29230733d213SAndy Adamson /* state_protect4_r. Currently only support SP4_NONE */ 29240733d213SAndy Adamson BUG_ON(exid->spa_how != SP4_NONE); 29250733d213SAndy Adamson WRITE32(exid->spa_how); 29260733d213SAndy Adamson 29270733d213SAndy Adamson /* The server_owner struct */ 29280733d213SAndy Adamson WRITE64(minor_id); /* Minor id */ 29290733d213SAndy Adamson /* major id */ 29300733d213SAndy Adamson WRITE32(major_id_sz); 29310733d213SAndy Adamson WRITEMEM(major_id, major_id_sz); 29320733d213SAndy Adamson 29330733d213SAndy Adamson /* Server scope */ 29340733d213SAndy Adamson WRITE32(server_scope_sz); 29350733d213SAndy Adamson WRITEMEM(server_scope, server_scope_sz); 29360733d213SAndy Adamson 29370733d213SAndy Adamson /* Implementation id */ 29380733d213SAndy Adamson WRITE32(0); /* zero length nfs_impl_id4 array */ 29390733d213SAndy Adamson ADJUST_ARGS(); 29400733d213SAndy Adamson return 0; 29412db134ebSAndy Adamson } 29422db134ebSAndy Adamson 29432db134ebSAndy Adamson static __be32 29442db134ebSAndy Adamson nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, 29452db134ebSAndy Adamson struct nfsd4_create_session *sess) 29462db134ebSAndy Adamson { 2947ec6b5d7bSAndy Adamson ENCODE_HEAD; 2948ec6b5d7bSAndy Adamson 2949ec6b5d7bSAndy Adamson if (nfserr) 29502db134ebSAndy Adamson return nfserr; 2951ec6b5d7bSAndy Adamson 2952ec6b5d7bSAndy Adamson RESERVE_SPACE(24); 2953ec6b5d7bSAndy Adamson WRITEMEM(sess->sessionid.data, NFS4_MAX_SESSIONID_LEN); 2954ec6b5d7bSAndy Adamson WRITE32(sess->seqid); 2955ec6b5d7bSAndy Adamson WRITE32(sess->flags); 2956ec6b5d7bSAndy Adamson ADJUST_ARGS(); 2957ec6b5d7bSAndy Adamson 2958ec6b5d7bSAndy Adamson RESERVE_SPACE(28); 2959ec6b5d7bSAndy Adamson WRITE32(0); /* headerpadsz */ 2960ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxreq_sz); 2961ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxresp_sz); 2962ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxresp_cached); 2963ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxops); 2964ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxreqs); 2965ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.nr_rdma_attrs); 2966ec6b5d7bSAndy Adamson ADJUST_ARGS(); 2967ec6b5d7bSAndy Adamson 2968ec6b5d7bSAndy Adamson if (sess->fore_channel.nr_rdma_attrs) { 2969ec6b5d7bSAndy Adamson RESERVE_SPACE(4); 2970ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.rdma_attrs); 2971ec6b5d7bSAndy Adamson ADJUST_ARGS(); 2972ec6b5d7bSAndy Adamson } 2973ec6b5d7bSAndy Adamson 2974ec6b5d7bSAndy Adamson RESERVE_SPACE(28); 2975ec6b5d7bSAndy Adamson WRITE32(0); /* headerpadsz */ 2976ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxreq_sz); 2977ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxresp_sz); 2978ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxresp_cached); 2979ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxops); 2980ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxreqs); 2981ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.nr_rdma_attrs); 2982ec6b5d7bSAndy Adamson ADJUST_ARGS(); 2983ec6b5d7bSAndy Adamson 2984ec6b5d7bSAndy Adamson if (sess->back_channel.nr_rdma_attrs) { 2985ec6b5d7bSAndy Adamson RESERVE_SPACE(4); 2986ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.rdma_attrs); 2987ec6b5d7bSAndy Adamson ADJUST_ARGS(); 2988ec6b5d7bSAndy Adamson } 2989ec6b5d7bSAndy Adamson return 0; 29902db134ebSAndy Adamson } 29912db134ebSAndy Adamson 29922db134ebSAndy Adamson static __be32 29932db134ebSAndy Adamson nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr, 29942db134ebSAndy Adamson struct nfsd4_destroy_session *destroy_session) 29952db134ebSAndy Adamson { 29962db134ebSAndy Adamson return nfserr; 29972db134ebSAndy Adamson } 29982db134ebSAndy Adamson 2999bf864a31SAndy Adamson __be32 30002db134ebSAndy Adamson nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, 30012db134ebSAndy Adamson struct nfsd4_sequence *seq) 30022db134ebSAndy Adamson { 3003b85d4c01SBenny Halevy ENCODE_HEAD; 3004b85d4c01SBenny Halevy 3005b85d4c01SBenny Halevy if (nfserr) 30062db134ebSAndy Adamson return nfserr; 3007b85d4c01SBenny Halevy 3008b85d4c01SBenny Halevy RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 20); 3009b85d4c01SBenny Halevy WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); 3010b85d4c01SBenny Halevy WRITE32(seq->seqid); 3011b85d4c01SBenny Halevy WRITE32(seq->slotid); 3012b85d4c01SBenny Halevy WRITE32(seq->maxslots); 3013b85d4c01SBenny Halevy /* 3014b85d4c01SBenny Halevy * FIXME: for now: 3015b85d4c01SBenny Halevy * target_maxslots = maxslots 3016b85d4c01SBenny Halevy * status_flags = 0 3017b85d4c01SBenny Halevy */ 3018b85d4c01SBenny Halevy WRITE32(seq->maxslots); 3019b85d4c01SBenny Halevy WRITE32(0); 3020b85d4c01SBenny Halevy 3021b85d4c01SBenny Halevy ADJUST_ARGS(); 3022b85d4c01SBenny Halevy return 0; 30232db134ebSAndy Adamson } 30242db134ebSAndy Adamson 30252db134ebSAndy Adamson static __be32 3026695e12f8SBenny Halevy nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) 3027695e12f8SBenny Halevy { 3028695e12f8SBenny Halevy return nfserr; 3029695e12f8SBenny Halevy } 3030695e12f8SBenny Halevy 3031695e12f8SBenny Halevy typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *); 3032695e12f8SBenny Halevy 30332db134ebSAndy Adamson /* 30342db134ebSAndy Adamson * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1 30352db134ebSAndy Adamson * since we don't need to filter out obsolete ops as this is 30362db134ebSAndy Adamson * done in the decoding phase. 30372db134ebSAndy Adamson */ 3038695e12f8SBenny Halevy static nfsd4_enc nfsd4_enc_ops[] = { 3039ad1060c8SJ. Bruce Fields [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access, 3040ad1060c8SJ. Bruce Fields [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close, 3041ad1060c8SJ. Bruce Fields [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit, 3042ad1060c8SJ. Bruce Fields [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create, 3043ad1060c8SJ. Bruce Fields [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop, 3044ad1060c8SJ. Bruce Fields [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop, 3045ad1060c8SJ. Bruce Fields [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr, 3046ad1060c8SJ. Bruce Fields [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh, 3047ad1060c8SJ. Bruce Fields [OP_LINK] = (nfsd4_enc)nfsd4_encode_link, 3048ad1060c8SJ. Bruce Fields [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock, 3049ad1060c8SJ. Bruce Fields [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt, 3050ad1060c8SJ. Bruce Fields [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku, 3051ad1060c8SJ. Bruce Fields [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop, 3052ad1060c8SJ. Bruce Fields [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop, 3053ad1060c8SJ. Bruce Fields [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop, 3054ad1060c8SJ. Bruce Fields [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open, 305584f09f46SBenny Halevy [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop, 3056ad1060c8SJ. Bruce Fields [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm, 3057ad1060c8SJ. Bruce Fields [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade, 3058ad1060c8SJ. Bruce Fields [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop, 3059ad1060c8SJ. Bruce Fields [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop, 3060ad1060c8SJ. Bruce Fields [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop, 3061ad1060c8SJ. Bruce Fields [OP_READ] = (nfsd4_enc)nfsd4_encode_read, 3062ad1060c8SJ. Bruce Fields [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir, 3063ad1060c8SJ. Bruce Fields [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink, 3064ad1060c8SJ. Bruce Fields [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove, 3065ad1060c8SJ. Bruce Fields [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename, 3066ad1060c8SJ. Bruce Fields [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop, 3067ad1060c8SJ. Bruce Fields [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop, 3068ad1060c8SJ. Bruce Fields [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop, 3069ad1060c8SJ. Bruce Fields [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo, 3070ad1060c8SJ. Bruce Fields [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr, 3071ad1060c8SJ. Bruce Fields [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid, 3072ad1060c8SJ. Bruce Fields [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop, 3073ad1060c8SJ. Bruce Fields [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop, 3074ad1060c8SJ. Bruce Fields [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write, 3075ad1060c8SJ. Bruce Fields [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop, 30762db134ebSAndy Adamson 30772db134ebSAndy Adamson /* NFSv4.1 operations */ 30782db134ebSAndy Adamson [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop, 30792db134ebSAndy Adamson [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_noop, 30802db134ebSAndy Adamson [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, 30812db134ebSAndy Adamson [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, 30822db134ebSAndy Adamson [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, 30832db134ebSAndy Adamson [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, 30842db134ebSAndy Adamson [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 30852db134ebSAndy Adamson [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, 30862db134ebSAndy Adamson [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, 30872db134ebSAndy Adamson [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, 30882db134ebSAndy Adamson [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, 30892db134ebSAndy Adamson [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, 30902db134ebSAndy Adamson [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_noop, 30912db134ebSAndy Adamson [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, 30922db134ebSAndy Adamson [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, 30932db134ebSAndy Adamson [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_noop, 30942db134ebSAndy Adamson [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 30952db134ebSAndy Adamson [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop, 30962db134ebSAndy Adamson [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop, 3097695e12f8SBenny Halevy }; 3098695e12f8SBenny Halevy 3099496c262cSAndy Adamson /* 3100496c262cSAndy Adamson * Calculate the total amount of memory that the compound response has taken 3101496c262cSAndy Adamson * after encoding the current operation. 3102496c262cSAndy Adamson * 3103496c262cSAndy Adamson * pad: add on 8 bytes for the next operation's op_code and status so that 3104496c262cSAndy Adamson * there is room to cache a failure on the next operation. 3105496c262cSAndy Adamson * 3106496c262cSAndy Adamson * Compare this length to the session se_fmaxresp_cached. 3107496c262cSAndy Adamson * 3108496c262cSAndy Adamson * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so 3109496c262cSAndy Adamson * will be at least a page and will therefore hold the xdr_buf head. 3110496c262cSAndy Adamson */ 3111496c262cSAndy Adamson static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) 3112496c262cSAndy Adamson { 3113496c262cSAndy Adamson int status = 0; 3114496c262cSAndy Adamson struct xdr_buf *xb = &resp->rqstp->rq_res; 3115496c262cSAndy Adamson struct nfsd4_compoundargs *args = resp->rqstp->rq_argp; 3116496c262cSAndy Adamson struct nfsd4_session *session = NULL; 3117496c262cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3118496c262cSAndy Adamson u32 length, tlen = 0, pad = 8; 3119496c262cSAndy Adamson 3120496c262cSAndy Adamson if (!nfsd4_has_session(&resp->cstate)) 3121496c262cSAndy Adamson return status; 3122496c262cSAndy Adamson 3123496c262cSAndy Adamson session = resp->cstate.session; 3124496c262cSAndy Adamson if (session == NULL || slot->sl_cache_entry.ce_cachethis == 0) 3125496c262cSAndy Adamson return status; 3126496c262cSAndy Adamson 3127496c262cSAndy Adamson if (resp->opcnt >= args->opcnt) 3128496c262cSAndy Adamson pad = 0; /* this is the last operation */ 3129496c262cSAndy Adamson 3130496c262cSAndy Adamson if (xb->page_len == 0) { 3131496c262cSAndy Adamson length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; 3132496c262cSAndy Adamson } else { 3133496c262cSAndy Adamson if (xb->tail[0].iov_base && xb->tail[0].iov_len > 0) 3134496c262cSAndy Adamson tlen = (char *)resp->p - (char *)xb->tail[0].iov_base; 3135496c262cSAndy Adamson 3136496c262cSAndy Adamson length = xb->head[0].iov_len + xb->page_len + tlen + pad; 3137496c262cSAndy Adamson } 3138496c262cSAndy Adamson dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, 3139496c262cSAndy Adamson length, xb->page_len, tlen, pad); 3140496c262cSAndy Adamson 3141496c262cSAndy Adamson if (length <= session->se_fmaxresp_cached) 3142496c262cSAndy Adamson return status; 3143496c262cSAndy Adamson else 3144496c262cSAndy Adamson return nfserr_rep_too_big_to_cache; 3145496c262cSAndy Adamson } 3146496c262cSAndy Adamson 31471da177e4SLinus Torvalds void 31481da177e4SLinus Torvalds nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 31491da177e4SLinus Torvalds { 31502ebbc012SAl Viro __be32 *statp; 31511da177e4SLinus Torvalds ENCODE_HEAD; 31521da177e4SLinus Torvalds 31531da177e4SLinus Torvalds RESERVE_SPACE(8); 31541da177e4SLinus Torvalds WRITE32(op->opnum); 31551da177e4SLinus Torvalds statp = p++; /* to be backfilled at the end */ 31561da177e4SLinus Torvalds ADJUST_ARGS(); 31571da177e4SLinus Torvalds 3158695e12f8SBenny Halevy if (op->opnum == OP_ILLEGAL) 3159695e12f8SBenny Halevy goto status; 3160695e12f8SBenny Halevy BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || 3161695e12f8SBenny Halevy !nfsd4_enc_ops[op->opnum]); 3162695e12f8SBenny Halevy op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); 3163496c262cSAndy Adamson /* nfsd4_check_drc_limit guarantees enough room for error status */ 3164496c262cSAndy Adamson if (!op->status && nfsd4_check_drc_limit(resp)) 3165496c262cSAndy Adamson op->status = nfserr_rep_too_big_to_cache; 3166695e12f8SBenny Halevy status: 31671da177e4SLinus Torvalds /* 31681da177e4SLinus Torvalds * Note: We write the status directly, instead of using WRITE32(), 31691da177e4SLinus Torvalds * since it is already in network byte order. 31701da177e4SLinus Torvalds */ 31711da177e4SLinus Torvalds *statp = op->status; 31721da177e4SLinus Torvalds } 31731da177e4SLinus Torvalds 31741da177e4SLinus Torvalds /* 31751da177e4SLinus Torvalds * Encode the reply stored in the stateowner reply cache 31761da177e4SLinus Torvalds * 31771da177e4SLinus Torvalds * XDR note: do not encode rp->rp_buflen: the buffer contains the 31781da177e4SLinus Torvalds * previously sent already encoded operation. 31791da177e4SLinus Torvalds * 31801da177e4SLinus Torvalds * called with nfs4_lock_state() held 31811da177e4SLinus Torvalds */ 31821da177e4SLinus Torvalds void 31831da177e4SLinus Torvalds nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 31841da177e4SLinus Torvalds { 31851da177e4SLinus Torvalds ENCODE_HEAD; 31861da177e4SLinus Torvalds struct nfs4_replay *rp = op->replay; 31871da177e4SLinus Torvalds 31881da177e4SLinus Torvalds BUG_ON(!rp); 31891da177e4SLinus Torvalds 31901da177e4SLinus Torvalds RESERVE_SPACE(8); 31911da177e4SLinus Torvalds WRITE32(op->opnum); 31921da177e4SLinus Torvalds *p++ = rp->rp_status; /* already xdr'ed */ 31931da177e4SLinus Torvalds ADJUST_ARGS(); 31941da177e4SLinus Torvalds 31951da177e4SLinus Torvalds RESERVE_SPACE(rp->rp_buflen); 31961da177e4SLinus Torvalds WRITEMEM(rp->rp_buf, rp->rp_buflen); 31971da177e4SLinus Torvalds ADJUST_ARGS(); 31981da177e4SLinus Torvalds } 31991da177e4SLinus Torvalds 32001da177e4SLinus Torvalds /* 32011da177e4SLinus Torvalds * END OF "GENERIC" ENCODE ROUTINES. 32021da177e4SLinus Torvalds */ 32031da177e4SLinus Torvalds 32041da177e4SLinus Torvalds int 32052ebbc012SAl Viro nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) 32061da177e4SLinus Torvalds { 32071da177e4SLinus Torvalds return xdr_ressize_check(rqstp, p); 32081da177e4SLinus Torvalds } 32091da177e4SLinus Torvalds 32101da177e4SLinus Torvalds void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args) 32111da177e4SLinus Torvalds { 32121da177e4SLinus Torvalds if (args->ops != args->iops) { 32131da177e4SLinus Torvalds kfree(args->ops); 32141da177e4SLinus Torvalds args->ops = args->iops; 32151da177e4SLinus Torvalds } 32161da177e4SLinus Torvalds kfree(args->tmpp); 32171da177e4SLinus Torvalds args->tmpp = NULL; 32181da177e4SLinus Torvalds while (args->to_free) { 32191da177e4SLinus Torvalds struct tmpbuf *tb = args->to_free; 32201da177e4SLinus Torvalds args->to_free = tb->next; 32211da177e4SLinus Torvalds tb->release(tb->buf); 32221da177e4SLinus Torvalds kfree(tb); 32231da177e4SLinus Torvalds } 32241da177e4SLinus Torvalds } 32251da177e4SLinus Torvalds 32261da177e4SLinus Torvalds int 32272ebbc012SAl Viro nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) 32281da177e4SLinus Torvalds { 3229b37ad28bSAl Viro __be32 status; 32301da177e4SLinus Torvalds 32311da177e4SLinus Torvalds args->p = p; 32321da177e4SLinus Torvalds args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; 32331da177e4SLinus Torvalds args->pagelist = rqstp->rq_arg.pages; 32341da177e4SLinus Torvalds args->pagelen = rqstp->rq_arg.page_len; 32351da177e4SLinus Torvalds args->tmpp = NULL; 32361da177e4SLinus Torvalds args->to_free = NULL; 32371da177e4SLinus Torvalds args->ops = args->iops; 32381da177e4SLinus Torvalds args->rqstp = rqstp; 32391da177e4SLinus Torvalds 32401da177e4SLinus Torvalds status = nfsd4_decode_compound(args); 32411da177e4SLinus Torvalds if (status) { 32421da177e4SLinus Torvalds nfsd4_release_compoundargs(args); 32431da177e4SLinus Torvalds } 32441da177e4SLinus Torvalds return !status; 32451da177e4SLinus Torvalds } 32461da177e4SLinus Torvalds 32471da177e4SLinus Torvalds int 32482ebbc012SAl Viro nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp) 32491da177e4SLinus Torvalds { 32501da177e4SLinus Torvalds /* 32511da177e4SLinus Torvalds * All that remains is to write the tag and operation count... 32521da177e4SLinus Torvalds */ 32531da177e4SLinus Torvalds struct kvec *iov; 32541da177e4SLinus Torvalds p = resp->tagp; 32551da177e4SLinus Torvalds *p++ = htonl(resp->taglen); 32561da177e4SLinus Torvalds memcpy(p, resp->tag, resp->taglen); 32571da177e4SLinus Torvalds p += XDR_QUADLEN(resp->taglen); 32581da177e4SLinus Torvalds *p++ = htonl(resp->opcnt); 32591da177e4SLinus Torvalds 32601da177e4SLinus Torvalds if (rqstp->rq_res.page_len) 32611da177e4SLinus Torvalds iov = &rqstp->rq_res.tail[0]; 32621da177e4SLinus Torvalds else 32631da177e4SLinus Torvalds iov = &rqstp->rq_res.head[0]; 32641da177e4SLinus Torvalds iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; 32651da177e4SLinus Torvalds BUG_ON(iov->iov_len > PAGE_SIZE); 32666668958fSAndy Adamson if (nfsd4_has_session(&resp->cstate)) { 3267bf864a31SAndy Adamson if (resp->cstate.status == nfserr_replay_cache && 3268bf864a31SAndy Adamson !nfsd4_not_cached(resp)) { 3269da3846a2SAndy Adamson iov->iov_len = resp->cstate.iovlen; 3270da3846a2SAndy Adamson } else { 3271da3846a2SAndy Adamson nfsd4_store_cache_entry(resp); 3272da3846a2SAndy Adamson dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__); 3273da3846a2SAndy Adamson resp->cstate.slot->sl_inuse = 0; 3274da3846a2SAndy Adamson } 3275da3846a2SAndy Adamson if (resp->cstate.session) 3276da3846a2SAndy Adamson nfsd4_put_session(resp->cstate.session); 3277da3846a2SAndy Adamson } 32781da177e4SLinus Torvalds return 1; 32791da177e4SLinus Torvalds } 32801da177e4SLinus Torvalds 32811da177e4SLinus Torvalds /* 32821da177e4SLinus Torvalds * Local variables: 32831da177e4SLinus Torvalds * c-basic-offset: 8 32841da177e4SLinus Torvalds * End: 32851da177e4SLinus Torvalds */ 3286