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 435a0e3ad6STejun Heo #include <linux/slab.h> 441da177e4SLinus Torvalds #include <linux/namei.h> 45341eb184SBoaz Harrosh #include <linux/statfs.h> 460733d213SAndy Adamson #include <linux/utsname.h> 4717456804SBryan Schumaker #include <linux/pagemap.h> 484796f457SJ. Bruce Fields #include <linux/sunrpc/svcauth_gss.h> 499a74af21SBoaz Harrosh 502ca72e17SJ. Bruce Fields #include "idmap.h" 512ca72e17SJ. Bruce Fields #include "acl.h" 529a74af21SBoaz Harrosh #include "xdr4.h" 530a3adadeSJ. Bruce Fields #include "vfs.h" 5417456804SBryan Schumaker #include "state.h" 551091006cSJ. Bruce Fields #include "cache.h" 562ca72e17SJ. Bruce Fields 571da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_XDR 581da177e4SLinus Torvalds 5942ca0993SJ.Bruce Fields /* 6042ca0993SJ.Bruce Fields * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing 6142ca0993SJ.Bruce Fields * directory in order to indicate to the client that a filesystem boundary is present 6242ca0993SJ.Bruce Fields * We use a fixed fsid for a referral 6342ca0993SJ.Bruce Fields */ 6442ca0993SJ.Bruce Fields #define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL 6542ca0993SJ.Bruce Fields #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL 6642ca0993SJ.Bruce Fields 67b37ad28bSAl Viro static __be32 68b37ad28bSAl Viro check_filename(char *str, int len, __be32 err) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds int i; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds if (len == 0) 731da177e4SLinus Torvalds return nfserr_inval; 741da177e4SLinus Torvalds if (isdotent(str, len)) 751da177e4SLinus Torvalds return err; 761da177e4SLinus Torvalds for (i = 0; i < len; i++) 771da177e4SLinus Torvalds if (str[i] == '/') 781da177e4SLinus Torvalds return err; 791da177e4SLinus Torvalds return 0; 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds #define DECODE_HEAD \ 832ebbc012SAl Viro __be32 *p; \ 84b37ad28bSAl Viro __be32 status 851da177e4SLinus Torvalds #define DECODE_TAIL \ 861da177e4SLinus Torvalds status = 0; \ 871da177e4SLinus Torvalds out: \ 881da177e4SLinus Torvalds return status; \ 891da177e4SLinus Torvalds xdr_error: \ 90817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 91817cb9d4SChuck Lever __FILE__, __LINE__); \ 921da177e4SLinus Torvalds status = nfserr_bad_xdr; \ 931da177e4SLinus Torvalds goto out 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds #define READ32(x) (x) = ntohl(*p++) 961da177e4SLinus Torvalds #define READ64(x) do { \ 971da177e4SLinus Torvalds (x) = (u64)ntohl(*p++) << 32; \ 981da177e4SLinus Torvalds (x) |= ntohl(*p++); \ 991da177e4SLinus Torvalds } while (0) 1001da177e4SLinus Torvalds #define READTIME(x) do { \ 1011da177e4SLinus Torvalds p++; \ 1021da177e4SLinus Torvalds (x) = ntohl(*p++); \ 1031da177e4SLinus Torvalds p++; \ 1041da177e4SLinus Torvalds } while (0) 1051da177e4SLinus Torvalds #define READMEM(x,nbytes) do { \ 1061da177e4SLinus Torvalds x = (char *)p; \ 1071da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1081da177e4SLinus Torvalds } while (0) 1091da177e4SLinus Torvalds #define SAVEMEM(x,nbytes) do { \ 1101da177e4SLinus Torvalds if (!(x = (p==argp->tmp || p == argp->tmpp) ? \ 1111da177e4SLinus Torvalds savemem(argp, p, nbytes) : \ 1121da177e4SLinus Torvalds (char *)p)) { \ 113817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 114817cb9d4SChuck Lever __FILE__, __LINE__); \ 1151da177e4SLinus Torvalds goto xdr_error; \ 1161da177e4SLinus Torvalds } \ 1171da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1181da177e4SLinus Torvalds } while (0) 1191da177e4SLinus Torvalds #define COPYMEM(x,nbytes) do { \ 1201da177e4SLinus Torvalds memcpy((x), p, nbytes); \ 1211da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1221da177e4SLinus Torvalds } while (0) 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds /* READ_BUF, read_buf(): nbytes must be <= PAGE_SIZE */ 1251da177e4SLinus Torvalds #define READ_BUF(nbytes) do { \ 1261da177e4SLinus Torvalds if (nbytes <= (u32)((char *)argp->end - (char *)argp->p)) { \ 1271da177e4SLinus Torvalds p = argp->p; \ 1281da177e4SLinus Torvalds argp->p += XDR_QUADLEN(nbytes); \ 1291da177e4SLinus Torvalds } else if (!(p = read_buf(argp, nbytes))) { \ 130817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 131817cb9d4SChuck Lever __FILE__, __LINE__); \ 1321da177e4SLinus Torvalds goto xdr_error; \ 1331da177e4SLinus Torvalds } \ 1341da177e4SLinus Torvalds } while (0) 1351da177e4SLinus Torvalds 136ca2a05aaSJ. Bruce Fields static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) 1371da177e4SLinus Torvalds { 1381da177e4SLinus Torvalds /* We want more bytes than seem to be available. 1391da177e4SLinus Torvalds * Maybe we need a new page, maybe we have just run out 1401da177e4SLinus Torvalds */ 141ca2a05aaSJ. Bruce Fields unsigned int avail = (char *)argp->end - (char *)argp->p; 1422ebbc012SAl Viro __be32 *p; 1431da177e4SLinus Torvalds if (avail + argp->pagelen < nbytes) 1441da177e4SLinus Torvalds return NULL; 1451da177e4SLinus Torvalds if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */ 1461da177e4SLinus Torvalds return NULL; 1471da177e4SLinus Torvalds /* ok, we can do it with the current plus the next page */ 1481da177e4SLinus Torvalds if (nbytes <= sizeof(argp->tmp)) 1491da177e4SLinus Torvalds p = argp->tmp; 1501da177e4SLinus Torvalds else { 1511da177e4SLinus Torvalds kfree(argp->tmpp); 1521da177e4SLinus Torvalds p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL); 1531da177e4SLinus Torvalds if (!p) 1541da177e4SLinus Torvalds return NULL; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds } 157ca2a05aaSJ. Bruce Fields /* 158ca2a05aaSJ. Bruce Fields * The following memcpy is safe because read_buf is always 159ca2a05aaSJ. Bruce Fields * called with nbytes > avail, and the two cases above both 160ca2a05aaSJ. Bruce Fields * guarantee p points to at least nbytes bytes. 161ca2a05aaSJ. Bruce Fields */ 1621da177e4SLinus Torvalds memcpy(p, argp->p, avail); 1631da177e4SLinus Torvalds /* step to next page */ 1641da177e4SLinus Torvalds argp->p = page_address(argp->pagelist[0]); 1651da177e4SLinus Torvalds argp->pagelist++; 1661da177e4SLinus Torvalds if (argp->pagelen < PAGE_SIZE) { 1672bc3c117SNeil Brown argp->end = argp->p + (argp->pagelen>>2); 1681da177e4SLinus Torvalds argp->pagelen = 0; 1691da177e4SLinus Torvalds } else { 1702bc3c117SNeil Brown argp->end = argp->p + (PAGE_SIZE>>2); 1711da177e4SLinus Torvalds argp->pagelen -= PAGE_SIZE; 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); 1741da177e4SLinus Torvalds argp->p += XDR_QUADLEN(nbytes - avail); 1751da177e4SLinus Torvalds return p; 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 17860adfc50SAndy Adamson static int zero_clientid(clientid_t *clid) 17960adfc50SAndy Adamson { 18060adfc50SAndy Adamson return (clid->cl_boot == 0) && (clid->cl_id == 0); 18160adfc50SAndy Adamson } 18260adfc50SAndy Adamson 1831da177e4SLinus Torvalds static int 1841da177e4SLinus Torvalds defer_free(struct nfsd4_compoundargs *argp, 1851da177e4SLinus Torvalds void (*release)(const void *), void *p) 1861da177e4SLinus Torvalds { 1871da177e4SLinus Torvalds struct tmpbuf *tb; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds tb = kmalloc(sizeof(*tb), GFP_KERNEL); 1901da177e4SLinus Torvalds if (!tb) 1911da177e4SLinus Torvalds return -ENOMEM; 1921da177e4SLinus Torvalds tb->buf = p; 1931da177e4SLinus Torvalds tb->release = release; 1941da177e4SLinus Torvalds tb->next = argp->to_free; 1951da177e4SLinus Torvalds argp->to_free = tb; 1961da177e4SLinus Torvalds return 0; 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds 1992ebbc012SAl Viro static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) 2001da177e4SLinus Torvalds { 2011da177e4SLinus Torvalds if (p == argp->tmp) { 20267114fe6SThomas Meyer p = kmemdup(argp->tmp, nbytes, GFP_KERNEL); 203a4db5fe5SJ. Bruce Fields if (!p) 204a4db5fe5SJ. Bruce Fields return NULL; 2051da177e4SLinus Torvalds } else { 20673dff8beSEric Sesterhenn BUG_ON(p != argp->tmpp); 2071da177e4SLinus Torvalds argp->tmpp = NULL; 2081da177e4SLinus Torvalds } 2091da177e4SLinus Torvalds if (defer_free(argp, kfree, p)) { 210a4db5fe5SJ. Bruce Fields kfree(p); 2111da177e4SLinus Torvalds return NULL; 2121da177e4SLinus Torvalds } else 2131da177e4SLinus Torvalds return (char *)p; 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 216b37ad28bSAl Viro static __be32 2171da177e4SLinus Torvalds nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) 2181da177e4SLinus Torvalds { 2191da177e4SLinus Torvalds u32 bmlen; 2201da177e4SLinus Torvalds DECODE_HEAD; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds bmval[0] = 0; 2231da177e4SLinus Torvalds bmval[1] = 0; 2247e705706SAndy Adamson bmval[2] = 0; 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds READ_BUF(4); 2271da177e4SLinus Torvalds READ32(bmlen); 2281da177e4SLinus Torvalds if (bmlen > 1000) 2291da177e4SLinus Torvalds goto xdr_error; 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds READ_BUF(bmlen << 2); 2321da177e4SLinus Torvalds if (bmlen > 0) 2331da177e4SLinus Torvalds READ32(bmval[0]); 2341da177e4SLinus Torvalds if (bmlen > 1) 2351da177e4SLinus Torvalds READ32(bmval[1]); 2367e705706SAndy Adamson if (bmlen > 2) 2377e705706SAndy Adamson READ32(bmval[2]); 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds DECODE_TAIL; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 242b37ad28bSAl Viro static __be32 2433c8e0316SYu Zhiguo nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, 244c0d6fc8aSBenny Halevy struct iattr *iattr, struct nfs4_acl **acl) 2451da177e4SLinus Torvalds { 2461da177e4SLinus Torvalds int expected_len, len = 0; 2471da177e4SLinus Torvalds u32 dummy32; 2481da177e4SLinus Torvalds char *buf; 249b8dd7b9aSAl Viro int host_err; 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds DECODE_HEAD; 2521da177e4SLinus Torvalds iattr->ia_valid = 0; 2531da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, bmval))) 2541da177e4SLinus Torvalds return status; 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds READ_BUF(4); 2571da177e4SLinus Torvalds READ32(expected_len); 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds if (bmval[0] & FATTR4_WORD0_SIZE) { 2601da177e4SLinus Torvalds READ_BUF(8); 2611da177e4SLinus Torvalds len += 8; 2621da177e4SLinus Torvalds READ64(iattr->ia_size); 2631da177e4SLinus Torvalds iattr->ia_valid |= ATTR_SIZE; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds if (bmval[0] & FATTR4_WORD0_ACL) { 26628e05dd8SJ. Bruce Fields int nace; 26728e05dd8SJ. Bruce Fields struct nfs4_ace *ace; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds READ_BUF(4); len += 4; 2701da177e4SLinus Torvalds READ32(nace); 2711da177e4SLinus Torvalds 27228e05dd8SJ. Bruce Fields if (nace > NFS4_ACL_MAX) 27328e05dd8SJ. Bruce Fields return nfserr_resource; 27428e05dd8SJ. Bruce Fields 27528e05dd8SJ. Bruce Fields *acl = nfs4_acl_new(nace); 2761da177e4SLinus Torvalds if (*acl == NULL) { 277b8dd7b9aSAl Viro host_err = -ENOMEM; 2781da177e4SLinus Torvalds goto out_nfserr; 2791da177e4SLinus Torvalds } 28028e05dd8SJ. Bruce Fields defer_free(argp, kfree, *acl); 2811da177e4SLinus Torvalds 28228e05dd8SJ. Bruce Fields (*acl)->naces = nace; 28328e05dd8SJ. Bruce Fields for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { 2841da177e4SLinus Torvalds READ_BUF(16); len += 16; 28528e05dd8SJ. Bruce Fields READ32(ace->type); 28628e05dd8SJ. Bruce Fields READ32(ace->flag); 28728e05dd8SJ. Bruce Fields READ32(ace->access_mask); 2881da177e4SLinus Torvalds READ32(dummy32); 2891da177e4SLinus Torvalds READ_BUF(dummy32); 2901da177e4SLinus Torvalds len += XDR_QUADLEN(dummy32) << 2; 2911da177e4SLinus Torvalds READMEM(buf, dummy32); 29228e05dd8SJ. Bruce Fields ace->whotype = nfs4_acl_get_whotype(buf, dummy32); 2933c726023SJ. Bruce Fields status = nfs_ok; 29428e05dd8SJ. Bruce Fields if (ace->whotype != NFS4_ACL_WHO_NAMED) 29528e05dd8SJ. Bruce Fields ace->who = 0; 29628e05dd8SJ. Bruce Fields else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) 2973c726023SJ. Bruce Fields status = nfsd_map_name_to_gid(argp->rqstp, 29828e05dd8SJ. Bruce Fields buf, dummy32, &ace->who); 2991da177e4SLinus Torvalds else 3003c726023SJ. Bruce Fields status = nfsd_map_name_to_uid(argp->rqstp, 30128e05dd8SJ. Bruce Fields buf, dummy32, &ace->who); 3023c726023SJ. Bruce Fields if (status) 3033c726023SJ. Bruce Fields return status; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds } else 3061da177e4SLinus Torvalds *acl = NULL; 3071da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_MODE) { 3081da177e4SLinus Torvalds READ_BUF(4); 3091da177e4SLinus Torvalds len += 4; 3101da177e4SLinus Torvalds READ32(iattr->ia_mode); 3111da177e4SLinus Torvalds iattr->ia_mode &= (S_IFMT | S_IALLUGO); 3121da177e4SLinus Torvalds iattr->ia_valid |= ATTR_MODE; 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_OWNER) { 3151da177e4SLinus Torvalds READ_BUF(4); 3161da177e4SLinus Torvalds len += 4; 3171da177e4SLinus Torvalds READ32(dummy32); 3181da177e4SLinus Torvalds READ_BUF(dummy32); 3191da177e4SLinus Torvalds len += (XDR_QUADLEN(dummy32) << 2); 3201da177e4SLinus Torvalds READMEM(buf, dummy32); 32147c85291SNeilBrown if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) 32247c85291SNeilBrown return status; 3231da177e4SLinus Torvalds iattr->ia_valid |= ATTR_UID; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) { 3261da177e4SLinus Torvalds READ_BUF(4); 3271da177e4SLinus Torvalds len += 4; 3281da177e4SLinus Torvalds READ32(dummy32); 3291da177e4SLinus Torvalds READ_BUF(dummy32); 3301da177e4SLinus Torvalds len += (XDR_QUADLEN(dummy32) << 2); 3311da177e4SLinus Torvalds READMEM(buf, dummy32); 33247c85291SNeilBrown if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) 33347c85291SNeilBrown return status; 3341da177e4SLinus Torvalds iattr->ia_valid |= ATTR_GID; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) { 3371da177e4SLinus Torvalds READ_BUF(4); 3381da177e4SLinus Torvalds len += 4; 3391da177e4SLinus Torvalds READ32(dummy32); 3401da177e4SLinus Torvalds switch (dummy32) { 3411da177e4SLinus Torvalds case NFS4_SET_TO_CLIENT_TIME: 3421da177e4SLinus Torvalds /* We require the high 32 bits of 'seconds' to be 0, and we ignore 3431da177e4SLinus Torvalds all 32 bits of 'nseconds'. */ 3441da177e4SLinus Torvalds READ_BUF(12); 3451da177e4SLinus Torvalds len += 12; 3461da177e4SLinus Torvalds READ32(dummy32); 3471da177e4SLinus Torvalds if (dummy32) 3481da177e4SLinus Torvalds return nfserr_inval; 3491da177e4SLinus Torvalds READ32(iattr->ia_atime.tv_sec); 3501da177e4SLinus Torvalds READ32(iattr->ia_atime.tv_nsec); 3511da177e4SLinus Torvalds if (iattr->ia_atime.tv_nsec >= (u32)1000000000) 3521da177e4SLinus Torvalds return nfserr_inval; 3531da177e4SLinus Torvalds iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); 3541da177e4SLinus Torvalds break; 3551da177e4SLinus Torvalds case NFS4_SET_TO_SERVER_TIME: 3561da177e4SLinus Torvalds iattr->ia_valid |= ATTR_ATIME; 3571da177e4SLinus Torvalds break; 3581da177e4SLinus Torvalds default: 3591da177e4SLinus Torvalds goto xdr_error; 3601da177e4SLinus Torvalds } 3611da177e4SLinus Torvalds } 3621da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_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_mtime.tv_sec); 3761da177e4SLinus Torvalds READ32(iattr->ia_mtime.tv_nsec); 3771da177e4SLinus Torvalds if (iattr->ia_mtime.tv_nsec >= (u32)1000000000) 3781da177e4SLinus Torvalds return nfserr_inval; 3791da177e4SLinus Torvalds iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); 3801da177e4SLinus Torvalds break; 3811da177e4SLinus Torvalds case NFS4_SET_TO_SERVER_TIME: 3821da177e4SLinus Torvalds iattr->ia_valid |= ATTR_MTIME; 3831da177e4SLinus Torvalds break; 3841da177e4SLinus Torvalds default: 3851da177e4SLinus Torvalds goto xdr_error; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds } 3883c8e0316SYu Zhiguo if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 3893c8e0316SYu Zhiguo || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 3903c8e0316SYu Zhiguo || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) 3913c8e0316SYu Zhiguo READ_BUF(expected_len - len); 3923c8e0316SYu Zhiguo else if (len != expected_len) 3931da177e4SLinus Torvalds goto xdr_error; 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds DECODE_TAIL; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds out_nfserr: 398b8dd7b9aSAl Viro status = nfserrno(host_err); 3991da177e4SLinus Torvalds goto out; 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds 402b37ad28bSAl Viro static __be32 403e31a1b66SBenny Halevy nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid) 404e31a1b66SBenny Halevy { 405e31a1b66SBenny Halevy DECODE_HEAD; 406e31a1b66SBenny Halevy 407e31a1b66SBenny Halevy READ_BUF(sizeof(stateid_t)); 408e31a1b66SBenny Halevy READ32(sid->si_generation); 409e31a1b66SBenny Halevy COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); 410e31a1b66SBenny Halevy 411e31a1b66SBenny Halevy DECODE_TAIL; 412e31a1b66SBenny Halevy } 413e31a1b66SBenny Halevy 414e31a1b66SBenny Halevy static __be32 4151da177e4SLinus Torvalds nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access) 4161da177e4SLinus Torvalds { 4171da177e4SLinus Torvalds DECODE_HEAD; 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds READ_BUF(4); 4201da177e4SLinus Torvalds READ32(access->ac_req_access); 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds DECODE_TAIL; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 425acb2887eSJ. Bruce Fields static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) 426acb2887eSJ. Bruce Fields { 427acb2887eSJ. Bruce Fields DECODE_HEAD; 42812fc3e92SJ. Bruce Fields u32 dummy, uid, gid; 429acb2887eSJ. Bruce Fields char *machine_name; 430acb2887eSJ. Bruce Fields int i; 431acb2887eSJ. Bruce Fields int nr_secflavs; 432acb2887eSJ. Bruce Fields 433acb2887eSJ. Bruce Fields /* callback_sec_params4 */ 434acb2887eSJ. Bruce Fields READ_BUF(4); 435acb2887eSJ. Bruce Fields READ32(nr_secflavs); 43612fc3e92SJ. Bruce Fields cbs->flavor = (u32)(-1); 437acb2887eSJ. Bruce Fields for (i = 0; i < nr_secflavs; ++i) { 438acb2887eSJ. Bruce Fields READ_BUF(4); 439acb2887eSJ. Bruce Fields READ32(dummy); 440acb2887eSJ. Bruce Fields switch (dummy) { 441acb2887eSJ. Bruce Fields case RPC_AUTH_NULL: 442acb2887eSJ. Bruce Fields /* Nothing to read */ 44312fc3e92SJ. Bruce Fields if (cbs->flavor == (u32)(-1)) 44412fc3e92SJ. Bruce Fields cbs->flavor = RPC_AUTH_NULL; 445acb2887eSJ. Bruce Fields break; 446acb2887eSJ. Bruce Fields case RPC_AUTH_UNIX: 447acb2887eSJ. Bruce Fields READ_BUF(8); 448acb2887eSJ. Bruce Fields /* stamp */ 449acb2887eSJ. Bruce Fields READ32(dummy); 450acb2887eSJ. Bruce Fields 451acb2887eSJ. Bruce Fields /* machine name */ 452acb2887eSJ. Bruce Fields READ32(dummy); 453acb2887eSJ. Bruce Fields READ_BUF(dummy); 454acb2887eSJ. Bruce Fields SAVEMEM(machine_name, dummy); 455acb2887eSJ. Bruce Fields 456acb2887eSJ. Bruce Fields /* uid, gid */ 457acb2887eSJ. Bruce Fields READ_BUF(8); 45812fc3e92SJ. Bruce Fields READ32(uid); 45912fc3e92SJ. Bruce Fields READ32(gid); 460acb2887eSJ. Bruce Fields 461acb2887eSJ. Bruce Fields /* more gids */ 462acb2887eSJ. Bruce Fields READ_BUF(4); 463acb2887eSJ. Bruce Fields READ32(dummy); 464acb2887eSJ. Bruce Fields READ_BUF(dummy * 4); 46512fc3e92SJ. Bruce Fields if (cbs->flavor == (u32)(-1)) { 46612fc3e92SJ. Bruce Fields cbs->uid = uid; 46712fc3e92SJ. Bruce Fields cbs->gid = gid; 46812fc3e92SJ. Bruce Fields cbs->flavor = RPC_AUTH_UNIX; 46912fc3e92SJ. Bruce Fields } 470acb2887eSJ. Bruce Fields break; 471acb2887eSJ. Bruce Fields case RPC_AUTH_GSS: 472acb2887eSJ. Bruce Fields dprintk("RPC_AUTH_GSS callback secflavor " 473acb2887eSJ. Bruce Fields "not supported!\n"); 474acb2887eSJ. Bruce Fields READ_BUF(8); 475acb2887eSJ. Bruce Fields /* gcbp_service */ 476acb2887eSJ. Bruce Fields READ32(dummy); 477acb2887eSJ. Bruce Fields /* gcbp_handle_from_server */ 478acb2887eSJ. Bruce Fields READ32(dummy); 479acb2887eSJ. Bruce Fields READ_BUF(dummy); 480acb2887eSJ. Bruce Fields p += XDR_QUADLEN(dummy); 481acb2887eSJ. Bruce Fields /* gcbp_handle_from_client */ 482acb2887eSJ. Bruce Fields READ_BUF(4); 483acb2887eSJ. Bruce Fields READ32(dummy); 484acb2887eSJ. Bruce Fields READ_BUF(dummy); 485acb2887eSJ. Bruce Fields break; 486acb2887eSJ. Bruce Fields default: 487acb2887eSJ. Bruce Fields dprintk("Illegal callback secflavor\n"); 488acb2887eSJ. Bruce Fields return nfserr_inval; 489acb2887eSJ. Bruce Fields } 490acb2887eSJ. Bruce Fields } 491acb2887eSJ. Bruce Fields DECODE_TAIL; 492acb2887eSJ. Bruce Fields } 493acb2887eSJ. Bruce Fields 494cb73a9f4SJ. Bruce Fields static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) 495cb73a9f4SJ. Bruce Fields { 496cb73a9f4SJ. Bruce Fields DECODE_HEAD; 497cb73a9f4SJ. Bruce Fields 498cb73a9f4SJ. Bruce Fields READ_BUF(4); 499cb73a9f4SJ. Bruce Fields READ32(bc->bc_cb_program); 500cb73a9f4SJ. Bruce Fields nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); 501cb73a9f4SJ. Bruce Fields 502cb73a9f4SJ. Bruce Fields DECODE_TAIL; 503cb73a9f4SJ. Bruce Fields } 504cb73a9f4SJ. Bruce Fields 5051d1bc8f2SJ. Bruce Fields static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) 5061d1bc8f2SJ. Bruce Fields { 5071d1bc8f2SJ. Bruce Fields DECODE_HEAD; 5081d1bc8f2SJ. Bruce Fields 5091d1bc8f2SJ. Bruce Fields READ_BUF(NFS4_MAX_SESSIONID_LEN + 8); 5101d1bc8f2SJ. Bruce Fields COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); 5111d1bc8f2SJ. Bruce Fields READ32(bcts->dir); 5126ce2357fSBryan Schumaker /* XXX: skipping ctsa_use_conn_in_rdma_mode. Perhaps Tom Tucker 5136ce2357fSBryan Schumaker * could help us figure out we should be using it. */ 5141d1bc8f2SJ. Bruce Fields DECODE_TAIL; 5151d1bc8f2SJ. Bruce Fields } 5161d1bc8f2SJ. Bruce Fields 517b37ad28bSAl Viro static __be32 5181da177e4SLinus Torvalds nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) 5191da177e4SLinus Torvalds { 5201da177e4SLinus Torvalds DECODE_HEAD; 5211da177e4SLinus Torvalds 522e31a1b66SBenny Halevy READ_BUF(4); 5231da177e4SLinus Torvalds READ32(close->cl_seqid); 524e31a1b66SBenny Halevy return nfsd4_decode_stateid(argp, &close->cl_stateid); 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds DECODE_TAIL; 5271da177e4SLinus Torvalds } 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds 530b37ad28bSAl Viro static __be32 5311da177e4SLinus Torvalds nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds DECODE_HEAD; 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds READ_BUF(12); 5361da177e4SLinus Torvalds READ64(commit->co_offset); 5371da177e4SLinus Torvalds READ32(commit->co_count); 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds DECODE_TAIL; 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds 542b37ad28bSAl Viro static __be32 5431da177e4SLinus Torvalds nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create) 5441da177e4SLinus Torvalds { 5451da177e4SLinus Torvalds DECODE_HEAD; 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds READ_BUF(4); 5481da177e4SLinus Torvalds READ32(create->cr_type); 5491da177e4SLinus Torvalds switch (create->cr_type) { 5501da177e4SLinus Torvalds case NF4LNK: 5511da177e4SLinus Torvalds READ_BUF(4); 5521da177e4SLinus Torvalds READ32(create->cr_linklen); 5531da177e4SLinus Torvalds READ_BUF(create->cr_linklen); 5541da177e4SLinus Torvalds SAVEMEM(create->cr_linkname, create->cr_linklen); 5551da177e4SLinus Torvalds break; 5561da177e4SLinus Torvalds case NF4BLK: 5571da177e4SLinus Torvalds case NF4CHR: 5581da177e4SLinus Torvalds READ_BUF(8); 5591da177e4SLinus Torvalds READ32(create->cr_specdata1); 5601da177e4SLinus Torvalds READ32(create->cr_specdata2); 5611da177e4SLinus Torvalds break; 5621da177e4SLinus Torvalds case NF4SOCK: 5631da177e4SLinus Torvalds case NF4FIFO: 5641da177e4SLinus Torvalds case NF4DIR: 5651da177e4SLinus Torvalds default: 5661da177e4SLinus Torvalds break; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds READ_BUF(4); 5701da177e4SLinus Torvalds READ32(create->cr_namelen); 5711da177e4SLinus Torvalds READ_BUF(create->cr_namelen); 5721da177e4SLinus Torvalds SAVEMEM(create->cr_name, create->cr_namelen); 5731da177e4SLinus Torvalds if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) 5741da177e4SLinus Torvalds return status; 5751da177e4SLinus Torvalds 5763c8e0316SYu Zhiguo status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, 5773c8e0316SYu Zhiguo &create->cr_acl); 578c0d6fc8aSBenny Halevy if (status) 5791da177e4SLinus Torvalds goto out; 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds DECODE_TAIL; 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 584b37ad28bSAl Viro static inline __be32 5851da177e4SLinus Torvalds nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr) 5861da177e4SLinus Torvalds { 587e31a1b66SBenny Halevy return nfsd4_decode_stateid(argp, &dr->dr_stateid); 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds 590b37ad28bSAl Viro static inline __be32 5911da177e4SLinus Torvalds nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) 5921da177e4SLinus Torvalds { 5931da177e4SLinus Torvalds return nfsd4_decode_bitmap(argp, getattr->ga_bmval); 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds 596b37ad28bSAl Viro static __be32 5971da177e4SLinus Torvalds nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) 5981da177e4SLinus Torvalds { 5991da177e4SLinus Torvalds DECODE_HEAD; 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds READ_BUF(4); 6021da177e4SLinus Torvalds READ32(link->li_namelen); 6031da177e4SLinus Torvalds READ_BUF(link->li_namelen); 6041da177e4SLinus Torvalds SAVEMEM(link->li_name, link->li_namelen); 6051da177e4SLinus Torvalds if ((status = check_filename(link->li_name, link->li_namelen, nfserr_inval))) 6061da177e4SLinus Torvalds return status; 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds DECODE_TAIL; 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 611b37ad28bSAl Viro static __be32 6121da177e4SLinus Torvalds nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) 6131da177e4SLinus Torvalds { 6141da177e4SLinus Torvalds DECODE_HEAD; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds /* 6171da177e4SLinus Torvalds * type, reclaim(boolean), offset, length, new_lock_owner(boolean) 6181da177e4SLinus Torvalds */ 6191da177e4SLinus Torvalds READ_BUF(28); 6201da177e4SLinus Torvalds READ32(lock->lk_type); 6211da177e4SLinus Torvalds if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT)) 6221da177e4SLinus Torvalds goto xdr_error; 6231da177e4SLinus Torvalds READ32(lock->lk_reclaim); 6241da177e4SLinus Torvalds READ64(lock->lk_offset); 6251da177e4SLinus Torvalds READ64(lock->lk_length); 6261da177e4SLinus Torvalds READ32(lock->lk_is_new); 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds if (lock->lk_is_new) { 629e31a1b66SBenny Halevy READ_BUF(4); 6301da177e4SLinus Torvalds READ32(lock->lk_new_open_seqid); 631e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid); 632e31a1b66SBenny Halevy if (status) 633e31a1b66SBenny Halevy return status; 634e31a1b66SBenny Halevy READ_BUF(8 + sizeof(clientid_t)); 6351da177e4SLinus Torvalds READ32(lock->lk_new_lock_seqid); 6361da177e4SLinus Torvalds COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t)); 6371da177e4SLinus Torvalds READ32(lock->lk_new_owner.len); 6381da177e4SLinus Torvalds READ_BUF(lock->lk_new_owner.len); 6391da177e4SLinus Torvalds READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len); 6401da177e4SLinus Torvalds } else { 641e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid); 642e31a1b66SBenny Halevy if (status) 643e31a1b66SBenny Halevy return status; 644e31a1b66SBenny Halevy READ_BUF(4); 6451da177e4SLinus Torvalds READ32(lock->lk_old_lock_seqid); 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds DECODE_TAIL; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 651b37ad28bSAl Viro static __be32 6521da177e4SLinus Torvalds nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) 6531da177e4SLinus Torvalds { 6541da177e4SLinus Torvalds DECODE_HEAD; 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds READ_BUF(32); 6571da177e4SLinus Torvalds READ32(lockt->lt_type); 6581da177e4SLinus Torvalds if((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT)) 6591da177e4SLinus Torvalds goto xdr_error; 6601da177e4SLinus Torvalds READ64(lockt->lt_offset); 6611da177e4SLinus Torvalds READ64(lockt->lt_length); 6621da177e4SLinus Torvalds COPYMEM(&lockt->lt_clientid, 8); 6631da177e4SLinus Torvalds READ32(lockt->lt_owner.len); 6641da177e4SLinus Torvalds READ_BUF(lockt->lt_owner.len); 6651da177e4SLinus Torvalds READMEM(lockt->lt_owner.data, lockt->lt_owner.len); 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds DECODE_TAIL; 6681da177e4SLinus Torvalds } 6691da177e4SLinus Torvalds 670b37ad28bSAl Viro static __be32 6711da177e4SLinus Torvalds nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) 6721da177e4SLinus Torvalds { 6731da177e4SLinus Torvalds DECODE_HEAD; 6741da177e4SLinus Torvalds 675e31a1b66SBenny Halevy READ_BUF(8); 6761da177e4SLinus Torvalds READ32(locku->lu_type); 6771da177e4SLinus Torvalds if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT)) 6781da177e4SLinus Torvalds goto xdr_error; 6791da177e4SLinus Torvalds READ32(locku->lu_seqid); 680e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &locku->lu_stateid); 681e31a1b66SBenny Halevy if (status) 682e31a1b66SBenny Halevy return status; 683e31a1b66SBenny Halevy READ_BUF(16); 6841da177e4SLinus Torvalds READ64(locku->lu_offset); 6851da177e4SLinus Torvalds READ64(locku->lu_length); 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds DECODE_TAIL; 6881da177e4SLinus Torvalds } 6891da177e4SLinus Torvalds 690b37ad28bSAl Viro static __be32 6911da177e4SLinus Torvalds nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) 6921da177e4SLinus Torvalds { 6931da177e4SLinus Torvalds DECODE_HEAD; 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds READ_BUF(4); 6961da177e4SLinus Torvalds READ32(lookup->lo_len); 6971da177e4SLinus Torvalds READ_BUF(lookup->lo_len); 6981da177e4SLinus Torvalds SAVEMEM(lookup->lo_name, lookup->lo_len); 6991da177e4SLinus Torvalds if ((status = check_filename(lookup->lo_name, lookup->lo_len, nfserr_noent))) 7001da177e4SLinus Torvalds return status; 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds DECODE_TAIL; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds 7052c8bd7e0SBenny Halevy static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when) 70604f9e664SJ. Bruce Fields { 70704f9e664SJ. Bruce Fields __be32 *p; 70804f9e664SJ. Bruce Fields u32 w; 70904f9e664SJ. Bruce Fields 71004f9e664SJ. Bruce Fields READ_BUF(4); 71104f9e664SJ. Bruce Fields READ32(w); 7122c8bd7e0SBenny Halevy *share_access = w & NFS4_SHARE_ACCESS_MASK; 7132c8bd7e0SBenny Halevy *deleg_want = w & NFS4_SHARE_WANT_MASK; 7142c8bd7e0SBenny Halevy if (deleg_when) 7152c8bd7e0SBenny Halevy *deleg_when = w & NFS4_SHARE_WHEN_MASK; 7162c8bd7e0SBenny Halevy 71704f9e664SJ. Bruce Fields switch (w & NFS4_SHARE_ACCESS_MASK) { 71804f9e664SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 71904f9e664SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 72004f9e664SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 72104f9e664SJ. Bruce Fields break; 72204f9e664SJ. Bruce Fields default: 72304f9e664SJ. Bruce Fields return nfserr_bad_xdr; 72404f9e664SJ. Bruce Fields } 725fc0d14feSBenny Halevy w &= ~NFS4_SHARE_ACCESS_MASK; 72604f9e664SJ. Bruce Fields if (!w) 72704f9e664SJ. Bruce Fields return nfs_ok; 72804f9e664SJ. Bruce Fields if (!argp->minorversion) 72904f9e664SJ. Bruce Fields return nfserr_bad_xdr; 73004f9e664SJ. Bruce Fields switch (w & NFS4_SHARE_WANT_MASK) { 73104f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_NO_PREFERENCE: 73204f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_READ_DELEG: 73304f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_WRITE_DELEG: 73404f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_ANY_DELEG: 73504f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_NO_DELEG: 73604f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_CANCEL: 73704f9e664SJ. Bruce Fields break; 73804f9e664SJ. Bruce Fields default: 73904f9e664SJ. Bruce Fields return nfserr_bad_xdr; 74004f9e664SJ. Bruce Fields } 74192bac8c5SBenny Halevy w &= ~NFS4_SHARE_WANT_MASK; 74204f9e664SJ. Bruce Fields if (!w) 74304f9e664SJ. Bruce Fields return nfs_ok; 7442c8bd7e0SBenny Halevy 7452c8bd7e0SBenny Halevy if (!deleg_when) /* open_downgrade */ 7462c8bd7e0SBenny Halevy return nfserr_inval; 74704f9e664SJ. Bruce Fields switch (w) { 74804f9e664SJ. Bruce Fields case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL: 74904f9e664SJ. Bruce Fields case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED: 750c668fc6dSBenny Halevy case (NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL | 751c668fc6dSBenny Halevy NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED): 75204f9e664SJ. Bruce Fields return nfs_ok; 75304f9e664SJ. Bruce Fields } 75404f9e664SJ. Bruce Fields xdr_error: 75504f9e664SJ. Bruce Fields return nfserr_bad_xdr; 75604f9e664SJ. Bruce Fields } 75704f9e664SJ. Bruce Fields 75804f9e664SJ. Bruce Fields static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x) 75904f9e664SJ. Bruce Fields { 76004f9e664SJ. Bruce Fields __be32 *p; 76104f9e664SJ. Bruce Fields 76204f9e664SJ. Bruce Fields READ_BUF(4); 76304f9e664SJ. Bruce Fields READ32(*x); 76404f9e664SJ. Bruce Fields /* Note: unlinke access bits, deny bits may be zero. */ 76501cd4afaSDan Carpenter if (*x & ~NFS4_SHARE_DENY_BOTH) 76604f9e664SJ. Bruce Fields return nfserr_bad_xdr; 76704f9e664SJ. Bruce Fields return nfs_ok; 76804f9e664SJ. Bruce Fields xdr_error: 76904f9e664SJ. Bruce Fields return nfserr_bad_xdr; 77004f9e664SJ. Bruce Fields } 77104f9e664SJ. Bruce Fields 772a084daf5SJ. Bruce Fields static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o) 773a084daf5SJ. Bruce Fields { 774a084daf5SJ. Bruce Fields __be32 *p; 775a084daf5SJ. Bruce Fields 776a084daf5SJ. Bruce Fields READ_BUF(4); 777a084daf5SJ. Bruce Fields READ32(o->len); 778a084daf5SJ. Bruce Fields 779a084daf5SJ. Bruce Fields if (o->len == 0 || o->len > NFS4_OPAQUE_LIMIT) 780a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 781a084daf5SJ. Bruce Fields 782a084daf5SJ. Bruce Fields READ_BUF(o->len); 783a084daf5SJ. Bruce Fields SAVEMEM(o->data, o->len); 784a084daf5SJ. Bruce Fields return nfs_ok; 785a084daf5SJ. Bruce Fields xdr_error: 786a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 787a084daf5SJ. Bruce Fields } 788a084daf5SJ. Bruce Fields 789b37ad28bSAl Viro static __be32 7901da177e4SLinus Torvalds nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) 7911da177e4SLinus Torvalds { 7921da177e4SLinus Torvalds DECODE_HEAD; 7932c8bd7e0SBenny Halevy u32 dummy; 7941da177e4SLinus Torvalds 7951da177e4SLinus Torvalds memset(open->op_bmval, 0, sizeof(open->op_bmval)); 7961da177e4SLinus Torvalds open->op_iattr.ia_valid = 0; 797fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 7981da177e4SLinus Torvalds 7991da177e4SLinus Torvalds /* seqid, share_access, share_deny, clientid, ownerlen */ 80004f9e664SJ. Bruce Fields READ_BUF(4); 8011da177e4SLinus Torvalds READ32(open->op_seqid); 8022c8bd7e0SBenny Halevy /* decode, yet ignore deleg_when until supported */ 8032c8bd7e0SBenny Halevy status = nfsd4_decode_share_access(argp, &open->op_share_access, 8042c8bd7e0SBenny Halevy &open->op_deleg_want, &dummy); 80504f9e664SJ. Bruce Fields if (status) 80604f9e664SJ. Bruce Fields goto xdr_error; 80704f9e664SJ. Bruce Fields status = nfsd4_decode_share_deny(argp, &open->op_share_deny); 80804f9e664SJ. Bruce Fields if (status) 80904f9e664SJ. Bruce Fields goto xdr_error; 810a084daf5SJ. Bruce Fields READ_BUF(sizeof(clientid_t)); 8111da177e4SLinus Torvalds COPYMEM(&open->op_clientid, sizeof(clientid_t)); 812a084daf5SJ. Bruce Fields status = nfsd4_decode_opaque(argp, &open->op_owner); 813a084daf5SJ. Bruce Fields if (status) 814a084daf5SJ. Bruce Fields goto xdr_error; 815a084daf5SJ. Bruce Fields READ_BUF(4); 8161da177e4SLinus Torvalds READ32(open->op_create); 8171da177e4SLinus Torvalds switch (open->op_create) { 8181da177e4SLinus Torvalds case NFS4_OPEN_NOCREATE: 8191da177e4SLinus Torvalds break; 8201da177e4SLinus Torvalds case NFS4_OPEN_CREATE: 8211da177e4SLinus Torvalds READ_BUF(4); 8221da177e4SLinus Torvalds READ32(open->op_createmode); 8231da177e4SLinus Torvalds switch (open->op_createmode) { 8241da177e4SLinus Torvalds case NFS4_CREATE_UNCHECKED: 8251da177e4SLinus Torvalds case NFS4_CREATE_GUARDED: 826c0d6fc8aSBenny Halevy status = nfsd4_decode_fattr(argp, open->op_bmval, 8273c8e0316SYu Zhiguo &open->op_iattr, &open->op_acl); 828c0d6fc8aSBenny Halevy if (status) 8291da177e4SLinus Torvalds goto out; 8301da177e4SLinus Torvalds break; 8311da177e4SLinus Torvalds case NFS4_CREATE_EXCLUSIVE: 832ab4684d1SChuck Lever READ_BUF(NFS4_VERIFIER_SIZE); 833ab4684d1SChuck Lever COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); 8341da177e4SLinus Torvalds break; 83579fb54abSBenny Halevy case NFS4_CREATE_EXCLUSIVE4_1: 83679fb54abSBenny Halevy if (argp->minorversion < 1) 83779fb54abSBenny Halevy goto xdr_error; 838ab4684d1SChuck Lever READ_BUF(NFS4_VERIFIER_SIZE); 839ab4684d1SChuck Lever COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); 84079fb54abSBenny Halevy status = nfsd4_decode_fattr(argp, open->op_bmval, 8413c8e0316SYu Zhiguo &open->op_iattr, &open->op_acl); 84279fb54abSBenny Halevy if (status) 84379fb54abSBenny Halevy goto out; 84479fb54abSBenny Halevy break; 8451da177e4SLinus Torvalds default: 8461da177e4SLinus Torvalds goto xdr_error; 8471da177e4SLinus Torvalds } 8481da177e4SLinus Torvalds break; 8491da177e4SLinus Torvalds default: 8501da177e4SLinus Torvalds goto xdr_error; 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds /* open_claim */ 8541da177e4SLinus Torvalds READ_BUF(4); 8551da177e4SLinus Torvalds READ32(open->op_claim_type); 8561da177e4SLinus Torvalds switch (open->op_claim_type) { 8571da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_NULL: 8581da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_PREV: 8591da177e4SLinus Torvalds READ_BUF(4); 8601da177e4SLinus Torvalds READ32(open->op_fname.len); 8611da177e4SLinus Torvalds READ_BUF(open->op_fname.len); 8621da177e4SLinus Torvalds SAVEMEM(open->op_fname.data, open->op_fname.len); 8631da177e4SLinus Torvalds if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) 8641da177e4SLinus Torvalds return status; 8651da177e4SLinus Torvalds break; 8661da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_PREVIOUS: 8671da177e4SLinus Torvalds READ_BUF(4); 8681da177e4SLinus Torvalds READ32(open->op_delegate_type); 8691da177e4SLinus Torvalds break; 8701da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_CUR: 871e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); 872e31a1b66SBenny Halevy if (status) 873e31a1b66SBenny Halevy return status; 874e31a1b66SBenny Halevy READ_BUF(4); 8751da177e4SLinus Torvalds READ32(open->op_fname.len); 8761da177e4SLinus Torvalds READ_BUF(open->op_fname.len); 8771da177e4SLinus Torvalds SAVEMEM(open->op_fname.data, open->op_fname.len); 8781da177e4SLinus Torvalds if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) 8791da177e4SLinus Torvalds return status; 8801da177e4SLinus Torvalds break; 8818b289b2cSJ. Bruce Fields case NFS4_OPEN_CLAIM_FH: 8828b289b2cSJ. Bruce Fields case NFS4_OPEN_CLAIM_DELEG_PREV_FH: 8838b289b2cSJ. Bruce Fields if (argp->minorversion < 1) 8848b289b2cSJ. Bruce Fields goto xdr_error; 8858b289b2cSJ. Bruce Fields /* void */ 8868b289b2cSJ. Bruce Fields break; 8878b289b2cSJ. Bruce Fields case NFS4_OPEN_CLAIM_DELEG_CUR_FH: 8888b289b2cSJ. Bruce Fields if (argp->minorversion < 1) 8898b289b2cSJ. Bruce Fields goto xdr_error; 8908b289b2cSJ. Bruce Fields status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); 8918b289b2cSJ. Bruce Fields if (status) 8928b289b2cSJ. Bruce Fields return status; 8938b289b2cSJ. Bruce Fields break; 8941da177e4SLinus Torvalds default: 8951da177e4SLinus Torvalds goto xdr_error; 8961da177e4SLinus Torvalds } 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds DECODE_TAIL; 8991da177e4SLinus Torvalds } 9001da177e4SLinus Torvalds 901b37ad28bSAl Viro static __be32 9021da177e4SLinus Torvalds nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) 9031da177e4SLinus Torvalds { 9041da177e4SLinus Torvalds DECODE_HEAD; 9051da177e4SLinus Torvalds 906e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); 907e31a1b66SBenny Halevy if (status) 908e31a1b66SBenny Halevy return status; 909e31a1b66SBenny Halevy READ_BUF(4); 9101da177e4SLinus Torvalds READ32(open_conf->oc_seqid); 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds DECODE_TAIL; 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 915b37ad28bSAl Viro static __be32 9161da177e4SLinus Torvalds nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down) 9171da177e4SLinus Torvalds { 9181da177e4SLinus Torvalds DECODE_HEAD; 9191da177e4SLinus Torvalds 920e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open_down->od_stateid); 921e31a1b66SBenny Halevy if (status) 922e31a1b66SBenny Halevy return status; 92304f9e664SJ. Bruce Fields READ_BUF(4); 9241da177e4SLinus Torvalds READ32(open_down->od_seqid); 9252c8bd7e0SBenny Halevy status = nfsd4_decode_share_access(argp, &open_down->od_share_access, 9262c8bd7e0SBenny Halevy &open_down->od_deleg_want, NULL); 92704f9e664SJ. Bruce Fields if (status) 92804f9e664SJ. Bruce Fields return status; 92904f9e664SJ. Bruce Fields status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny); 93004f9e664SJ. Bruce Fields if (status) 93104f9e664SJ. Bruce Fields return status; 9321da177e4SLinus Torvalds DECODE_TAIL; 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds 935b37ad28bSAl Viro static __be32 9361da177e4SLinus Torvalds nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) 9371da177e4SLinus Torvalds { 9381da177e4SLinus Torvalds DECODE_HEAD; 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds READ_BUF(4); 9411da177e4SLinus Torvalds READ32(putfh->pf_fhlen); 9421da177e4SLinus Torvalds if (putfh->pf_fhlen > NFS4_FHSIZE) 9431da177e4SLinus Torvalds goto xdr_error; 9441da177e4SLinus Torvalds READ_BUF(putfh->pf_fhlen); 9451da177e4SLinus Torvalds SAVEMEM(putfh->pf_fhval, putfh->pf_fhlen); 9461da177e4SLinus Torvalds 9471da177e4SLinus Torvalds DECODE_TAIL; 9481da177e4SLinus Torvalds } 9491da177e4SLinus Torvalds 950b37ad28bSAl Viro static __be32 9511da177e4SLinus Torvalds nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) 9521da177e4SLinus Torvalds { 9531da177e4SLinus Torvalds DECODE_HEAD; 9541da177e4SLinus Torvalds 955e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &read->rd_stateid); 956e31a1b66SBenny Halevy if (status) 957e31a1b66SBenny Halevy return status; 958e31a1b66SBenny Halevy READ_BUF(12); 9591da177e4SLinus Torvalds READ64(read->rd_offset); 9601da177e4SLinus Torvalds READ32(read->rd_length); 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds DECODE_TAIL; 9631da177e4SLinus Torvalds } 9641da177e4SLinus Torvalds 965b37ad28bSAl Viro static __be32 9661da177e4SLinus Torvalds nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir) 9671da177e4SLinus Torvalds { 9681da177e4SLinus Torvalds DECODE_HEAD; 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds READ_BUF(24); 9711da177e4SLinus Torvalds READ64(readdir->rd_cookie); 9721da177e4SLinus Torvalds COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data)); 9731da177e4SLinus Torvalds READ32(readdir->rd_dircount); /* just in case you needed a useless field... */ 9741da177e4SLinus Torvalds READ32(readdir->rd_maxcount); 9751da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval))) 9761da177e4SLinus Torvalds goto out; 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds DECODE_TAIL; 9791da177e4SLinus Torvalds } 9801da177e4SLinus Torvalds 981b37ad28bSAl Viro static __be32 9821da177e4SLinus Torvalds nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove) 9831da177e4SLinus Torvalds { 9841da177e4SLinus Torvalds DECODE_HEAD; 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds READ_BUF(4); 9871da177e4SLinus Torvalds READ32(remove->rm_namelen); 9881da177e4SLinus Torvalds READ_BUF(remove->rm_namelen); 9891da177e4SLinus Torvalds SAVEMEM(remove->rm_name, remove->rm_namelen); 9901da177e4SLinus Torvalds if ((status = check_filename(remove->rm_name, remove->rm_namelen, nfserr_noent))) 9911da177e4SLinus Torvalds return status; 9921da177e4SLinus Torvalds 9931da177e4SLinus Torvalds DECODE_TAIL; 9941da177e4SLinus Torvalds } 9951da177e4SLinus Torvalds 996b37ad28bSAl Viro static __be32 9971da177e4SLinus Torvalds nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename) 9981da177e4SLinus Torvalds { 9991da177e4SLinus Torvalds DECODE_HEAD; 10001da177e4SLinus Torvalds 10011da177e4SLinus Torvalds READ_BUF(4); 10021da177e4SLinus Torvalds READ32(rename->rn_snamelen); 10031da177e4SLinus Torvalds READ_BUF(rename->rn_snamelen + 4); 10041da177e4SLinus Torvalds SAVEMEM(rename->rn_sname, rename->rn_snamelen); 10051da177e4SLinus Torvalds READ32(rename->rn_tnamelen); 10061da177e4SLinus Torvalds READ_BUF(rename->rn_tnamelen); 10071da177e4SLinus Torvalds SAVEMEM(rename->rn_tname, rename->rn_tnamelen); 10081da177e4SLinus Torvalds if ((status = check_filename(rename->rn_sname, rename->rn_snamelen, nfserr_noent))) 10091da177e4SLinus Torvalds return status; 10101da177e4SLinus Torvalds if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen, nfserr_inval))) 10111da177e4SLinus Torvalds return status; 10121da177e4SLinus Torvalds 10131da177e4SLinus Torvalds DECODE_TAIL; 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds 1016b37ad28bSAl Viro static __be32 10171da177e4SLinus Torvalds nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) 10181da177e4SLinus Torvalds { 10191da177e4SLinus Torvalds DECODE_HEAD; 10201da177e4SLinus Torvalds 10211da177e4SLinus Torvalds READ_BUF(sizeof(clientid_t)); 10221da177e4SLinus Torvalds COPYMEM(clientid, sizeof(clientid_t)); 10231da177e4SLinus Torvalds 10241da177e4SLinus Torvalds DECODE_TAIL; 10251da177e4SLinus Torvalds } 10261da177e4SLinus Torvalds 1027b37ad28bSAl Viro static __be32 1028dcb488a3SAndy Adamson nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, 1029dcb488a3SAndy Adamson struct nfsd4_secinfo *secinfo) 1030dcb488a3SAndy Adamson { 1031dcb488a3SAndy Adamson DECODE_HEAD; 1032dcb488a3SAndy Adamson 1033dcb488a3SAndy Adamson READ_BUF(4); 1034dcb488a3SAndy Adamson READ32(secinfo->si_namelen); 1035dcb488a3SAndy Adamson READ_BUF(secinfo->si_namelen); 1036dcb488a3SAndy Adamson SAVEMEM(secinfo->si_name, secinfo->si_namelen); 1037dcb488a3SAndy Adamson status = check_filename(secinfo->si_name, secinfo->si_namelen, 1038dcb488a3SAndy Adamson nfserr_noent); 1039dcb488a3SAndy Adamson if (status) 1040dcb488a3SAndy Adamson return status; 1041dcb488a3SAndy Adamson DECODE_TAIL; 1042dcb488a3SAndy Adamson } 1043dcb488a3SAndy Adamson 1044dcb488a3SAndy Adamson static __be32 104504f4ad16SJ. Bruce Fields nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, 104604f4ad16SJ. Bruce Fields struct nfsd4_secinfo_no_name *sin) 104704f4ad16SJ. Bruce Fields { 104804f4ad16SJ. Bruce Fields DECODE_HEAD; 104904f4ad16SJ. Bruce Fields 105004f4ad16SJ. Bruce Fields READ_BUF(4); 105104f4ad16SJ. Bruce Fields READ32(sin->sin_style); 105204f4ad16SJ. Bruce Fields DECODE_TAIL; 105304f4ad16SJ. Bruce Fields } 105404f4ad16SJ. Bruce Fields 105504f4ad16SJ. Bruce Fields static __be32 10561da177e4SLinus Torvalds nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) 10571da177e4SLinus Torvalds { 1058e31a1b66SBenny Halevy __be32 status; 10591da177e4SLinus Torvalds 1060e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); 1061e31a1b66SBenny Halevy if (status) 1062e31a1b66SBenny Halevy return status; 10633c8e0316SYu Zhiguo return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, 10643c8e0316SYu Zhiguo &setattr->sa_acl); 10651da177e4SLinus Torvalds } 10661da177e4SLinus Torvalds 1067b37ad28bSAl Viro static __be32 10681da177e4SLinus Torvalds nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid) 10691da177e4SLinus Torvalds { 10701da177e4SLinus Torvalds DECODE_HEAD; 10711da177e4SLinus Torvalds 1072ab4684d1SChuck Lever READ_BUF(NFS4_VERIFIER_SIZE); 1073ab4684d1SChuck Lever COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE); 10741da177e4SLinus Torvalds 1075a084daf5SJ. Bruce Fields status = nfsd4_decode_opaque(argp, &setclientid->se_name); 1076a084daf5SJ. Bruce Fields if (status) 1077a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 1078a084daf5SJ. Bruce Fields READ_BUF(8); 10791da177e4SLinus Torvalds READ32(setclientid->se_callback_prog); 10801da177e4SLinus Torvalds READ32(setclientid->se_callback_netid_len); 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds READ_BUF(setclientid->se_callback_netid_len + 4); 10831da177e4SLinus Torvalds SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len); 10841da177e4SLinus Torvalds READ32(setclientid->se_callback_addr_len); 10851da177e4SLinus Torvalds 10861da177e4SLinus Torvalds READ_BUF(setclientid->se_callback_addr_len + 4); 10871da177e4SLinus Torvalds SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len); 10881da177e4SLinus Torvalds READ32(setclientid->se_callback_ident); 10891da177e4SLinus Torvalds 10901da177e4SLinus Torvalds DECODE_TAIL; 10911da177e4SLinus Torvalds } 10921da177e4SLinus Torvalds 1093b37ad28bSAl Viro static __be32 10941da177e4SLinus Torvalds nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c) 10951da177e4SLinus Torvalds { 10961da177e4SLinus Torvalds DECODE_HEAD; 10971da177e4SLinus Torvalds 1098ab4684d1SChuck Lever READ_BUF(8 + NFS4_VERIFIER_SIZE); 10991da177e4SLinus Torvalds COPYMEM(&scd_c->sc_clientid, 8); 1100ab4684d1SChuck Lever COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE); 11011da177e4SLinus Torvalds 11021da177e4SLinus Torvalds DECODE_TAIL; 11031da177e4SLinus Torvalds } 11041da177e4SLinus Torvalds 11051da177e4SLinus Torvalds /* Also used for NVERIFY */ 1106b37ad28bSAl Viro static __be32 11071da177e4SLinus Torvalds nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) 11081da177e4SLinus Torvalds { 11091da177e4SLinus Torvalds #if 0 11101da177e4SLinus Torvalds struct nfsd4_compoundargs save = { 11111da177e4SLinus Torvalds .p = argp->p, 11121da177e4SLinus Torvalds .end = argp->end, 11131da177e4SLinus Torvalds .rqstp = argp->rqstp, 11141da177e4SLinus Torvalds }; 11151da177e4SLinus Torvalds u32 ve_bmval[2]; 11161da177e4SLinus Torvalds struct iattr ve_iattr; /* request */ 11171da177e4SLinus Torvalds struct nfs4_acl *ve_acl; /* request */ 11181da177e4SLinus Torvalds #endif 11191da177e4SLinus Torvalds DECODE_HEAD; 11201da177e4SLinus Torvalds 11211da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) 11221da177e4SLinus Torvalds goto out; 11231da177e4SLinus Torvalds 11241da177e4SLinus Torvalds /* For convenience's sake, we compare raw xdr'd attributes in 11251da177e4SLinus Torvalds * nfsd4_proc_verify; however we still decode here just to return 11261da177e4SLinus Torvalds * correct error in case of bad xdr. */ 11271da177e4SLinus Torvalds #if 0 11281da177e4SLinus Torvalds status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl); 11291da177e4SLinus Torvalds if (status == nfserr_inval) { 11301da177e4SLinus Torvalds status = nfserrno(status); 11311da177e4SLinus Torvalds goto out; 11321da177e4SLinus Torvalds } 11331da177e4SLinus Torvalds #endif 11341da177e4SLinus Torvalds READ_BUF(4); 11351da177e4SLinus Torvalds READ32(verify->ve_attrlen); 11361da177e4SLinus Torvalds READ_BUF(verify->ve_attrlen); 11371da177e4SLinus Torvalds SAVEMEM(verify->ve_attrval, verify->ve_attrlen); 11381da177e4SLinus Torvalds 11391da177e4SLinus Torvalds DECODE_TAIL; 11401da177e4SLinus Torvalds } 11411da177e4SLinus Torvalds 1142*70cc7f75SJ. Bruce Fields static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) 11435a80a54dSJ. Bruce Fields { 11445a80a54dSJ. Bruce Fields int i = 1; 1145*70cc7f75SJ. Bruce Fields int buflen = write->wr_buflen; 11465a80a54dSJ. Bruce Fields 1147*70cc7f75SJ. Bruce Fields vec[0].iov_base = write->wr_head.iov_base; 1148*70cc7f75SJ. Bruce Fields vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len); 11495a80a54dSJ. Bruce Fields buflen -= vec[0].iov_len; 11505a80a54dSJ. Bruce Fields 11515a80a54dSJ. Bruce Fields while (buflen) { 1152*70cc7f75SJ. Bruce Fields vec[i].iov_base = page_address(write->wr_pagelist[i - 1]); 11535a80a54dSJ. Bruce Fields vec[i].iov_len = min_t(int, PAGE_SIZE, buflen); 11545a80a54dSJ. Bruce Fields buflen -= vec[i].iov_len; 11555a80a54dSJ. Bruce Fields i++; 11565a80a54dSJ. Bruce Fields } 11575a80a54dSJ. Bruce Fields return i; 11585a80a54dSJ. Bruce Fields } 11595a80a54dSJ. Bruce Fields 1160b37ad28bSAl Viro static __be32 11611da177e4SLinus Torvalds nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) 11621da177e4SLinus Torvalds { 11631da177e4SLinus Torvalds int avail; 11641da177e4SLinus Torvalds int len; 11651da177e4SLinus Torvalds DECODE_HEAD; 11661da177e4SLinus Torvalds 1167e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &write->wr_stateid); 1168e31a1b66SBenny Halevy if (status) 1169e31a1b66SBenny Halevy return status; 1170e31a1b66SBenny Halevy READ_BUF(16); 11711da177e4SLinus Torvalds READ64(write->wr_offset); 11721da177e4SLinus Torvalds READ32(write->wr_stable_how); 11731da177e4SLinus Torvalds if (write->wr_stable_how > 2) 11741da177e4SLinus Torvalds goto xdr_error; 11751da177e4SLinus Torvalds READ32(write->wr_buflen); 11761da177e4SLinus Torvalds 11771da177e4SLinus Torvalds /* Sorry .. no magic macros for this.. * 11781da177e4SLinus Torvalds * READ_BUF(write->wr_buflen); 11791da177e4SLinus Torvalds * SAVEMEM(write->wr_buf, write->wr_buflen); 11801da177e4SLinus Torvalds */ 11811da177e4SLinus Torvalds avail = (char*)argp->end - (char*)argp->p; 11821da177e4SLinus Torvalds if (avail + argp->pagelen < write->wr_buflen) { 1183817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", 1184817cb9d4SChuck Lever __FILE__, __LINE__); 11851da177e4SLinus Torvalds goto xdr_error; 11861da177e4SLinus Torvalds } 1187*70cc7f75SJ. Bruce Fields write->wr_head.iov_base = p; 1188*70cc7f75SJ. Bruce Fields write->wr_head.iov_len = avail; 11895a80a54dSJ. Bruce Fields WARN_ON(avail != (XDR_QUADLEN(avail) << 2)); 1190*70cc7f75SJ. Bruce Fields write->wr_pagelist = argp->pagelist; 11915a80a54dSJ. Bruce Fields 11925a80a54dSJ. Bruce Fields len = XDR_QUADLEN(write->wr_buflen) << 2; 11935a80a54dSJ. Bruce Fields if (len >= avail) { 11945a80a54dSJ. Bruce Fields int pages; 11955a80a54dSJ. Bruce Fields 11965a80a54dSJ. Bruce Fields len -= avail; 11975a80a54dSJ. Bruce Fields 11985a80a54dSJ. Bruce Fields pages = len >> PAGE_SHIFT; 11995a80a54dSJ. Bruce Fields argp->pagelist += pages; 12005a80a54dSJ. Bruce Fields argp->pagelen -= pages * PAGE_SIZE; 12015a80a54dSJ. Bruce Fields len -= pages * PAGE_SIZE; 12025a80a54dSJ. Bruce Fields 12035a80a54dSJ. Bruce Fields argp->p = (__be32 *)page_address(argp->pagelist[0]); 12045a80a54dSJ. Bruce Fields argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); 12051da177e4SLinus Torvalds } 12065a80a54dSJ. Bruce Fields argp->p += XDR_QUADLEN(len); 1207*70cc7f75SJ. Bruce Fields write->wr_vlen = fill_in_write_vector(argp->rqstp->rq_vec, write); 12085a80a54dSJ. Bruce Fields WARN_ON_ONCE(write->wr_vlen > ARRAY_SIZE(argp->rqstp->rq_vec)); 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds DECODE_TAIL; 12111da177e4SLinus Torvalds } 12121da177e4SLinus Torvalds 1213b37ad28bSAl Viro static __be32 12141da177e4SLinus Torvalds nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner) 12151da177e4SLinus Torvalds { 12161da177e4SLinus Torvalds DECODE_HEAD; 12171da177e4SLinus Torvalds 12181da177e4SLinus Torvalds READ_BUF(12); 12191da177e4SLinus Torvalds COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); 12201da177e4SLinus Torvalds READ32(rlockowner->rl_owner.len); 12211da177e4SLinus Torvalds READ_BUF(rlockowner->rl_owner.len); 12221da177e4SLinus Torvalds READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len); 12231da177e4SLinus Torvalds 122460adfc50SAndy Adamson if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid)) 122560adfc50SAndy Adamson return nfserr_inval; 12261da177e4SLinus Torvalds DECODE_TAIL; 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds 1229b37ad28bSAl Viro static __be32 12302db134ebSAndy Adamson nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, 12310733d213SAndy Adamson struct nfsd4_exchange_id *exid) 12322db134ebSAndy Adamson { 12335afa040bSMi Jinlong int dummy, tmp; 12340733d213SAndy Adamson DECODE_HEAD; 12350733d213SAndy Adamson 12360733d213SAndy Adamson READ_BUF(NFS4_VERIFIER_SIZE); 12370733d213SAndy Adamson COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE); 12380733d213SAndy Adamson 1239a084daf5SJ. Bruce Fields status = nfsd4_decode_opaque(argp, &exid->clname); 1240a084daf5SJ. Bruce Fields if (status) 1241a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 12420733d213SAndy Adamson 12430733d213SAndy Adamson READ_BUF(4); 12440733d213SAndy Adamson READ32(exid->flags); 12450733d213SAndy Adamson 12460733d213SAndy Adamson /* Ignore state_protect4_a */ 12470733d213SAndy Adamson READ_BUF(4); 12480733d213SAndy Adamson READ32(exid->spa_how); 12490733d213SAndy Adamson switch (exid->spa_how) { 12500733d213SAndy Adamson case SP4_NONE: 12510733d213SAndy Adamson break; 12520733d213SAndy Adamson case SP4_MACH_CRED: 12530733d213SAndy Adamson /* spo_must_enforce */ 12540733d213SAndy Adamson READ_BUF(4); 12550733d213SAndy Adamson READ32(dummy); 12560733d213SAndy Adamson READ_BUF(dummy * 4); 12570733d213SAndy Adamson p += dummy; 12580733d213SAndy Adamson 12590733d213SAndy Adamson /* spo_must_allow */ 12600733d213SAndy Adamson READ_BUF(4); 12610733d213SAndy Adamson READ32(dummy); 12620733d213SAndy Adamson READ_BUF(dummy * 4); 12630733d213SAndy Adamson p += dummy; 12640733d213SAndy Adamson break; 12650733d213SAndy Adamson case SP4_SSV: 12660733d213SAndy Adamson /* ssp_ops */ 12670733d213SAndy Adamson READ_BUF(4); 12680733d213SAndy Adamson READ32(dummy); 12690733d213SAndy Adamson READ_BUF(dummy * 4); 12700733d213SAndy Adamson p += dummy; 12710733d213SAndy Adamson 12720733d213SAndy Adamson READ_BUF(4); 12730733d213SAndy Adamson READ32(dummy); 12740733d213SAndy Adamson READ_BUF(dummy * 4); 12750733d213SAndy Adamson p += dummy; 12760733d213SAndy Adamson 12770733d213SAndy Adamson /* ssp_hash_algs<> */ 12780733d213SAndy Adamson READ_BUF(4); 12795afa040bSMi Jinlong READ32(tmp); 12805afa040bSMi Jinlong while (tmp--) { 12810733d213SAndy Adamson READ_BUF(4); 12820733d213SAndy Adamson READ32(dummy); 12830733d213SAndy Adamson READ_BUF(dummy); 12840733d213SAndy Adamson p += XDR_QUADLEN(dummy); 12855afa040bSMi Jinlong } 12865afa040bSMi Jinlong 12875afa040bSMi Jinlong /* ssp_encr_algs<> */ 12885afa040bSMi Jinlong READ_BUF(4); 12895afa040bSMi Jinlong READ32(tmp); 12905afa040bSMi Jinlong while (tmp--) { 12915afa040bSMi Jinlong READ_BUF(4); 12925afa040bSMi Jinlong READ32(dummy); 12935afa040bSMi Jinlong READ_BUF(dummy); 12945afa040bSMi Jinlong p += XDR_QUADLEN(dummy); 12955afa040bSMi Jinlong } 12960733d213SAndy Adamson 12970733d213SAndy Adamson /* ssp_window and ssp_num_gss_handles */ 12980733d213SAndy Adamson READ_BUF(8); 12990733d213SAndy Adamson READ32(dummy); 13000733d213SAndy Adamson READ32(dummy); 13010733d213SAndy Adamson break; 13020733d213SAndy Adamson default: 13030733d213SAndy Adamson goto xdr_error; 13040733d213SAndy Adamson } 13050733d213SAndy Adamson 13060733d213SAndy Adamson /* Ignore Implementation ID */ 13070733d213SAndy Adamson READ_BUF(4); /* nfs_impl_id4 array length */ 13080733d213SAndy Adamson READ32(dummy); 13090733d213SAndy Adamson 13100733d213SAndy Adamson if (dummy > 1) 13110733d213SAndy Adamson goto xdr_error; 13120733d213SAndy Adamson 13130733d213SAndy Adamson if (dummy == 1) { 13140733d213SAndy Adamson /* nii_domain */ 13150733d213SAndy Adamson READ_BUF(4); 13160733d213SAndy Adamson READ32(dummy); 13170733d213SAndy Adamson READ_BUF(dummy); 13180733d213SAndy Adamson p += XDR_QUADLEN(dummy); 13190733d213SAndy Adamson 13200733d213SAndy Adamson /* nii_name */ 13210733d213SAndy Adamson READ_BUF(4); 13220733d213SAndy Adamson READ32(dummy); 13230733d213SAndy Adamson READ_BUF(dummy); 13240733d213SAndy Adamson p += XDR_QUADLEN(dummy); 13250733d213SAndy Adamson 13260733d213SAndy Adamson /* nii_date */ 13270733d213SAndy Adamson READ_BUF(12); 13280733d213SAndy Adamson p += 3; 13290733d213SAndy Adamson } 13300733d213SAndy Adamson DECODE_TAIL; 13312db134ebSAndy Adamson } 13322db134ebSAndy Adamson 13332db134ebSAndy Adamson static __be32 13342db134ebSAndy Adamson nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, 13352db134ebSAndy Adamson struct nfsd4_create_session *sess) 13362db134ebSAndy Adamson { 1337ec6b5d7bSAndy Adamson DECODE_HEAD; 1338ec6b5d7bSAndy Adamson u32 dummy; 1339ec6b5d7bSAndy Adamson 1340ec6b5d7bSAndy Adamson READ_BUF(16); 1341ec6b5d7bSAndy Adamson COPYMEM(&sess->clientid, 8); 1342ec6b5d7bSAndy Adamson READ32(sess->seqid); 1343ec6b5d7bSAndy Adamson READ32(sess->flags); 1344ec6b5d7bSAndy Adamson 1345ec6b5d7bSAndy Adamson /* Fore channel attrs */ 1346ec6b5d7bSAndy Adamson READ_BUF(28); 1347ec6b5d7bSAndy Adamson READ32(dummy); /* headerpadsz is always 0 */ 1348ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxreq_sz); 1349ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxresp_sz); 1350ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxresp_cached); 1351ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxops); 1352ec6b5d7bSAndy Adamson READ32(sess->fore_channel.maxreqs); 1353ec6b5d7bSAndy Adamson READ32(sess->fore_channel.nr_rdma_attrs); 1354ec6b5d7bSAndy Adamson if (sess->fore_channel.nr_rdma_attrs == 1) { 1355ec6b5d7bSAndy Adamson READ_BUF(4); 1356ec6b5d7bSAndy Adamson READ32(sess->fore_channel.rdma_attrs); 1357ec6b5d7bSAndy Adamson } else if (sess->fore_channel.nr_rdma_attrs > 1) { 1358ec6b5d7bSAndy Adamson dprintk("Too many fore channel attr bitmaps!\n"); 1359ec6b5d7bSAndy Adamson goto xdr_error; 1360ec6b5d7bSAndy Adamson } 1361ec6b5d7bSAndy Adamson 1362ec6b5d7bSAndy Adamson /* Back channel attrs */ 1363ec6b5d7bSAndy Adamson READ_BUF(28); 1364ec6b5d7bSAndy Adamson READ32(dummy); /* headerpadsz is always 0 */ 1365ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxreq_sz); 1366ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxresp_sz); 1367ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxresp_cached); 1368ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxops); 1369ec6b5d7bSAndy Adamson READ32(sess->back_channel.maxreqs); 1370ec6b5d7bSAndy Adamson READ32(sess->back_channel.nr_rdma_attrs); 1371ec6b5d7bSAndy Adamson if (sess->back_channel.nr_rdma_attrs == 1) { 1372ec6b5d7bSAndy Adamson READ_BUF(4); 1373ec6b5d7bSAndy Adamson READ32(sess->back_channel.rdma_attrs); 1374ec6b5d7bSAndy Adamson } else if (sess->back_channel.nr_rdma_attrs > 1) { 1375ec6b5d7bSAndy Adamson dprintk("Too many back channel attr bitmaps!\n"); 1376ec6b5d7bSAndy Adamson goto xdr_error; 1377ec6b5d7bSAndy Adamson } 1378ec6b5d7bSAndy Adamson 1379acb2887eSJ. Bruce Fields READ_BUF(4); 1380ec6b5d7bSAndy Adamson READ32(sess->callback_prog); 1381acb2887eSJ. Bruce Fields nfsd4_decode_cb_sec(argp, &sess->cb_sec); 1382ec6b5d7bSAndy Adamson DECODE_TAIL; 13832db134ebSAndy Adamson } 13842db134ebSAndy Adamson 13852db134ebSAndy Adamson static __be32 13862db134ebSAndy Adamson nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp, 13872db134ebSAndy Adamson struct nfsd4_destroy_session *destroy_session) 13882db134ebSAndy Adamson { 1389e10e0cfcSBenny Halevy DECODE_HEAD; 1390e10e0cfcSBenny Halevy READ_BUF(NFS4_MAX_SESSIONID_LEN); 1391e10e0cfcSBenny Halevy COPYMEM(destroy_session->sessionid.data, NFS4_MAX_SESSIONID_LEN); 1392e10e0cfcSBenny Halevy 1393e10e0cfcSBenny Halevy DECODE_TAIL; 13942db134ebSAndy Adamson } 13952db134ebSAndy Adamson 13962db134ebSAndy Adamson static __be32 1397e1ca12dfSBryan Schumaker nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, 1398e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 1399e1ca12dfSBryan Schumaker { 1400e1ca12dfSBryan Schumaker DECODE_HEAD; 1401e1ca12dfSBryan Schumaker 1402e1ca12dfSBryan Schumaker READ_BUF(sizeof(stateid_t)); 1403e1ca12dfSBryan Schumaker READ32(free_stateid->fr_stateid.si_generation); 1404e1ca12dfSBryan Schumaker COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t)); 1405e1ca12dfSBryan Schumaker 1406e1ca12dfSBryan Schumaker DECODE_TAIL; 1407e1ca12dfSBryan Schumaker } 1408e1ca12dfSBryan Schumaker 1409e1ca12dfSBryan Schumaker static __be32 14102db134ebSAndy Adamson nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, 14112db134ebSAndy Adamson struct nfsd4_sequence *seq) 14122db134ebSAndy Adamson { 1413b85d4c01SBenny Halevy DECODE_HEAD; 1414b85d4c01SBenny Halevy 1415b85d4c01SBenny Halevy READ_BUF(NFS4_MAX_SESSIONID_LEN + 16); 1416b85d4c01SBenny Halevy COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); 1417b85d4c01SBenny Halevy READ32(seq->seqid); 1418b85d4c01SBenny Halevy READ32(seq->slotid); 1419b85d4c01SBenny Halevy READ32(seq->maxslots); 1420b85d4c01SBenny Halevy READ32(seq->cachethis); 1421b85d4c01SBenny Halevy 1422b85d4c01SBenny Halevy DECODE_TAIL; 14232db134ebSAndy Adamson } 14242db134ebSAndy Adamson 142517456804SBryan Schumaker static __be32 142617456804SBryan Schumaker nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid) 142717456804SBryan Schumaker { 142817456804SBryan Schumaker int i; 142903cfb420SBryan Schumaker __be32 *p, status; 143003cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 143117456804SBryan Schumaker 143217456804SBryan Schumaker READ_BUF(4); 143317456804SBryan Schumaker test_stateid->ts_num_ids = ntohl(*p++); 143417456804SBryan Schumaker 143503cfb420SBryan Schumaker INIT_LIST_HEAD(&test_stateid->ts_stateid_list); 143617456804SBryan Schumaker 143717456804SBryan Schumaker for (i = 0; i < test_stateid->ts_num_ids; i++) { 143803cfb420SBryan Schumaker stateid = kmalloc(sizeof(struct nfsd4_test_stateid_id), GFP_KERNEL); 143903cfb420SBryan Schumaker if (!stateid) { 1440afcf6792SAl Viro status = nfserrno(-ENOMEM); 144103cfb420SBryan Schumaker goto out; 144203cfb420SBryan Schumaker } 144303cfb420SBryan Schumaker 144403cfb420SBryan Schumaker defer_free(argp, kfree, stateid); 144503cfb420SBryan Schumaker INIT_LIST_HEAD(&stateid->ts_id_list); 144603cfb420SBryan Schumaker list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list); 144703cfb420SBryan Schumaker 144803cfb420SBryan Schumaker status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid); 144917456804SBryan Schumaker if (status) 145003cfb420SBryan Schumaker goto out; 145117456804SBryan Schumaker } 145217456804SBryan Schumaker 145317456804SBryan Schumaker status = 0; 145417456804SBryan Schumaker out: 145517456804SBryan Schumaker return status; 145617456804SBryan Schumaker xdr_error: 145717456804SBryan Schumaker dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__); 145817456804SBryan Schumaker status = nfserr_bad_xdr; 145917456804SBryan Schumaker goto out; 146017456804SBryan Schumaker } 146117456804SBryan Schumaker 1462345c2842SMi Jinlong static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc) 1463345c2842SMi Jinlong { 1464345c2842SMi Jinlong DECODE_HEAD; 1465345c2842SMi Jinlong 1466345c2842SMi Jinlong READ_BUF(8); 1467345c2842SMi Jinlong COPYMEM(&dc->clientid, 8); 1468345c2842SMi Jinlong 1469345c2842SMi Jinlong DECODE_TAIL; 1470345c2842SMi Jinlong } 1471345c2842SMi Jinlong 14724dc6ec00SJ. Bruce Fields static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc) 14734dc6ec00SJ. Bruce Fields { 14744dc6ec00SJ. Bruce Fields DECODE_HEAD; 14754dc6ec00SJ. Bruce Fields 14764dc6ec00SJ. Bruce Fields READ_BUF(4); 14774dc6ec00SJ. Bruce Fields READ32(rc->rca_one_fs); 14784dc6ec00SJ. Bruce Fields 14794dc6ec00SJ. Bruce Fields DECODE_TAIL; 14804dc6ec00SJ. Bruce Fields } 14814dc6ec00SJ. Bruce Fields 14822db134ebSAndy Adamson static __be32 1483347e0ad9SBenny Halevy nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p) 1484347e0ad9SBenny Halevy { 1485347e0ad9SBenny Halevy return nfs_ok; 1486347e0ad9SBenny Halevy } 1487347e0ad9SBenny Halevy 14883c375c6fSBenny Halevy static __be32 14893c375c6fSBenny Halevy nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p) 14903c375c6fSBenny Halevy { 14911e685ec2SBenny Halevy return nfserr_notsupp; 14923c375c6fSBenny Halevy } 14933c375c6fSBenny Halevy 1494347e0ad9SBenny Halevy typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *); 1495347e0ad9SBenny Halevy 1496347e0ad9SBenny Halevy static nfsd4_dec nfsd4_dec_ops[] = { 1497ad1060c8SJ. Bruce Fields [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, 1498ad1060c8SJ. Bruce Fields [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, 1499ad1060c8SJ. Bruce Fields [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, 1500ad1060c8SJ. Bruce Fields [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, 1501ad1060c8SJ. Bruce Fields [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, 1502ad1060c8SJ. Bruce Fields [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, 1503ad1060c8SJ. Bruce Fields [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, 1504ad1060c8SJ. Bruce Fields [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, 1505ad1060c8SJ. Bruce Fields [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, 1506ad1060c8SJ. Bruce Fields [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, 1507ad1060c8SJ. Bruce Fields [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, 1508ad1060c8SJ. Bruce Fields [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, 1509ad1060c8SJ. Bruce Fields [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, 1510ad1060c8SJ. Bruce Fields [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, 1511ad1060c8SJ. Bruce Fields [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, 1512ad1060c8SJ. Bruce Fields [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, 1513ad1060c8SJ. Bruce Fields [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, 1514ad1060c8SJ. Bruce Fields [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, 1515ad1060c8SJ. Bruce Fields [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, 1516ad1060c8SJ. Bruce Fields [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, 1517a1c8c4d1SJ. Bruce Fields [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_noop, 1518ad1060c8SJ. Bruce Fields [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, 1519ad1060c8SJ. Bruce Fields [OP_READ] = (nfsd4_dec)nfsd4_decode_read, 1520ad1060c8SJ. Bruce Fields [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, 1521ad1060c8SJ. Bruce Fields [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, 1522ad1060c8SJ. Bruce Fields [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, 1523ad1060c8SJ. Bruce Fields [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, 1524ad1060c8SJ. Bruce Fields [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew, 1525ad1060c8SJ. Bruce Fields [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, 1526ad1060c8SJ. Bruce Fields [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, 1527ad1060c8SJ. Bruce Fields [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, 1528ad1060c8SJ. Bruce Fields [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, 1529ad1060c8SJ. Bruce Fields [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid, 1530ad1060c8SJ. Bruce Fields [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm, 1531ad1060c8SJ. Bruce Fields [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, 1532ad1060c8SJ. Bruce Fields [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, 1533ad1060c8SJ. Bruce Fields [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, 1534347e0ad9SBenny Halevy }; 1535347e0ad9SBenny Halevy 15362db134ebSAndy Adamson static nfsd4_dec nfsd41_dec_ops[] = { 15379064caaeSRandy Dunlap [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, 15389064caaeSRandy Dunlap [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, 15399064caaeSRandy Dunlap [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, 15409064caaeSRandy Dunlap [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, 15419064caaeSRandy Dunlap [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, 15429064caaeSRandy Dunlap [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, 15439064caaeSRandy Dunlap [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, 15449064caaeSRandy Dunlap [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, 15459064caaeSRandy Dunlap [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, 15469064caaeSRandy Dunlap [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, 15479064caaeSRandy Dunlap [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, 15489064caaeSRandy Dunlap [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, 15499064caaeSRandy Dunlap [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, 15509064caaeSRandy Dunlap [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, 15519064caaeSRandy Dunlap [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, 15529064caaeSRandy Dunlap [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, 15539064caaeSRandy Dunlap [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, 15549064caaeSRandy Dunlap [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp, 15559064caaeSRandy Dunlap [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, 15569064caaeSRandy Dunlap [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, 15579064caaeSRandy Dunlap [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp, 15589064caaeSRandy Dunlap [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, 15599064caaeSRandy Dunlap [OP_READ] = (nfsd4_dec)nfsd4_decode_read, 15609064caaeSRandy Dunlap [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, 15619064caaeSRandy Dunlap [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, 15629064caaeSRandy Dunlap [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, 15639064caaeSRandy Dunlap [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, 15649064caaeSRandy Dunlap [OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp, 15659064caaeSRandy Dunlap [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, 15669064caaeSRandy Dunlap [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, 15679064caaeSRandy Dunlap [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, 15689064caaeSRandy Dunlap [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, 15699064caaeSRandy Dunlap [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, 15709064caaeSRandy Dunlap [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp, 15719064caaeSRandy Dunlap [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, 15729064caaeSRandy Dunlap [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, 15739064caaeSRandy Dunlap [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, 15742db134ebSAndy Adamson 15752db134ebSAndy Adamson /* new operations for NFSv4.1 */ 1576cb73a9f4SJ. Bruce Fields [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, 15771d1bc8f2SJ. Bruce Fields [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, 15789064caaeSRandy Dunlap [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, 15799064caaeSRandy Dunlap [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, 15809064caaeSRandy Dunlap [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, 1581e1ca12dfSBryan Schumaker [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid, 15829064caaeSRandy Dunlap [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, 15839064caaeSRandy Dunlap [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, 15849064caaeSRandy Dunlap [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, 15859064caaeSRandy Dunlap [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, 15869064caaeSRandy Dunlap [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, 15879064caaeSRandy Dunlap [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, 158804f4ad16SJ. Bruce Fields [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name, 15899064caaeSRandy Dunlap [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, 15909064caaeSRandy Dunlap [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, 159117456804SBryan Schumaker [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid, 15929064caaeSRandy Dunlap [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, 1593345c2842SMi Jinlong [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid, 15944dc6ec00SJ. Bruce Fields [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, 15952db134ebSAndy Adamson }; 15962db134ebSAndy Adamson 1597f2feb96bSBenny Halevy struct nfsd4_minorversion_ops { 1598f2feb96bSBenny Halevy nfsd4_dec *decoders; 1599f2feb96bSBenny Halevy int nops; 1600f2feb96bSBenny Halevy }; 1601f2feb96bSBenny Halevy 1602f2feb96bSBenny Halevy static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { 1603ad1060c8SJ. Bruce Fields [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, 16042db134ebSAndy Adamson [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, 1605f2feb96bSBenny Halevy }; 1606f2feb96bSBenny Halevy 1607347e0ad9SBenny Halevy static __be32 16081da177e4SLinus Torvalds nfsd4_decode_compound(struct nfsd4_compoundargs *argp) 16091da177e4SLinus Torvalds { 16101da177e4SLinus Torvalds DECODE_HEAD; 16111da177e4SLinus Torvalds struct nfsd4_op *op; 1612f2feb96bSBenny Halevy struct nfsd4_minorversion_ops *ops; 16131091006cSJ. Bruce Fields bool cachethis = false; 16141da177e4SLinus Torvalds int i; 16151da177e4SLinus Torvalds 16161da177e4SLinus Torvalds READ_BUF(4); 16171da177e4SLinus Torvalds READ32(argp->taglen); 16181da177e4SLinus Torvalds READ_BUF(argp->taglen + 8); 16191da177e4SLinus Torvalds SAVEMEM(argp->tag, argp->taglen); 16201da177e4SLinus Torvalds READ32(argp->minorversion); 16211da177e4SLinus Torvalds READ32(argp->opcnt); 16221da177e4SLinus Torvalds 16231da177e4SLinus Torvalds if (argp->taglen > NFSD4_MAX_TAGLEN) 16241da177e4SLinus Torvalds goto xdr_error; 16251da177e4SLinus Torvalds if (argp->opcnt > 100) 16261da177e4SLinus Torvalds goto xdr_error; 16271da177e4SLinus Torvalds 1628e8c96f8cSTobias Klauser if (argp->opcnt > ARRAY_SIZE(argp->iops)) { 16291da177e4SLinus Torvalds argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); 16301da177e4SLinus Torvalds if (!argp->ops) { 16311da177e4SLinus Torvalds argp->ops = argp->iops; 1632817cb9d4SChuck Lever dprintk("nfsd: couldn't allocate room for COMPOUND\n"); 16331da177e4SLinus Torvalds goto xdr_error; 16341da177e4SLinus Torvalds } 16351da177e4SLinus Torvalds } 16361da177e4SLinus Torvalds 1637f2feb96bSBenny Halevy if (argp->minorversion >= ARRAY_SIZE(nfsd4_minorversion)) 163830cff1ffSBenny Halevy argp->opcnt = 0; 163930cff1ffSBenny Halevy 1640f2feb96bSBenny Halevy ops = &nfsd4_minorversion[argp->minorversion]; 16411da177e4SLinus Torvalds for (i = 0; i < argp->opcnt; i++) { 16421da177e4SLinus Torvalds op = &argp->ops[i]; 16431da177e4SLinus Torvalds op->replay = NULL; 16441da177e4SLinus Torvalds 16458a61b18cSJ. Bruce Fields READ_BUF(4); 16468a61b18cSJ. Bruce Fields READ32(op->opnum); 16471da177e4SLinus Torvalds 1648de3cab79SRicardo Labiaga if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) 1649f2feb96bSBenny Halevy op->status = ops->decoders[op->opnum](argp, &op->u); 1650347e0ad9SBenny Halevy else { 16511da177e4SLinus Torvalds op->opnum = OP_ILLEGAL; 16521da177e4SLinus Torvalds op->status = nfserr_op_illegal; 16531da177e4SLinus Torvalds } 16541da177e4SLinus Torvalds 16551da177e4SLinus Torvalds if (op->status) { 16561da177e4SLinus Torvalds argp->opcnt = i+1; 16571da177e4SLinus Torvalds break; 16581da177e4SLinus Torvalds } 16591091006cSJ. Bruce Fields /* 16601091006cSJ. Bruce Fields * We'll try to cache the result in the DRC if any one 16611091006cSJ. Bruce Fields * op in the compound wants to be cached: 16621091006cSJ. Bruce Fields */ 16631091006cSJ. Bruce Fields cachethis |= nfsd4_cache_this_op(op); 16641da177e4SLinus Torvalds } 16651091006cSJ. Bruce Fields /* Sessions make the DRC unnecessary: */ 16661091006cSJ. Bruce Fields if (argp->minorversion) 16671091006cSJ. Bruce Fields cachethis = false; 16681091006cSJ. Bruce Fields argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; 16691da177e4SLinus Torvalds 16701da177e4SLinus Torvalds DECODE_TAIL; 16711da177e4SLinus Torvalds } 16721da177e4SLinus Torvalds 16731da177e4SLinus Torvalds #define WRITE32(n) *p++ = htonl(n) 16741da177e4SLinus Torvalds #define WRITE64(n) do { \ 16751da177e4SLinus Torvalds *p++ = htonl((u32)((n) >> 32)); \ 16761da177e4SLinus Torvalds *p++ = htonl((u32)(n)); \ 16771da177e4SLinus Torvalds } while (0) 16785108b276SHarvey Harrison #define WRITEMEM(ptr,nbytes) do { if (nbytes > 0) { \ 16791da177e4SLinus Torvalds *(p + XDR_QUADLEN(nbytes) -1) = 0; \ 16801da177e4SLinus Torvalds memcpy(p, ptr, nbytes); \ 16811da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 16825108b276SHarvey Harrison }} while (0) 1683c654b8a9SJ. Bruce Fields 1684c654b8a9SJ. Bruce Fields static void write32(__be32 **p, u32 n) 1685c654b8a9SJ. Bruce Fields { 168645eaa1c1SJ. Bruce Fields *(*p)++ = htonl(n); 1687c654b8a9SJ. Bruce Fields } 1688c654b8a9SJ. Bruce Fields 1689c654b8a9SJ. Bruce Fields static void write64(__be32 **p, u64 n) 1690c654b8a9SJ. Bruce Fields { 169145eaa1c1SJ. Bruce Fields write32(p, (n >> 32)); 1692c654b8a9SJ. Bruce Fields write32(p, (u32)n); 1693c654b8a9SJ. Bruce Fields } 1694c654b8a9SJ. Bruce Fields 1695c654b8a9SJ. Bruce Fields static void write_change(__be32 **p, struct kstat *stat, struct inode *inode) 1696c654b8a9SJ. Bruce Fields { 1697c654b8a9SJ. Bruce Fields if (IS_I_VERSION(inode)) { 1698c654b8a9SJ. Bruce Fields write64(p, inode->i_version); 1699c654b8a9SJ. Bruce Fields } else { 1700c654b8a9SJ. Bruce Fields write32(p, stat->ctime.tv_sec); 1701c654b8a9SJ. Bruce Fields write32(p, stat->ctime.tv_nsec); 1702c654b8a9SJ. Bruce Fields } 1703c654b8a9SJ. Bruce Fields } 1704c654b8a9SJ. Bruce Fields 1705c654b8a9SJ. Bruce Fields static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) 1706c654b8a9SJ. Bruce Fields { 1707c654b8a9SJ. Bruce Fields write32(p, c->atomic); 1708c654b8a9SJ. Bruce Fields if (c->change_supported) { 1709c654b8a9SJ. Bruce Fields write64(p, c->before_change); 1710c654b8a9SJ. Bruce Fields write64(p, c->after_change); 1711c654b8a9SJ. Bruce Fields } else { 1712c654b8a9SJ. Bruce Fields write32(p, c->before_ctime_sec); 1713c654b8a9SJ. Bruce Fields write32(p, c->before_ctime_nsec); 1714c654b8a9SJ. Bruce Fields write32(p, c->after_ctime_sec); 1715c654b8a9SJ. Bruce Fields write32(p, c->after_ctime_nsec); 1716c654b8a9SJ. Bruce Fields } 1717c654b8a9SJ. Bruce Fields } 17181da177e4SLinus Torvalds 17191da177e4SLinus Torvalds #define RESERVE_SPACE(nbytes) do { \ 17201da177e4SLinus Torvalds p = resp->p; \ 17211da177e4SLinus Torvalds BUG_ON(p + XDR_QUADLEN(nbytes) > resp->end); \ 17221da177e4SLinus Torvalds } while (0) 17231da177e4SLinus Torvalds #define ADJUST_ARGS() resp->p = p 17241da177e4SLinus Torvalds 17251da177e4SLinus Torvalds /* 17261da177e4SLinus Torvalds * Header routine to setup seqid operation replay cache 17271da177e4SLinus Torvalds */ 17281da177e4SLinus Torvalds #define ENCODE_SEQID_OP_HEAD \ 17292ebbc012SAl Viro __be32 *save; \ 17301da177e4SLinus Torvalds \ 17311da177e4SLinus Torvalds save = resp->p; 17321da177e4SLinus Torvalds 17331da177e4SLinus Torvalds /* 17347fb64ceeSNeilBrown * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This 17357fb64ceeSNeilBrown * is where sequence id's are incremented, and the replay cache is filled. 17367fb64ceeSNeilBrown * Note that we increment sequence id's here, at the last moment, so we're sure 17377fb64ceeSNeilBrown * we know whether the error to be returned is a sequence id mutating error. 17381da177e4SLinus Torvalds */ 17391da177e4SLinus Torvalds 1740f3e42237SJ. Bruce Fields static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, __be32 nfserr) 1741f3e42237SJ. Bruce Fields { 1742f3e42237SJ. Bruce Fields struct nfs4_stateowner *stateowner = resp->cstate.replay_owner; 1743f3e42237SJ. Bruce Fields 1744f3e42237SJ. Bruce Fields if (seqid_mutating_err(ntohl(nfserr)) && stateowner) { 1745f3e42237SJ. Bruce Fields stateowner->so_seqid++; 1746f3e42237SJ. Bruce Fields stateowner->so_replay.rp_status = nfserr; 1747f3e42237SJ. Bruce Fields stateowner->so_replay.rp_buflen = 1748f3e42237SJ. Bruce Fields (char *)resp->p - (char *)save; 1749f3e42237SJ. Bruce Fields memcpy(stateowner->so_replay.rp_buf, save, 1750f3e42237SJ. Bruce Fields stateowner->so_replay.rp_buflen); 175138c387b5SJ. Bruce Fields nfsd4_purge_closed_stateid(stateowner); 1752f3e42237SJ. Bruce Fields } 1753f3e42237SJ. Bruce Fields } 17541da177e4SLinus Torvalds 175581c3f413SJ.Bruce Fields /* Encode as an array of strings the string given with components 1756e7a0444aSWeston Andros Adamson * separated @sep, escaped with esc_enter and esc_exit. 175781c3f413SJ.Bruce Fields */ 1758e7a0444aSWeston Andros Adamson static __be32 nfsd4_encode_components_esc(char sep, char *components, 1759e7a0444aSWeston Andros Adamson __be32 **pp, int *buflen, 1760e7a0444aSWeston Andros Adamson char esc_enter, char esc_exit) 176181c3f413SJ.Bruce Fields { 17622ebbc012SAl Viro __be32 *p = *pp; 17632ebbc012SAl Viro __be32 *countp = p; 176481c3f413SJ.Bruce Fields int strlen, count=0; 1765e7a0444aSWeston Andros Adamson char *str, *end, *next; 176681c3f413SJ.Bruce Fields 176781c3f413SJ.Bruce Fields dprintk("nfsd4_encode_components(%s)\n", components); 176881c3f413SJ.Bruce Fields if ((*buflen -= 4) < 0) 176981c3f413SJ.Bruce Fields return nfserr_resource; 177081c3f413SJ.Bruce Fields WRITE32(0); /* We will fill this in with @count later */ 177181c3f413SJ.Bruce Fields end = str = components; 177281c3f413SJ.Bruce Fields while (*end) { 1773e7a0444aSWeston Andros Adamson bool found_esc = false; 1774e7a0444aSWeston Andros Adamson 1775e7a0444aSWeston Andros Adamson /* try to parse as esc_start, ..., esc_end, sep */ 1776e7a0444aSWeston Andros Adamson if (*str == esc_enter) { 1777e7a0444aSWeston Andros Adamson for (; *end && (*end != esc_exit); end++) 1778e7a0444aSWeston Andros Adamson /* find esc_exit or end of string */; 1779e7a0444aSWeston Andros Adamson next = end + 1; 1780e7a0444aSWeston Andros Adamson if (*end && (!*next || *next == sep)) { 1781e7a0444aSWeston Andros Adamson str++; 1782e7a0444aSWeston Andros Adamson found_esc = true; 1783e7a0444aSWeston Andros Adamson } 1784e7a0444aSWeston Andros Adamson } 1785e7a0444aSWeston Andros Adamson 1786e7a0444aSWeston Andros Adamson if (!found_esc) 178781c3f413SJ.Bruce Fields for (; *end && (*end != sep); end++) 1788e7a0444aSWeston Andros Adamson /* find sep or end of string */; 1789e7a0444aSWeston Andros Adamson 179081c3f413SJ.Bruce Fields strlen = end - str; 179181c3f413SJ.Bruce Fields if (strlen) { 179281c3f413SJ.Bruce Fields if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) 179381c3f413SJ.Bruce Fields return nfserr_resource; 179481c3f413SJ.Bruce Fields WRITE32(strlen); 179581c3f413SJ.Bruce Fields WRITEMEM(str, strlen); 179681c3f413SJ.Bruce Fields count++; 179781c3f413SJ.Bruce Fields } 179881c3f413SJ.Bruce Fields else 179981c3f413SJ.Bruce Fields end++; 180081c3f413SJ.Bruce Fields str = end; 180181c3f413SJ.Bruce Fields } 180281c3f413SJ.Bruce Fields *pp = p; 180381c3f413SJ.Bruce Fields p = countp; 180481c3f413SJ.Bruce Fields WRITE32(count); 180581c3f413SJ.Bruce Fields return 0; 180681c3f413SJ.Bruce Fields } 180781c3f413SJ.Bruce Fields 1808e7a0444aSWeston Andros Adamson /* Encode as an array of strings the string given with components 1809e7a0444aSWeston Andros Adamson * separated @sep. 1810e7a0444aSWeston Andros Adamson */ 1811e7a0444aSWeston Andros Adamson static __be32 nfsd4_encode_components(char sep, char *components, 1812e7a0444aSWeston Andros Adamson __be32 **pp, int *buflen) 1813e7a0444aSWeston Andros Adamson { 1814e7a0444aSWeston Andros Adamson return nfsd4_encode_components_esc(sep, components, pp, buflen, 0, 0); 1815e7a0444aSWeston Andros Adamson } 1816e7a0444aSWeston Andros Adamson 181781c3f413SJ.Bruce Fields /* 181881c3f413SJ.Bruce Fields * encode a location element of a fs_locations structure 181981c3f413SJ.Bruce Fields */ 1820b37ad28bSAl Viro static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, 18212ebbc012SAl Viro __be32 **pp, int *buflen) 182281c3f413SJ.Bruce Fields { 1823b37ad28bSAl Viro __be32 status; 18242ebbc012SAl Viro __be32 *p = *pp; 182581c3f413SJ.Bruce Fields 1826e7a0444aSWeston Andros Adamson status = nfsd4_encode_components_esc(':', location->hosts, &p, buflen, 1827e7a0444aSWeston Andros Adamson '[', ']'); 182881c3f413SJ.Bruce Fields if (status) 182981c3f413SJ.Bruce Fields return status; 183081c3f413SJ.Bruce Fields status = nfsd4_encode_components('/', location->path, &p, buflen); 183181c3f413SJ.Bruce Fields if (status) 183281c3f413SJ.Bruce Fields return status; 183381c3f413SJ.Bruce Fields *pp = p; 183481c3f413SJ.Bruce Fields return 0; 183581c3f413SJ.Bruce Fields } 183681c3f413SJ.Bruce Fields 183781c3f413SJ.Bruce Fields /* 1838ed748aacSTrond Myklebust * Encode a path in RFC3530 'pathname4' format 183981c3f413SJ.Bruce Fields */ 1840ed748aacSTrond Myklebust static __be32 nfsd4_encode_path(const struct path *root, 1841ed748aacSTrond Myklebust const struct path *path, __be32 **pp, int *buflen) 184281c3f413SJ.Bruce Fields { 1843ed748aacSTrond Myklebust struct path cur = { 1844ed748aacSTrond Myklebust .mnt = path->mnt, 1845ed748aacSTrond Myklebust .dentry = path->dentry, 1846ed748aacSTrond Myklebust }; 1847ed748aacSTrond Myklebust __be32 *p = *pp; 1848ed748aacSTrond Myklebust struct dentry **components = NULL; 1849ed748aacSTrond Myklebust unsigned int ncomponents = 0; 1850ed748aacSTrond Myklebust __be32 err = nfserr_jukebox; 185181c3f413SJ.Bruce Fields 1852ed748aacSTrond Myklebust dprintk("nfsd4_encode_components("); 185381c3f413SJ.Bruce Fields 1854ed748aacSTrond Myklebust path_get(&cur); 1855ed748aacSTrond Myklebust /* First walk the path up to the nfsd root, and store the 1856ed748aacSTrond Myklebust * dentries/path components in an array. 1857ed748aacSTrond Myklebust */ 1858ed748aacSTrond Myklebust for (;;) { 1859ed748aacSTrond Myklebust if (cur.dentry == root->dentry && cur.mnt == root->mnt) 1860ed748aacSTrond Myklebust break; 1861ed748aacSTrond Myklebust if (cur.dentry == cur.mnt->mnt_root) { 1862ed748aacSTrond Myklebust if (follow_up(&cur)) 1863ed748aacSTrond Myklebust continue; 1864ed748aacSTrond Myklebust goto out_free; 186581c3f413SJ.Bruce Fields } 1866ed748aacSTrond Myklebust if ((ncomponents & 15) == 0) { 1867ed748aacSTrond Myklebust struct dentry **new; 1868ed748aacSTrond Myklebust new = krealloc(components, 1869ed748aacSTrond Myklebust sizeof(*new) * (ncomponents + 16), 1870ed748aacSTrond Myklebust GFP_KERNEL); 1871ed748aacSTrond Myklebust if (!new) 1872ed748aacSTrond Myklebust goto out_free; 1873ed748aacSTrond Myklebust components = new; 1874ed748aacSTrond Myklebust } 1875ed748aacSTrond Myklebust components[ncomponents++] = cur.dentry; 1876ed748aacSTrond Myklebust cur.dentry = dget_parent(cur.dentry); 1877ed748aacSTrond Myklebust } 1878ed748aacSTrond Myklebust 1879ed748aacSTrond Myklebust *buflen -= 4; 1880ed748aacSTrond Myklebust if (*buflen < 0) 1881ed748aacSTrond Myklebust goto out_free; 1882ed748aacSTrond Myklebust WRITE32(ncomponents); 1883ed748aacSTrond Myklebust 1884ed748aacSTrond Myklebust while (ncomponents) { 1885ed748aacSTrond Myklebust struct dentry *dentry = components[ncomponents - 1]; 1886ed748aacSTrond Myklebust unsigned int len = dentry->d_name.len; 1887ed748aacSTrond Myklebust 1888ed748aacSTrond Myklebust *buflen -= 4 + (XDR_QUADLEN(len) << 2); 1889ed748aacSTrond Myklebust if (*buflen < 0) 1890ed748aacSTrond Myklebust goto out_free; 1891ed748aacSTrond Myklebust WRITE32(len); 1892ed748aacSTrond Myklebust WRITEMEM(dentry->d_name.name, len); 1893ed748aacSTrond Myklebust dprintk("/%s", dentry->d_name.name); 1894ed748aacSTrond Myklebust dput(dentry); 1895ed748aacSTrond Myklebust ncomponents--; 1896ed748aacSTrond Myklebust } 1897ed748aacSTrond Myklebust 1898ed748aacSTrond Myklebust *pp = p; 1899ed748aacSTrond Myklebust err = 0; 1900ed748aacSTrond Myklebust out_free: 1901ed748aacSTrond Myklebust dprintk(")\n"); 1902ed748aacSTrond Myklebust while (ncomponents) 1903ed748aacSTrond Myklebust dput(components[--ncomponents]); 1904ed748aacSTrond Myklebust kfree(components); 1905ed748aacSTrond Myklebust path_put(&cur); 1906ed748aacSTrond Myklebust return err; 1907ed748aacSTrond Myklebust } 1908ed748aacSTrond Myklebust 1909ed748aacSTrond Myklebust static __be32 nfsd4_encode_fsloc_fsroot(struct svc_rqst *rqstp, 1910ed748aacSTrond Myklebust const struct path *path, __be32 **pp, int *buflen) 1911ed748aacSTrond Myklebust { 1912ed748aacSTrond Myklebust struct svc_export *exp_ps; 1913ed748aacSTrond Myklebust __be32 res; 1914ed748aacSTrond Myklebust 1915ed748aacSTrond Myklebust exp_ps = rqst_find_fsidzero_export(rqstp); 1916ed748aacSTrond Myklebust if (IS_ERR(exp_ps)) 1917ed748aacSTrond Myklebust return nfserrno(PTR_ERR(exp_ps)); 1918ed748aacSTrond Myklebust res = nfsd4_encode_path(&exp_ps->ex_path, path, pp, buflen); 1919ed748aacSTrond Myklebust exp_put(exp_ps); 1920ed748aacSTrond Myklebust return res; 192181c3f413SJ.Bruce Fields } 192281c3f413SJ.Bruce Fields 192381c3f413SJ.Bruce Fields /* 192481c3f413SJ.Bruce Fields * encode a fs_locations structure 192581c3f413SJ.Bruce Fields */ 1926b37ad28bSAl Viro static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp, 192781c3f413SJ.Bruce Fields struct svc_export *exp, 19282ebbc012SAl Viro __be32 **pp, int *buflen) 192981c3f413SJ.Bruce Fields { 1930b37ad28bSAl Viro __be32 status; 1931cc45f017SAl Viro int i; 19322ebbc012SAl Viro __be32 *p = *pp; 193381c3f413SJ.Bruce Fields struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; 193481c3f413SJ.Bruce Fields 1935ed748aacSTrond Myklebust status = nfsd4_encode_fsloc_fsroot(rqstp, &exp->ex_path, &p, buflen); 193681c3f413SJ.Bruce Fields if (status) 193781c3f413SJ.Bruce Fields return status; 193881c3f413SJ.Bruce Fields if ((*buflen -= 4) < 0) 193981c3f413SJ.Bruce Fields return nfserr_resource; 194081c3f413SJ.Bruce Fields WRITE32(fslocs->locations_count); 194181c3f413SJ.Bruce Fields for (i=0; i<fslocs->locations_count; i++) { 194281c3f413SJ.Bruce Fields status = nfsd4_encode_fs_location4(&fslocs->locations[i], 194381c3f413SJ.Bruce Fields &p, buflen); 194481c3f413SJ.Bruce Fields if (status) 194581c3f413SJ.Bruce Fields return status; 194681c3f413SJ.Bruce Fields } 194781c3f413SJ.Bruce Fields *pp = p; 194881c3f413SJ.Bruce Fields return 0; 194981c3f413SJ.Bruce Fields } 19501da177e4SLinus Torvalds 19513d2544b1SJ. Bruce Fields static u32 nfs4_file_type(umode_t mode) 19523d2544b1SJ. Bruce Fields { 19533d2544b1SJ. Bruce Fields switch (mode & S_IFMT) { 19543d2544b1SJ. Bruce Fields case S_IFIFO: return NF4FIFO; 19553d2544b1SJ. Bruce Fields case S_IFCHR: return NF4CHR; 19563d2544b1SJ. Bruce Fields case S_IFDIR: return NF4DIR; 19573d2544b1SJ. Bruce Fields case S_IFBLK: return NF4BLK; 19583d2544b1SJ. Bruce Fields case S_IFLNK: return NF4LNK; 19593d2544b1SJ. Bruce Fields case S_IFREG: return NF4REG; 19603d2544b1SJ. Bruce Fields case S_IFSOCK: return NF4SOCK; 19613d2544b1SJ. Bruce Fields default: return NF4BAD; 19621da177e4SLinus Torvalds }; 19633d2544b1SJ. Bruce Fields } 19641da177e4SLinus Torvalds 1965b37ad28bSAl Viro static __be32 19661da177e4SLinus Torvalds nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, 19672ebbc012SAl Viro __be32 **p, int *buflen) 19681da177e4SLinus Torvalds { 19691da177e4SLinus Torvalds int status; 19701da177e4SLinus Torvalds 19711da177e4SLinus Torvalds if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4) 19721da177e4SLinus Torvalds return nfserr_resource; 19731da177e4SLinus Torvalds if (whotype != NFS4_ACL_WHO_NAMED) 19741da177e4SLinus Torvalds status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1)); 19751da177e4SLinus Torvalds else if (group) 19761da177e4SLinus Torvalds status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1)); 19771da177e4SLinus Torvalds else 19781da177e4SLinus Torvalds status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1)); 19791da177e4SLinus Torvalds if (status < 0) 19801da177e4SLinus Torvalds return nfserrno(status); 19811da177e4SLinus Torvalds *p = xdr_encode_opaque(*p, NULL, status); 19821da177e4SLinus Torvalds *buflen -= (XDR_QUADLEN(status) << 2) + 4; 19831da177e4SLinus Torvalds BUG_ON(*buflen < 0); 19841da177e4SLinus Torvalds return 0; 19851da177e4SLinus Torvalds } 19861da177e4SLinus Torvalds 1987b37ad28bSAl Viro static inline __be32 19882ebbc012SAl Viro nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen) 19891da177e4SLinus Torvalds { 19901da177e4SLinus Torvalds return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen); 19911da177e4SLinus Torvalds } 19921da177e4SLinus Torvalds 1993b37ad28bSAl Viro static inline __be32 19942ebbc012SAl Viro nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen) 19951da177e4SLinus Torvalds { 19961da177e4SLinus Torvalds return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen); 19971da177e4SLinus Torvalds } 19981da177e4SLinus Torvalds 1999b37ad28bSAl Viro static inline __be32 20001da177e4SLinus Torvalds nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, 20012ebbc012SAl Viro __be32 **p, int *buflen) 20021da177e4SLinus Torvalds { 20031da177e4SLinus Torvalds return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen); 20041da177e4SLinus Torvalds } 20051da177e4SLinus Torvalds 200642ca0993SJ.Bruce Fields #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ 200742ca0993SJ.Bruce Fields FATTR4_WORD0_RDATTR_ERROR) 200842ca0993SJ.Bruce Fields #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID 200942ca0993SJ.Bruce Fields 2010b37ad28bSAl Viro static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) 201142ca0993SJ.Bruce Fields { 201242ca0993SJ.Bruce Fields /* As per referral draft: */ 201342ca0993SJ.Bruce Fields if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS || 201442ca0993SJ.Bruce Fields *bmval1 & ~WORD1_ABSENT_FS_ATTRS) { 201542ca0993SJ.Bruce Fields if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR || 201642ca0993SJ.Bruce Fields *bmval0 & FATTR4_WORD0_FS_LOCATIONS) 201742ca0993SJ.Bruce Fields *rdattr_err = NFSERR_MOVED; 201842ca0993SJ.Bruce Fields else 201942ca0993SJ.Bruce Fields return nfserr_moved; 202042ca0993SJ.Bruce Fields } 202142ca0993SJ.Bruce Fields *bmval0 &= WORD0_ABSENT_FS_ATTRS; 202242ca0993SJ.Bruce Fields *bmval1 &= WORD1_ABSENT_FS_ATTRS; 202342ca0993SJ.Bruce Fields return 0; 202442ca0993SJ.Bruce Fields } 20251da177e4SLinus Torvalds 2026ae7095a7SJ. Bruce Fields 2027ae7095a7SJ. Bruce Fields static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) 2028ae7095a7SJ. Bruce Fields { 2029ae7095a7SJ. Bruce Fields struct path path = exp->ex_path; 2030ae7095a7SJ. Bruce Fields int err; 2031ae7095a7SJ. Bruce Fields 2032ae7095a7SJ. Bruce Fields path_get(&path); 2033ae7095a7SJ. Bruce Fields while (follow_up(&path)) { 2034ae7095a7SJ. Bruce Fields if (path.dentry != path.mnt->mnt_root) 2035ae7095a7SJ. Bruce Fields break; 2036ae7095a7SJ. Bruce Fields } 2037ae7095a7SJ. Bruce Fields err = vfs_getattr(path.mnt, path.dentry, stat); 2038ae7095a7SJ. Bruce Fields path_put(&path); 2039ae7095a7SJ. Bruce Fields return err; 2040ae7095a7SJ. Bruce Fields } 2041ae7095a7SJ. Bruce Fields 20421da177e4SLinus Torvalds /* 20431da177e4SLinus Torvalds * Note: @fhp can be NULL; in this case, we might have to compose the filehandle 20441da177e4SLinus Torvalds * ourselves. 20451da177e4SLinus Torvalds * 20461da177e4SLinus Torvalds * @countp is the buffer size in _words_; upon successful return this becomes 20471da177e4SLinus Torvalds * replaced with the number of words written. 20481da177e4SLinus Torvalds */ 2049b37ad28bSAl Viro __be32 20501da177e4SLinus Torvalds nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, 20512ebbc012SAl Viro struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, 2052406a7ea9SFrank Filz struct svc_rqst *rqstp, int ignore_crossmnt) 20531da177e4SLinus Torvalds { 20541da177e4SLinus Torvalds u32 bmval0 = bmval[0]; 20551da177e4SLinus Torvalds u32 bmval1 = bmval[1]; 20567e705706SAndy Adamson u32 bmval2 = bmval[2]; 20571da177e4SLinus Torvalds struct kstat stat; 20581da177e4SLinus Torvalds struct svc_fh tempfh; 20591da177e4SLinus Torvalds struct kstatfs statfs; 20601da177e4SLinus Torvalds int buflen = *countp << 2; 20612ebbc012SAl Viro __be32 *attrlenp; 20621da177e4SLinus Torvalds u32 dummy; 20631da177e4SLinus Torvalds u64 dummy64; 206442ca0993SJ.Bruce Fields u32 rdattr_err = 0; 20652ebbc012SAl Viro __be32 *p = buffer; 2066b37ad28bSAl Viro __be32 status; 2067b8dd7b9aSAl Viro int err; 20681da177e4SLinus Torvalds int aclsupport = 0; 20691da177e4SLinus Torvalds struct nfs4_acl *acl = NULL; 20707e705706SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 20717e705706SAndy Adamson u32 minorversion = resp->cstate.minorversion; 2072ebabe9a9SChristoph Hellwig struct path path = { 2073ebabe9a9SChristoph Hellwig .mnt = exp->ex_path.mnt, 2074ebabe9a9SChristoph Hellwig .dentry = dentry, 2075ebabe9a9SChristoph Hellwig }; 20761da177e4SLinus Torvalds 20771da177e4SLinus Torvalds BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); 20787e705706SAndy Adamson BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); 20797e705706SAndy Adamson BUG_ON(bmval1 & ~nfsd_suppattrs1(minorversion)); 20807e705706SAndy Adamson BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion)); 20811da177e4SLinus Torvalds 208242ca0993SJ.Bruce Fields if (exp->ex_fslocs.migrated) { 20837e705706SAndy Adamson BUG_ON(bmval[2]); 208442ca0993SJ.Bruce Fields status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err); 208542ca0993SJ.Bruce Fields if (status) 208642ca0993SJ.Bruce Fields goto out; 208742ca0993SJ.Bruce Fields } 208842ca0993SJ.Bruce Fields 208954775491SJan Blunck err = vfs_getattr(exp->ex_path.mnt, dentry, &stat); 2090b8dd7b9aSAl Viro if (err) 20911da177e4SLinus Torvalds goto out_nfserr; 2092a16e92edSJ. Bruce Fields if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | 2093a16e92edSJ. Bruce Fields FATTR4_WORD0_MAXNAME)) || 20941da177e4SLinus Torvalds (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | 20951da177e4SLinus Torvalds FATTR4_WORD1_SPACE_TOTAL))) { 2096ebabe9a9SChristoph Hellwig err = vfs_statfs(&path, &statfs); 2097b8dd7b9aSAl Viro if (err) 20981da177e4SLinus Torvalds goto out_nfserr; 20991da177e4SLinus Torvalds } 21001da177e4SLinus Torvalds if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) { 21011da177e4SLinus Torvalds fh_init(&tempfh, NFS4_FHSIZE); 21021da177e4SLinus Torvalds status = fh_compose(&tempfh, exp, dentry, NULL); 21031da177e4SLinus Torvalds if (status) 21041da177e4SLinus Torvalds goto out; 21051da177e4SLinus Torvalds fhp = &tempfh; 21061da177e4SLinus Torvalds } 21071da177e4SLinus Torvalds if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT 21081da177e4SLinus Torvalds | FATTR4_WORD0_SUPPORTED_ATTRS)) { 2109b8dd7b9aSAl Viro err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); 2110b8dd7b9aSAl Viro aclsupport = (err == 0); 21111da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACL) { 2112b8dd7b9aSAl Viro if (err == -EOPNOTSUPP) 21131da177e4SLinus Torvalds bmval0 &= ~FATTR4_WORD0_ACL; 2114b8dd7b9aSAl Viro else if (err == -EINVAL) { 21151da177e4SLinus Torvalds status = nfserr_attrnotsupp; 21161da177e4SLinus Torvalds goto out; 2117b8dd7b9aSAl Viro } else if (err != 0) 21181da177e4SLinus Torvalds goto out_nfserr; 21191da177e4SLinus Torvalds } 21201da177e4SLinus Torvalds } 21212b44f1baSBenny Halevy 21222b44f1baSBenny Halevy if (bmval2) { 21231da177e4SLinus Torvalds if ((buflen -= 16) < 0) 21241da177e4SLinus Torvalds goto out_resource; 21257e705706SAndy Adamson WRITE32(3); 21267e705706SAndy Adamson WRITE32(bmval0); 21277e705706SAndy Adamson WRITE32(bmval1); 21287e705706SAndy Adamson WRITE32(bmval2); 21292b44f1baSBenny Halevy } else if (bmval1) { 21302b44f1baSBenny Halevy if ((buflen -= 12) < 0) 21312b44f1baSBenny Halevy goto out_resource; 21321da177e4SLinus Torvalds WRITE32(2); 21331da177e4SLinus Torvalds WRITE32(bmval0); 21341da177e4SLinus Torvalds WRITE32(bmval1); 21357e705706SAndy Adamson } else { 21362b44f1baSBenny Halevy if ((buflen -= 8) < 0) 21372b44f1baSBenny Halevy goto out_resource; 21387e705706SAndy Adamson WRITE32(1); 21397e705706SAndy Adamson WRITE32(bmval0); 21407e705706SAndy Adamson } 21411da177e4SLinus Torvalds attrlenp = p++; /* to be backfilled later */ 21421da177e4SLinus Torvalds 21431da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { 21447e705706SAndy Adamson u32 word0 = nfsd_suppattrs0(minorversion); 21457e705706SAndy Adamson u32 word1 = nfsd_suppattrs1(minorversion); 21467e705706SAndy Adamson u32 word2 = nfsd_suppattrs2(minorversion); 21477e705706SAndy Adamson 214842ca0993SJ.Bruce Fields if (!aclsupport) 214942ca0993SJ.Bruce Fields word0 &= ~FATTR4_WORD0_ACL; 21507e705706SAndy Adamson if (!word2) { 21512b44f1baSBenny Halevy if ((buflen -= 12) < 0) 21522b44f1baSBenny Halevy goto out_resource; 21531da177e4SLinus Torvalds WRITE32(2); 215442ca0993SJ.Bruce Fields WRITE32(word0); 21557e705706SAndy Adamson WRITE32(word1); 21567e705706SAndy Adamson } else { 21572b44f1baSBenny Halevy if ((buflen -= 16) < 0) 21582b44f1baSBenny Halevy goto out_resource; 21597e705706SAndy Adamson WRITE32(3); 21607e705706SAndy Adamson WRITE32(word0); 21617e705706SAndy Adamson WRITE32(word1); 21627e705706SAndy Adamson WRITE32(word2); 21637e705706SAndy Adamson } 21641da177e4SLinus Torvalds } 21651da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_TYPE) { 21661da177e4SLinus Torvalds if ((buflen -= 4) < 0) 21671da177e4SLinus Torvalds goto out_resource; 21683d2544b1SJ. Bruce Fields dummy = nfs4_file_type(stat.mode); 21691da177e4SLinus Torvalds if (dummy == NF4BAD) 21701da177e4SLinus Torvalds goto out_serverfault; 21711da177e4SLinus Torvalds WRITE32(dummy); 21721da177e4SLinus Torvalds } 21731da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { 21741da177e4SLinus Torvalds if ((buflen -= 4) < 0) 21751da177e4SLinus Torvalds goto out_resource; 217649640001SNeilBrown if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) 2177e34ac862SNeilBrown WRITE32(NFS4_FH_PERSISTENT); 217849640001SNeilBrown else 2179e34ac862SNeilBrown WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); 21801da177e4SLinus Torvalds } 21811da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CHANGE) { 21821da177e4SLinus Torvalds if ((buflen -= 8) < 0) 21831da177e4SLinus Torvalds goto out_resource; 2184c654b8a9SJ. Bruce Fields write_change(&p, &stat, dentry->d_inode); 21851da177e4SLinus Torvalds } 21861da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SIZE) { 21871da177e4SLinus Torvalds if ((buflen -= 8) < 0) 21881da177e4SLinus Torvalds goto out_resource; 21891da177e4SLinus Torvalds WRITE64(stat.size); 21901da177e4SLinus Torvalds } 21911da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) { 21921da177e4SLinus Torvalds if ((buflen -= 4) < 0) 21931da177e4SLinus Torvalds goto out_resource; 21941da177e4SLinus Torvalds WRITE32(1); 21951da177e4SLinus Torvalds } 21961da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) { 21971da177e4SLinus Torvalds if ((buflen -= 4) < 0) 21981da177e4SLinus Torvalds goto out_resource; 21991da177e4SLinus Torvalds WRITE32(1); 22001da177e4SLinus Torvalds } 22011da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_NAMED_ATTR) { 22021da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22031da177e4SLinus Torvalds goto out_resource; 22041da177e4SLinus Torvalds WRITE32(0); 22051da177e4SLinus Torvalds } 22061da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FSID) { 22071da177e4SLinus Torvalds if ((buflen -= 16) < 0) 22081da177e4SLinus Torvalds goto out_resource; 220942ca0993SJ.Bruce Fields if (exp->ex_fslocs.migrated) { 221042ca0993SJ.Bruce Fields WRITE64(NFS4_REFERRAL_FSID_MAJOR); 221142ca0993SJ.Bruce Fields WRITE64(NFS4_REFERRAL_FSID_MINOR); 2212af6a4e28SNeilBrown } else switch(fsid_source(fhp)) { 2213af6a4e28SNeilBrown case FSIDSOURCE_FSID: 22141da177e4SLinus Torvalds WRITE64((u64)exp->ex_fsid); 22151da177e4SLinus Torvalds WRITE64((u64)0); 2216af6a4e28SNeilBrown break; 2217af6a4e28SNeilBrown case FSIDSOURCE_DEV: 22181da177e4SLinus Torvalds WRITE32(0); 22191da177e4SLinus Torvalds WRITE32(MAJOR(stat.dev)); 22201da177e4SLinus Torvalds WRITE32(0); 22211da177e4SLinus Torvalds WRITE32(MINOR(stat.dev)); 2222af6a4e28SNeilBrown break; 2223af6a4e28SNeilBrown case FSIDSOURCE_UUID: 2224af6a4e28SNeilBrown WRITEMEM(exp->ex_uuid, 16); 2225af6a4e28SNeilBrown break; 22261da177e4SLinus Torvalds } 22271da177e4SLinus Torvalds } 22281da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { 22291da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22301da177e4SLinus Torvalds goto out_resource; 22311da177e4SLinus Torvalds WRITE32(0); 22321da177e4SLinus Torvalds } 22331da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_LEASE_TIME) { 22341da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22351da177e4SLinus Torvalds goto out_resource; 2236cf07d2eaSJ. Bruce Fields WRITE32(nfsd4_lease); 22371da177e4SLinus Torvalds } 22381da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { 22391da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22401da177e4SLinus Torvalds goto out_resource; 224142ca0993SJ.Bruce Fields WRITE32(rdattr_err); 22421da177e4SLinus Torvalds } 22431da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACL) { 22441da177e4SLinus Torvalds struct nfs4_ace *ace; 22451da177e4SLinus Torvalds 22461da177e4SLinus Torvalds if (acl == NULL) { 22471da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22481da177e4SLinus Torvalds goto out_resource; 22491da177e4SLinus Torvalds 22501da177e4SLinus Torvalds WRITE32(0); 22511da177e4SLinus Torvalds goto out_acl; 22521da177e4SLinus Torvalds } 22531da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22541da177e4SLinus Torvalds goto out_resource; 22551da177e4SLinus Torvalds WRITE32(acl->naces); 22561da177e4SLinus Torvalds 225728e05dd8SJ. Bruce Fields for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { 22581da177e4SLinus Torvalds if ((buflen -= 4*3) < 0) 22591da177e4SLinus Torvalds goto out_resource; 22601da177e4SLinus Torvalds WRITE32(ace->type); 22611da177e4SLinus Torvalds WRITE32(ace->flag); 22621da177e4SLinus Torvalds WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL); 22631da177e4SLinus Torvalds status = nfsd4_encode_aclname(rqstp, ace->whotype, 22641da177e4SLinus Torvalds ace->who, ace->flag & NFS4_ACE_IDENTIFIER_GROUP, 22651da177e4SLinus Torvalds &p, &buflen); 22661da177e4SLinus Torvalds if (status == nfserr_resource) 22671da177e4SLinus Torvalds goto out_resource; 22681da177e4SLinus Torvalds if (status) 22691da177e4SLinus Torvalds goto out; 22701da177e4SLinus Torvalds } 22711da177e4SLinus Torvalds } 22721da177e4SLinus Torvalds out_acl: 22731da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACLSUPPORT) { 22741da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22751da177e4SLinus Torvalds goto out_resource; 22761da177e4SLinus Torvalds WRITE32(aclsupport ? 22771da177e4SLinus Torvalds ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0); 22781da177e4SLinus Torvalds } 22791da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CANSETTIME) { 22801da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22811da177e4SLinus Torvalds goto out_resource; 22821da177e4SLinus Torvalds WRITE32(1); 22831da177e4SLinus Torvalds } 22841da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { 22851da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22861da177e4SLinus Torvalds goto out_resource; 22872930d381SJ. Bruce Fields WRITE32(0); 22881da177e4SLinus Torvalds } 22891da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { 22901da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22911da177e4SLinus Torvalds goto out_resource; 22921da177e4SLinus Torvalds WRITE32(1); 22931da177e4SLinus Torvalds } 22941da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) { 22951da177e4SLinus Torvalds if ((buflen -= 4) < 0) 22961da177e4SLinus Torvalds goto out_resource; 22971da177e4SLinus Torvalds WRITE32(1); 22981da177e4SLinus Torvalds } 22991da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILEHANDLE) { 23001da177e4SLinus Torvalds buflen -= (XDR_QUADLEN(fhp->fh_handle.fh_size) << 2) + 4; 23011da177e4SLinus Torvalds if (buflen < 0) 23021da177e4SLinus Torvalds goto out_resource; 23031da177e4SLinus Torvalds WRITE32(fhp->fh_handle.fh_size); 23041da177e4SLinus Torvalds WRITEMEM(&fhp->fh_handle.fh_base, fhp->fh_handle.fh_size); 23051da177e4SLinus Torvalds } 23061da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILEID) { 23071da177e4SLinus Torvalds if ((buflen -= 8) < 0) 23081da177e4SLinus Torvalds goto out_resource; 230940ee5dc6SPeter Staubach WRITE64(stat.ino); 23101da177e4SLinus Torvalds } 23111da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { 23121da177e4SLinus Torvalds if ((buflen -= 8) < 0) 23131da177e4SLinus Torvalds goto out_resource; 23141da177e4SLinus Torvalds WRITE64((u64) statfs.f_ffree); 23151da177e4SLinus Torvalds } 23161da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_FREE) { 23171da177e4SLinus Torvalds if ((buflen -= 8) < 0) 23181da177e4SLinus Torvalds goto out_resource; 23191da177e4SLinus Torvalds WRITE64((u64) statfs.f_ffree); 23201da177e4SLinus Torvalds } 23211da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { 23221da177e4SLinus Torvalds if ((buflen -= 8) < 0) 23231da177e4SLinus Torvalds goto out_resource; 23241da177e4SLinus Torvalds WRITE64((u64) statfs.f_files); 23251da177e4SLinus Torvalds } 232681c3f413SJ.Bruce Fields if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { 232781c3f413SJ.Bruce Fields status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen); 232881c3f413SJ.Bruce Fields if (status == nfserr_resource) 232981c3f413SJ.Bruce Fields goto out_resource; 233081c3f413SJ.Bruce Fields if (status) 233181c3f413SJ.Bruce Fields goto out; 233281c3f413SJ.Bruce Fields } 23331da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { 23341da177e4SLinus Torvalds if ((buflen -= 4) < 0) 23351da177e4SLinus Torvalds goto out_resource; 23361da177e4SLinus Torvalds WRITE32(1); 23371da177e4SLinus Torvalds } 23381da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { 23391da177e4SLinus Torvalds if ((buflen -= 8) < 0) 23401da177e4SLinus Torvalds goto out_resource; 23411da177e4SLinus Torvalds WRITE64(~(u64)0); 23421da177e4SLinus Torvalds } 23431da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXLINK) { 23441da177e4SLinus Torvalds if ((buflen -= 4) < 0) 23451da177e4SLinus Torvalds goto out_resource; 23461da177e4SLinus Torvalds WRITE32(255); 23471da177e4SLinus Torvalds } 23481da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXNAME) { 23491da177e4SLinus Torvalds if ((buflen -= 4) < 0) 23501da177e4SLinus Torvalds goto out_resource; 2351a16e92edSJ. Bruce Fields WRITE32(statfs.f_namelen); 23521da177e4SLinus Torvalds } 23531da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXREAD) { 23541da177e4SLinus Torvalds if ((buflen -= 8) < 0) 23551da177e4SLinus Torvalds goto out_resource; 23567adae489SGreg Banks WRITE64((u64) svc_max_payload(rqstp)); 23571da177e4SLinus Torvalds } 23581da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXWRITE) { 23591da177e4SLinus Torvalds if ((buflen -= 8) < 0) 23601da177e4SLinus Torvalds goto out_resource; 23617adae489SGreg Banks WRITE64((u64) svc_max_payload(rqstp)); 23621da177e4SLinus Torvalds } 23631da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_MODE) { 23641da177e4SLinus Torvalds if ((buflen -= 4) < 0) 23651da177e4SLinus Torvalds goto out_resource; 23661da177e4SLinus Torvalds WRITE32(stat.mode & S_IALLUGO); 23671da177e4SLinus Torvalds } 23681da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_NO_TRUNC) { 23691da177e4SLinus Torvalds if ((buflen -= 4) < 0) 23701da177e4SLinus Torvalds goto out_resource; 23711da177e4SLinus Torvalds WRITE32(1); 23721da177e4SLinus Torvalds } 23731da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_NUMLINKS) { 23741da177e4SLinus Torvalds if ((buflen -= 4) < 0) 23751da177e4SLinus Torvalds goto out_resource; 23761da177e4SLinus Torvalds WRITE32(stat.nlink); 23771da177e4SLinus Torvalds } 23781da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_OWNER) { 23791da177e4SLinus Torvalds status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen); 23801da177e4SLinus Torvalds if (status == nfserr_resource) 23811da177e4SLinus Torvalds goto out_resource; 23821da177e4SLinus Torvalds if (status) 23831da177e4SLinus Torvalds goto out; 23841da177e4SLinus Torvalds } 23851da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { 23861da177e4SLinus Torvalds status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen); 23871da177e4SLinus Torvalds if (status == nfserr_resource) 23881da177e4SLinus Torvalds goto out_resource; 23891da177e4SLinus Torvalds if (status) 23901da177e4SLinus Torvalds goto out; 23911da177e4SLinus Torvalds } 23921da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_RAWDEV) { 23931da177e4SLinus Torvalds if ((buflen -= 8) < 0) 23941da177e4SLinus Torvalds goto out_resource; 23951da177e4SLinus Torvalds WRITE32((u32) MAJOR(stat.rdev)); 23961da177e4SLinus Torvalds WRITE32((u32) MINOR(stat.rdev)); 23971da177e4SLinus Torvalds } 23981da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { 23991da177e4SLinus Torvalds if ((buflen -= 8) < 0) 24001da177e4SLinus Torvalds goto out_resource; 24011da177e4SLinus Torvalds dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize; 24021da177e4SLinus Torvalds WRITE64(dummy64); 24031da177e4SLinus Torvalds } 24041da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_FREE) { 24051da177e4SLinus Torvalds if ((buflen -= 8) < 0) 24061da177e4SLinus Torvalds goto out_resource; 24071da177e4SLinus Torvalds dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize; 24081da177e4SLinus Torvalds WRITE64(dummy64); 24091da177e4SLinus Torvalds } 24101da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { 24111da177e4SLinus Torvalds if ((buflen -= 8) < 0) 24121da177e4SLinus Torvalds goto out_resource; 24131da177e4SLinus Torvalds dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize; 24141da177e4SLinus Torvalds WRITE64(dummy64); 24151da177e4SLinus Torvalds } 24161da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_USED) { 24171da177e4SLinus Torvalds if ((buflen -= 8) < 0) 24181da177e4SLinus Torvalds goto out_resource; 24191da177e4SLinus Torvalds dummy64 = (u64)stat.blocks << 9; 24201da177e4SLinus Torvalds WRITE64(dummy64); 24211da177e4SLinus Torvalds } 24221da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { 24231da177e4SLinus Torvalds if ((buflen -= 12) < 0) 24241da177e4SLinus Torvalds goto out_resource; 24251da177e4SLinus Torvalds WRITE32(0); 24261da177e4SLinus Torvalds WRITE32(stat.atime.tv_sec); 24271da177e4SLinus Torvalds WRITE32(stat.atime.tv_nsec); 24281da177e4SLinus Torvalds } 24291da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_DELTA) { 24301da177e4SLinus Torvalds if ((buflen -= 12) < 0) 24311da177e4SLinus Torvalds goto out_resource; 24321da177e4SLinus Torvalds WRITE32(0); 24331da177e4SLinus Torvalds WRITE32(1); 24341da177e4SLinus Torvalds WRITE32(0); 24351da177e4SLinus Torvalds } 24361da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_METADATA) { 24371da177e4SLinus Torvalds if ((buflen -= 12) < 0) 24381da177e4SLinus Torvalds goto out_resource; 24391da177e4SLinus Torvalds WRITE32(0); 24401da177e4SLinus Torvalds WRITE32(stat.ctime.tv_sec); 24411da177e4SLinus Torvalds WRITE32(stat.ctime.tv_nsec); 24421da177e4SLinus Torvalds } 24431da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { 24441da177e4SLinus Torvalds if ((buflen -= 12) < 0) 24451da177e4SLinus Torvalds goto out_resource; 24461da177e4SLinus Torvalds WRITE32(0); 24471da177e4SLinus Torvalds WRITE32(stat.mtime.tv_sec); 24481da177e4SLinus Torvalds WRITE32(stat.mtime.tv_nsec); 24491da177e4SLinus Torvalds } 24501da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { 24511da177e4SLinus Torvalds if ((buflen -= 8) < 0) 24521da177e4SLinus Torvalds goto out_resource; 2453406a7ea9SFrank Filz /* 2454406a7ea9SFrank Filz * Get parent's attributes if not ignoring crossmount 2455406a7ea9SFrank Filz * and this is the root of a cross-mounted filesystem. 2456406a7ea9SFrank Filz */ 2457406a7ea9SFrank Filz if (ignore_crossmnt == 0 && 2458ae7095a7SJ. Bruce Fields dentry == exp->ex_path.mnt->mnt_root) 2459ae7095a7SJ. Bruce Fields get_parent_attributes(exp, &stat); 246040ee5dc6SPeter Staubach WRITE64(stat.ino); 24611da177e4SLinus Torvalds } 24628c18f205SBenny Halevy if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { 24638c18f205SBenny Halevy WRITE32(3); 24648c18f205SBenny Halevy WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); 24658c18f205SBenny Halevy WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD1); 24668c18f205SBenny Halevy WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD2); 24678c18f205SBenny Halevy } 24687e705706SAndy Adamson 24691da177e4SLinus Torvalds *attrlenp = htonl((char *)p - (char *)attrlenp - 4); 24701da177e4SLinus Torvalds *countp = p - buffer; 24711da177e4SLinus Torvalds status = nfs_ok; 24721da177e4SLinus Torvalds 24731da177e4SLinus Torvalds out: 247428e05dd8SJ. Bruce Fields kfree(acl); 24751da177e4SLinus Torvalds if (fhp == &tempfh) 24761da177e4SLinus Torvalds fh_put(&tempfh); 24771da177e4SLinus Torvalds return status; 24781da177e4SLinus Torvalds out_nfserr: 2479b8dd7b9aSAl Viro status = nfserrno(err); 24801da177e4SLinus Torvalds goto out; 24811da177e4SLinus Torvalds out_resource: 24821da177e4SLinus Torvalds *countp = 0; 24831da177e4SLinus Torvalds status = nfserr_resource; 24841da177e4SLinus Torvalds goto out; 24851da177e4SLinus Torvalds out_serverfault: 24861da177e4SLinus Torvalds status = nfserr_serverfault; 24871da177e4SLinus Torvalds goto out; 24881da177e4SLinus Torvalds } 24891da177e4SLinus Torvalds 2490c0ce6ec8SJ. Bruce Fields static inline int attributes_need_mount(u32 *bmval) 2491c0ce6ec8SJ. Bruce Fields { 2492c0ce6ec8SJ. Bruce Fields if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME)) 2493c0ce6ec8SJ. Bruce Fields return 1; 2494c0ce6ec8SJ. Bruce Fields if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) 2495c0ce6ec8SJ. Bruce Fields return 1; 2496c0ce6ec8SJ. Bruce Fields return 0; 2497c0ce6ec8SJ. Bruce Fields } 2498c0ce6ec8SJ. Bruce Fields 2499b37ad28bSAl Viro static __be32 25001da177e4SLinus Torvalds nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, 25012ebbc012SAl Viro const char *name, int namlen, __be32 *p, int *buflen) 25021da177e4SLinus Torvalds { 25031da177e4SLinus Torvalds struct svc_export *exp = cd->rd_fhp->fh_export; 25041da177e4SLinus Torvalds struct dentry *dentry; 2505b37ad28bSAl Viro __be32 nfserr; 2506406a7ea9SFrank Filz int ignore_crossmnt = 0; 25071da177e4SLinus Torvalds 25081da177e4SLinus Torvalds dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); 25091da177e4SLinus Torvalds if (IS_ERR(dentry)) 25101da177e4SLinus Torvalds return nfserrno(PTR_ERR(dentry)); 2511b2c0cea6SJ. Bruce Fields if (!dentry->d_inode) { 2512b2c0cea6SJ. Bruce Fields /* 2513b2c0cea6SJ. Bruce Fields * nfsd_buffered_readdir drops the i_mutex between 2514b2c0cea6SJ. Bruce Fields * readdir and calling this callback, leaving a window 2515b2c0cea6SJ. Bruce Fields * where this directory entry could have gone away. 2516b2c0cea6SJ. Bruce Fields */ 2517b2c0cea6SJ. Bruce Fields dput(dentry); 2518b2c0cea6SJ. Bruce Fields return nfserr_noent; 2519b2c0cea6SJ. Bruce Fields } 25201da177e4SLinus Torvalds 25211da177e4SLinus Torvalds exp_get(exp); 2522406a7ea9SFrank Filz /* 2523406a7ea9SFrank Filz * In the case of a mountpoint, the client may be asking for 2524406a7ea9SFrank Filz * attributes that are only properties of the underlying filesystem 2525406a7ea9SFrank Filz * as opposed to the cross-mounted file system. In such a case, 2526406a7ea9SFrank Filz * we will not follow the cross mount and will fill the attribtutes 2527406a7ea9SFrank Filz * directly from the mountpoint dentry. 2528406a7ea9SFrank Filz */ 25293227fa41SJ. Bruce Fields if (nfsd_mountpoint(dentry, exp)) { 2530021d3a72SJ.Bruce Fields int err; 2531021d3a72SJ.Bruce Fields 25323227fa41SJ. Bruce Fields if (!(exp->ex_flags & NFSEXP_V4ROOT) 25333227fa41SJ. Bruce Fields && !attributes_need_mount(cd->rd_bmval)) { 25343227fa41SJ. Bruce Fields ignore_crossmnt = 1; 25353227fa41SJ. Bruce Fields goto out_encode; 25363227fa41SJ. Bruce Fields } 2537dcb488a3SAndy Adamson /* 2538dcb488a3SAndy Adamson * Why the heck aren't we just using nfsd_lookup?? 2539dcb488a3SAndy Adamson * Different "."/".." handling? Something else? 2540dcb488a3SAndy Adamson * At least, add a comment here to explain.... 2541dcb488a3SAndy Adamson */ 2542021d3a72SJ.Bruce Fields err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); 2543021d3a72SJ.Bruce Fields if (err) { 2544021d3a72SJ.Bruce Fields nfserr = nfserrno(err); 25451da177e4SLinus Torvalds goto out_put; 25461da177e4SLinus Torvalds } 2547dcb488a3SAndy Adamson nfserr = check_nfsd_access(exp, cd->rd_rqstp); 2548dcb488a3SAndy Adamson if (nfserr) 2549dcb488a3SAndy Adamson goto out_put; 25501da177e4SLinus Torvalds 25511da177e4SLinus Torvalds } 25523227fa41SJ. Bruce Fields out_encode: 25531da177e4SLinus Torvalds nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, 2554406a7ea9SFrank Filz cd->rd_rqstp, ignore_crossmnt); 25551da177e4SLinus Torvalds out_put: 25561da177e4SLinus Torvalds dput(dentry); 25571da177e4SLinus Torvalds exp_put(exp); 25581da177e4SLinus Torvalds return nfserr; 25591da177e4SLinus Torvalds } 25601da177e4SLinus Torvalds 25612ebbc012SAl Viro static __be32 * 2562b37ad28bSAl Viro nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr) 25631da177e4SLinus Torvalds { 25642ebbc012SAl Viro __be32 *attrlenp; 25651da177e4SLinus Torvalds 25661da177e4SLinus Torvalds if (buflen < 6) 25671da177e4SLinus Torvalds return NULL; 25681da177e4SLinus Torvalds *p++ = htonl(2); 25691da177e4SLinus Torvalds *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */ 25701da177e4SLinus Torvalds *p++ = htonl(0); /* bmval1 */ 25711da177e4SLinus Torvalds 25721da177e4SLinus Torvalds attrlenp = p++; 25731da177e4SLinus Torvalds *p++ = nfserr; /* no htonl */ 25741da177e4SLinus Torvalds *attrlenp = htonl((char *)p - (char *)attrlenp - 4); 25751da177e4SLinus Torvalds return p; 25761da177e4SLinus Torvalds } 25771da177e4SLinus Torvalds 25781da177e4SLinus Torvalds static int 2579a0ad13efSNeilBrown nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, 2580a0ad13efSNeilBrown loff_t offset, u64 ino, unsigned int d_type) 25811da177e4SLinus Torvalds { 2582a0ad13efSNeilBrown struct readdir_cd *ccd = ccdv; 25831da177e4SLinus Torvalds struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); 25841da177e4SLinus Torvalds int buflen; 25852ebbc012SAl Viro __be32 *p = cd->buffer; 2586b2c0cea6SJ. Bruce Fields __be32 *cookiep; 2587b37ad28bSAl Viro __be32 nfserr = nfserr_toosmall; 25881da177e4SLinus Torvalds 25891da177e4SLinus Torvalds /* In nfsv4, "." and ".." never make it onto the wire.. */ 25901da177e4SLinus Torvalds if (name && isdotent(name, namlen)) { 25911da177e4SLinus Torvalds cd->common.err = nfs_ok; 25921da177e4SLinus Torvalds return 0; 25931da177e4SLinus Torvalds } 25941da177e4SLinus Torvalds 25951da177e4SLinus Torvalds if (cd->offset) 25961da177e4SLinus Torvalds xdr_encode_hyper(cd->offset, (u64) offset); 25971da177e4SLinus Torvalds 25981da177e4SLinus Torvalds buflen = cd->buflen - 4 - XDR_QUADLEN(namlen); 25991da177e4SLinus Torvalds if (buflen < 0) 26001da177e4SLinus Torvalds goto fail; 26011da177e4SLinus Torvalds 26021da177e4SLinus Torvalds *p++ = xdr_one; /* mark entry present */ 2603b2c0cea6SJ. Bruce Fields cookiep = p; 26041da177e4SLinus Torvalds p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */ 26051da177e4SLinus Torvalds p = xdr_encode_array(p, name, namlen); /* name length & name */ 26061da177e4SLinus Torvalds 26071da177e4SLinus Torvalds nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, p, &buflen); 26081da177e4SLinus Torvalds switch (nfserr) { 26091da177e4SLinus Torvalds case nfs_ok: 26101da177e4SLinus Torvalds p += buflen; 26111da177e4SLinus Torvalds break; 26121da177e4SLinus Torvalds case nfserr_resource: 26131da177e4SLinus Torvalds nfserr = nfserr_toosmall; 26141da177e4SLinus Torvalds goto fail; 2615b2c0cea6SJ. Bruce Fields case nfserr_noent: 2616b2c0cea6SJ. Bruce Fields goto skip_entry; 26171da177e4SLinus Torvalds default: 26181da177e4SLinus Torvalds /* 26191da177e4SLinus Torvalds * If the client requested the RDATTR_ERROR attribute, 26201da177e4SLinus Torvalds * we stuff the error code into this attribute 26211da177e4SLinus Torvalds * and continue. If this attribute was not requested, 26221da177e4SLinus Torvalds * then in accordance with the spec, we fail the 26231da177e4SLinus Torvalds * entire READDIR operation(!) 26241da177e4SLinus Torvalds */ 26251da177e4SLinus Torvalds if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) 26261da177e4SLinus Torvalds goto fail; 26271da177e4SLinus Torvalds p = nfsd4_encode_rdattr_error(p, buflen, nfserr); 262834081efcSFred Isaman if (p == NULL) { 262934081efcSFred Isaman nfserr = nfserr_toosmall; 26301da177e4SLinus Torvalds goto fail; 26311da177e4SLinus Torvalds } 263234081efcSFred Isaman } 26331da177e4SLinus Torvalds cd->buflen -= (p - cd->buffer); 26341da177e4SLinus Torvalds cd->buffer = p; 2635b2c0cea6SJ. Bruce Fields cd->offset = cookiep; 2636b2c0cea6SJ. Bruce Fields skip_entry: 26371da177e4SLinus Torvalds cd->common.err = nfs_ok; 26381da177e4SLinus Torvalds return 0; 26391da177e4SLinus Torvalds fail: 26401da177e4SLinus Torvalds cd->common.err = nfserr; 26411da177e4SLinus Torvalds return -EINVAL; 26421da177e4SLinus Torvalds } 26431da177e4SLinus Torvalds 2644e2f282b9SBenny Halevy static void 2645e2f282b9SBenny Halevy nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) 2646e2f282b9SBenny Halevy { 2647bc749ca4SJ. Bruce Fields __be32 *p; 2648e2f282b9SBenny Halevy 2649e2f282b9SBenny Halevy RESERVE_SPACE(sizeof(stateid_t)); 2650e2f282b9SBenny Halevy WRITE32(sid->si_generation); 2651e2f282b9SBenny Halevy WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); 2652e2f282b9SBenny Halevy ADJUST_ARGS(); 2653e2f282b9SBenny Halevy } 2654e2f282b9SBenny Halevy 2655695e12f8SBenny Halevy static __be32 2656b37ad28bSAl Viro nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) 26571da177e4SLinus Torvalds { 2658bc749ca4SJ. Bruce Fields __be32 *p; 26591da177e4SLinus Torvalds 26601da177e4SLinus Torvalds if (!nfserr) { 26611da177e4SLinus Torvalds RESERVE_SPACE(8); 26621da177e4SLinus Torvalds WRITE32(access->ac_supported); 26631da177e4SLinus Torvalds WRITE32(access->ac_resp_access); 26641da177e4SLinus Torvalds ADJUST_ARGS(); 26651da177e4SLinus Torvalds } 2666695e12f8SBenny Halevy return nfserr; 26671da177e4SLinus Torvalds } 26681da177e4SLinus Torvalds 26691d1bc8f2SJ. Bruce Fields static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts) 26701d1bc8f2SJ. Bruce Fields { 26711d1bc8f2SJ. Bruce Fields __be32 *p; 26721d1bc8f2SJ. Bruce Fields 26731d1bc8f2SJ. Bruce Fields if (!nfserr) { 26741d1bc8f2SJ. Bruce Fields RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8); 26751d1bc8f2SJ. Bruce Fields WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); 26761d1bc8f2SJ. Bruce Fields WRITE32(bcts->dir); 26776e67b5d1SJ. Bruce Fields /* Sorry, we do not yet support RDMA over 4.1: */ 26781d1bc8f2SJ. Bruce Fields WRITE32(0); 26791d1bc8f2SJ. Bruce Fields ADJUST_ARGS(); 26801d1bc8f2SJ. Bruce Fields } 26811d1bc8f2SJ. Bruce Fields return nfserr; 26821d1bc8f2SJ. Bruce Fields } 26831d1bc8f2SJ. Bruce Fields 2684695e12f8SBenny Halevy static __be32 2685b37ad28bSAl Viro nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) 26861da177e4SLinus Torvalds { 26871da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 26881da177e4SLinus Torvalds 2689e2f282b9SBenny Halevy if (!nfserr) 2690e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &close->cl_stateid); 2691e2f282b9SBenny Halevy 2692f3e42237SJ. Bruce Fields encode_seqid_op_tail(resp, save, nfserr); 2693695e12f8SBenny Halevy return nfserr; 26941da177e4SLinus Torvalds } 26951da177e4SLinus Torvalds 26961da177e4SLinus Torvalds 2697695e12f8SBenny Halevy static __be32 2698b37ad28bSAl Viro nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) 26991da177e4SLinus Torvalds { 2700bc749ca4SJ. Bruce Fields __be32 *p; 27011da177e4SLinus Torvalds 27021da177e4SLinus Torvalds if (!nfserr) { 2703ab4684d1SChuck Lever RESERVE_SPACE(NFS4_VERIFIER_SIZE); 2704ab4684d1SChuck Lever WRITEMEM(commit->co_verf.data, NFS4_VERIFIER_SIZE); 27051da177e4SLinus Torvalds ADJUST_ARGS(); 27061da177e4SLinus Torvalds } 2707695e12f8SBenny Halevy return nfserr; 27081da177e4SLinus Torvalds } 27091da177e4SLinus Torvalds 2710695e12f8SBenny Halevy static __be32 2711b37ad28bSAl Viro nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) 27121da177e4SLinus Torvalds { 2713bc749ca4SJ. Bruce Fields __be32 *p; 27141da177e4SLinus Torvalds 27151da177e4SLinus Torvalds if (!nfserr) { 27161da177e4SLinus Torvalds RESERVE_SPACE(32); 2717c654b8a9SJ. Bruce Fields write_cinfo(&p, &create->cr_cinfo); 27181da177e4SLinus Torvalds WRITE32(2); 27191da177e4SLinus Torvalds WRITE32(create->cr_bmval[0]); 27201da177e4SLinus Torvalds WRITE32(create->cr_bmval[1]); 27211da177e4SLinus Torvalds ADJUST_ARGS(); 27221da177e4SLinus Torvalds } 2723695e12f8SBenny Halevy return nfserr; 27241da177e4SLinus Torvalds } 27251da177e4SLinus Torvalds 2726b37ad28bSAl Viro static __be32 2727b37ad28bSAl Viro nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr) 27281da177e4SLinus Torvalds { 27291da177e4SLinus Torvalds struct svc_fh *fhp = getattr->ga_fhp; 27301da177e4SLinus Torvalds int buflen; 27311da177e4SLinus Torvalds 27321da177e4SLinus Torvalds if (nfserr) 27331da177e4SLinus Torvalds return nfserr; 27341da177e4SLinus Torvalds 27351da177e4SLinus Torvalds buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2); 27361da177e4SLinus Torvalds nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry, 27371da177e4SLinus Torvalds resp->p, &buflen, getattr->ga_bmval, 2738406a7ea9SFrank Filz resp->rqstp, 0); 27391da177e4SLinus Torvalds if (!nfserr) 27401da177e4SLinus Torvalds resp->p += buflen; 27411da177e4SLinus Torvalds return nfserr; 27421da177e4SLinus Torvalds } 27431da177e4SLinus Torvalds 2744695e12f8SBenny Halevy static __be32 2745695e12f8SBenny Halevy nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp) 27461da177e4SLinus Torvalds { 2747695e12f8SBenny Halevy struct svc_fh *fhp = *fhpp; 27481da177e4SLinus Torvalds unsigned int len; 2749bc749ca4SJ. Bruce Fields __be32 *p; 27501da177e4SLinus Torvalds 27511da177e4SLinus Torvalds if (!nfserr) { 27521da177e4SLinus Torvalds len = fhp->fh_handle.fh_size; 27531da177e4SLinus Torvalds RESERVE_SPACE(len + 4); 27541da177e4SLinus Torvalds WRITE32(len); 27551da177e4SLinus Torvalds WRITEMEM(&fhp->fh_handle.fh_base, len); 27561da177e4SLinus Torvalds ADJUST_ARGS(); 27571da177e4SLinus Torvalds } 2758695e12f8SBenny Halevy return nfserr; 27591da177e4SLinus Torvalds } 27601da177e4SLinus Torvalds 27611da177e4SLinus Torvalds /* 27621da177e4SLinus Torvalds * Including all fields other than the name, a LOCK4denied structure requires 27631da177e4SLinus Torvalds * 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes. 27641da177e4SLinus Torvalds */ 27651da177e4SLinus Torvalds static void 27661da177e4SLinus Torvalds nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) 27671da177e4SLinus Torvalds { 27687c13f344SJ. Bruce Fields struct xdr_netobj *conf = &ld->ld_owner; 2769bc749ca4SJ. Bruce Fields __be32 *p; 27701da177e4SLinus Torvalds 27717c13f344SJ. Bruce Fields RESERVE_SPACE(32 + XDR_LEN(conf->len)); 27721da177e4SLinus Torvalds WRITE64(ld->ld_start); 27731da177e4SLinus Torvalds WRITE64(ld->ld_length); 27741da177e4SLinus Torvalds WRITE32(ld->ld_type); 27757c13f344SJ. Bruce Fields if (conf->len) { 27761da177e4SLinus Torvalds WRITEMEM(&ld->ld_clientid, 8); 27777c13f344SJ. Bruce Fields WRITE32(conf->len); 27787c13f344SJ. Bruce Fields WRITEMEM(conf->data, conf->len); 27797c13f344SJ. Bruce Fields kfree(conf->data); 27801da177e4SLinus Torvalds } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ 27811da177e4SLinus Torvalds WRITE64((u64)0); /* clientid */ 27821da177e4SLinus Torvalds WRITE32(0); /* length of owner name */ 27831da177e4SLinus Torvalds } 27841da177e4SLinus Torvalds ADJUST_ARGS(); 27851da177e4SLinus Torvalds } 27861da177e4SLinus Torvalds 2787695e12f8SBenny Halevy static __be32 2788b37ad28bSAl Viro nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) 27891da177e4SLinus Torvalds { 27901da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 27911da177e4SLinus Torvalds 2792e2f282b9SBenny Halevy if (!nfserr) 2793e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &lock->lk_resp_stateid); 2794e2f282b9SBenny Halevy else if (nfserr == nfserr_denied) 27951da177e4SLinus Torvalds nfsd4_encode_lock_denied(resp, &lock->lk_denied); 27961da177e4SLinus Torvalds 2797f3e42237SJ. Bruce Fields encode_seqid_op_tail(resp, save, nfserr); 2798695e12f8SBenny Halevy return nfserr; 27991da177e4SLinus Torvalds } 28001da177e4SLinus Torvalds 2801695e12f8SBenny Halevy static __be32 2802b37ad28bSAl Viro nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) 28031da177e4SLinus Torvalds { 28041da177e4SLinus Torvalds if (nfserr == nfserr_denied) 28051da177e4SLinus Torvalds nfsd4_encode_lock_denied(resp, &lockt->lt_denied); 2806695e12f8SBenny Halevy return nfserr; 28071da177e4SLinus Torvalds } 28081da177e4SLinus Torvalds 2809695e12f8SBenny Halevy static __be32 2810b37ad28bSAl Viro nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) 28111da177e4SLinus Torvalds { 28121da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 28131da177e4SLinus Torvalds 2814e2f282b9SBenny Halevy if (!nfserr) 2815e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &locku->lu_stateid); 28161da177e4SLinus Torvalds 2817f3e42237SJ. Bruce Fields encode_seqid_op_tail(resp, save, nfserr); 2818695e12f8SBenny Halevy return nfserr; 28191da177e4SLinus Torvalds } 28201da177e4SLinus Torvalds 28211da177e4SLinus Torvalds 2822695e12f8SBenny Halevy static __be32 2823b37ad28bSAl Viro nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) 28241da177e4SLinus Torvalds { 2825bc749ca4SJ. Bruce Fields __be32 *p; 28261da177e4SLinus Torvalds 28271da177e4SLinus Torvalds if (!nfserr) { 28281da177e4SLinus Torvalds RESERVE_SPACE(20); 2829c654b8a9SJ. Bruce Fields write_cinfo(&p, &link->li_cinfo); 28301da177e4SLinus Torvalds ADJUST_ARGS(); 28311da177e4SLinus Torvalds } 2832695e12f8SBenny Halevy return nfserr; 28331da177e4SLinus Torvalds } 28341da177e4SLinus Torvalds 28351da177e4SLinus Torvalds 2836695e12f8SBenny Halevy static __be32 2837b37ad28bSAl Viro nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) 28381da177e4SLinus Torvalds { 2839bc749ca4SJ. Bruce Fields __be32 *p; 28401da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 28411da177e4SLinus Torvalds 28421da177e4SLinus Torvalds if (nfserr) 28431da177e4SLinus Torvalds goto out; 28441da177e4SLinus Torvalds 2845e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &open->op_stateid); 2846e2f282b9SBenny Halevy RESERVE_SPACE(40); 2847c654b8a9SJ. Bruce Fields write_cinfo(&p, &open->op_cinfo); 28481da177e4SLinus Torvalds WRITE32(open->op_rflags); 28491da177e4SLinus Torvalds WRITE32(2); 28501da177e4SLinus Torvalds WRITE32(open->op_bmval[0]); 28511da177e4SLinus Torvalds WRITE32(open->op_bmval[1]); 28521da177e4SLinus Torvalds WRITE32(open->op_delegate_type); 28531da177e4SLinus Torvalds ADJUST_ARGS(); 28541da177e4SLinus Torvalds 28551da177e4SLinus Torvalds switch (open->op_delegate_type) { 28561da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_NONE: 28571da177e4SLinus Torvalds break; 28581da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_READ: 2859e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &open->op_delegate_stateid); 2860e2f282b9SBenny Halevy RESERVE_SPACE(20); 28617b190fecSNeilBrown WRITE32(open->op_recall); 28621da177e4SLinus Torvalds 28631da177e4SLinus Torvalds /* 28641da177e4SLinus Torvalds * TODO: ACE's in delegations 28651da177e4SLinus Torvalds */ 28661da177e4SLinus Torvalds WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); 28671da177e4SLinus Torvalds WRITE32(0); 28681da177e4SLinus Torvalds WRITE32(0); 28691da177e4SLinus Torvalds WRITE32(0); /* XXX: is NULL principal ok? */ 28701da177e4SLinus Torvalds ADJUST_ARGS(); 28711da177e4SLinus Torvalds break; 28721da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_WRITE: 2873e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &open->op_delegate_stateid); 2874e2f282b9SBenny Halevy RESERVE_SPACE(32); 28751da177e4SLinus Torvalds WRITE32(0); 28761da177e4SLinus Torvalds 28771da177e4SLinus Torvalds /* 28781da177e4SLinus Torvalds * TODO: space_limit's in delegations 28791da177e4SLinus Torvalds */ 28801da177e4SLinus Torvalds WRITE32(NFS4_LIMIT_SIZE); 28811da177e4SLinus Torvalds WRITE32(~(u32)0); 28821da177e4SLinus Torvalds WRITE32(~(u32)0); 28831da177e4SLinus Torvalds 28841da177e4SLinus Torvalds /* 28851da177e4SLinus Torvalds * TODO: ACE's in delegations 28861da177e4SLinus Torvalds */ 28871da177e4SLinus Torvalds WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); 28881da177e4SLinus Torvalds WRITE32(0); 28891da177e4SLinus Torvalds WRITE32(0); 28901da177e4SLinus Torvalds WRITE32(0); /* XXX: is NULL principal ok? */ 28911da177e4SLinus Torvalds ADJUST_ARGS(); 28921da177e4SLinus Torvalds break; 2893d24433cdSBenny Halevy case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */ 2894d24433cdSBenny Halevy switch (open->op_why_no_deleg) { 2895d24433cdSBenny Halevy case WND4_CONTENTION: 2896d24433cdSBenny Halevy case WND4_RESOURCE: 2897d24433cdSBenny Halevy RESERVE_SPACE(8); 2898d24433cdSBenny Halevy WRITE32(open->op_why_no_deleg); 2899d24433cdSBenny Halevy WRITE32(0); /* deleg signaling not supported yet */ 2900d24433cdSBenny Halevy break; 2901d24433cdSBenny Halevy default: 2902d24433cdSBenny Halevy RESERVE_SPACE(4); 2903d24433cdSBenny Halevy WRITE32(open->op_why_no_deleg); 2904d24433cdSBenny Halevy } 2905d24433cdSBenny Halevy ADJUST_ARGS(); 2906d24433cdSBenny Halevy break; 29071da177e4SLinus Torvalds default: 29081da177e4SLinus Torvalds BUG(); 29091da177e4SLinus Torvalds } 29101da177e4SLinus Torvalds /* XXX save filehandle here */ 29111da177e4SLinus Torvalds out: 2912f3e42237SJ. Bruce Fields encode_seqid_op_tail(resp, save, nfserr); 2913695e12f8SBenny Halevy return nfserr; 29141da177e4SLinus Torvalds } 29151da177e4SLinus Torvalds 2916695e12f8SBenny Halevy static __be32 2917b37ad28bSAl Viro nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) 29181da177e4SLinus Torvalds { 29191da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 29201da177e4SLinus Torvalds 2921e2f282b9SBenny Halevy if (!nfserr) 2922e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &oc->oc_resp_stateid); 29231da177e4SLinus Torvalds 2924f3e42237SJ. Bruce Fields encode_seqid_op_tail(resp, save, nfserr); 2925695e12f8SBenny Halevy return nfserr; 29261da177e4SLinus Torvalds } 29271da177e4SLinus Torvalds 2928695e12f8SBenny Halevy static __be32 2929b37ad28bSAl Viro nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) 29301da177e4SLinus Torvalds { 29311da177e4SLinus Torvalds ENCODE_SEQID_OP_HEAD; 29321da177e4SLinus Torvalds 2933e2f282b9SBenny Halevy if (!nfserr) 2934e2f282b9SBenny Halevy nfsd4_encode_stateid(resp, &od->od_stateid); 29351da177e4SLinus Torvalds 2936f3e42237SJ. Bruce Fields encode_seqid_op_tail(resp, save, nfserr); 2937695e12f8SBenny Halevy return nfserr; 29381da177e4SLinus Torvalds } 29391da177e4SLinus Torvalds 2940b37ad28bSAl Viro static __be32 2941b37ad28bSAl Viro nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, 294244524359SNeilBrown struct nfsd4_read *read) 29431da177e4SLinus Torvalds { 29441da177e4SLinus Torvalds u32 eof; 29451da177e4SLinus Torvalds int v, pn; 29461da177e4SLinus Torvalds unsigned long maxcount; 29471da177e4SLinus Torvalds long len; 2948bc749ca4SJ. Bruce Fields __be32 *p; 29491da177e4SLinus Torvalds 29501da177e4SLinus Torvalds if (nfserr) 29511da177e4SLinus Torvalds return nfserr; 29521da177e4SLinus Torvalds if (resp->xbuf->page_len) 29531da177e4SLinus Torvalds return nfserr_resource; 29541da177e4SLinus Torvalds 29551da177e4SLinus Torvalds RESERVE_SPACE(8); /* eof flag and byte count */ 29561da177e4SLinus Torvalds 29577adae489SGreg Banks maxcount = svc_max_payload(resp->rqstp); 29581da177e4SLinus Torvalds if (maxcount > read->rd_length) 29591da177e4SLinus Torvalds maxcount = read->rd_length; 29601da177e4SLinus Torvalds 29611da177e4SLinus Torvalds len = maxcount; 29621da177e4SLinus Torvalds v = 0; 29631da177e4SLinus Torvalds while (len > 0) { 296444524359SNeilBrown pn = resp->rqstp->rq_resused++; 29653cc03b16SNeilBrown resp->rqstp->rq_vec[v].iov_base = 296644524359SNeilBrown page_address(resp->rqstp->rq_respages[pn]); 29673cc03b16SNeilBrown resp->rqstp->rq_vec[v].iov_len = 296844524359SNeilBrown len < PAGE_SIZE ? len : PAGE_SIZE; 29691da177e4SLinus Torvalds v++; 29701da177e4SLinus Torvalds len -= PAGE_SIZE; 29711da177e4SLinus Torvalds } 29721da177e4SLinus Torvalds read->rd_vlen = v; 29731da177e4SLinus Torvalds 2974039a87caSJ. Bruce Fields nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp, 29753cc03b16SNeilBrown read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, 29761da177e4SLinus Torvalds &maxcount); 29771da177e4SLinus Torvalds 29781da177e4SLinus Torvalds if (nfserr) 29791da177e4SLinus Torvalds return nfserr; 298044524359SNeilBrown eof = (read->rd_offset + maxcount >= 298144524359SNeilBrown read->rd_fhp->fh_dentry->d_inode->i_size); 29821da177e4SLinus Torvalds 29831da177e4SLinus Torvalds WRITE32(eof); 29841da177e4SLinus Torvalds WRITE32(maxcount); 29851da177e4SLinus Torvalds ADJUST_ARGS(); 29866ed6deccSNeilBrown resp->xbuf->head[0].iov_len = (char*)p 29876ed6deccSNeilBrown - (char*)resp->xbuf->head[0].iov_base; 29881da177e4SLinus Torvalds resp->xbuf->page_len = maxcount; 29891da177e4SLinus Torvalds 29906ed6deccSNeilBrown /* Use rest of head for padding and remaining ops: */ 29916ed6deccSNeilBrown resp->xbuf->tail[0].iov_base = p; 29921da177e4SLinus Torvalds resp->xbuf->tail[0].iov_len = 0; 29931da177e4SLinus Torvalds if (maxcount&3) { 29946ed6deccSNeilBrown RESERVE_SPACE(4); 29956ed6deccSNeilBrown WRITE32(0); 29961da177e4SLinus Torvalds resp->xbuf->tail[0].iov_base += maxcount&3; 29971da177e4SLinus Torvalds resp->xbuf->tail[0].iov_len = 4 - (maxcount&3); 29986ed6deccSNeilBrown ADJUST_ARGS(); 29991da177e4SLinus Torvalds } 30001da177e4SLinus Torvalds return 0; 30011da177e4SLinus Torvalds } 30021da177e4SLinus Torvalds 3003b37ad28bSAl Viro static __be32 3004b37ad28bSAl Viro nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) 30051da177e4SLinus Torvalds { 30061da177e4SLinus Torvalds int maxcount; 30071da177e4SLinus Torvalds char *page; 3008bc749ca4SJ. Bruce Fields __be32 *p; 30091da177e4SLinus Torvalds 30101da177e4SLinus Torvalds if (nfserr) 30111da177e4SLinus Torvalds return nfserr; 30121da177e4SLinus Torvalds if (resp->xbuf->page_len) 30131da177e4SLinus Torvalds return nfserr_resource; 30141da177e4SLinus Torvalds 301544524359SNeilBrown page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); 30161da177e4SLinus Torvalds 30171da177e4SLinus Torvalds maxcount = PAGE_SIZE; 30181da177e4SLinus Torvalds RESERVE_SPACE(4); 30191da177e4SLinus Torvalds 30201da177e4SLinus Torvalds /* 30211da177e4SLinus Torvalds * XXX: By default, the ->readlink() VFS op will truncate symlinks 30221da177e4SLinus Torvalds * if they would overflow the buffer. Is this kosher in NFSv4? If 30231da177e4SLinus Torvalds * not, one easy fix is: if ->readlink() precisely fills the buffer, 30241da177e4SLinus Torvalds * assume that truncation occurred, and return NFS4ERR_RESOURCE. 30251da177e4SLinus Torvalds */ 30261da177e4SLinus Torvalds nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, page, &maxcount); 30271da177e4SLinus Torvalds if (nfserr == nfserr_isdir) 30281da177e4SLinus Torvalds return nfserr_inval; 30291da177e4SLinus Torvalds if (nfserr) 30301da177e4SLinus Torvalds return nfserr; 30311da177e4SLinus Torvalds 30321da177e4SLinus Torvalds WRITE32(maxcount); 30331da177e4SLinus Torvalds ADJUST_ARGS(); 30346ed6deccSNeilBrown resp->xbuf->head[0].iov_len = (char*)p 30356ed6deccSNeilBrown - (char*)resp->xbuf->head[0].iov_base; 30361da177e4SLinus Torvalds resp->xbuf->page_len = maxcount; 30376ed6deccSNeilBrown 30386ed6deccSNeilBrown /* Use rest of head for padding and remaining ops: */ 30396ed6deccSNeilBrown resp->xbuf->tail[0].iov_base = p; 30406ed6deccSNeilBrown resp->xbuf->tail[0].iov_len = 0; 30411da177e4SLinus Torvalds if (maxcount&3) { 30426ed6deccSNeilBrown RESERVE_SPACE(4); 30436ed6deccSNeilBrown WRITE32(0); 30441da177e4SLinus Torvalds resp->xbuf->tail[0].iov_base += maxcount&3; 30451da177e4SLinus Torvalds resp->xbuf->tail[0].iov_len = 4 - (maxcount&3); 30466ed6deccSNeilBrown ADJUST_ARGS(); 30471da177e4SLinus Torvalds } 30481da177e4SLinus Torvalds return 0; 30491da177e4SLinus Torvalds } 30501da177e4SLinus Torvalds 3051b37ad28bSAl Viro static __be32 3052b37ad28bSAl Viro nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir) 30531da177e4SLinus Torvalds { 30541da177e4SLinus Torvalds int maxcount; 30551da177e4SLinus Torvalds loff_t offset; 30562ebbc012SAl Viro __be32 *page, *savep, *tailbase; 3057bc749ca4SJ. Bruce Fields __be32 *p; 30581da177e4SLinus Torvalds 30591da177e4SLinus Torvalds if (nfserr) 30601da177e4SLinus Torvalds return nfserr; 30611da177e4SLinus Torvalds if (resp->xbuf->page_len) 30621da177e4SLinus Torvalds return nfserr_resource; 30631da177e4SLinus Torvalds 3064ab4684d1SChuck Lever RESERVE_SPACE(NFS4_VERIFIER_SIZE); 30651da177e4SLinus Torvalds savep = p; 30661da177e4SLinus Torvalds 30671da177e4SLinus Torvalds /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */ 30681da177e4SLinus Torvalds WRITE32(0); 30691da177e4SLinus Torvalds WRITE32(0); 30701da177e4SLinus Torvalds ADJUST_ARGS(); 30711da177e4SLinus Torvalds resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base; 3072bb6e8a9fSNeilBrown tailbase = p; 30731da177e4SLinus Torvalds 30741da177e4SLinus Torvalds maxcount = PAGE_SIZE; 30751da177e4SLinus Torvalds if (maxcount > readdir->rd_maxcount) 30761da177e4SLinus Torvalds maxcount = readdir->rd_maxcount; 30771da177e4SLinus Torvalds 30781da177e4SLinus Torvalds /* 30791da177e4SLinus Torvalds * Convert from bytes to words, account for the two words already 30801da177e4SLinus Torvalds * written, make sure to leave two words at the end for the next 30811da177e4SLinus Torvalds * pointer and eof field. 30821da177e4SLinus Torvalds */ 30831da177e4SLinus Torvalds maxcount = (maxcount >> 2) - 4; 30841da177e4SLinus Torvalds if (maxcount < 0) { 30851da177e4SLinus Torvalds nfserr = nfserr_toosmall; 30861da177e4SLinus Torvalds goto err_no_verf; 30871da177e4SLinus Torvalds } 30881da177e4SLinus Torvalds 308944524359SNeilBrown page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); 30901da177e4SLinus Torvalds readdir->common.err = 0; 30911da177e4SLinus Torvalds readdir->buflen = maxcount; 30921da177e4SLinus Torvalds readdir->buffer = page; 30931da177e4SLinus Torvalds readdir->offset = NULL; 30941da177e4SLinus Torvalds 30951da177e4SLinus Torvalds offset = readdir->rd_cookie; 30961da177e4SLinus Torvalds nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, 30971da177e4SLinus Torvalds &offset, 30981da177e4SLinus Torvalds &readdir->common, nfsd4_encode_dirent); 30991da177e4SLinus Torvalds if (nfserr == nfs_ok && 31001da177e4SLinus Torvalds readdir->common.err == nfserr_toosmall && 31011da177e4SLinus Torvalds readdir->buffer == page) 31021da177e4SLinus Torvalds nfserr = nfserr_toosmall; 31031da177e4SLinus Torvalds if (nfserr) 31041da177e4SLinus Torvalds goto err_no_verf; 31051da177e4SLinus Torvalds 31061da177e4SLinus Torvalds if (readdir->offset) 31071da177e4SLinus Torvalds xdr_encode_hyper(readdir->offset, offset); 31081da177e4SLinus Torvalds 31091da177e4SLinus Torvalds p = readdir->buffer; 31101da177e4SLinus Torvalds *p++ = 0; /* no more entries */ 31111da177e4SLinus Torvalds *p++ = htonl(readdir->common.err == nfserr_eof); 311244524359SNeilBrown resp->xbuf->page_len = ((char*)p) - (char*)page_address( 311344524359SNeilBrown resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); 31141da177e4SLinus Torvalds 3115bb6e8a9fSNeilBrown /* Use rest of head for padding and remaining ops: */ 3116bb6e8a9fSNeilBrown resp->xbuf->tail[0].iov_base = tailbase; 31171da177e4SLinus Torvalds resp->xbuf->tail[0].iov_len = 0; 31181da177e4SLinus Torvalds resp->p = resp->xbuf->tail[0].iov_base; 3119bb6e8a9fSNeilBrown resp->end = resp->p + (PAGE_SIZE - resp->xbuf->head[0].iov_len)/4; 31201da177e4SLinus Torvalds 31211da177e4SLinus Torvalds return 0; 31221da177e4SLinus Torvalds err_no_verf: 31231da177e4SLinus Torvalds p = savep; 31241da177e4SLinus Torvalds ADJUST_ARGS(); 31251da177e4SLinus Torvalds return nfserr; 31261da177e4SLinus Torvalds } 31271da177e4SLinus Torvalds 3128695e12f8SBenny Halevy static __be32 3129b37ad28bSAl Viro nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) 31301da177e4SLinus Torvalds { 3131bc749ca4SJ. Bruce Fields __be32 *p; 31321da177e4SLinus Torvalds 31331da177e4SLinus Torvalds if (!nfserr) { 31341da177e4SLinus Torvalds RESERVE_SPACE(20); 3135c654b8a9SJ. Bruce Fields write_cinfo(&p, &remove->rm_cinfo); 31361da177e4SLinus Torvalds ADJUST_ARGS(); 31371da177e4SLinus Torvalds } 3138695e12f8SBenny Halevy return nfserr; 31391da177e4SLinus Torvalds } 31401da177e4SLinus Torvalds 3141695e12f8SBenny Halevy static __be32 3142b37ad28bSAl Viro nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) 31431da177e4SLinus Torvalds { 3144bc749ca4SJ. Bruce Fields __be32 *p; 31451da177e4SLinus Torvalds 31461da177e4SLinus Torvalds if (!nfserr) { 31471da177e4SLinus Torvalds RESERVE_SPACE(40); 3148c654b8a9SJ. Bruce Fields write_cinfo(&p, &rename->rn_sinfo); 3149c654b8a9SJ. Bruce Fields write_cinfo(&p, &rename->rn_tinfo); 31501da177e4SLinus Torvalds ADJUST_ARGS(); 31511da177e4SLinus Torvalds } 3152695e12f8SBenny Halevy return nfserr; 31531da177e4SLinus Torvalds } 31541da177e4SLinus Torvalds 3155695e12f8SBenny Halevy static __be32 315622b6dee8SMi Jinlong nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, 315722b6dee8SMi Jinlong __be32 nfserr,struct svc_export *exp) 3158dcb488a3SAndy Adamson { 3159dcb488a3SAndy Adamson int i = 0; 31604796f457SJ. Bruce Fields u32 nflavs; 31614796f457SJ. Bruce Fields struct exp_flavor_info *flavs; 31624796f457SJ. Bruce Fields struct exp_flavor_info def_flavs[2]; 3163bc749ca4SJ. Bruce Fields __be32 *p; 3164dcb488a3SAndy Adamson 3165dcb488a3SAndy Adamson if (nfserr) 3166dcb488a3SAndy Adamson goto out; 31674796f457SJ. Bruce Fields if (exp->ex_nflavors) { 31684796f457SJ. Bruce Fields flavs = exp->ex_flavors; 31694796f457SJ. Bruce Fields nflavs = exp->ex_nflavors; 31704796f457SJ. Bruce Fields } else { /* Handling of some defaults in absence of real secinfo: */ 31714796f457SJ. Bruce Fields flavs = def_flavs; 31724796f457SJ. Bruce Fields if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) { 31734796f457SJ. Bruce Fields nflavs = 2; 31744796f457SJ. Bruce Fields flavs[0].pseudoflavor = RPC_AUTH_UNIX; 31754796f457SJ. Bruce Fields flavs[1].pseudoflavor = RPC_AUTH_NULL; 31764796f457SJ. Bruce Fields } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) { 31774796f457SJ. Bruce Fields nflavs = 1; 31784796f457SJ. Bruce Fields flavs[0].pseudoflavor 31794796f457SJ. Bruce Fields = svcauth_gss_flavor(exp->ex_client); 31804796f457SJ. Bruce Fields } else { 31814796f457SJ. Bruce Fields nflavs = 1; 31824796f457SJ. Bruce Fields flavs[0].pseudoflavor 31834796f457SJ. Bruce Fields = exp->ex_client->flavour->flavour; 31844796f457SJ. Bruce Fields } 31854796f457SJ. Bruce Fields } 31864796f457SJ. Bruce Fields 3187dcb488a3SAndy Adamson RESERVE_SPACE(4); 31884796f457SJ. Bruce Fields WRITE32(nflavs); 3189dcb488a3SAndy Adamson ADJUST_ARGS(); 31904796f457SJ. Bruce Fields for (i = 0; i < nflavs; i++) { 31914796f457SJ. Bruce Fields u32 flav = flavs[i].pseudoflavor; 3192dcb488a3SAndy Adamson struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav); 3193dcb488a3SAndy Adamson 3194dcb488a3SAndy Adamson if (gm) { 3195dcb488a3SAndy Adamson RESERVE_SPACE(4); 3196dcb488a3SAndy Adamson WRITE32(RPC_AUTH_GSS); 3197dcb488a3SAndy Adamson ADJUST_ARGS(); 3198dcb488a3SAndy Adamson RESERVE_SPACE(4 + gm->gm_oid.len); 3199dcb488a3SAndy Adamson WRITE32(gm->gm_oid.len); 3200dcb488a3SAndy Adamson WRITEMEM(gm->gm_oid.data, gm->gm_oid.len); 3201dcb488a3SAndy Adamson ADJUST_ARGS(); 3202dcb488a3SAndy Adamson RESERVE_SPACE(4); 3203dcb488a3SAndy Adamson WRITE32(0); /* qop */ 3204dcb488a3SAndy Adamson ADJUST_ARGS(); 3205dcb488a3SAndy Adamson RESERVE_SPACE(4); 3206dcb488a3SAndy Adamson WRITE32(gss_pseudoflavor_to_service(gm, flav)); 3207dcb488a3SAndy Adamson ADJUST_ARGS(); 3208dcb488a3SAndy Adamson gss_mech_put(gm); 3209dcb488a3SAndy Adamson } else { 3210dcb488a3SAndy Adamson RESERVE_SPACE(4); 3211dcb488a3SAndy Adamson WRITE32(flav); 3212dcb488a3SAndy Adamson ADJUST_ARGS(); 3213dcb488a3SAndy Adamson } 3214dcb488a3SAndy Adamson } 3215dcb488a3SAndy Adamson out: 3216dcb488a3SAndy Adamson if (exp) 3217dcb488a3SAndy Adamson exp_put(exp); 3218695e12f8SBenny Halevy return nfserr; 3219dcb488a3SAndy Adamson } 3220dcb488a3SAndy Adamson 322122b6dee8SMi Jinlong static __be32 322222b6dee8SMi Jinlong nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, 322322b6dee8SMi Jinlong struct nfsd4_secinfo *secinfo) 322422b6dee8SMi Jinlong { 322522b6dee8SMi Jinlong return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->si_exp); 322622b6dee8SMi Jinlong } 322722b6dee8SMi Jinlong 322822b6dee8SMi Jinlong static __be32 322922b6dee8SMi Jinlong nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, 323022b6dee8SMi Jinlong struct nfsd4_secinfo_no_name *secinfo) 323122b6dee8SMi Jinlong { 323222b6dee8SMi Jinlong return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->sin_exp); 323322b6dee8SMi Jinlong } 323422b6dee8SMi Jinlong 32351da177e4SLinus Torvalds /* 32361da177e4SLinus Torvalds * The SETATTR encode routine is special -- it always encodes a bitmap, 32371da177e4SLinus Torvalds * regardless of the error status. 32381da177e4SLinus Torvalds */ 3239695e12f8SBenny Halevy static __be32 3240b37ad28bSAl Viro nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) 32411da177e4SLinus Torvalds { 3242bc749ca4SJ. Bruce Fields __be32 *p; 32431da177e4SLinus Torvalds 32441da177e4SLinus Torvalds RESERVE_SPACE(12); 32451da177e4SLinus Torvalds if (nfserr) { 32461da177e4SLinus Torvalds WRITE32(2); 32471da177e4SLinus Torvalds WRITE32(0); 32481da177e4SLinus Torvalds WRITE32(0); 32491da177e4SLinus Torvalds } 32501da177e4SLinus Torvalds else { 32511da177e4SLinus Torvalds WRITE32(2); 32521da177e4SLinus Torvalds WRITE32(setattr->sa_bmval[0]); 32531da177e4SLinus Torvalds WRITE32(setattr->sa_bmval[1]); 32541da177e4SLinus Torvalds } 32551da177e4SLinus Torvalds ADJUST_ARGS(); 3256695e12f8SBenny Halevy return nfserr; 32571da177e4SLinus Torvalds } 32581da177e4SLinus Torvalds 3259695e12f8SBenny Halevy static __be32 3260b37ad28bSAl Viro nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) 32611da177e4SLinus Torvalds { 3262bc749ca4SJ. Bruce Fields __be32 *p; 32631da177e4SLinus Torvalds 32641da177e4SLinus Torvalds if (!nfserr) { 3265ab4684d1SChuck Lever RESERVE_SPACE(8 + NFS4_VERIFIER_SIZE); 32661da177e4SLinus Torvalds WRITEMEM(&scd->se_clientid, 8); 3267ab4684d1SChuck Lever WRITEMEM(&scd->se_confirm, NFS4_VERIFIER_SIZE); 32681da177e4SLinus Torvalds ADJUST_ARGS(); 32691da177e4SLinus Torvalds } 32701da177e4SLinus Torvalds else if (nfserr == nfserr_clid_inuse) { 32711da177e4SLinus Torvalds RESERVE_SPACE(8); 32721da177e4SLinus Torvalds WRITE32(0); 32731da177e4SLinus Torvalds WRITE32(0); 32741da177e4SLinus Torvalds ADJUST_ARGS(); 32751da177e4SLinus Torvalds } 3276695e12f8SBenny Halevy return nfserr; 32771da177e4SLinus Torvalds } 32781da177e4SLinus Torvalds 3279695e12f8SBenny Halevy static __be32 3280b37ad28bSAl Viro nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) 32811da177e4SLinus Torvalds { 3282bc749ca4SJ. Bruce Fields __be32 *p; 32831da177e4SLinus Torvalds 32841da177e4SLinus Torvalds if (!nfserr) { 32851da177e4SLinus Torvalds RESERVE_SPACE(16); 32861da177e4SLinus Torvalds WRITE32(write->wr_bytes_written); 32871da177e4SLinus Torvalds WRITE32(write->wr_how_written); 3288ab4684d1SChuck Lever WRITEMEM(write->wr_verifier.data, NFS4_VERIFIER_SIZE); 32891da177e4SLinus Torvalds ADJUST_ARGS(); 32901da177e4SLinus Torvalds } 3291695e12f8SBenny Halevy return nfserr; 32921da177e4SLinus Torvalds } 32931da177e4SLinus Torvalds 3294695e12f8SBenny Halevy static __be32 329557b7b43bSJ. Bruce Fields nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, 32962db134ebSAndy Adamson struct nfsd4_exchange_id *exid) 32972db134ebSAndy Adamson { 3298bc749ca4SJ. Bruce Fields __be32 *p; 32990733d213SAndy Adamson char *major_id; 33000733d213SAndy Adamson char *server_scope; 33010733d213SAndy Adamson int major_id_sz; 33020733d213SAndy Adamson int server_scope_sz; 33030733d213SAndy Adamson uint64_t minor_id = 0; 33040733d213SAndy Adamson 33050733d213SAndy Adamson if (nfserr) 33062db134ebSAndy Adamson return nfserr; 33070733d213SAndy Adamson 33080733d213SAndy Adamson major_id = utsname()->nodename; 33090733d213SAndy Adamson major_id_sz = strlen(major_id); 33100733d213SAndy Adamson server_scope = utsname()->nodename; 33110733d213SAndy Adamson server_scope_sz = strlen(server_scope); 33120733d213SAndy Adamson 33130733d213SAndy Adamson RESERVE_SPACE( 33140733d213SAndy Adamson 8 /* eir_clientid */ + 33150733d213SAndy Adamson 4 /* eir_sequenceid */ + 33160733d213SAndy Adamson 4 /* eir_flags */ + 33170733d213SAndy Adamson 4 /* spr_how (SP4_NONE) */ + 33180733d213SAndy Adamson 8 /* so_minor_id */ + 33190733d213SAndy Adamson 4 /* so_major_id.len */ + 33200733d213SAndy Adamson (XDR_QUADLEN(major_id_sz) * 4) + 33210733d213SAndy Adamson 4 /* eir_server_scope.len */ + 33220733d213SAndy Adamson (XDR_QUADLEN(server_scope_sz) * 4) + 33230733d213SAndy Adamson 4 /* eir_server_impl_id.count (0) */); 33240733d213SAndy Adamson 33250733d213SAndy Adamson WRITEMEM(&exid->clientid, 8); 33260733d213SAndy Adamson WRITE32(exid->seqid); 33270733d213SAndy Adamson WRITE32(exid->flags); 33280733d213SAndy Adamson 33290733d213SAndy Adamson /* state_protect4_r. Currently only support SP4_NONE */ 33300733d213SAndy Adamson BUG_ON(exid->spa_how != SP4_NONE); 33310733d213SAndy Adamson WRITE32(exid->spa_how); 33320733d213SAndy Adamson 33330733d213SAndy Adamson /* The server_owner struct */ 33340733d213SAndy Adamson WRITE64(minor_id); /* Minor id */ 33350733d213SAndy Adamson /* major id */ 33360733d213SAndy Adamson WRITE32(major_id_sz); 33370733d213SAndy Adamson WRITEMEM(major_id, major_id_sz); 33380733d213SAndy Adamson 33390733d213SAndy Adamson /* Server scope */ 33400733d213SAndy Adamson WRITE32(server_scope_sz); 33410733d213SAndy Adamson WRITEMEM(server_scope, server_scope_sz); 33420733d213SAndy Adamson 33430733d213SAndy Adamson /* Implementation id */ 33440733d213SAndy Adamson WRITE32(0); /* zero length nfs_impl_id4 array */ 33450733d213SAndy Adamson ADJUST_ARGS(); 33460733d213SAndy Adamson return 0; 33472db134ebSAndy Adamson } 33482db134ebSAndy Adamson 33492db134ebSAndy Adamson static __be32 335057b7b43bSJ. Bruce Fields nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, 33512db134ebSAndy Adamson struct nfsd4_create_session *sess) 33522db134ebSAndy Adamson { 3353bc749ca4SJ. Bruce Fields __be32 *p; 3354ec6b5d7bSAndy Adamson 3355ec6b5d7bSAndy Adamson if (nfserr) 33562db134ebSAndy Adamson return nfserr; 3357ec6b5d7bSAndy Adamson 3358ec6b5d7bSAndy Adamson RESERVE_SPACE(24); 3359ec6b5d7bSAndy Adamson WRITEMEM(sess->sessionid.data, NFS4_MAX_SESSIONID_LEN); 3360ec6b5d7bSAndy Adamson WRITE32(sess->seqid); 3361ec6b5d7bSAndy Adamson WRITE32(sess->flags); 3362ec6b5d7bSAndy Adamson ADJUST_ARGS(); 3363ec6b5d7bSAndy Adamson 3364ec6b5d7bSAndy Adamson RESERVE_SPACE(28); 3365ec6b5d7bSAndy Adamson WRITE32(0); /* headerpadsz */ 3366ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxreq_sz); 3367ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxresp_sz); 3368ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxresp_cached); 3369ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxops); 3370ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.maxreqs); 3371ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.nr_rdma_attrs); 3372ec6b5d7bSAndy Adamson ADJUST_ARGS(); 3373ec6b5d7bSAndy Adamson 3374ec6b5d7bSAndy Adamson if (sess->fore_channel.nr_rdma_attrs) { 3375ec6b5d7bSAndy Adamson RESERVE_SPACE(4); 3376ec6b5d7bSAndy Adamson WRITE32(sess->fore_channel.rdma_attrs); 3377ec6b5d7bSAndy Adamson ADJUST_ARGS(); 3378ec6b5d7bSAndy Adamson } 3379ec6b5d7bSAndy Adamson 3380ec6b5d7bSAndy Adamson RESERVE_SPACE(28); 3381ec6b5d7bSAndy Adamson WRITE32(0); /* headerpadsz */ 3382ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxreq_sz); 3383ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxresp_sz); 3384ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxresp_cached); 3385ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxops); 3386ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.maxreqs); 3387ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.nr_rdma_attrs); 3388ec6b5d7bSAndy Adamson ADJUST_ARGS(); 3389ec6b5d7bSAndy Adamson 3390ec6b5d7bSAndy Adamson if (sess->back_channel.nr_rdma_attrs) { 3391ec6b5d7bSAndy Adamson RESERVE_SPACE(4); 3392ec6b5d7bSAndy Adamson WRITE32(sess->back_channel.rdma_attrs); 3393ec6b5d7bSAndy Adamson ADJUST_ARGS(); 3394ec6b5d7bSAndy Adamson } 3395ec6b5d7bSAndy Adamson return 0; 33962db134ebSAndy Adamson } 33972db134ebSAndy Adamson 33982db134ebSAndy Adamson static __be32 339957b7b43bSJ. Bruce Fields nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, __be32 nfserr, 34002db134ebSAndy Adamson struct nfsd4_destroy_session *destroy_session) 34012db134ebSAndy Adamson { 34022db134ebSAndy Adamson return nfserr; 34032db134ebSAndy Adamson } 34042db134ebSAndy Adamson 3405c47d832bSDaniel Mack static __be32 3406d1829b38SJ. Bruce Fields nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, 3407e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 3408e1ca12dfSBryan Schumaker { 3409e1ca12dfSBryan Schumaker __be32 *p; 3410e1ca12dfSBryan Schumaker 3411e1ca12dfSBryan Schumaker if (nfserr) 3412e1ca12dfSBryan Schumaker return nfserr; 3413e1ca12dfSBryan Schumaker 3414e1ca12dfSBryan Schumaker RESERVE_SPACE(4); 3415d1829b38SJ. Bruce Fields *p++ = nfserr; 3416e1ca12dfSBryan Schumaker ADJUST_ARGS(); 3417e1ca12dfSBryan Schumaker return nfserr; 3418e1ca12dfSBryan Schumaker } 3419e1ca12dfSBryan Schumaker 3420e1ca12dfSBryan Schumaker static __be32 342157b7b43bSJ. Bruce Fields nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, 34222db134ebSAndy Adamson struct nfsd4_sequence *seq) 34232db134ebSAndy Adamson { 3424bc749ca4SJ. Bruce Fields __be32 *p; 3425b85d4c01SBenny Halevy 3426b85d4c01SBenny Halevy if (nfserr) 34272db134ebSAndy Adamson return nfserr; 3428b85d4c01SBenny Halevy 3429b85d4c01SBenny Halevy RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 20); 3430b85d4c01SBenny Halevy WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); 3431b85d4c01SBenny Halevy WRITE32(seq->seqid); 3432b85d4c01SBenny Halevy WRITE32(seq->slotid); 3433b7d7ca35SJ. Bruce Fields /* Note slotid's are numbered from zero: */ 3434b7d7ca35SJ. Bruce Fields WRITE32(seq->maxslots - 1); /* sr_highest_slotid */ 3435b7d7ca35SJ. Bruce Fields WRITE32(seq->maxslots - 1); /* sr_target_highest_slotid */ 34360d7bb719SJ. Bruce Fields WRITE32(seq->status_flags); 3437b85d4c01SBenny Halevy 3438b85d4c01SBenny Halevy ADJUST_ARGS(); 3439557ce264SAndy Adamson resp->cstate.datap = p; /* DRC cache data pointer */ 3440b85d4c01SBenny Halevy return 0; 34412db134ebSAndy Adamson } 34422db134ebSAndy Adamson 34432355c596SJ. Bruce Fields static __be32 344457b7b43bSJ. Bruce Fields nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, 344517456804SBryan Schumaker struct nfsd4_test_stateid *test_stateid) 344617456804SBryan Schumaker { 344703cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid, *next; 344817456804SBryan Schumaker __be32 *p; 344917456804SBryan Schumaker 345003cfb420SBryan Schumaker RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids)); 345117456804SBryan Schumaker *p++ = htonl(test_stateid->ts_num_ids); 345217456804SBryan Schumaker 345303cfb420SBryan Schumaker list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) { 345402f5fde5SAl Viro *p++ = stateid->ts_id_status; 345517456804SBryan Schumaker } 345617456804SBryan Schumaker 345703cfb420SBryan Schumaker ADJUST_ARGS(); 345817456804SBryan Schumaker return nfserr; 345917456804SBryan Schumaker } 346017456804SBryan Schumaker 34612db134ebSAndy Adamson static __be32 3462695e12f8SBenny Halevy nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) 3463695e12f8SBenny Halevy { 3464695e12f8SBenny Halevy return nfserr; 3465695e12f8SBenny Halevy } 3466695e12f8SBenny Halevy 3467695e12f8SBenny Halevy typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *); 3468695e12f8SBenny Halevy 34692db134ebSAndy Adamson /* 34702db134ebSAndy Adamson * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1 34712db134ebSAndy Adamson * since we don't need to filter out obsolete ops as this is 34722db134ebSAndy Adamson * done in the decoding phase. 34732db134ebSAndy Adamson */ 3474695e12f8SBenny Halevy static nfsd4_enc nfsd4_enc_ops[] = { 3475ad1060c8SJ. Bruce Fields [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access, 3476ad1060c8SJ. Bruce Fields [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close, 3477ad1060c8SJ. Bruce Fields [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit, 3478ad1060c8SJ. Bruce Fields [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create, 3479ad1060c8SJ. Bruce Fields [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop, 3480ad1060c8SJ. Bruce Fields [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop, 3481ad1060c8SJ. Bruce Fields [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr, 3482ad1060c8SJ. Bruce Fields [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh, 3483ad1060c8SJ. Bruce Fields [OP_LINK] = (nfsd4_enc)nfsd4_encode_link, 3484ad1060c8SJ. Bruce Fields [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock, 3485ad1060c8SJ. Bruce Fields [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt, 3486ad1060c8SJ. Bruce Fields [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku, 3487ad1060c8SJ. Bruce Fields [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop, 3488ad1060c8SJ. Bruce Fields [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop, 3489ad1060c8SJ. Bruce Fields [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop, 3490ad1060c8SJ. Bruce Fields [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open, 349184f09f46SBenny Halevy [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop, 3492ad1060c8SJ. Bruce Fields [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm, 3493ad1060c8SJ. Bruce Fields [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade, 3494ad1060c8SJ. Bruce Fields [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop, 3495ad1060c8SJ. Bruce Fields [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop, 3496ad1060c8SJ. Bruce Fields [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop, 3497ad1060c8SJ. Bruce Fields [OP_READ] = (nfsd4_enc)nfsd4_encode_read, 3498ad1060c8SJ. Bruce Fields [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir, 3499ad1060c8SJ. Bruce Fields [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink, 3500ad1060c8SJ. Bruce Fields [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove, 3501ad1060c8SJ. Bruce Fields [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename, 3502ad1060c8SJ. Bruce Fields [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop, 3503ad1060c8SJ. Bruce Fields [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop, 3504ad1060c8SJ. Bruce Fields [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop, 3505ad1060c8SJ. Bruce Fields [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo, 3506ad1060c8SJ. Bruce Fields [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr, 3507ad1060c8SJ. Bruce Fields [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid, 3508ad1060c8SJ. Bruce Fields [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop, 3509ad1060c8SJ. Bruce Fields [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop, 3510ad1060c8SJ. Bruce Fields [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write, 3511ad1060c8SJ. Bruce Fields [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop, 35122db134ebSAndy Adamson 35132db134ebSAndy Adamson /* NFSv4.1 operations */ 35142db134ebSAndy Adamson [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop, 35151d1bc8f2SJ. Bruce Fields [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session, 35162db134ebSAndy Adamson [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, 35172db134ebSAndy Adamson [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, 35182db134ebSAndy Adamson [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, 3519e1ca12dfSBryan Schumaker [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_free_stateid, 35202db134ebSAndy Adamson [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 35212db134ebSAndy Adamson [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, 35222db134ebSAndy Adamson [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, 35232db134ebSAndy Adamson [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, 35242db134ebSAndy Adamson [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, 35252db134ebSAndy Adamson [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, 352622b6dee8SMi Jinlong [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name, 35272db134ebSAndy Adamson [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, 35282db134ebSAndy Adamson [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, 352917456804SBryan Schumaker [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid, 35302db134ebSAndy Adamson [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 35312db134ebSAndy Adamson [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop, 35322db134ebSAndy Adamson [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop, 3533695e12f8SBenny Halevy }; 3534695e12f8SBenny Halevy 3535496c262cSAndy Adamson /* 3536496c262cSAndy Adamson * Calculate the total amount of memory that the compound response has taken 353758e7b33aSMi Jinlong * after encoding the current operation with pad. 3538496c262cSAndy Adamson * 353958e7b33aSMi Jinlong * pad: if operation is non-idempotent, pad was calculate by op_rsize_bop() 354058e7b33aSMi Jinlong * which was specified at nfsd4_operation, else pad is zero. 3541496c262cSAndy Adamson * 354258e7b33aSMi Jinlong * Compare this length to the session se_fmaxresp_sz and se_fmaxresp_cached. 3543496c262cSAndy Adamson * 3544496c262cSAndy Adamson * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so 3545496c262cSAndy Adamson * will be at least a page and will therefore hold the xdr_buf head. 3546496c262cSAndy Adamson */ 354757b7b43bSJ. Bruce Fields __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) 3548496c262cSAndy Adamson { 3549496c262cSAndy Adamson struct xdr_buf *xb = &resp->rqstp->rq_res; 3550496c262cSAndy Adamson struct nfsd4_session *session = NULL; 3551496c262cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 355258e7b33aSMi Jinlong u32 length, tlen = 0; 3553496c262cSAndy Adamson 3554496c262cSAndy Adamson if (!nfsd4_has_session(&resp->cstate)) 355558e7b33aSMi Jinlong return 0; 3556496c262cSAndy Adamson 3557496c262cSAndy Adamson session = resp->cstate.session; 355858e7b33aSMi Jinlong if (session == NULL) 355958e7b33aSMi Jinlong return 0; 3560496c262cSAndy Adamson 3561496c262cSAndy Adamson if (xb->page_len == 0) { 3562496c262cSAndy Adamson length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; 3563496c262cSAndy Adamson } else { 3564496c262cSAndy Adamson if (xb->tail[0].iov_base && xb->tail[0].iov_len > 0) 3565496c262cSAndy Adamson tlen = (char *)resp->p - (char *)xb->tail[0].iov_base; 3566496c262cSAndy Adamson 3567496c262cSAndy Adamson length = xb->head[0].iov_len + xb->page_len + tlen + pad; 3568496c262cSAndy Adamson } 3569496c262cSAndy Adamson dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, 3570496c262cSAndy Adamson length, xb->page_len, tlen, pad); 3571496c262cSAndy Adamson 357258e7b33aSMi Jinlong if (length > session->se_fchannel.maxresp_sz) 357358e7b33aSMi Jinlong return nfserr_rep_too_big; 357458e7b33aSMi Jinlong 357573e79482SJ. Bruce Fields if ((slot->sl_flags & NFSD4_SLOT_CACHETHIS) && 357658e7b33aSMi Jinlong length > session->se_fchannel.maxresp_cached) 3577496c262cSAndy Adamson return nfserr_rep_too_big_to_cache; 357858e7b33aSMi Jinlong 357958e7b33aSMi Jinlong return 0; 3580496c262cSAndy Adamson } 3581496c262cSAndy Adamson 35821da177e4SLinus Torvalds void 35831da177e4SLinus Torvalds nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 35841da177e4SLinus Torvalds { 35852ebbc012SAl Viro __be32 *statp; 3586bc749ca4SJ. Bruce Fields __be32 *p; 35871da177e4SLinus Torvalds 35881da177e4SLinus Torvalds RESERVE_SPACE(8); 35891da177e4SLinus Torvalds WRITE32(op->opnum); 35901da177e4SLinus Torvalds statp = p++; /* to be backfilled at the end */ 35911da177e4SLinus Torvalds ADJUST_ARGS(); 35921da177e4SLinus Torvalds 3593695e12f8SBenny Halevy if (op->opnum == OP_ILLEGAL) 3594695e12f8SBenny Halevy goto status; 3595695e12f8SBenny Halevy BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || 3596695e12f8SBenny Halevy !nfsd4_enc_ops[op->opnum]); 3597695e12f8SBenny Halevy op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); 3598496c262cSAndy Adamson /* nfsd4_check_drc_limit guarantees enough room for error status */ 359958e7b33aSMi Jinlong if (!op->status) 360058e7b33aSMi Jinlong op->status = nfsd4_check_resp_size(resp, 0); 3601695e12f8SBenny Halevy status: 36021da177e4SLinus Torvalds /* 36031da177e4SLinus Torvalds * Note: We write the status directly, instead of using WRITE32(), 36041da177e4SLinus Torvalds * since it is already in network byte order. 36051da177e4SLinus Torvalds */ 36061da177e4SLinus Torvalds *statp = op->status; 36071da177e4SLinus Torvalds } 36081da177e4SLinus Torvalds 36091da177e4SLinus Torvalds /* 36101da177e4SLinus Torvalds * Encode the reply stored in the stateowner reply cache 36111da177e4SLinus Torvalds * 36121da177e4SLinus Torvalds * XDR note: do not encode rp->rp_buflen: the buffer contains the 36131da177e4SLinus Torvalds * previously sent already encoded operation. 36141da177e4SLinus Torvalds * 36151da177e4SLinus Torvalds * called with nfs4_lock_state() held 36161da177e4SLinus Torvalds */ 36171da177e4SLinus Torvalds void 36181da177e4SLinus Torvalds nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 36191da177e4SLinus Torvalds { 3620bc749ca4SJ. Bruce Fields __be32 *p; 36211da177e4SLinus Torvalds struct nfs4_replay *rp = op->replay; 36221da177e4SLinus Torvalds 36231da177e4SLinus Torvalds BUG_ON(!rp); 36241da177e4SLinus Torvalds 36251da177e4SLinus Torvalds RESERVE_SPACE(8); 36261da177e4SLinus Torvalds WRITE32(op->opnum); 36271da177e4SLinus Torvalds *p++ = rp->rp_status; /* already xdr'ed */ 36281da177e4SLinus Torvalds ADJUST_ARGS(); 36291da177e4SLinus Torvalds 36301da177e4SLinus Torvalds RESERVE_SPACE(rp->rp_buflen); 36311da177e4SLinus Torvalds WRITEMEM(rp->rp_buf, rp->rp_buflen); 36321da177e4SLinus Torvalds ADJUST_ARGS(); 36331da177e4SLinus Torvalds } 36341da177e4SLinus Torvalds 36351da177e4SLinus Torvalds int 36362ebbc012SAl Viro nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) 36371da177e4SLinus Torvalds { 36381da177e4SLinus Torvalds return xdr_ressize_check(rqstp, p); 36391da177e4SLinus Torvalds } 36401da177e4SLinus Torvalds 36413e98abffSJ. Bruce Fields int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp) 36421da177e4SLinus Torvalds { 36433e98abffSJ. Bruce Fields struct svc_rqst *rqstp = rq; 36443e98abffSJ. Bruce Fields struct nfsd4_compoundargs *args = rqstp->rq_argp; 36453e98abffSJ. Bruce Fields 36461da177e4SLinus Torvalds if (args->ops != args->iops) { 36471da177e4SLinus Torvalds kfree(args->ops); 36481da177e4SLinus Torvalds args->ops = args->iops; 36491da177e4SLinus Torvalds } 36501da177e4SLinus Torvalds kfree(args->tmpp); 36511da177e4SLinus Torvalds args->tmpp = NULL; 36521da177e4SLinus Torvalds while (args->to_free) { 36531da177e4SLinus Torvalds struct tmpbuf *tb = args->to_free; 36541da177e4SLinus Torvalds args->to_free = tb->next; 36551da177e4SLinus Torvalds tb->release(tb->buf); 36561da177e4SLinus Torvalds kfree(tb); 36571da177e4SLinus Torvalds } 36583e98abffSJ. Bruce Fields return 1; 36591da177e4SLinus Torvalds } 36601da177e4SLinus Torvalds 36611da177e4SLinus Torvalds int 36622ebbc012SAl Viro nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) 36631da177e4SLinus Torvalds { 36641da177e4SLinus Torvalds args->p = p; 36651da177e4SLinus Torvalds args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; 36661da177e4SLinus Torvalds args->pagelist = rqstp->rq_arg.pages; 36671da177e4SLinus Torvalds args->pagelen = rqstp->rq_arg.page_len; 36681da177e4SLinus Torvalds args->tmpp = NULL; 36691da177e4SLinus Torvalds args->to_free = NULL; 36701da177e4SLinus Torvalds args->ops = args->iops; 36711da177e4SLinus Torvalds args->rqstp = rqstp; 36721da177e4SLinus Torvalds 36733e98abffSJ. Bruce Fields return !nfsd4_decode_compound(args); 36741da177e4SLinus Torvalds } 36751da177e4SLinus Torvalds 36761da177e4SLinus Torvalds int 36772ebbc012SAl Viro nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp) 36781da177e4SLinus Torvalds { 36791da177e4SLinus Torvalds /* 36801da177e4SLinus Torvalds * All that remains is to write the tag and operation count... 36811da177e4SLinus Torvalds */ 3682557ce264SAndy Adamson struct nfsd4_compound_state *cs = &resp->cstate; 36831da177e4SLinus Torvalds struct kvec *iov; 36841da177e4SLinus Torvalds p = resp->tagp; 36851da177e4SLinus Torvalds *p++ = htonl(resp->taglen); 36861da177e4SLinus Torvalds memcpy(p, resp->tag, resp->taglen); 36871da177e4SLinus Torvalds p += XDR_QUADLEN(resp->taglen); 36881da177e4SLinus Torvalds *p++ = htonl(resp->opcnt); 36891da177e4SLinus Torvalds 36901da177e4SLinus Torvalds if (rqstp->rq_res.page_len) 36911da177e4SLinus Torvalds iov = &rqstp->rq_res.tail[0]; 36921da177e4SLinus Torvalds else 36931da177e4SLinus Torvalds iov = &rqstp->rq_res.head[0]; 36941da177e4SLinus Torvalds iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; 36951da177e4SLinus Torvalds BUG_ON(iov->iov_len > PAGE_SIZE); 369626c0c75eSJ. Bruce Fields if (nfsd4_has_session(cs)) { 369726c0c75eSJ. Bruce Fields if (cs->status != nfserr_replay_cache) { 3698da3846a2SAndy Adamson nfsd4_store_cache_entry(resp); 369973e79482SJ. Bruce Fields cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 370026c0c75eSJ. Bruce Fields } 3701d7682988SBenny Halevy /* Renew the clientid on success and on replay */ 3702d7682988SBenny Halevy release_session_client(cs->session); 370376407f76SJ. Bruce Fields nfsd4_put_session(cs->session); 3704da3846a2SAndy Adamson } 37051da177e4SLinus Torvalds return 1; 37061da177e4SLinus Torvalds } 37071da177e4SLinus Torvalds 37081da177e4SLinus Torvalds /* 37091da177e4SLinus Torvalds * Local variables: 37101da177e4SLinus Torvalds * c-basic-offset: 8 37111da177e4SLinus Torvalds * End: 37121da177e4SLinus Torvalds */ 3713