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 365a0e3ad6STejun Heo #include <linux/slab.h> 371da177e4SLinus Torvalds #include <linux/namei.h> 38341eb184SBoaz Harrosh #include <linux/statfs.h> 390733d213SAndy Adamson #include <linux/utsname.h> 4017456804SBryan Schumaker #include <linux/pagemap.h> 414796f457SJ. Bruce Fields #include <linux/sunrpc/svcauth_gss.h> 429a74af21SBoaz Harrosh 432ca72e17SJ. Bruce Fields #include "idmap.h" 442ca72e17SJ. Bruce Fields #include "acl.h" 459a74af21SBoaz Harrosh #include "xdr4.h" 460a3adadeSJ. Bruce Fields #include "vfs.h" 4717456804SBryan Schumaker #include "state.h" 481091006cSJ. Bruce Fields #include "cache.h" 493d733711SStanislav Kinsbursky #include "netns.h" 509cf514ccSChristoph Hellwig #include "pnfs.h" 512ca72e17SJ. Bruce Fields 5218032ca0SDavid Quigley #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 5318032ca0SDavid Quigley #include <linux/security.h> 5418032ca0SDavid Quigley #endif 5518032ca0SDavid Quigley 5618032ca0SDavid Quigley 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 68a36b1725SJ. Bruce Fields check_filename(char *str, int len) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds int i; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds if (len == 0) 731da177e4SLinus Torvalds return nfserr_inval; 741da177e4SLinus Torvalds if (isdotent(str, len)) 75a36b1725SJ. Bruce Fields return nfserr_badname; 761da177e4SLinus Torvalds for (i = 0; i < len; i++) 771da177e4SLinus Torvalds if (str[i] == '/') 78a36b1725SJ. Bruce Fields return nfserr_badname; 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 READMEM(x,nbytes) do { \ 961da177e4SLinus Torvalds x = (char *)p; \ 971da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 981da177e4SLinus Torvalds } while (0) 991da177e4SLinus Torvalds #define SAVEMEM(x,nbytes) do { \ 1001da177e4SLinus Torvalds if (!(x = (p==argp->tmp || p == argp->tmpp) ? \ 1011da177e4SLinus Torvalds savemem(argp, p, nbytes) : \ 1021da177e4SLinus Torvalds (char *)p)) { \ 103817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 104817cb9d4SChuck Lever __FILE__, __LINE__); \ 1051da177e4SLinus Torvalds goto xdr_error; \ 1061da177e4SLinus Torvalds } \ 1071da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1081da177e4SLinus Torvalds } while (0) 1091da177e4SLinus Torvalds #define COPYMEM(x,nbytes) do { \ 1101da177e4SLinus Torvalds memcpy((x), p, nbytes); \ 1111da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1121da177e4SLinus Torvalds } while (0) 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds /* READ_BUF, read_buf(): nbytes must be <= PAGE_SIZE */ 1151da177e4SLinus Torvalds #define READ_BUF(nbytes) do { \ 1161da177e4SLinus Torvalds if (nbytes <= (u32)((char *)argp->end - (char *)argp->p)) { \ 1171da177e4SLinus Torvalds p = argp->p; \ 1181da177e4SLinus Torvalds argp->p += XDR_QUADLEN(nbytes); \ 1191da177e4SLinus Torvalds } else if (!(p = read_buf(argp, nbytes))) { \ 120817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 121817cb9d4SChuck Lever __FILE__, __LINE__); \ 1221da177e4SLinus Torvalds goto xdr_error; \ 1231da177e4SLinus Torvalds } \ 1241da177e4SLinus Torvalds } while (0) 1251da177e4SLinus Torvalds 126590b7431SJ. Bruce Fields static void next_decode_page(struct nfsd4_compoundargs *argp) 127590b7431SJ. Bruce Fields { 128590b7431SJ. Bruce Fields argp->p = page_address(argp->pagelist[0]); 129365da4adSJ. Bruce Fields argp->pagelist++; 130590b7431SJ. Bruce Fields if (argp->pagelen < PAGE_SIZE) { 131590b7431SJ. Bruce Fields argp->end = argp->p + (argp->pagelen>>2); 132590b7431SJ. Bruce Fields argp->pagelen = 0; 133590b7431SJ. Bruce Fields } else { 134590b7431SJ. Bruce Fields argp->end = argp->p + (PAGE_SIZE>>2); 135590b7431SJ. Bruce Fields argp->pagelen -= PAGE_SIZE; 136590b7431SJ. Bruce Fields } 137590b7431SJ. Bruce Fields } 138590b7431SJ. Bruce Fields 139ca2a05aaSJ. Bruce Fields static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds /* We want more bytes than seem to be available. 1421da177e4SLinus Torvalds * Maybe we need a new page, maybe we have just run out 1431da177e4SLinus Torvalds */ 144ca2a05aaSJ. Bruce Fields unsigned int avail = (char *)argp->end - (char *)argp->p; 1452ebbc012SAl Viro __be32 *p; 1461da177e4SLinus Torvalds if (avail + argp->pagelen < nbytes) 1471da177e4SLinus Torvalds return NULL; 1481da177e4SLinus Torvalds if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */ 1491da177e4SLinus Torvalds return NULL; 1501da177e4SLinus Torvalds /* ok, we can do it with the current plus the next page */ 1511da177e4SLinus Torvalds if (nbytes <= sizeof(argp->tmp)) 1521da177e4SLinus Torvalds p = argp->tmp; 1531da177e4SLinus Torvalds else { 1541da177e4SLinus Torvalds kfree(argp->tmpp); 1551da177e4SLinus Torvalds p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL); 1561da177e4SLinus Torvalds if (!p) 1571da177e4SLinus Torvalds return NULL; 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds } 160ca2a05aaSJ. Bruce Fields /* 161ca2a05aaSJ. Bruce Fields * The following memcpy is safe because read_buf is always 162ca2a05aaSJ. Bruce Fields * called with nbytes > avail, and the two cases above both 163ca2a05aaSJ. Bruce Fields * guarantee p points to at least nbytes bytes. 164ca2a05aaSJ. Bruce Fields */ 1651da177e4SLinus Torvalds memcpy(p, argp->p, avail); 166590b7431SJ. Bruce Fields next_decode_page(argp); 1671da177e4SLinus Torvalds memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); 1681da177e4SLinus Torvalds argp->p += XDR_QUADLEN(nbytes - avail); 1691da177e4SLinus Torvalds return p; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 17260adfc50SAndy Adamson static int zero_clientid(clientid_t *clid) 17360adfc50SAndy Adamson { 17460adfc50SAndy Adamson return (clid->cl_boot == 0) && (clid->cl_id == 0); 17560adfc50SAndy Adamson } 17660adfc50SAndy Adamson 1772d8498dbSChristoph Hellwig /** 178d5e23383SJ. Bruce Fields * svcxdr_tmpalloc - allocate memory to be freed after compound processing 179ce043ac8SJ. Bruce Fields * @argp: NFSv4 compound argument structure 180ce043ac8SJ. Bruce Fields * @p: pointer to be freed (with kfree()) 1812d8498dbSChristoph Hellwig * 1822d8498dbSChristoph Hellwig * Marks @p to be freed when processing the compound operation 1832d8498dbSChristoph Hellwig * described in @argp finishes. 1842d8498dbSChristoph Hellwig */ 185d5e23383SJ. Bruce Fields static void * 186d5e23383SJ. Bruce Fields svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len) 1871da177e4SLinus Torvalds { 188d5e23383SJ. Bruce Fields struct svcxdr_tmpbuf *tb; 1891da177e4SLinus Torvalds 190d5e23383SJ. Bruce Fields tb = kmalloc(sizeof(*tb) + len, GFP_KERNEL); 1911da177e4SLinus Torvalds if (!tb) 192d5e23383SJ. Bruce Fields return NULL; 1931da177e4SLinus Torvalds tb->next = argp->to_free; 1941da177e4SLinus Torvalds argp->to_free = tb; 195d5e23383SJ. Bruce Fields return tb->buf; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 19829c353b3SJ. Bruce Fields /* 19929c353b3SJ. Bruce Fields * For xdr strings that need to be passed to other kernel api's 20029c353b3SJ. Bruce Fields * as null-terminated strings. 20129c353b3SJ. Bruce Fields * 20229c353b3SJ. Bruce Fields * Note null-terminating in place usually isn't safe since the 20329c353b3SJ. Bruce Fields * buffer might end on a page boundary. 20429c353b3SJ. Bruce Fields */ 20529c353b3SJ. Bruce Fields static char * 20629c353b3SJ. Bruce Fields svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len) 20729c353b3SJ. Bruce Fields { 208d5e23383SJ. Bruce Fields char *p = svcxdr_tmpalloc(argp, len + 1); 20929c353b3SJ. Bruce Fields 21029c353b3SJ. Bruce Fields if (!p) 21129c353b3SJ. Bruce Fields return NULL; 21229c353b3SJ. Bruce Fields memcpy(p, buf, len); 21329c353b3SJ. Bruce Fields p[len] = '\0'; 21429c353b3SJ. Bruce Fields return p; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds 2172d8498dbSChristoph Hellwig /** 2182d8498dbSChristoph Hellwig * savemem - duplicate a chunk of memory for later processing 2192d8498dbSChristoph Hellwig * @argp: NFSv4 compound argument structure to be freed with 2202d8498dbSChristoph Hellwig * @p: pointer to be duplicated 2212d8498dbSChristoph Hellwig * @nbytes: length to be duplicated 2222d8498dbSChristoph Hellwig * 2232d8498dbSChristoph Hellwig * Returns a pointer to a copy of @nbytes bytes of memory at @p 2242d8498dbSChristoph Hellwig * that are preserved until processing of the NFSv4 compound 2252d8498dbSChristoph Hellwig * operation described by @argp finishes. 2262d8498dbSChristoph Hellwig */ 2272ebbc012SAl Viro static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) 2281da177e4SLinus Torvalds { 229d5e23383SJ. Bruce Fields void *ret; 230d5e23383SJ. Bruce Fields 231d5e23383SJ. Bruce Fields ret = svcxdr_tmpalloc(argp, nbytes); 232d5e23383SJ. Bruce Fields if (!ret) 233a4db5fe5SJ. Bruce Fields return NULL; 234d5e23383SJ. Bruce Fields memcpy(ret, p, nbytes); 235d5e23383SJ. Bruce Fields return ret; 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds 2384c94e13eSChristoph Hellwig /* 2394c94e13eSChristoph Hellwig * We require the high 32 bits of 'seconds' to be 0, and 2404c94e13eSChristoph Hellwig * we ignore all 32 bits of 'nseconds'. 2414c94e13eSChristoph Hellwig */ 2424c94e13eSChristoph Hellwig static __be32 2434c94e13eSChristoph Hellwig nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec *tv) 2444c94e13eSChristoph Hellwig { 2454c94e13eSChristoph Hellwig DECODE_HEAD; 2464c94e13eSChristoph Hellwig u64 sec; 2474c94e13eSChristoph Hellwig 2484c94e13eSChristoph Hellwig READ_BUF(12); 2494c94e13eSChristoph Hellwig p = xdr_decode_hyper(p, &sec); 2504c94e13eSChristoph Hellwig tv->tv_sec = sec; 2514c94e13eSChristoph Hellwig tv->tv_nsec = be32_to_cpup(p++); 2524c94e13eSChristoph Hellwig if (tv->tv_nsec >= (u32)1000000000) 2534c94e13eSChristoph Hellwig return nfserr_inval; 2544c94e13eSChristoph Hellwig 2554c94e13eSChristoph Hellwig DECODE_TAIL; 2564c94e13eSChristoph Hellwig } 2574c94e13eSChristoph Hellwig 258b37ad28bSAl Viro static __be32 2591da177e4SLinus Torvalds nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) 2601da177e4SLinus Torvalds { 2611da177e4SLinus Torvalds u32 bmlen; 2621da177e4SLinus Torvalds DECODE_HEAD; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds bmval[0] = 0; 2651da177e4SLinus Torvalds bmval[1] = 0; 2667e705706SAndy Adamson bmval[2] = 0; 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds READ_BUF(4); 26906553991SJ. Bruce Fields bmlen = be32_to_cpup(p++); 2701da177e4SLinus Torvalds if (bmlen > 1000) 2711da177e4SLinus Torvalds goto xdr_error; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds READ_BUF(bmlen << 2); 2741da177e4SLinus Torvalds if (bmlen > 0) 27506553991SJ. Bruce Fields bmval[0] = be32_to_cpup(p++); 2761da177e4SLinus Torvalds if (bmlen > 1) 27706553991SJ. Bruce Fields bmval[1] = be32_to_cpup(p++); 2787e705706SAndy Adamson if (bmlen > 2) 27906553991SJ. Bruce Fields bmval[2] = be32_to_cpup(p++); 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds DECODE_TAIL; 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds 284b37ad28bSAl Viro static __be32 2853c8e0316SYu Zhiguo nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, 28618032ca0SDavid Quigley struct iattr *iattr, struct nfs4_acl **acl, 28718032ca0SDavid Quigley struct xdr_netobj *label) 2881da177e4SLinus Torvalds { 2891da177e4SLinus Torvalds int expected_len, len = 0; 2901da177e4SLinus Torvalds u32 dummy32; 2911da177e4SLinus Torvalds char *buf; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds DECODE_HEAD; 2941da177e4SLinus Torvalds iattr->ia_valid = 0; 2951da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, bmval))) 2961da177e4SLinus Torvalds return status; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds READ_BUF(4); 29906553991SJ. Bruce Fields expected_len = be32_to_cpup(p++); 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds if (bmval[0] & FATTR4_WORD0_SIZE) { 3021da177e4SLinus Torvalds READ_BUF(8); 3031da177e4SLinus Torvalds len += 8; 304542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &iattr->ia_size); 3051da177e4SLinus Torvalds iattr->ia_valid |= ATTR_SIZE; 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds if (bmval[0] & FATTR4_WORD0_ACL) { 30864a817cfSJ. Bruce Fields u32 nace; 30928e05dd8SJ. Bruce Fields struct nfs4_ace *ace; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds READ_BUF(4); len += 4; 31206553991SJ. Bruce Fields nace = be32_to_cpup(p++); 3131da177e4SLinus Torvalds 31428e05dd8SJ. Bruce Fields if (nace > NFS4_ACL_MAX) 315798df338SJ. Bruce Fields return nfserr_fbig; 31628e05dd8SJ. Bruce Fields 317d5e23383SJ. Bruce Fields *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace)); 318eba1c99cSKinglong Mee if (*acl == NULL) 319eba1c99cSKinglong Mee return nfserr_jukebox; 320eba1c99cSKinglong Mee 32128e05dd8SJ. Bruce Fields (*acl)->naces = nace; 32228e05dd8SJ. Bruce Fields for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { 3231da177e4SLinus Torvalds READ_BUF(16); len += 16; 32406553991SJ. Bruce Fields ace->type = be32_to_cpup(p++); 32506553991SJ. Bruce Fields ace->flag = be32_to_cpup(p++); 32606553991SJ. Bruce Fields ace->access_mask = be32_to_cpup(p++); 32706553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 3281da177e4SLinus Torvalds READ_BUF(dummy32); 3291da177e4SLinus Torvalds len += XDR_QUADLEN(dummy32) << 2; 3301da177e4SLinus Torvalds READMEM(buf, dummy32); 33128e05dd8SJ. Bruce Fields ace->whotype = nfs4_acl_get_whotype(buf, dummy32); 3323c726023SJ. Bruce Fields status = nfs_ok; 33328e05dd8SJ. Bruce Fields if (ace->whotype != NFS4_ACL_WHO_NAMED) 334ab8e4aeeSEric W. Biederman ; 33528e05dd8SJ. Bruce Fields else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) 3363c726023SJ. Bruce Fields status = nfsd_map_name_to_gid(argp->rqstp, 337ab8e4aeeSEric W. Biederman buf, dummy32, &ace->who_gid); 3381da177e4SLinus Torvalds else 3393c726023SJ. Bruce Fields status = nfsd_map_name_to_uid(argp->rqstp, 340ab8e4aeeSEric W. Biederman buf, dummy32, &ace->who_uid); 3413c726023SJ. Bruce Fields if (status) 3423c726023SJ. Bruce Fields return status; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds } else 3451da177e4SLinus Torvalds *acl = NULL; 3461da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_MODE) { 3471da177e4SLinus Torvalds READ_BUF(4); 3481da177e4SLinus Torvalds len += 4; 34906553991SJ. Bruce Fields iattr->ia_mode = be32_to_cpup(p++); 3501da177e4SLinus Torvalds iattr->ia_mode &= (S_IFMT | S_IALLUGO); 3511da177e4SLinus Torvalds iattr->ia_valid |= ATTR_MODE; 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_OWNER) { 3541da177e4SLinus Torvalds READ_BUF(4); 3551da177e4SLinus Torvalds len += 4; 35606553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 3571da177e4SLinus Torvalds READ_BUF(dummy32); 3581da177e4SLinus Torvalds len += (XDR_QUADLEN(dummy32) << 2); 3591da177e4SLinus Torvalds READMEM(buf, dummy32); 36047c85291SNeilBrown if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) 36147c85291SNeilBrown return status; 3621da177e4SLinus Torvalds iattr->ia_valid |= ATTR_UID; 3631da177e4SLinus Torvalds } 3641da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) { 3651da177e4SLinus Torvalds READ_BUF(4); 3661da177e4SLinus Torvalds len += 4; 36706553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 3681da177e4SLinus Torvalds READ_BUF(dummy32); 3691da177e4SLinus Torvalds len += (XDR_QUADLEN(dummy32) << 2); 3701da177e4SLinus Torvalds READMEM(buf, dummy32); 37147c85291SNeilBrown if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) 37247c85291SNeilBrown return status; 3731da177e4SLinus Torvalds iattr->ia_valid |= ATTR_GID; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) { 3761da177e4SLinus Torvalds READ_BUF(4); 3771da177e4SLinus Torvalds len += 4; 37806553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 3791da177e4SLinus Torvalds switch (dummy32) { 3801da177e4SLinus Torvalds case NFS4_SET_TO_CLIENT_TIME: 3811da177e4SLinus Torvalds len += 12; 3824c94e13eSChristoph Hellwig status = nfsd4_decode_time(argp, &iattr->ia_atime); 3834c94e13eSChristoph Hellwig if (status) 3844c94e13eSChristoph Hellwig return status; 3851da177e4SLinus Torvalds iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); 3861da177e4SLinus Torvalds break; 3871da177e4SLinus Torvalds case NFS4_SET_TO_SERVER_TIME: 3881da177e4SLinus Torvalds iattr->ia_valid |= ATTR_ATIME; 3891da177e4SLinus Torvalds break; 3901da177e4SLinus Torvalds default: 3911da177e4SLinus Torvalds goto xdr_error; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { 3951da177e4SLinus Torvalds READ_BUF(4); 3961da177e4SLinus Torvalds len += 4; 39706553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 3981da177e4SLinus Torvalds switch (dummy32) { 3991da177e4SLinus Torvalds case NFS4_SET_TO_CLIENT_TIME: 4001da177e4SLinus Torvalds len += 12; 4014c94e13eSChristoph Hellwig status = nfsd4_decode_time(argp, &iattr->ia_mtime); 4024c94e13eSChristoph Hellwig if (status) 4034c94e13eSChristoph Hellwig return status; 4041da177e4SLinus Torvalds iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); 4051da177e4SLinus Torvalds break; 4061da177e4SLinus Torvalds case NFS4_SET_TO_SERVER_TIME: 4071da177e4SLinus Torvalds iattr->ia_valid |= ATTR_MTIME; 4081da177e4SLinus Torvalds break; 4091da177e4SLinus Torvalds default: 4101da177e4SLinus Torvalds goto xdr_error; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds } 41318032ca0SDavid Quigley 41418032ca0SDavid Quigley label->len = 0; 41518032ca0SDavid Quigley #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 41618032ca0SDavid Quigley if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { 41718032ca0SDavid Quigley READ_BUF(4); 41818032ca0SDavid Quigley len += 4; 41906553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); /* lfs: we don't use it */ 42018032ca0SDavid Quigley READ_BUF(4); 42118032ca0SDavid Quigley len += 4; 42206553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); /* pi: we don't use it either */ 42318032ca0SDavid Quigley READ_BUF(4); 42418032ca0SDavid Quigley len += 4; 42506553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 42618032ca0SDavid Quigley READ_BUF(dummy32); 4271ec8c0c4SKinglong Mee if (dummy32 > NFS4_MAXLABELLEN) 42818032ca0SDavid Quigley return nfserr_badlabel; 42918032ca0SDavid Quigley len += (XDR_QUADLEN(dummy32) << 2); 43018032ca0SDavid Quigley READMEM(buf, dummy32); 43129c353b3SJ. Bruce Fields label->len = dummy32; 43229c353b3SJ. Bruce Fields label->data = svcxdr_dupstr(argp, buf, dummy32); 43318032ca0SDavid Quigley if (!label->data) 43418032ca0SDavid Quigley return nfserr_jukebox; 43518032ca0SDavid Quigley } 43618032ca0SDavid Quigley #endif 43718032ca0SDavid Quigley 4383c8e0316SYu Zhiguo if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 4393c8e0316SYu Zhiguo || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 4403c8e0316SYu Zhiguo || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) 4413c8e0316SYu Zhiguo READ_BUF(expected_len - len); 4423c8e0316SYu Zhiguo else if (len != expected_len) 4431da177e4SLinus Torvalds goto xdr_error; 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds DECODE_TAIL; 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds 448b37ad28bSAl Viro static __be32 449e31a1b66SBenny Halevy nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid) 450e31a1b66SBenny Halevy { 451e31a1b66SBenny Halevy DECODE_HEAD; 452e31a1b66SBenny Halevy 453e31a1b66SBenny Halevy READ_BUF(sizeof(stateid_t)); 45406553991SJ. Bruce Fields sid->si_generation = be32_to_cpup(p++); 455e31a1b66SBenny Halevy COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); 456e31a1b66SBenny Halevy 457e31a1b66SBenny Halevy DECODE_TAIL; 458e31a1b66SBenny Halevy } 459e31a1b66SBenny Halevy 460e31a1b66SBenny Halevy static __be32 4611da177e4SLinus Torvalds nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access) 4621da177e4SLinus Torvalds { 4631da177e4SLinus Torvalds DECODE_HEAD; 4641da177e4SLinus Torvalds 4651da177e4SLinus Torvalds READ_BUF(4); 46606553991SJ. Bruce Fields access->ac_req_access = be32_to_cpup(p++); 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds DECODE_TAIL; 4691da177e4SLinus Torvalds } 4701da177e4SLinus Torvalds 471acb2887eSJ. Bruce Fields static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) 472acb2887eSJ. Bruce Fields { 473acb2887eSJ. Bruce Fields DECODE_HEAD; 47412fc3e92SJ. Bruce Fields u32 dummy, uid, gid; 475acb2887eSJ. Bruce Fields char *machine_name; 476acb2887eSJ. Bruce Fields int i; 477acb2887eSJ. Bruce Fields int nr_secflavs; 478acb2887eSJ. Bruce Fields 479acb2887eSJ. Bruce Fields /* callback_sec_params4 */ 480acb2887eSJ. Bruce Fields READ_BUF(4); 48106553991SJ. Bruce Fields nr_secflavs = be32_to_cpup(p++); 48257569a70SJ. Bruce Fields if (nr_secflavs) 48312fc3e92SJ. Bruce Fields cbs->flavor = (u32)(-1); 48457569a70SJ. Bruce Fields else 48557569a70SJ. Bruce Fields /* Is this legal? Be generous, take it to mean AUTH_NONE: */ 48657569a70SJ. Bruce Fields cbs->flavor = 0; 487acb2887eSJ. Bruce Fields for (i = 0; i < nr_secflavs; ++i) { 488acb2887eSJ. Bruce Fields READ_BUF(4); 48906553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 490acb2887eSJ. Bruce Fields switch (dummy) { 491acb2887eSJ. Bruce Fields case RPC_AUTH_NULL: 492acb2887eSJ. Bruce Fields /* Nothing to read */ 49312fc3e92SJ. Bruce Fields if (cbs->flavor == (u32)(-1)) 49412fc3e92SJ. Bruce Fields cbs->flavor = RPC_AUTH_NULL; 495acb2887eSJ. Bruce Fields break; 496acb2887eSJ. Bruce Fields case RPC_AUTH_UNIX: 497acb2887eSJ. Bruce Fields READ_BUF(8); 498acb2887eSJ. Bruce Fields /* stamp */ 49906553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 500acb2887eSJ. Bruce Fields 501acb2887eSJ. Bruce Fields /* machine name */ 50206553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 503acb2887eSJ. Bruce Fields READ_BUF(dummy); 504acb2887eSJ. Bruce Fields SAVEMEM(machine_name, dummy); 505acb2887eSJ. Bruce Fields 506acb2887eSJ. Bruce Fields /* uid, gid */ 507acb2887eSJ. Bruce Fields READ_BUF(8); 50806553991SJ. Bruce Fields uid = be32_to_cpup(p++); 50906553991SJ. Bruce Fields gid = be32_to_cpup(p++); 510acb2887eSJ. Bruce Fields 511acb2887eSJ. Bruce Fields /* more gids */ 512acb2887eSJ. Bruce Fields READ_BUF(4); 51306553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 514acb2887eSJ. Bruce Fields READ_BUF(dummy * 4); 51512fc3e92SJ. Bruce Fields if (cbs->flavor == (u32)(-1)) { 51603bc6d1cSEric W. Biederman kuid_t kuid = make_kuid(&init_user_ns, uid); 51703bc6d1cSEric W. Biederman kgid_t kgid = make_kgid(&init_user_ns, gid); 51803bc6d1cSEric W. Biederman if (uid_valid(kuid) && gid_valid(kgid)) { 51903bc6d1cSEric W. Biederman cbs->uid = kuid; 52003bc6d1cSEric W. Biederman cbs->gid = kgid; 52112fc3e92SJ. Bruce Fields cbs->flavor = RPC_AUTH_UNIX; 52203bc6d1cSEric W. Biederman } else { 52303bc6d1cSEric W. Biederman dprintk("RPC_AUTH_UNIX with invalid" 52403bc6d1cSEric W. Biederman "uid or gid ignoring!\n"); 52503bc6d1cSEric W. Biederman } 52612fc3e92SJ. Bruce Fields } 527acb2887eSJ. Bruce Fields break; 528acb2887eSJ. Bruce Fields case RPC_AUTH_GSS: 529acb2887eSJ. Bruce Fields dprintk("RPC_AUTH_GSS callback secflavor " 530acb2887eSJ. Bruce Fields "not supported!\n"); 531acb2887eSJ. Bruce Fields READ_BUF(8); 532acb2887eSJ. Bruce Fields /* gcbp_service */ 53306553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 534acb2887eSJ. Bruce Fields /* gcbp_handle_from_server */ 53506553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 536acb2887eSJ. Bruce Fields READ_BUF(dummy); 537acb2887eSJ. Bruce Fields p += XDR_QUADLEN(dummy); 538acb2887eSJ. Bruce Fields /* gcbp_handle_from_client */ 539acb2887eSJ. Bruce Fields READ_BUF(4); 54006553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 541acb2887eSJ. Bruce Fields READ_BUF(dummy); 542acb2887eSJ. Bruce Fields break; 543acb2887eSJ. Bruce Fields default: 544acb2887eSJ. Bruce Fields dprintk("Illegal callback secflavor\n"); 545acb2887eSJ. Bruce Fields return nfserr_inval; 546acb2887eSJ. Bruce Fields } 547acb2887eSJ. Bruce Fields } 548acb2887eSJ. Bruce Fields DECODE_TAIL; 549acb2887eSJ. Bruce Fields } 550acb2887eSJ. Bruce Fields 551cb73a9f4SJ. Bruce Fields static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) 552cb73a9f4SJ. Bruce Fields { 553cb73a9f4SJ. Bruce Fields DECODE_HEAD; 554cb73a9f4SJ. Bruce Fields 555cb73a9f4SJ. Bruce Fields READ_BUF(4); 55606553991SJ. Bruce Fields bc->bc_cb_program = be32_to_cpup(p++); 557cb73a9f4SJ. Bruce Fields nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); 558cb73a9f4SJ. Bruce Fields 559cb73a9f4SJ. Bruce Fields DECODE_TAIL; 560cb73a9f4SJ. Bruce Fields } 561cb73a9f4SJ. Bruce Fields 5621d1bc8f2SJ. Bruce Fields static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) 5631d1bc8f2SJ. Bruce Fields { 5641d1bc8f2SJ. Bruce Fields DECODE_HEAD; 5651d1bc8f2SJ. Bruce Fields 5661d1bc8f2SJ. Bruce Fields READ_BUF(NFS4_MAX_SESSIONID_LEN + 8); 5671d1bc8f2SJ. Bruce Fields COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); 56806553991SJ. Bruce Fields bcts->dir = be32_to_cpup(p++); 5696ce2357fSBryan Schumaker /* XXX: skipping ctsa_use_conn_in_rdma_mode. Perhaps Tom Tucker 5706ce2357fSBryan Schumaker * could help us figure out we should be using it. */ 5711d1bc8f2SJ. Bruce Fields DECODE_TAIL; 5721d1bc8f2SJ. Bruce Fields } 5731d1bc8f2SJ. Bruce Fields 574b37ad28bSAl Viro static __be32 5751da177e4SLinus Torvalds nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) 5761da177e4SLinus Torvalds { 5771da177e4SLinus Torvalds DECODE_HEAD; 5781da177e4SLinus Torvalds 579e31a1b66SBenny Halevy READ_BUF(4); 58006553991SJ. Bruce Fields close->cl_seqid = be32_to_cpup(p++); 581e31a1b66SBenny Halevy return nfsd4_decode_stateid(argp, &close->cl_stateid); 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds DECODE_TAIL; 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds 587b37ad28bSAl Viro static __be32 5881da177e4SLinus Torvalds nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit) 5891da177e4SLinus Torvalds { 5901da177e4SLinus Torvalds DECODE_HEAD; 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds READ_BUF(12); 593542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &commit->co_offset); 59406553991SJ. Bruce Fields commit->co_count = be32_to_cpup(p++); 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds DECODE_TAIL; 5971da177e4SLinus Torvalds } 5981da177e4SLinus Torvalds 599b37ad28bSAl Viro static __be32 6001da177e4SLinus Torvalds nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create) 6011da177e4SLinus Torvalds { 6021da177e4SLinus Torvalds DECODE_HEAD; 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds READ_BUF(4); 60506553991SJ. Bruce Fields create->cr_type = be32_to_cpup(p++); 6061da177e4SLinus Torvalds switch (create->cr_type) { 6071da177e4SLinus Torvalds case NF4LNK: 6081da177e4SLinus Torvalds READ_BUF(4); 6097fb84306SJ. Bruce Fields create->cr_datalen = be32_to_cpup(p++); 6107fb84306SJ. Bruce Fields READ_BUF(create->cr_datalen); 61129c353b3SJ. Bruce Fields create->cr_data = svcxdr_dupstr(argp, p, create->cr_datalen); 6127fb84306SJ. Bruce Fields if (!create->cr_data) 61376f47128SJ. Bruce Fields return nfserr_jukebox; 6141da177e4SLinus Torvalds break; 6151da177e4SLinus Torvalds case NF4BLK: 6161da177e4SLinus Torvalds case NF4CHR: 6171da177e4SLinus Torvalds READ_BUF(8); 61806553991SJ. Bruce Fields create->cr_specdata1 = be32_to_cpup(p++); 61906553991SJ. Bruce Fields create->cr_specdata2 = be32_to_cpup(p++); 6201da177e4SLinus Torvalds break; 6211da177e4SLinus Torvalds case NF4SOCK: 6221da177e4SLinus Torvalds case NF4FIFO: 6231da177e4SLinus Torvalds case NF4DIR: 6241da177e4SLinus Torvalds default: 6251da177e4SLinus Torvalds break; 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds READ_BUF(4); 62906553991SJ. Bruce Fields create->cr_namelen = be32_to_cpup(p++); 6301da177e4SLinus Torvalds READ_BUF(create->cr_namelen); 6311da177e4SLinus Torvalds SAVEMEM(create->cr_name, create->cr_namelen); 632a36b1725SJ. Bruce Fields if ((status = check_filename(create->cr_name, create->cr_namelen))) 6331da177e4SLinus Torvalds return status; 6341da177e4SLinus Torvalds 6353c8e0316SYu Zhiguo status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, 63618032ca0SDavid Quigley &create->cr_acl, &create->cr_label); 637c0d6fc8aSBenny Halevy if (status) 6381da177e4SLinus Torvalds goto out; 6391da177e4SLinus Torvalds 6401da177e4SLinus Torvalds DECODE_TAIL; 6411da177e4SLinus Torvalds } 6421da177e4SLinus Torvalds 643b37ad28bSAl Viro static inline __be32 6441da177e4SLinus Torvalds nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr) 6451da177e4SLinus Torvalds { 646e31a1b66SBenny Halevy return nfsd4_decode_stateid(argp, &dr->dr_stateid); 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 649b37ad28bSAl Viro static inline __be32 6501da177e4SLinus Torvalds nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) 6511da177e4SLinus Torvalds { 6521da177e4SLinus Torvalds return nfsd4_decode_bitmap(argp, getattr->ga_bmval); 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds 655b37ad28bSAl Viro static __be32 6561da177e4SLinus Torvalds nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) 6571da177e4SLinus Torvalds { 6581da177e4SLinus Torvalds DECODE_HEAD; 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds READ_BUF(4); 66106553991SJ. Bruce Fields link->li_namelen = be32_to_cpup(p++); 6621da177e4SLinus Torvalds READ_BUF(link->li_namelen); 6631da177e4SLinus Torvalds SAVEMEM(link->li_name, link->li_namelen); 664a36b1725SJ. Bruce Fields if ((status = check_filename(link->li_name, link->li_namelen))) 6651da177e4SLinus Torvalds return status; 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds DECODE_TAIL; 6681da177e4SLinus Torvalds } 6691da177e4SLinus Torvalds 670b37ad28bSAl Viro static __be32 6711da177e4SLinus Torvalds nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) 6721da177e4SLinus Torvalds { 6731da177e4SLinus Torvalds DECODE_HEAD; 6741da177e4SLinus Torvalds 6751da177e4SLinus Torvalds /* 6761da177e4SLinus Torvalds * type, reclaim(boolean), offset, length, new_lock_owner(boolean) 6771da177e4SLinus Torvalds */ 6781da177e4SLinus Torvalds READ_BUF(28); 67906553991SJ. Bruce Fields lock->lk_type = be32_to_cpup(p++); 6801da177e4SLinus Torvalds if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT)) 6811da177e4SLinus Torvalds goto xdr_error; 68206553991SJ. Bruce Fields lock->lk_reclaim = be32_to_cpup(p++); 683542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &lock->lk_offset); 684542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &lock->lk_length); 68506553991SJ. Bruce Fields lock->lk_is_new = be32_to_cpup(p++); 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds if (lock->lk_is_new) { 688e31a1b66SBenny Halevy READ_BUF(4); 68906553991SJ. Bruce Fields lock->lk_new_open_seqid = be32_to_cpup(p++); 690e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid); 691e31a1b66SBenny Halevy if (status) 692e31a1b66SBenny Halevy return status; 693e31a1b66SBenny Halevy READ_BUF(8 + sizeof(clientid_t)); 69406553991SJ. Bruce Fields lock->lk_new_lock_seqid = be32_to_cpup(p++); 6951da177e4SLinus Torvalds COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t)); 69606553991SJ. Bruce Fields lock->lk_new_owner.len = be32_to_cpup(p++); 6971da177e4SLinus Torvalds READ_BUF(lock->lk_new_owner.len); 6981da177e4SLinus Torvalds READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len); 6991da177e4SLinus Torvalds } else { 700e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid); 701e31a1b66SBenny Halevy if (status) 702e31a1b66SBenny Halevy return status; 703e31a1b66SBenny Halevy READ_BUF(4); 70406553991SJ. Bruce Fields lock->lk_old_lock_seqid = be32_to_cpup(p++); 7051da177e4SLinus Torvalds } 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds DECODE_TAIL; 7081da177e4SLinus Torvalds } 7091da177e4SLinus Torvalds 710b37ad28bSAl Viro static __be32 7111da177e4SLinus Torvalds nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) 7121da177e4SLinus Torvalds { 7131da177e4SLinus Torvalds DECODE_HEAD; 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds READ_BUF(32); 71606553991SJ. Bruce Fields lockt->lt_type = be32_to_cpup(p++); 7171da177e4SLinus Torvalds if((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT)) 7181da177e4SLinus Torvalds goto xdr_error; 719542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &lockt->lt_offset); 720542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &lockt->lt_length); 7211da177e4SLinus Torvalds COPYMEM(&lockt->lt_clientid, 8); 72206553991SJ. Bruce Fields lockt->lt_owner.len = be32_to_cpup(p++); 7231da177e4SLinus Torvalds READ_BUF(lockt->lt_owner.len); 7241da177e4SLinus Torvalds READMEM(lockt->lt_owner.data, lockt->lt_owner.len); 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds DECODE_TAIL; 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds 729b37ad28bSAl Viro static __be32 7301da177e4SLinus Torvalds nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) 7311da177e4SLinus Torvalds { 7321da177e4SLinus Torvalds DECODE_HEAD; 7331da177e4SLinus Torvalds 734e31a1b66SBenny Halevy READ_BUF(8); 73506553991SJ. Bruce Fields locku->lu_type = be32_to_cpup(p++); 7361da177e4SLinus Torvalds if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT)) 7371da177e4SLinus Torvalds goto xdr_error; 73806553991SJ. Bruce Fields locku->lu_seqid = be32_to_cpup(p++); 739e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &locku->lu_stateid); 740e31a1b66SBenny Halevy if (status) 741e31a1b66SBenny Halevy return status; 742e31a1b66SBenny Halevy READ_BUF(16); 743542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &locku->lu_offset); 744542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &locku->lu_length); 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds DECODE_TAIL; 7471da177e4SLinus Torvalds } 7481da177e4SLinus Torvalds 749b37ad28bSAl Viro static __be32 7501da177e4SLinus Torvalds nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) 7511da177e4SLinus Torvalds { 7521da177e4SLinus Torvalds DECODE_HEAD; 7531da177e4SLinus Torvalds 7541da177e4SLinus Torvalds READ_BUF(4); 75506553991SJ. Bruce Fields lookup->lo_len = be32_to_cpup(p++); 7561da177e4SLinus Torvalds READ_BUF(lookup->lo_len); 7571da177e4SLinus Torvalds SAVEMEM(lookup->lo_name, lookup->lo_len); 758a36b1725SJ. Bruce Fields if ((status = check_filename(lookup->lo_name, lookup->lo_len))) 7591da177e4SLinus Torvalds return status; 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds DECODE_TAIL; 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds 7642c8bd7e0SBenny Halevy static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when) 76504f9e664SJ. Bruce Fields { 76604f9e664SJ. Bruce Fields __be32 *p; 76704f9e664SJ. Bruce Fields u32 w; 76804f9e664SJ. Bruce Fields 76904f9e664SJ. Bruce Fields READ_BUF(4); 77006553991SJ. Bruce Fields w = be32_to_cpup(p++); 7712c8bd7e0SBenny Halevy *share_access = w & NFS4_SHARE_ACCESS_MASK; 7722c8bd7e0SBenny Halevy *deleg_want = w & NFS4_SHARE_WANT_MASK; 7732c8bd7e0SBenny Halevy if (deleg_when) 7742c8bd7e0SBenny Halevy *deleg_when = w & NFS4_SHARE_WHEN_MASK; 7752c8bd7e0SBenny Halevy 77604f9e664SJ. Bruce Fields switch (w & NFS4_SHARE_ACCESS_MASK) { 77704f9e664SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 77804f9e664SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 77904f9e664SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 78004f9e664SJ. Bruce Fields break; 78104f9e664SJ. Bruce Fields default: 78204f9e664SJ. Bruce Fields return nfserr_bad_xdr; 78304f9e664SJ. Bruce Fields } 784fc0d14feSBenny Halevy w &= ~NFS4_SHARE_ACCESS_MASK; 78504f9e664SJ. Bruce Fields if (!w) 78604f9e664SJ. Bruce Fields return nfs_ok; 78704f9e664SJ. Bruce Fields if (!argp->minorversion) 78804f9e664SJ. Bruce Fields return nfserr_bad_xdr; 78904f9e664SJ. Bruce Fields switch (w & NFS4_SHARE_WANT_MASK) { 79004f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_NO_PREFERENCE: 79104f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_READ_DELEG: 79204f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_WRITE_DELEG: 79304f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_ANY_DELEG: 79404f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_NO_DELEG: 79504f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_CANCEL: 79604f9e664SJ. Bruce Fields break; 79704f9e664SJ. Bruce Fields default: 79804f9e664SJ. Bruce Fields return nfserr_bad_xdr; 79904f9e664SJ. Bruce Fields } 80092bac8c5SBenny Halevy w &= ~NFS4_SHARE_WANT_MASK; 80104f9e664SJ. Bruce Fields if (!w) 80204f9e664SJ. Bruce Fields return nfs_ok; 8032c8bd7e0SBenny Halevy 8042c8bd7e0SBenny Halevy if (!deleg_when) /* open_downgrade */ 8052c8bd7e0SBenny Halevy return nfserr_inval; 80604f9e664SJ. Bruce Fields switch (w) { 80704f9e664SJ. Bruce Fields case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL: 80804f9e664SJ. Bruce Fields case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED: 809c668fc6dSBenny Halevy case (NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL | 810c668fc6dSBenny Halevy NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED): 81104f9e664SJ. Bruce Fields return nfs_ok; 81204f9e664SJ. Bruce Fields } 81304f9e664SJ. Bruce Fields xdr_error: 81404f9e664SJ. Bruce Fields return nfserr_bad_xdr; 81504f9e664SJ. Bruce Fields } 81604f9e664SJ. Bruce Fields 81704f9e664SJ. Bruce Fields static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x) 81804f9e664SJ. Bruce Fields { 81904f9e664SJ. Bruce Fields __be32 *p; 82004f9e664SJ. Bruce Fields 82104f9e664SJ. Bruce Fields READ_BUF(4); 82206553991SJ. Bruce Fields *x = be32_to_cpup(p++); 82304f9e664SJ. Bruce Fields /* Note: unlinke access bits, deny bits may be zero. */ 82401cd4afaSDan Carpenter if (*x & ~NFS4_SHARE_DENY_BOTH) 82504f9e664SJ. Bruce Fields return nfserr_bad_xdr; 82604f9e664SJ. Bruce Fields return nfs_ok; 82704f9e664SJ. Bruce Fields xdr_error: 82804f9e664SJ. Bruce Fields return nfserr_bad_xdr; 82904f9e664SJ. Bruce Fields } 83004f9e664SJ. Bruce Fields 831a084daf5SJ. Bruce Fields static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o) 832a084daf5SJ. Bruce Fields { 833a084daf5SJ. Bruce Fields __be32 *p; 834a084daf5SJ. Bruce Fields 835a084daf5SJ. Bruce Fields READ_BUF(4); 83606553991SJ. Bruce Fields o->len = be32_to_cpup(p++); 837a084daf5SJ. Bruce Fields 838a084daf5SJ. Bruce Fields if (o->len == 0 || o->len > NFS4_OPAQUE_LIMIT) 839a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 840a084daf5SJ. Bruce Fields 841a084daf5SJ. Bruce Fields READ_BUF(o->len); 842a084daf5SJ. Bruce Fields SAVEMEM(o->data, o->len); 843a084daf5SJ. Bruce Fields return nfs_ok; 844a084daf5SJ. Bruce Fields xdr_error: 845a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 846a084daf5SJ. Bruce Fields } 847a084daf5SJ. Bruce Fields 848b37ad28bSAl Viro static __be32 8491da177e4SLinus Torvalds nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) 8501da177e4SLinus Torvalds { 8511da177e4SLinus Torvalds DECODE_HEAD; 8522c8bd7e0SBenny Halevy u32 dummy; 8531da177e4SLinus Torvalds 8541da177e4SLinus Torvalds memset(open->op_bmval, 0, sizeof(open->op_bmval)); 8551da177e4SLinus Torvalds open->op_iattr.ia_valid = 0; 856fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 8571da177e4SLinus Torvalds 8589d313b17SJ. Bruce Fields open->op_xdr_error = 0; 8591da177e4SLinus Torvalds /* seqid, share_access, share_deny, clientid, ownerlen */ 86004f9e664SJ. Bruce Fields READ_BUF(4); 86106553991SJ. Bruce Fields open->op_seqid = be32_to_cpup(p++); 8622c8bd7e0SBenny Halevy /* decode, yet ignore deleg_when until supported */ 8632c8bd7e0SBenny Halevy status = nfsd4_decode_share_access(argp, &open->op_share_access, 8642c8bd7e0SBenny Halevy &open->op_deleg_want, &dummy); 86504f9e664SJ. Bruce Fields if (status) 86604f9e664SJ. Bruce Fields goto xdr_error; 86704f9e664SJ. Bruce Fields status = nfsd4_decode_share_deny(argp, &open->op_share_deny); 86804f9e664SJ. Bruce Fields if (status) 86904f9e664SJ. Bruce Fields goto xdr_error; 870a084daf5SJ. Bruce Fields READ_BUF(sizeof(clientid_t)); 8711da177e4SLinus Torvalds COPYMEM(&open->op_clientid, sizeof(clientid_t)); 872a084daf5SJ. Bruce Fields status = nfsd4_decode_opaque(argp, &open->op_owner); 873a084daf5SJ. Bruce Fields if (status) 874a084daf5SJ. Bruce Fields goto xdr_error; 875a084daf5SJ. Bruce Fields READ_BUF(4); 87606553991SJ. Bruce Fields open->op_create = be32_to_cpup(p++); 8771da177e4SLinus Torvalds switch (open->op_create) { 8781da177e4SLinus Torvalds case NFS4_OPEN_NOCREATE: 8791da177e4SLinus Torvalds break; 8801da177e4SLinus Torvalds case NFS4_OPEN_CREATE: 8811da177e4SLinus Torvalds READ_BUF(4); 88206553991SJ. Bruce Fields open->op_createmode = be32_to_cpup(p++); 8831da177e4SLinus Torvalds switch (open->op_createmode) { 8841da177e4SLinus Torvalds case NFS4_CREATE_UNCHECKED: 8851da177e4SLinus Torvalds case NFS4_CREATE_GUARDED: 886c0d6fc8aSBenny Halevy status = nfsd4_decode_fattr(argp, open->op_bmval, 88718032ca0SDavid Quigley &open->op_iattr, &open->op_acl, &open->op_label); 888c0d6fc8aSBenny Halevy if (status) 8891da177e4SLinus Torvalds goto out; 8901da177e4SLinus Torvalds break; 8911da177e4SLinus Torvalds case NFS4_CREATE_EXCLUSIVE: 892ab4684d1SChuck Lever READ_BUF(NFS4_VERIFIER_SIZE); 893ab4684d1SChuck Lever COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); 8941da177e4SLinus Torvalds break; 89579fb54abSBenny Halevy case NFS4_CREATE_EXCLUSIVE4_1: 89679fb54abSBenny Halevy if (argp->minorversion < 1) 89779fb54abSBenny Halevy goto xdr_error; 898ab4684d1SChuck Lever READ_BUF(NFS4_VERIFIER_SIZE); 899ab4684d1SChuck Lever COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); 90079fb54abSBenny Halevy status = nfsd4_decode_fattr(argp, open->op_bmval, 90118032ca0SDavid Quigley &open->op_iattr, &open->op_acl, &open->op_label); 90279fb54abSBenny Halevy if (status) 90379fb54abSBenny Halevy goto out; 90479fb54abSBenny Halevy break; 9051da177e4SLinus Torvalds default: 9061da177e4SLinus Torvalds goto xdr_error; 9071da177e4SLinus Torvalds } 9081da177e4SLinus Torvalds break; 9091da177e4SLinus Torvalds default: 9101da177e4SLinus Torvalds goto xdr_error; 9111da177e4SLinus Torvalds } 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds /* open_claim */ 9141da177e4SLinus Torvalds READ_BUF(4); 91506553991SJ. Bruce Fields open->op_claim_type = be32_to_cpup(p++); 9161da177e4SLinus Torvalds switch (open->op_claim_type) { 9171da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_NULL: 9181da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_PREV: 9191da177e4SLinus Torvalds READ_BUF(4); 92006553991SJ. Bruce Fields open->op_fname.len = be32_to_cpup(p++); 9211da177e4SLinus Torvalds READ_BUF(open->op_fname.len); 9221da177e4SLinus Torvalds SAVEMEM(open->op_fname.data, open->op_fname.len); 923a36b1725SJ. Bruce Fields if ((status = check_filename(open->op_fname.data, open->op_fname.len))) 9241da177e4SLinus Torvalds return status; 9251da177e4SLinus Torvalds break; 9261da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_PREVIOUS: 9271da177e4SLinus Torvalds READ_BUF(4); 92806553991SJ. Bruce Fields open->op_delegate_type = be32_to_cpup(p++); 9291da177e4SLinus Torvalds break; 9301da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_CUR: 931e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); 932e31a1b66SBenny Halevy if (status) 933e31a1b66SBenny Halevy return status; 934e31a1b66SBenny Halevy READ_BUF(4); 93506553991SJ. Bruce Fields open->op_fname.len = be32_to_cpup(p++); 9361da177e4SLinus Torvalds READ_BUF(open->op_fname.len); 9371da177e4SLinus Torvalds SAVEMEM(open->op_fname.data, open->op_fname.len); 938a36b1725SJ. Bruce Fields if ((status = check_filename(open->op_fname.data, open->op_fname.len))) 9391da177e4SLinus Torvalds return status; 9401da177e4SLinus Torvalds break; 9418b289b2cSJ. Bruce Fields case NFS4_OPEN_CLAIM_FH: 9428b289b2cSJ. Bruce Fields case NFS4_OPEN_CLAIM_DELEG_PREV_FH: 9438b289b2cSJ. Bruce Fields if (argp->minorversion < 1) 9448b289b2cSJ. Bruce Fields goto xdr_error; 9458b289b2cSJ. Bruce Fields /* void */ 9468b289b2cSJ. Bruce Fields break; 9478b289b2cSJ. Bruce Fields case NFS4_OPEN_CLAIM_DELEG_CUR_FH: 9488b289b2cSJ. Bruce Fields if (argp->minorversion < 1) 9498b289b2cSJ. Bruce Fields goto xdr_error; 9508b289b2cSJ. Bruce Fields status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); 9518b289b2cSJ. Bruce Fields if (status) 9528b289b2cSJ. Bruce Fields return status; 9538b289b2cSJ. Bruce Fields break; 9541da177e4SLinus Torvalds default: 9551da177e4SLinus Torvalds goto xdr_error; 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds DECODE_TAIL; 9591da177e4SLinus Torvalds } 9601da177e4SLinus Torvalds 961b37ad28bSAl Viro static __be32 9621da177e4SLinus Torvalds nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) 9631da177e4SLinus Torvalds { 9641da177e4SLinus Torvalds DECODE_HEAD; 9651da177e4SLinus Torvalds 966e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 967e1a90ebdSAnna Schumaker return nfserr_notsupp; 968e1a90ebdSAnna Schumaker 969e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); 970e31a1b66SBenny Halevy if (status) 971e31a1b66SBenny Halevy return status; 972e31a1b66SBenny Halevy READ_BUF(4); 97306553991SJ. Bruce Fields open_conf->oc_seqid = be32_to_cpup(p++); 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds DECODE_TAIL; 9761da177e4SLinus Torvalds } 9771da177e4SLinus Torvalds 978b37ad28bSAl Viro static __be32 9791da177e4SLinus Torvalds nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down) 9801da177e4SLinus Torvalds { 9811da177e4SLinus Torvalds DECODE_HEAD; 9821da177e4SLinus Torvalds 983e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open_down->od_stateid); 984e31a1b66SBenny Halevy if (status) 985e31a1b66SBenny Halevy return status; 98604f9e664SJ. Bruce Fields READ_BUF(4); 98706553991SJ. Bruce Fields open_down->od_seqid = be32_to_cpup(p++); 9882c8bd7e0SBenny Halevy status = nfsd4_decode_share_access(argp, &open_down->od_share_access, 9892c8bd7e0SBenny Halevy &open_down->od_deleg_want, NULL); 99004f9e664SJ. Bruce Fields if (status) 99104f9e664SJ. Bruce Fields return status; 99204f9e664SJ. Bruce Fields status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny); 99304f9e664SJ. Bruce Fields if (status) 99404f9e664SJ. Bruce Fields return status; 9951da177e4SLinus Torvalds DECODE_TAIL; 9961da177e4SLinus Torvalds } 9971da177e4SLinus Torvalds 998b37ad28bSAl Viro static __be32 9991da177e4SLinus Torvalds nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) 10001da177e4SLinus Torvalds { 10011da177e4SLinus Torvalds DECODE_HEAD; 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds READ_BUF(4); 100406553991SJ. Bruce Fields putfh->pf_fhlen = be32_to_cpup(p++); 10051da177e4SLinus Torvalds if (putfh->pf_fhlen > NFS4_FHSIZE) 10061da177e4SLinus Torvalds goto xdr_error; 10071da177e4SLinus Torvalds READ_BUF(putfh->pf_fhlen); 10081da177e4SLinus Torvalds SAVEMEM(putfh->pf_fhval, putfh->pf_fhlen); 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds DECODE_TAIL; 10111da177e4SLinus Torvalds } 10121da177e4SLinus Torvalds 1013b37ad28bSAl Viro static __be32 1014e1a90ebdSAnna Schumaker nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p) 1015e1a90ebdSAnna Schumaker { 1016e1a90ebdSAnna Schumaker if (argp->minorversion == 0) 1017e1a90ebdSAnna Schumaker return nfs_ok; 1018e1a90ebdSAnna Schumaker return nfserr_notsupp; 1019e1a90ebdSAnna Schumaker } 1020e1a90ebdSAnna Schumaker 1021e1a90ebdSAnna Schumaker static __be32 10221da177e4SLinus Torvalds nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) 10231da177e4SLinus Torvalds { 10241da177e4SLinus Torvalds DECODE_HEAD; 10251da177e4SLinus Torvalds 1026e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &read->rd_stateid); 1027e31a1b66SBenny Halevy if (status) 1028e31a1b66SBenny Halevy return status; 1029e31a1b66SBenny Halevy READ_BUF(12); 1030542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &read->rd_offset); 103106553991SJ. Bruce Fields read->rd_length = be32_to_cpup(p++); 10321da177e4SLinus Torvalds 10331da177e4SLinus Torvalds DECODE_TAIL; 10341da177e4SLinus Torvalds } 10351da177e4SLinus Torvalds 1036b37ad28bSAl Viro static __be32 10371da177e4SLinus Torvalds nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir) 10381da177e4SLinus Torvalds { 10391da177e4SLinus Torvalds DECODE_HEAD; 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds READ_BUF(24); 1042542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &readdir->rd_cookie); 10431da177e4SLinus Torvalds COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data)); 104406553991SJ. Bruce Fields readdir->rd_dircount = be32_to_cpup(p++); 104506553991SJ. Bruce Fields readdir->rd_maxcount = be32_to_cpup(p++); 10461da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval))) 10471da177e4SLinus Torvalds goto out; 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds DECODE_TAIL; 10501da177e4SLinus Torvalds } 10511da177e4SLinus Torvalds 1052b37ad28bSAl Viro static __be32 10531da177e4SLinus Torvalds nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove) 10541da177e4SLinus Torvalds { 10551da177e4SLinus Torvalds DECODE_HEAD; 10561da177e4SLinus Torvalds 10571da177e4SLinus Torvalds READ_BUF(4); 105806553991SJ. Bruce Fields remove->rm_namelen = be32_to_cpup(p++); 10591da177e4SLinus Torvalds READ_BUF(remove->rm_namelen); 10601da177e4SLinus Torvalds SAVEMEM(remove->rm_name, remove->rm_namelen); 1061a36b1725SJ. Bruce Fields if ((status = check_filename(remove->rm_name, remove->rm_namelen))) 10621da177e4SLinus Torvalds return status; 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds DECODE_TAIL; 10651da177e4SLinus Torvalds } 10661da177e4SLinus Torvalds 1067b37ad28bSAl Viro static __be32 10681da177e4SLinus Torvalds nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename) 10691da177e4SLinus Torvalds { 10701da177e4SLinus Torvalds DECODE_HEAD; 10711da177e4SLinus Torvalds 10721da177e4SLinus Torvalds READ_BUF(4); 107306553991SJ. Bruce Fields rename->rn_snamelen = be32_to_cpup(p++); 10741da177e4SLinus Torvalds READ_BUF(rename->rn_snamelen + 4); 10751da177e4SLinus Torvalds SAVEMEM(rename->rn_sname, rename->rn_snamelen); 107606553991SJ. Bruce Fields rename->rn_tnamelen = be32_to_cpup(p++); 10771da177e4SLinus Torvalds READ_BUF(rename->rn_tnamelen); 10781da177e4SLinus Torvalds SAVEMEM(rename->rn_tname, rename->rn_tnamelen); 1079a36b1725SJ. Bruce Fields if ((status = check_filename(rename->rn_sname, rename->rn_snamelen))) 10801da177e4SLinus Torvalds return status; 1081a36b1725SJ. Bruce Fields if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen))) 10821da177e4SLinus Torvalds return status; 10831da177e4SLinus Torvalds 10841da177e4SLinus Torvalds DECODE_TAIL; 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds 1087b37ad28bSAl Viro static __be32 10881da177e4SLinus Torvalds nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) 10891da177e4SLinus Torvalds { 10901da177e4SLinus Torvalds DECODE_HEAD; 10911da177e4SLinus Torvalds 1092e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 1093e1a90ebdSAnna Schumaker return nfserr_notsupp; 1094e1a90ebdSAnna Schumaker 10951da177e4SLinus Torvalds READ_BUF(sizeof(clientid_t)); 10961da177e4SLinus Torvalds COPYMEM(clientid, sizeof(clientid_t)); 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds DECODE_TAIL; 10991da177e4SLinus Torvalds } 11001da177e4SLinus Torvalds 1101b37ad28bSAl Viro static __be32 1102dcb488a3SAndy Adamson nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, 1103dcb488a3SAndy Adamson struct nfsd4_secinfo *secinfo) 1104dcb488a3SAndy Adamson { 1105dcb488a3SAndy Adamson DECODE_HEAD; 1106dcb488a3SAndy Adamson 1107dcb488a3SAndy Adamson READ_BUF(4); 110806553991SJ. Bruce Fields secinfo->si_namelen = be32_to_cpup(p++); 1109dcb488a3SAndy Adamson READ_BUF(secinfo->si_namelen); 1110dcb488a3SAndy Adamson SAVEMEM(secinfo->si_name, secinfo->si_namelen); 1111a36b1725SJ. Bruce Fields status = check_filename(secinfo->si_name, secinfo->si_namelen); 1112dcb488a3SAndy Adamson if (status) 1113dcb488a3SAndy Adamson return status; 1114dcb488a3SAndy Adamson DECODE_TAIL; 1115dcb488a3SAndy Adamson } 1116dcb488a3SAndy Adamson 1117dcb488a3SAndy Adamson static __be32 111804f4ad16SJ. Bruce Fields nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, 111904f4ad16SJ. Bruce Fields struct nfsd4_secinfo_no_name *sin) 112004f4ad16SJ. Bruce Fields { 112104f4ad16SJ. Bruce Fields DECODE_HEAD; 112204f4ad16SJ. Bruce Fields 112304f4ad16SJ. Bruce Fields READ_BUF(4); 112406553991SJ. Bruce Fields sin->sin_style = be32_to_cpup(p++); 112504f4ad16SJ. Bruce Fields DECODE_TAIL; 112604f4ad16SJ. Bruce Fields } 112704f4ad16SJ. Bruce Fields 112804f4ad16SJ. Bruce Fields static __be32 11291da177e4SLinus Torvalds nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) 11301da177e4SLinus Torvalds { 1131e31a1b66SBenny Halevy __be32 status; 11321da177e4SLinus Torvalds 1133e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); 1134e31a1b66SBenny Halevy if (status) 1135e31a1b66SBenny Halevy return status; 11363c8e0316SYu Zhiguo return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, 113718032ca0SDavid Quigley &setattr->sa_acl, &setattr->sa_label); 11381da177e4SLinus Torvalds } 11391da177e4SLinus Torvalds 1140b37ad28bSAl Viro static __be32 11411da177e4SLinus Torvalds nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid) 11421da177e4SLinus Torvalds { 11431da177e4SLinus Torvalds DECODE_HEAD; 11441da177e4SLinus Torvalds 1145e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 1146e1a90ebdSAnna Schumaker return nfserr_notsupp; 1147e1a90ebdSAnna Schumaker 1148ab4684d1SChuck Lever READ_BUF(NFS4_VERIFIER_SIZE); 1149ab4684d1SChuck Lever COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE); 11501da177e4SLinus Torvalds 1151a084daf5SJ. Bruce Fields status = nfsd4_decode_opaque(argp, &setclientid->se_name); 1152a084daf5SJ. Bruce Fields if (status) 1153a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 1154a084daf5SJ. Bruce Fields READ_BUF(8); 115506553991SJ. Bruce Fields setclientid->se_callback_prog = be32_to_cpup(p++); 115606553991SJ. Bruce Fields setclientid->se_callback_netid_len = be32_to_cpup(p++); 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds READ_BUF(setclientid->se_callback_netid_len + 4); 11591da177e4SLinus Torvalds SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len); 116006553991SJ. Bruce Fields setclientid->se_callback_addr_len = be32_to_cpup(p++); 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds READ_BUF(setclientid->se_callback_addr_len + 4); 11631da177e4SLinus Torvalds SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len); 116406553991SJ. Bruce Fields setclientid->se_callback_ident = be32_to_cpup(p++); 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds DECODE_TAIL; 11671da177e4SLinus Torvalds } 11681da177e4SLinus Torvalds 1169b37ad28bSAl Viro static __be32 11701da177e4SLinus Torvalds nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c) 11711da177e4SLinus Torvalds { 11721da177e4SLinus Torvalds DECODE_HEAD; 11731da177e4SLinus Torvalds 1174e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 1175e1a90ebdSAnna Schumaker return nfserr_notsupp; 1176e1a90ebdSAnna Schumaker 1177ab4684d1SChuck Lever READ_BUF(8 + NFS4_VERIFIER_SIZE); 11781da177e4SLinus Torvalds COPYMEM(&scd_c->sc_clientid, 8); 1179ab4684d1SChuck Lever COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE); 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds DECODE_TAIL; 11821da177e4SLinus Torvalds } 11831da177e4SLinus Torvalds 11841da177e4SLinus Torvalds /* Also used for NVERIFY */ 1185b37ad28bSAl Viro static __be32 11861da177e4SLinus Torvalds nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) 11871da177e4SLinus Torvalds { 11881da177e4SLinus Torvalds DECODE_HEAD; 11891da177e4SLinus Torvalds 11901da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) 11911da177e4SLinus Torvalds goto out; 11921da177e4SLinus Torvalds 11931da177e4SLinus Torvalds /* For convenience's sake, we compare raw xdr'd attributes in 1194e5f95703SJ. Bruce Fields * nfsd4_proc_verify */ 1195e5f95703SJ. Bruce Fields 11961da177e4SLinus Torvalds READ_BUF(4); 119706553991SJ. Bruce Fields verify->ve_attrlen = be32_to_cpup(p++); 11981da177e4SLinus Torvalds READ_BUF(verify->ve_attrlen); 11991da177e4SLinus Torvalds SAVEMEM(verify->ve_attrval, verify->ve_attrlen); 12001da177e4SLinus Torvalds 12011da177e4SLinus Torvalds DECODE_TAIL; 12021da177e4SLinus Torvalds } 12031da177e4SLinus Torvalds 1204b37ad28bSAl Viro static __be32 12051da177e4SLinus Torvalds nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) 12061da177e4SLinus Torvalds { 12071da177e4SLinus Torvalds int avail; 12081da177e4SLinus Torvalds int len; 12091da177e4SLinus Torvalds DECODE_HEAD; 12101da177e4SLinus Torvalds 1211e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &write->wr_stateid); 1212e31a1b66SBenny Halevy if (status) 1213e31a1b66SBenny Halevy return status; 1214e31a1b66SBenny Halevy READ_BUF(16); 1215542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &write->wr_offset); 121606553991SJ. Bruce Fields write->wr_stable_how = be32_to_cpup(p++); 12171da177e4SLinus Torvalds if (write->wr_stable_how > 2) 12181da177e4SLinus Torvalds goto xdr_error; 121906553991SJ. Bruce Fields write->wr_buflen = be32_to_cpup(p++); 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds /* Sorry .. no magic macros for this.. * 12221da177e4SLinus Torvalds * READ_BUF(write->wr_buflen); 12231da177e4SLinus Torvalds * SAVEMEM(write->wr_buf, write->wr_buflen); 12241da177e4SLinus Torvalds */ 12251da177e4SLinus Torvalds avail = (char*)argp->end - (char*)argp->p; 12261da177e4SLinus Torvalds if (avail + argp->pagelen < write->wr_buflen) { 1227817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", 1228817cb9d4SChuck Lever __FILE__, __LINE__); 12291da177e4SLinus Torvalds goto xdr_error; 12301da177e4SLinus Torvalds } 123170cc7f75SJ. Bruce Fields write->wr_head.iov_base = p; 123270cc7f75SJ. Bruce Fields write->wr_head.iov_len = avail; 123370cc7f75SJ. Bruce Fields write->wr_pagelist = argp->pagelist; 12345a80a54dSJ. Bruce Fields 12355a80a54dSJ. Bruce Fields len = XDR_QUADLEN(write->wr_buflen) << 2; 12365a80a54dSJ. Bruce Fields if (len >= avail) { 12375a80a54dSJ. Bruce Fields int pages; 12385a80a54dSJ. Bruce Fields 12395a80a54dSJ. Bruce Fields len -= avail; 12405a80a54dSJ. Bruce Fields 12415a80a54dSJ. Bruce Fields pages = len >> PAGE_SHIFT; 12425a80a54dSJ. Bruce Fields argp->pagelist += pages; 12435a80a54dSJ. Bruce Fields argp->pagelen -= pages * PAGE_SIZE; 12445a80a54dSJ. Bruce Fields len -= pages * PAGE_SIZE; 12455a80a54dSJ. Bruce Fields 12465a80a54dSJ. Bruce Fields argp->p = (__be32 *)page_address(argp->pagelist[0]); 1247365da4adSJ. Bruce Fields argp->pagelist++; 12485a80a54dSJ. Bruce Fields argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); 12491da177e4SLinus Torvalds } 12505a80a54dSJ. Bruce Fields argp->p += XDR_QUADLEN(len); 12511da177e4SLinus Torvalds 12521da177e4SLinus Torvalds DECODE_TAIL; 12531da177e4SLinus Torvalds } 12541da177e4SLinus Torvalds 1255b37ad28bSAl Viro static __be32 12561da177e4SLinus Torvalds nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner) 12571da177e4SLinus Torvalds { 12581da177e4SLinus Torvalds DECODE_HEAD; 12591da177e4SLinus Torvalds 1260e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 1261e1a90ebdSAnna Schumaker return nfserr_notsupp; 1262e1a90ebdSAnna Schumaker 12631da177e4SLinus Torvalds READ_BUF(12); 12641da177e4SLinus Torvalds COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); 126506553991SJ. Bruce Fields rlockowner->rl_owner.len = be32_to_cpup(p++); 12661da177e4SLinus Torvalds READ_BUF(rlockowner->rl_owner.len); 12671da177e4SLinus Torvalds READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len); 12681da177e4SLinus Torvalds 126960adfc50SAndy Adamson if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid)) 127060adfc50SAndy Adamson return nfserr_inval; 12711da177e4SLinus Torvalds DECODE_TAIL; 12721da177e4SLinus Torvalds } 12731da177e4SLinus Torvalds 1274b37ad28bSAl Viro static __be32 12752db134ebSAndy Adamson nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, 12760733d213SAndy Adamson struct nfsd4_exchange_id *exid) 12772db134ebSAndy Adamson { 12785afa040bSMi Jinlong int dummy, tmp; 12790733d213SAndy Adamson DECODE_HEAD; 12800733d213SAndy Adamson 12810733d213SAndy Adamson READ_BUF(NFS4_VERIFIER_SIZE); 12820733d213SAndy Adamson COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE); 12830733d213SAndy Adamson 1284a084daf5SJ. Bruce Fields status = nfsd4_decode_opaque(argp, &exid->clname); 1285a084daf5SJ. Bruce Fields if (status) 1286a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 12870733d213SAndy Adamson 12880733d213SAndy Adamson READ_BUF(4); 128906553991SJ. Bruce Fields exid->flags = be32_to_cpup(p++); 12900733d213SAndy Adamson 12910733d213SAndy Adamson /* Ignore state_protect4_a */ 12920733d213SAndy Adamson READ_BUF(4); 129306553991SJ. Bruce Fields exid->spa_how = be32_to_cpup(p++); 12940733d213SAndy Adamson switch (exid->spa_how) { 12950733d213SAndy Adamson case SP4_NONE: 12960733d213SAndy Adamson break; 12970733d213SAndy Adamson case SP4_MACH_CRED: 12980733d213SAndy Adamson /* spo_must_enforce */ 12990733d213SAndy Adamson READ_BUF(4); 130006553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13010733d213SAndy Adamson READ_BUF(dummy * 4); 13020733d213SAndy Adamson p += dummy; 13030733d213SAndy Adamson 13040733d213SAndy Adamson /* spo_must_allow */ 13050733d213SAndy Adamson READ_BUF(4); 130606553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13070733d213SAndy Adamson READ_BUF(dummy * 4); 13080733d213SAndy Adamson p += dummy; 13090733d213SAndy Adamson break; 13100733d213SAndy Adamson case SP4_SSV: 13110733d213SAndy Adamson /* ssp_ops */ 13120733d213SAndy Adamson READ_BUF(4); 131306553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13140733d213SAndy Adamson READ_BUF(dummy * 4); 13150733d213SAndy Adamson p += dummy; 13160733d213SAndy Adamson 13170733d213SAndy Adamson READ_BUF(4); 131806553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13190733d213SAndy Adamson READ_BUF(dummy * 4); 13200733d213SAndy Adamson p += dummy; 13210733d213SAndy Adamson 13220733d213SAndy Adamson /* ssp_hash_algs<> */ 13230733d213SAndy Adamson READ_BUF(4); 132406553991SJ. Bruce Fields tmp = be32_to_cpup(p++); 13255afa040bSMi Jinlong while (tmp--) { 13260733d213SAndy Adamson READ_BUF(4); 132706553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13280733d213SAndy Adamson READ_BUF(dummy); 13290733d213SAndy Adamson p += XDR_QUADLEN(dummy); 13305afa040bSMi Jinlong } 13315afa040bSMi Jinlong 13325afa040bSMi Jinlong /* ssp_encr_algs<> */ 13335afa040bSMi Jinlong READ_BUF(4); 133406553991SJ. Bruce Fields tmp = be32_to_cpup(p++); 13355afa040bSMi Jinlong while (tmp--) { 13365afa040bSMi Jinlong READ_BUF(4); 133706553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13385afa040bSMi Jinlong READ_BUF(dummy); 13395afa040bSMi Jinlong p += XDR_QUADLEN(dummy); 13405afa040bSMi Jinlong } 13410733d213SAndy Adamson 13420733d213SAndy Adamson /* ssp_window and ssp_num_gss_handles */ 13430733d213SAndy Adamson READ_BUF(8); 134406553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 134506553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13460733d213SAndy Adamson break; 13470733d213SAndy Adamson default: 13480733d213SAndy Adamson goto xdr_error; 13490733d213SAndy Adamson } 13500733d213SAndy Adamson 13510733d213SAndy Adamson /* Ignore Implementation ID */ 13520733d213SAndy Adamson READ_BUF(4); /* nfs_impl_id4 array length */ 135306553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13540733d213SAndy Adamson 13550733d213SAndy Adamson if (dummy > 1) 13560733d213SAndy Adamson goto xdr_error; 13570733d213SAndy Adamson 13580733d213SAndy Adamson if (dummy == 1) { 13590733d213SAndy Adamson /* nii_domain */ 13600733d213SAndy Adamson READ_BUF(4); 136106553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13620733d213SAndy Adamson READ_BUF(dummy); 13630733d213SAndy Adamson p += XDR_QUADLEN(dummy); 13640733d213SAndy Adamson 13650733d213SAndy Adamson /* nii_name */ 13660733d213SAndy Adamson READ_BUF(4); 136706553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13680733d213SAndy Adamson READ_BUF(dummy); 13690733d213SAndy Adamson p += XDR_QUADLEN(dummy); 13700733d213SAndy Adamson 13710733d213SAndy Adamson /* nii_date */ 13720733d213SAndy Adamson READ_BUF(12); 13730733d213SAndy Adamson p += 3; 13740733d213SAndy Adamson } 13750733d213SAndy Adamson DECODE_TAIL; 13762db134ebSAndy Adamson } 13772db134ebSAndy Adamson 13782db134ebSAndy Adamson static __be32 13792db134ebSAndy Adamson nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, 13802db134ebSAndy Adamson struct nfsd4_create_session *sess) 13812db134ebSAndy Adamson { 1382ec6b5d7bSAndy Adamson DECODE_HEAD; 1383ec6b5d7bSAndy Adamson u32 dummy; 1384ec6b5d7bSAndy Adamson 1385ec6b5d7bSAndy Adamson READ_BUF(16); 1386ec6b5d7bSAndy Adamson COPYMEM(&sess->clientid, 8); 138706553991SJ. Bruce Fields sess->seqid = be32_to_cpup(p++); 138806553991SJ. Bruce Fields sess->flags = be32_to_cpup(p++); 1389ec6b5d7bSAndy Adamson 1390ec6b5d7bSAndy Adamson /* Fore channel attrs */ 1391ec6b5d7bSAndy Adamson READ_BUF(28); 139206553991SJ. Bruce Fields dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */ 139306553991SJ. Bruce Fields sess->fore_channel.maxreq_sz = be32_to_cpup(p++); 139406553991SJ. Bruce Fields sess->fore_channel.maxresp_sz = be32_to_cpup(p++); 139506553991SJ. Bruce Fields sess->fore_channel.maxresp_cached = be32_to_cpup(p++); 139606553991SJ. Bruce Fields sess->fore_channel.maxops = be32_to_cpup(p++); 139706553991SJ. Bruce Fields sess->fore_channel.maxreqs = be32_to_cpup(p++); 139806553991SJ. Bruce Fields sess->fore_channel.nr_rdma_attrs = be32_to_cpup(p++); 1399ec6b5d7bSAndy Adamson if (sess->fore_channel.nr_rdma_attrs == 1) { 1400ec6b5d7bSAndy Adamson READ_BUF(4); 140106553991SJ. Bruce Fields sess->fore_channel.rdma_attrs = be32_to_cpup(p++); 1402ec6b5d7bSAndy Adamson } else if (sess->fore_channel.nr_rdma_attrs > 1) { 1403ec6b5d7bSAndy Adamson dprintk("Too many fore channel attr bitmaps!\n"); 1404ec6b5d7bSAndy Adamson goto xdr_error; 1405ec6b5d7bSAndy Adamson } 1406ec6b5d7bSAndy Adamson 1407ec6b5d7bSAndy Adamson /* Back channel attrs */ 1408ec6b5d7bSAndy Adamson READ_BUF(28); 140906553991SJ. Bruce Fields dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */ 141006553991SJ. Bruce Fields sess->back_channel.maxreq_sz = be32_to_cpup(p++); 141106553991SJ. Bruce Fields sess->back_channel.maxresp_sz = be32_to_cpup(p++); 141206553991SJ. Bruce Fields sess->back_channel.maxresp_cached = be32_to_cpup(p++); 141306553991SJ. Bruce Fields sess->back_channel.maxops = be32_to_cpup(p++); 141406553991SJ. Bruce Fields sess->back_channel.maxreqs = be32_to_cpup(p++); 141506553991SJ. Bruce Fields sess->back_channel.nr_rdma_attrs = be32_to_cpup(p++); 1416ec6b5d7bSAndy Adamson if (sess->back_channel.nr_rdma_attrs == 1) { 1417ec6b5d7bSAndy Adamson READ_BUF(4); 141806553991SJ. Bruce Fields sess->back_channel.rdma_attrs = be32_to_cpup(p++); 1419ec6b5d7bSAndy Adamson } else if (sess->back_channel.nr_rdma_attrs > 1) { 1420ec6b5d7bSAndy Adamson dprintk("Too many back channel attr bitmaps!\n"); 1421ec6b5d7bSAndy Adamson goto xdr_error; 1422ec6b5d7bSAndy Adamson } 1423ec6b5d7bSAndy Adamson 1424acb2887eSJ. Bruce Fields READ_BUF(4); 142506553991SJ. Bruce Fields sess->callback_prog = be32_to_cpup(p++); 1426acb2887eSJ. Bruce Fields nfsd4_decode_cb_sec(argp, &sess->cb_sec); 1427ec6b5d7bSAndy Adamson DECODE_TAIL; 14282db134ebSAndy Adamson } 14292db134ebSAndy Adamson 14302db134ebSAndy Adamson static __be32 14312db134ebSAndy Adamson nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp, 14322db134ebSAndy Adamson struct nfsd4_destroy_session *destroy_session) 14332db134ebSAndy Adamson { 1434e10e0cfcSBenny Halevy DECODE_HEAD; 1435e10e0cfcSBenny Halevy READ_BUF(NFS4_MAX_SESSIONID_LEN); 1436e10e0cfcSBenny Halevy COPYMEM(destroy_session->sessionid.data, NFS4_MAX_SESSIONID_LEN); 1437e10e0cfcSBenny Halevy 1438e10e0cfcSBenny Halevy DECODE_TAIL; 14392db134ebSAndy Adamson } 14402db134ebSAndy Adamson 14412db134ebSAndy Adamson static __be32 1442e1ca12dfSBryan Schumaker nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, 1443e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 1444e1ca12dfSBryan Schumaker { 1445e1ca12dfSBryan Schumaker DECODE_HEAD; 1446e1ca12dfSBryan Schumaker 1447e1ca12dfSBryan Schumaker READ_BUF(sizeof(stateid_t)); 144806553991SJ. Bruce Fields free_stateid->fr_stateid.si_generation = be32_to_cpup(p++); 1449e1ca12dfSBryan Schumaker COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t)); 1450e1ca12dfSBryan Schumaker 1451e1ca12dfSBryan Schumaker DECODE_TAIL; 1452e1ca12dfSBryan Schumaker } 1453e1ca12dfSBryan Schumaker 1454e1ca12dfSBryan Schumaker static __be32 14552db134ebSAndy Adamson nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, 14562db134ebSAndy Adamson struct nfsd4_sequence *seq) 14572db134ebSAndy Adamson { 1458b85d4c01SBenny Halevy DECODE_HEAD; 1459b85d4c01SBenny Halevy 1460b85d4c01SBenny Halevy READ_BUF(NFS4_MAX_SESSIONID_LEN + 16); 1461b85d4c01SBenny Halevy COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); 146206553991SJ. Bruce Fields seq->seqid = be32_to_cpup(p++); 146306553991SJ. Bruce Fields seq->slotid = be32_to_cpup(p++); 146406553991SJ. Bruce Fields seq->maxslots = be32_to_cpup(p++); 146506553991SJ. Bruce Fields seq->cachethis = be32_to_cpup(p++); 1466b85d4c01SBenny Halevy 1467b85d4c01SBenny Halevy DECODE_TAIL; 14682db134ebSAndy Adamson } 14692db134ebSAndy Adamson 147017456804SBryan Schumaker static __be32 147117456804SBryan Schumaker nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid) 147217456804SBryan Schumaker { 147317456804SBryan Schumaker int i; 147403cfb420SBryan Schumaker __be32 *p, status; 147503cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 147617456804SBryan Schumaker 147717456804SBryan Schumaker READ_BUF(4); 147817456804SBryan Schumaker test_stateid->ts_num_ids = ntohl(*p++); 147917456804SBryan Schumaker 148003cfb420SBryan Schumaker INIT_LIST_HEAD(&test_stateid->ts_stateid_list); 148117456804SBryan Schumaker 148217456804SBryan Schumaker for (i = 0; i < test_stateid->ts_num_ids; i++) { 1483d5e23383SJ. Bruce Fields stateid = svcxdr_tmpalloc(argp, sizeof(*stateid)); 148403cfb420SBryan Schumaker if (!stateid) { 1485afcf6792SAl Viro status = nfserrno(-ENOMEM); 148603cfb420SBryan Schumaker goto out; 148703cfb420SBryan Schumaker } 148803cfb420SBryan Schumaker 148903cfb420SBryan Schumaker INIT_LIST_HEAD(&stateid->ts_id_list); 149003cfb420SBryan Schumaker list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list); 149103cfb420SBryan Schumaker 149203cfb420SBryan Schumaker status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid); 149317456804SBryan Schumaker if (status) 149403cfb420SBryan Schumaker goto out; 149517456804SBryan Schumaker } 149617456804SBryan Schumaker 149717456804SBryan Schumaker status = 0; 149817456804SBryan Schumaker out: 149917456804SBryan Schumaker return status; 150017456804SBryan Schumaker xdr_error: 150117456804SBryan Schumaker dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__); 150217456804SBryan Schumaker status = nfserr_bad_xdr; 150317456804SBryan Schumaker goto out; 150417456804SBryan Schumaker } 150517456804SBryan Schumaker 1506345c2842SMi Jinlong static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc) 1507345c2842SMi Jinlong { 1508345c2842SMi Jinlong DECODE_HEAD; 1509345c2842SMi Jinlong 1510345c2842SMi Jinlong READ_BUF(8); 1511345c2842SMi Jinlong COPYMEM(&dc->clientid, 8); 1512345c2842SMi Jinlong 1513345c2842SMi Jinlong DECODE_TAIL; 1514345c2842SMi Jinlong } 1515345c2842SMi Jinlong 15164dc6ec00SJ. Bruce Fields static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc) 15174dc6ec00SJ. Bruce Fields { 15184dc6ec00SJ. Bruce Fields DECODE_HEAD; 15194dc6ec00SJ. Bruce Fields 15204dc6ec00SJ. Bruce Fields READ_BUF(4); 152106553991SJ. Bruce Fields rc->rca_one_fs = be32_to_cpup(p++); 15224dc6ec00SJ. Bruce Fields 15234dc6ec00SJ. Bruce Fields DECODE_TAIL; 15244dc6ec00SJ. Bruce Fields } 15254dc6ec00SJ. Bruce Fields 15269cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 15279cf514ccSChristoph Hellwig static __be32 15289cf514ccSChristoph Hellwig nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, 15299cf514ccSChristoph Hellwig struct nfsd4_getdeviceinfo *gdev) 15309cf514ccSChristoph Hellwig { 15319cf514ccSChristoph Hellwig DECODE_HEAD; 15329cf514ccSChristoph Hellwig u32 num, i; 15339cf514ccSChristoph Hellwig 15349cf514ccSChristoph Hellwig READ_BUF(sizeof(struct nfsd4_deviceid) + 3 * 4); 15359cf514ccSChristoph Hellwig COPYMEM(&gdev->gd_devid, sizeof(struct nfsd4_deviceid)); 15369cf514ccSChristoph Hellwig gdev->gd_layout_type = be32_to_cpup(p++); 15379cf514ccSChristoph Hellwig gdev->gd_maxcount = be32_to_cpup(p++); 15389cf514ccSChristoph Hellwig num = be32_to_cpup(p++); 15399cf514ccSChristoph Hellwig if (num) { 15409cf514ccSChristoph Hellwig READ_BUF(4 * num); 15419cf514ccSChristoph Hellwig gdev->gd_notify_types = be32_to_cpup(p++); 15429cf514ccSChristoph Hellwig for (i = 1; i < num; i++) { 15439cf514ccSChristoph Hellwig if (be32_to_cpup(p++)) { 15449cf514ccSChristoph Hellwig status = nfserr_inval; 15459cf514ccSChristoph Hellwig goto out; 15469cf514ccSChristoph Hellwig } 15479cf514ccSChristoph Hellwig } 15489cf514ccSChristoph Hellwig } 15499cf514ccSChristoph Hellwig DECODE_TAIL; 15509cf514ccSChristoph Hellwig } 15519cf514ccSChristoph Hellwig 15529cf514ccSChristoph Hellwig static __be32 15539cf514ccSChristoph Hellwig nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, 15549cf514ccSChristoph Hellwig struct nfsd4_layoutget *lgp) 15559cf514ccSChristoph Hellwig { 15569cf514ccSChristoph Hellwig DECODE_HEAD; 15579cf514ccSChristoph Hellwig 15589cf514ccSChristoph Hellwig READ_BUF(36); 15599cf514ccSChristoph Hellwig lgp->lg_signal = be32_to_cpup(p++); 15609cf514ccSChristoph Hellwig lgp->lg_layout_type = be32_to_cpup(p++); 15619cf514ccSChristoph Hellwig lgp->lg_seg.iomode = be32_to_cpup(p++); 15629cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lgp->lg_seg.offset); 15639cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lgp->lg_seg.length); 15649cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lgp->lg_minlength); 1565db59c0efSKinglong Mee 1566db59c0efSKinglong Mee status = nfsd4_decode_stateid(argp, &lgp->lg_sid); 1567db59c0efSKinglong Mee if (status) 1568db59c0efSKinglong Mee return status; 1569db59c0efSKinglong Mee 15709cf514ccSChristoph Hellwig READ_BUF(4); 15719cf514ccSChristoph Hellwig lgp->lg_maxcount = be32_to_cpup(p++); 15729cf514ccSChristoph Hellwig 15739cf514ccSChristoph Hellwig DECODE_TAIL; 15749cf514ccSChristoph Hellwig } 15759cf514ccSChristoph Hellwig 15769cf514ccSChristoph Hellwig static __be32 15779cf514ccSChristoph Hellwig nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, 15789cf514ccSChristoph Hellwig struct nfsd4_layoutcommit *lcp) 15799cf514ccSChristoph Hellwig { 15809cf514ccSChristoph Hellwig DECODE_HEAD; 15819cf514ccSChristoph Hellwig u32 timechange; 15829cf514ccSChristoph Hellwig 15839cf514ccSChristoph Hellwig READ_BUF(20); 15849cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lcp->lc_seg.offset); 15859cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lcp->lc_seg.length); 15869cf514ccSChristoph Hellwig lcp->lc_reclaim = be32_to_cpup(p++); 1587db59c0efSKinglong Mee 1588db59c0efSKinglong Mee status = nfsd4_decode_stateid(argp, &lcp->lc_sid); 1589db59c0efSKinglong Mee if (status) 1590db59c0efSKinglong Mee return status; 1591db59c0efSKinglong Mee 15929cf514ccSChristoph Hellwig READ_BUF(4); 15939cf514ccSChristoph Hellwig lcp->lc_newoffset = be32_to_cpup(p++); 15949cf514ccSChristoph Hellwig if (lcp->lc_newoffset) { 15959cf514ccSChristoph Hellwig READ_BUF(8); 15969cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lcp->lc_last_wr); 15979cf514ccSChristoph Hellwig } else 15989cf514ccSChristoph Hellwig lcp->lc_last_wr = 0; 15999cf514ccSChristoph Hellwig READ_BUF(4); 16009cf514ccSChristoph Hellwig timechange = be32_to_cpup(p++); 16019cf514ccSChristoph Hellwig if (timechange) { 16029cf514ccSChristoph Hellwig status = nfsd4_decode_time(argp, &lcp->lc_mtime); 16039cf514ccSChristoph Hellwig if (status) 16049cf514ccSChristoph Hellwig return status; 16059cf514ccSChristoph Hellwig } else { 16069cf514ccSChristoph Hellwig lcp->lc_mtime.tv_nsec = UTIME_NOW; 16079cf514ccSChristoph Hellwig } 16089cf514ccSChristoph Hellwig READ_BUF(8); 16099cf514ccSChristoph Hellwig lcp->lc_layout_type = be32_to_cpup(p++); 16109cf514ccSChristoph Hellwig 16119cf514ccSChristoph Hellwig /* 16129cf514ccSChristoph Hellwig * Save the layout update in XDR format and let the layout driver deal 16139cf514ccSChristoph Hellwig * with it later. 16149cf514ccSChristoph Hellwig */ 16159cf514ccSChristoph Hellwig lcp->lc_up_len = be32_to_cpup(p++); 16169cf514ccSChristoph Hellwig if (lcp->lc_up_len > 0) { 16179cf514ccSChristoph Hellwig READ_BUF(lcp->lc_up_len); 16189cf514ccSChristoph Hellwig READMEM(lcp->lc_up_layout, lcp->lc_up_len); 16199cf514ccSChristoph Hellwig } 16209cf514ccSChristoph Hellwig 16219cf514ccSChristoph Hellwig DECODE_TAIL; 16229cf514ccSChristoph Hellwig } 16239cf514ccSChristoph Hellwig 16249cf514ccSChristoph Hellwig static __be32 16259cf514ccSChristoph Hellwig nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, 16269cf514ccSChristoph Hellwig struct nfsd4_layoutreturn *lrp) 16279cf514ccSChristoph Hellwig { 16289cf514ccSChristoph Hellwig DECODE_HEAD; 16299cf514ccSChristoph Hellwig 16309cf514ccSChristoph Hellwig READ_BUF(16); 16319cf514ccSChristoph Hellwig lrp->lr_reclaim = be32_to_cpup(p++); 16329cf514ccSChristoph Hellwig lrp->lr_layout_type = be32_to_cpup(p++); 16339cf514ccSChristoph Hellwig lrp->lr_seg.iomode = be32_to_cpup(p++); 16349cf514ccSChristoph Hellwig lrp->lr_return_type = be32_to_cpup(p++); 16359cf514ccSChristoph Hellwig if (lrp->lr_return_type == RETURN_FILE) { 16369cf514ccSChristoph Hellwig READ_BUF(16); 16379cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lrp->lr_seg.offset); 16389cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lrp->lr_seg.length); 1639db59c0efSKinglong Mee 1640db59c0efSKinglong Mee status = nfsd4_decode_stateid(argp, &lrp->lr_sid); 1641db59c0efSKinglong Mee if (status) 1642db59c0efSKinglong Mee return status; 1643db59c0efSKinglong Mee 16449cf514ccSChristoph Hellwig READ_BUF(4); 16459cf514ccSChristoph Hellwig lrp->lrf_body_len = be32_to_cpup(p++); 16469cf514ccSChristoph Hellwig if (lrp->lrf_body_len > 0) { 16479cf514ccSChristoph Hellwig READ_BUF(lrp->lrf_body_len); 16489cf514ccSChristoph Hellwig READMEM(lrp->lrf_body, lrp->lrf_body_len); 16499cf514ccSChristoph Hellwig } 16509cf514ccSChristoph Hellwig } else { 16519cf514ccSChristoph Hellwig lrp->lr_seg.offset = 0; 16529cf514ccSChristoph Hellwig lrp->lr_seg.length = NFS4_MAX_UINT64; 16539cf514ccSChristoph Hellwig } 16549cf514ccSChristoph Hellwig 16559cf514ccSChristoph Hellwig DECODE_TAIL; 16569cf514ccSChristoph Hellwig } 16579cf514ccSChristoph Hellwig #endif /* CONFIG_NFSD_PNFS */ 16589cf514ccSChristoph Hellwig 16592db134ebSAndy Adamson static __be32 166095d871f0SAnna Schumaker nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, 166195d871f0SAnna Schumaker struct nfsd4_fallocate *fallocate) 166295d871f0SAnna Schumaker { 166395d871f0SAnna Schumaker DECODE_HEAD; 166495d871f0SAnna Schumaker 166595d871f0SAnna Schumaker status = nfsd4_decode_stateid(argp, &fallocate->falloc_stateid); 166695d871f0SAnna Schumaker if (status) 166795d871f0SAnna Schumaker return status; 166895d871f0SAnna Schumaker 166995d871f0SAnna Schumaker READ_BUF(16); 167095d871f0SAnna Schumaker p = xdr_decode_hyper(p, &fallocate->falloc_offset); 167195d871f0SAnna Schumaker xdr_decode_hyper(p, &fallocate->falloc_length); 167295d871f0SAnna Schumaker 167395d871f0SAnna Schumaker DECODE_TAIL; 167495d871f0SAnna Schumaker } 167595d871f0SAnna Schumaker 167695d871f0SAnna Schumaker static __be32 167724bab491SAnna Schumaker nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) 167824bab491SAnna Schumaker { 167924bab491SAnna Schumaker DECODE_HEAD; 168024bab491SAnna Schumaker 168124bab491SAnna Schumaker status = nfsd4_decode_stateid(argp, &seek->seek_stateid); 168224bab491SAnna Schumaker if (status) 168324bab491SAnna Schumaker return status; 168424bab491SAnna Schumaker 168524bab491SAnna Schumaker READ_BUF(8 + 4); 168624bab491SAnna Schumaker p = xdr_decode_hyper(p, &seek->seek_offset); 168724bab491SAnna Schumaker seek->seek_whence = be32_to_cpup(p); 168824bab491SAnna Schumaker 168924bab491SAnna Schumaker DECODE_TAIL; 169024bab491SAnna Schumaker } 169124bab491SAnna Schumaker 169224bab491SAnna Schumaker static __be32 1693347e0ad9SBenny Halevy nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p) 1694347e0ad9SBenny Halevy { 1695347e0ad9SBenny Halevy return nfs_ok; 1696347e0ad9SBenny Halevy } 1697347e0ad9SBenny Halevy 16983c375c6fSBenny Halevy static __be32 16993c375c6fSBenny Halevy nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p) 17003c375c6fSBenny Halevy { 17011e685ec2SBenny Halevy return nfserr_notsupp; 17023c375c6fSBenny Halevy } 17033c375c6fSBenny Halevy 1704347e0ad9SBenny Halevy typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *); 1705347e0ad9SBenny Halevy 1706347e0ad9SBenny Halevy static nfsd4_dec nfsd4_dec_ops[] = { 1707ad1060c8SJ. Bruce Fields [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, 1708ad1060c8SJ. Bruce Fields [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, 1709ad1060c8SJ. Bruce Fields [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, 1710ad1060c8SJ. Bruce Fields [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, 1711ad1060c8SJ. Bruce Fields [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, 1712ad1060c8SJ. Bruce Fields [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, 1713ad1060c8SJ. Bruce Fields [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, 1714ad1060c8SJ. Bruce Fields [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, 1715ad1060c8SJ. Bruce Fields [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, 1716ad1060c8SJ. Bruce Fields [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, 1717ad1060c8SJ. Bruce Fields [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, 1718ad1060c8SJ. Bruce Fields [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, 1719ad1060c8SJ. Bruce Fields [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, 1720ad1060c8SJ. Bruce Fields [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, 1721ad1060c8SJ. Bruce Fields [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, 1722ad1060c8SJ. Bruce Fields [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, 1723ad1060c8SJ. Bruce Fields [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, 1724ad1060c8SJ. Bruce Fields [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, 1725ad1060c8SJ. Bruce Fields [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, 1726ad1060c8SJ. Bruce Fields [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, 1727e1a90ebdSAnna Schumaker [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh, 1728ad1060c8SJ. Bruce Fields [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, 1729ad1060c8SJ. Bruce Fields [OP_READ] = (nfsd4_dec)nfsd4_decode_read, 1730ad1060c8SJ. Bruce Fields [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, 1731ad1060c8SJ. Bruce Fields [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, 1732ad1060c8SJ. Bruce Fields [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, 1733ad1060c8SJ. Bruce Fields [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, 1734ad1060c8SJ. Bruce Fields [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew, 1735ad1060c8SJ. Bruce Fields [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, 1736ad1060c8SJ. Bruce Fields [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, 1737ad1060c8SJ. Bruce Fields [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, 1738ad1060c8SJ. Bruce Fields [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, 1739ad1060c8SJ. Bruce Fields [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid, 1740ad1060c8SJ. Bruce Fields [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm, 1741ad1060c8SJ. Bruce Fields [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, 1742ad1060c8SJ. Bruce Fields [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, 1743ad1060c8SJ. Bruce Fields [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, 17442db134ebSAndy Adamson 17452db134ebSAndy Adamson /* new operations for NFSv4.1 */ 1746cb73a9f4SJ. Bruce Fields [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, 17471d1bc8f2SJ. Bruce Fields [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, 17489064caaeSRandy Dunlap [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, 17499064caaeSRandy Dunlap [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, 17509064caaeSRandy Dunlap [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, 1751e1ca12dfSBryan Schumaker [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid, 17529064caaeSRandy Dunlap [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, 17539cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 17549cf514ccSChristoph Hellwig [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_getdeviceinfo, 17559cf514ccSChristoph Hellwig [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, 17569cf514ccSChristoph Hellwig [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_layoutcommit, 17579cf514ccSChristoph Hellwig [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_layoutget, 17589cf514ccSChristoph Hellwig [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_layoutreturn, 17599cf514ccSChristoph Hellwig #else 17609064caaeSRandy Dunlap [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, 17619064caaeSRandy Dunlap [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, 17629064caaeSRandy Dunlap [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, 17639064caaeSRandy Dunlap [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, 17649064caaeSRandy Dunlap [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, 17659cf514ccSChristoph Hellwig #endif 176604f4ad16SJ. Bruce Fields [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name, 17679064caaeSRandy Dunlap [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, 17689064caaeSRandy Dunlap [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, 176917456804SBryan Schumaker [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid, 17709064caaeSRandy Dunlap [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, 1771345c2842SMi Jinlong [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid, 17724dc6ec00SJ. Bruce Fields [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, 177387a15a80SAnna Schumaker 177487a15a80SAnna Schumaker /* new operations for NFSv4.2 */ 177595d871f0SAnna Schumaker [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate, 177687a15a80SAnna Schumaker [OP_COPY] = (nfsd4_dec)nfsd4_decode_notsupp, 177787a15a80SAnna Schumaker [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp, 1778b0cb9085SAnna Schumaker [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate, 177987a15a80SAnna Schumaker [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp, 178087a15a80SAnna Schumaker [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp, 178187a15a80SAnna Schumaker [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp, 178287a15a80SAnna Schumaker [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_notsupp, 178387a15a80SAnna Schumaker [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_notsupp, 178487a15a80SAnna Schumaker [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp, 178524bab491SAnna Schumaker [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek, 178687a15a80SAnna Schumaker [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp, 17872db134ebSAndy Adamson }; 17882db134ebSAndy Adamson 1789e1a90ebdSAnna Schumaker static inline bool 1790e1a90ebdSAnna Schumaker nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op) 1791e1a90ebdSAnna Schumaker { 17928217d146SAnna Schumaker if (op->opnum < FIRST_NFS4_OP) 1793e1a90ebdSAnna Schumaker return false; 17948217d146SAnna Schumaker else if (argp->minorversion == 0 && op->opnum > LAST_NFS40_OP) 1795e1a90ebdSAnna Schumaker return false; 17968217d146SAnna Schumaker else if (argp->minorversion == 1 && op->opnum > LAST_NFS41_OP) 17978217d146SAnna Schumaker return false; 17988217d146SAnna Schumaker else if (argp->minorversion == 2 && op->opnum > LAST_NFS42_OP) 1799e1a90ebdSAnna Schumaker return false; 1800e1a90ebdSAnna Schumaker return true; 1801e1a90ebdSAnna Schumaker } 1802f2feb96bSBenny Halevy 1803347e0ad9SBenny Halevy static __be32 18041da177e4SLinus Torvalds nfsd4_decode_compound(struct nfsd4_compoundargs *argp) 18051da177e4SLinus Torvalds { 18061da177e4SLinus Torvalds DECODE_HEAD; 18071da177e4SLinus Torvalds struct nfsd4_op *op; 18081091006cSJ. Bruce Fields bool cachethis = false; 1809a5cddc88SJ. Bruce Fields int auth_slack= argp->rqstp->rq_auth_slack; 1810a5cddc88SJ. Bruce Fields int max_reply = auth_slack + 8; /* opcnt, status */ 1811b0e35fdaSJ. Bruce Fields int readcount = 0; 1812b0e35fdaSJ. Bruce Fields int readbytes = 0; 18131da177e4SLinus Torvalds int i; 18141da177e4SLinus Torvalds 18151da177e4SLinus Torvalds READ_BUF(4); 181606553991SJ. Bruce Fields argp->taglen = be32_to_cpup(p++); 18171da177e4SLinus Torvalds READ_BUF(argp->taglen + 8); 18181da177e4SLinus Torvalds SAVEMEM(argp->tag, argp->taglen); 181906553991SJ. Bruce Fields argp->minorversion = be32_to_cpup(p++); 182006553991SJ. Bruce Fields argp->opcnt = be32_to_cpup(p++); 18214f0cefbfSJ. Bruce Fields max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2); 18221da177e4SLinus Torvalds 18231da177e4SLinus Torvalds if (argp->taglen > NFSD4_MAX_TAGLEN) 18241da177e4SLinus Torvalds goto xdr_error; 18251da177e4SLinus Torvalds if (argp->opcnt > 100) 18261da177e4SLinus Torvalds goto xdr_error; 18271da177e4SLinus Torvalds 1828e8c96f8cSTobias Klauser if (argp->opcnt > ARRAY_SIZE(argp->iops)) { 18295d6031caSJ. Bruce Fields argp->ops = kzalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); 18301da177e4SLinus Torvalds if (!argp->ops) { 18311da177e4SLinus Torvalds argp->ops = argp->iops; 1832817cb9d4SChuck Lever dprintk("nfsd: couldn't allocate room for COMPOUND\n"); 18331da177e4SLinus Torvalds goto xdr_error; 18341da177e4SLinus Torvalds } 18351da177e4SLinus Torvalds } 18361da177e4SLinus Torvalds 1837e1a90ebdSAnna Schumaker if (argp->minorversion > NFSD_SUPPORTED_MINOR_VERSION) 183830cff1ffSBenny Halevy argp->opcnt = 0; 183930cff1ffSBenny Halevy 18401da177e4SLinus Torvalds for (i = 0; i < argp->opcnt; i++) { 18411da177e4SLinus Torvalds op = &argp->ops[i]; 18421da177e4SLinus Torvalds op->replay = NULL; 18431da177e4SLinus Torvalds 18448a61b18cSJ. Bruce Fields READ_BUF(4); 184506553991SJ. Bruce Fields op->opnum = be32_to_cpup(p++); 18461da177e4SLinus Torvalds 1847e1a90ebdSAnna Schumaker if (nfsd4_opnum_in_range(argp, op)) 1848e1a90ebdSAnna Schumaker op->status = nfsd4_dec_ops[op->opnum](argp, &op->u); 1849347e0ad9SBenny Halevy else { 18501da177e4SLinus Torvalds op->opnum = OP_ILLEGAL; 18511da177e4SLinus Torvalds op->status = nfserr_op_illegal; 18521da177e4SLinus Torvalds } 18531091006cSJ. Bruce Fields /* 18541091006cSJ. Bruce Fields * We'll try to cache the result in the DRC if any one 18551091006cSJ. Bruce Fields * op in the compound wants to be cached: 18561091006cSJ. Bruce Fields */ 18571091006cSJ. Bruce Fields cachethis |= nfsd4_cache_this_op(op); 18586ff40decSJ. Bruce Fields 1859b0e35fdaSJ. Bruce Fields if (op->opnum == OP_READ) { 1860b0e35fdaSJ. Bruce Fields readcount++; 1861b0e35fdaSJ. Bruce Fields readbytes += nfsd4_max_reply(argp->rqstp, op); 1862b0e35fdaSJ. Bruce Fields } else 18634f0cefbfSJ. Bruce Fields max_reply += nfsd4_max_reply(argp->rqstp, op); 1864f7b43d0cSJ. Bruce Fields /* 1865f7b43d0cSJ. Bruce Fields * OP_LOCK may return a conflicting lock. (Special case 1866f7b43d0cSJ. Bruce Fields * because it will just skip encoding this if it runs 1867f7b43d0cSJ. Bruce Fields * out of xdr buffer space, and it is the only operation 1868f7b43d0cSJ. Bruce Fields * that behaves this way.) 1869f7b43d0cSJ. Bruce Fields */ 1870f7b43d0cSJ. Bruce Fields if (op->opnum == OP_LOCK) 1871f7b43d0cSJ. Bruce Fields max_reply += NFS4_OPAQUE_LIMIT; 1872e372ba60SJ. Bruce Fields 1873e372ba60SJ. Bruce Fields if (op->status) { 1874e372ba60SJ. Bruce Fields argp->opcnt = i+1; 1875e372ba60SJ. Bruce Fields break; 1876e372ba60SJ. Bruce Fields } 18771da177e4SLinus Torvalds } 18781091006cSJ. Bruce Fields /* Sessions make the DRC unnecessary: */ 18791091006cSJ. Bruce Fields if (argp->minorversion) 18801091006cSJ. Bruce Fields cachethis = false; 1881b0e35fdaSJ. Bruce Fields svc_reserve(argp->rqstp, max_reply + readbytes); 18821091006cSJ. Bruce Fields argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; 18831da177e4SLinus Torvalds 1884a5cddc88SJ. Bruce Fields if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack) 1885779fb0f3SJeff Layton clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags); 1886b0e35fdaSJ. Bruce Fields 18871da177e4SLinus Torvalds DECODE_TAIL; 18881da177e4SLinus Torvalds } 18891da177e4SLinus Torvalds 1890d05d5744SJ. Bruce Fields static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode) 1891c654b8a9SJ. Bruce Fields { 1892c654b8a9SJ. Bruce Fields if (IS_I_VERSION(inode)) { 1893d05d5744SJ. Bruce Fields p = xdr_encode_hyper(p, inode->i_version); 1894c654b8a9SJ. Bruce Fields } else { 1895d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(stat->ctime.tv_sec); 1896d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(stat->ctime.tv_nsec); 1897c654b8a9SJ. Bruce Fields } 1898d05d5744SJ. Bruce Fields return p; 1899c654b8a9SJ. Bruce Fields } 1900c654b8a9SJ. Bruce Fields 1901d05d5744SJ. Bruce Fields static __be32 *encode_cinfo(__be32 *p, struct nfsd4_change_info *c) 1902c654b8a9SJ. Bruce Fields { 1903d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->atomic); 1904c654b8a9SJ. Bruce Fields if (c->change_supported) { 1905d05d5744SJ. Bruce Fields p = xdr_encode_hyper(p, c->before_change); 1906d05d5744SJ. Bruce Fields p = xdr_encode_hyper(p, c->after_change); 1907c654b8a9SJ. Bruce Fields } else { 1908d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->before_ctime_sec); 1909d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->before_ctime_nsec); 1910d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->after_ctime_sec); 1911d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->after_ctime_nsec); 1912c654b8a9SJ. Bruce Fields } 1913d05d5744SJ. Bruce Fields return p; 1914c654b8a9SJ. Bruce Fields } 19151da177e4SLinus Torvalds 191681c3f413SJ.Bruce Fields /* Encode as an array of strings the string given with components 1917e7a0444aSWeston Andros Adamson * separated @sep, escaped with esc_enter and esc_exit. 191881c3f413SJ.Bruce Fields */ 1919ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep, 1920ddd1ea56SJ. Bruce Fields char *components, char esc_enter, 1921ddd1ea56SJ. Bruce Fields char esc_exit) 192281c3f413SJ.Bruce Fields { 1923ddd1ea56SJ. Bruce Fields __be32 *p; 1924082d4bd7SJ. Bruce Fields __be32 pathlen; 1925082d4bd7SJ. Bruce Fields int pathlen_offset; 192681c3f413SJ.Bruce Fields int strlen, count=0; 1927e7a0444aSWeston Andros Adamson char *str, *end, *next; 192881c3f413SJ.Bruce Fields 192981c3f413SJ.Bruce Fields dprintk("nfsd4_encode_components(%s)\n", components); 1930082d4bd7SJ. Bruce Fields 1931082d4bd7SJ. Bruce Fields pathlen_offset = xdr->buf->len; 1932ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 1933ddd1ea56SJ. Bruce Fields if (!p) 193481c3f413SJ.Bruce Fields return nfserr_resource; 1935082d4bd7SJ. Bruce Fields p++; /* We will fill this in with @count later */ 1936082d4bd7SJ. Bruce Fields 193781c3f413SJ.Bruce Fields end = str = components; 193881c3f413SJ.Bruce Fields while (*end) { 1939e7a0444aSWeston Andros Adamson bool found_esc = false; 1940e7a0444aSWeston Andros Adamson 1941e7a0444aSWeston Andros Adamson /* try to parse as esc_start, ..., esc_end, sep */ 1942e7a0444aSWeston Andros Adamson if (*str == esc_enter) { 1943e7a0444aSWeston Andros Adamson for (; *end && (*end != esc_exit); end++) 1944e7a0444aSWeston Andros Adamson /* find esc_exit or end of string */; 1945e7a0444aSWeston Andros Adamson next = end + 1; 1946e7a0444aSWeston Andros Adamson if (*end && (!*next || *next == sep)) { 1947e7a0444aSWeston Andros Adamson str++; 1948e7a0444aSWeston Andros Adamson found_esc = true; 1949e7a0444aSWeston Andros Adamson } 1950e7a0444aSWeston Andros Adamson } 1951e7a0444aSWeston Andros Adamson 1952e7a0444aSWeston Andros Adamson if (!found_esc) 195381c3f413SJ.Bruce Fields for (; *end && (*end != sep); end++) 1954e7a0444aSWeston Andros Adamson /* find sep or end of string */; 1955e7a0444aSWeston Andros Adamson 195681c3f413SJ.Bruce Fields strlen = end - str; 195781c3f413SJ.Bruce Fields if (strlen) { 1958ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, strlen + 4); 1959ddd1ea56SJ. Bruce Fields if (!p) 196081c3f413SJ.Bruce Fields return nfserr_resource; 19610c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, str, strlen); 196281c3f413SJ.Bruce Fields count++; 196381c3f413SJ.Bruce Fields } 196481c3f413SJ.Bruce Fields else 196581c3f413SJ.Bruce Fields end++; 19665a64e569SBenjamin Coddington if (found_esc) 19675a64e569SBenjamin Coddington end = next; 19685a64e569SBenjamin Coddington 196981c3f413SJ.Bruce Fields str = end; 197081c3f413SJ.Bruce Fields } 1971bf7491f1SBenjamin Coddington pathlen = htonl(count); 1972082d4bd7SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4); 197381c3f413SJ.Bruce Fields return 0; 197481c3f413SJ.Bruce Fields } 197581c3f413SJ.Bruce Fields 1976e7a0444aSWeston Andros Adamson /* Encode as an array of strings the string given with components 1977e7a0444aSWeston Andros Adamson * separated @sep. 1978e7a0444aSWeston Andros Adamson */ 1979ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_components(struct xdr_stream *xdr, char sep, 1980ddd1ea56SJ. Bruce Fields char *components) 1981e7a0444aSWeston Andros Adamson { 1982ddd1ea56SJ. Bruce Fields return nfsd4_encode_components_esc(xdr, sep, components, 0, 0); 1983e7a0444aSWeston Andros Adamson } 1984e7a0444aSWeston Andros Adamson 198581c3f413SJ.Bruce Fields /* 198681c3f413SJ.Bruce Fields * encode a location element of a fs_locations structure 198781c3f413SJ.Bruce Fields */ 1988ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_fs_location4(struct xdr_stream *xdr, 1989ddd1ea56SJ. Bruce Fields struct nfsd4_fs_location *location) 199081c3f413SJ.Bruce Fields { 1991b37ad28bSAl Viro __be32 status; 199281c3f413SJ.Bruce Fields 1993ddd1ea56SJ. Bruce Fields status = nfsd4_encode_components_esc(xdr, ':', location->hosts, 1994e7a0444aSWeston Andros Adamson '[', ']'); 199581c3f413SJ.Bruce Fields if (status) 199681c3f413SJ.Bruce Fields return status; 1997ddd1ea56SJ. Bruce Fields status = nfsd4_encode_components(xdr, '/', location->path); 199881c3f413SJ.Bruce Fields if (status) 199981c3f413SJ.Bruce Fields return status; 200081c3f413SJ.Bruce Fields return 0; 200181c3f413SJ.Bruce Fields } 200281c3f413SJ.Bruce Fields 200381c3f413SJ.Bruce Fields /* 2004ed748aacSTrond Myklebust * Encode a path in RFC3530 'pathname4' format 200581c3f413SJ.Bruce Fields */ 2006ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_path(struct xdr_stream *xdr, 2007ddd1ea56SJ. Bruce Fields const struct path *root, 2008ddd1ea56SJ. Bruce Fields const struct path *path) 200981c3f413SJ.Bruce Fields { 2010301f0268SAl Viro struct path cur = *path; 2011ddd1ea56SJ. Bruce Fields __be32 *p; 2012ed748aacSTrond Myklebust struct dentry **components = NULL; 2013ed748aacSTrond Myklebust unsigned int ncomponents = 0; 2014ed748aacSTrond Myklebust __be32 err = nfserr_jukebox; 201581c3f413SJ.Bruce Fields 2016ed748aacSTrond Myklebust dprintk("nfsd4_encode_components("); 201781c3f413SJ.Bruce Fields 2018ed748aacSTrond Myklebust path_get(&cur); 2019ed748aacSTrond Myklebust /* First walk the path up to the nfsd root, and store the 2020ed748aacSTrond Myklebust * dentries/path components in an array. 2021ed748aacSTrond Myklebust */ 2022ed748aacSTrond Myklebust for (;;) { 2023b77a4b2eSKinglong Mee if (path_equal(&cur, root)) 2024ed748aacSTrond Myklebust break; 2025ed748aacSTrond Myklebust if (cur.dentry == cur.mnt->mnt_root) { 2026ed748aacSTrond Myklebust if (follow_up(&cur)) 2027ed748aacSTrond Myklebust continue; 2028ed748aacSTrond Myklebust goto out_free; 202981c3f413SJ.Bruce Fields } 2030ed748aacSTrond Myklebust if ((ncomponents & 15) == 0) { 2031ed748aacSTrond Myklebust struct dentry **new; 2032ed748aacSTrond Myklebust new = krealloc(components, 2033ed748aacSTrond Myklebust sizeof(*new) * (ncomponents + 16), 2034ed748aacSTrond Myklebust GFP_KERNEL); 2035ed748aacSTrond Myklebust if (!new) 2036ed748aacSTrond Myklebust goto out_free; 2037ed748aacSTrond Myklebust components = new; 2038ed748aacSTrond Myklebust } 2039ed748aacSTrond Myklebust components[ncomponents++] = cur.dentry; 2040ed748aacSTrond Myklebust cur.dentry = dget_parent(cur.dentry); 2041ed748aacSTrond Myklebust } 2042ddd1ea56SJ. Bruce Fields err = nfserr_resource; 2043ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2044ddd1ea56SJ. Bruce Fields if (!p) 2045ed748aacSTrond Myklebust goto out_free; 2046c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ncomponents); 2047ed748aacSTrond Myklebust 2048ed748aacSTrond Myklebust while (ncomponents) { 2049ed748aacSTrond Myklebust struct dentry *dentry = components[ncomponents - 1]; 2050301f0268SAl Viro unsigned int len; 2051ed748aacSTrond Myklebust 2052301f0268SAl Viro spin_lock(&dentry->d_lock); 2053301f0268SAl Viro len = dentry->d_name.len; 2054ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, len + 4); 2055ddd1ea56SJ. Bruce Fields if (!p) { 2056301f0268SAl Viro spin_unlock(&dentry->d_lock); 2057ed748aacSTrond Myklebust goto out_free; 2058301f0268SAl Viro } 20590c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, dentry->d_name.name, len); 2060a455589fSAl Viro dprintk("/%pd", dentry); 2061301f0268SAl Viro spin_unlock(&dentry->d_lock); 2062ed748aacSTrond Myklebust dput(dentry); 2063ed748aacSTrond Myklebust ncomponents--; 2064ed748aacSTrond Myklebust } 2065ed748aacSTrond Myklebust 2066ed748aacSTrond Myklebust err = 0; 2067ed748aacSTrond Myklebust out_free: 2068ed748aacSTrond Myklebust dprintk(")\n"); 2069ed748aacSTrond Myklebust while (ncomponents) 2070ed748aacSTrond Myklebust dput(components[--ncomponents]); 2071ed748aacSTrond Myklebust kfree(components); 2072ed748aacSTrond Myklebust path_put(&cur); 2073ed748aacSTrond Myklebust return err; 2074ed748aacSTrond Myklebust } 2075ed748aacSTrond Myklebust 2076ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_fsloc_fsroot(struct xdr_stream *xdr, 2077ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, const struct path *path) 2078ed748aacSTrond Myklebust { 2079ed748aacSTrond Myklebust struct svc_export *exp_ps; 2080ed748aacSTrond Myklebust __be32 res; 2081ed748aacSTrond Myklebust 2082ed748aacSTrond Myklebust exp_ps = rqst_find_fsidzero_export(rqstp); 2083ed748aacSTrond Myklebust if (IS_ERR(exp_ps)) 2084ed748aacSTrond Myklebust return nfserrno(PTR_ERR(exp_ps)); 2085ddd1ea56SJ. Bruce Fields res = nfsd4_encode_path(xdr, &exp_ps->ex_path, path); 2086ed748aacSTrond Myklebust exp_put(exp_ps); 2087ed748aacSTrond Myklebust return res; 208881c3f413SJ.Bruce Fields } 208981c3f413SJ.Bruce Fields 209081c3f413SJ.Bruce Fields /* 209181c3f413SJ.Bruce Fields * encode a fs_locations structure 209281c3f413SJ.Bruce Fields */ 2093ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_fs_locations(struct xdr_stream *xdr, 2094ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, struct svc_export *exp) 209581c3f413SJ.Bruce Fields { 2096b37ad28bSAl Viro __be32 status; 2097cc45f017SAl Viro int i; 2098ddd1ea56SJ. Bruce Fields __be32 *p; 209981c3f413SJ.Bruce Fields struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; 210081c3f413SJ.Bruce Fields 2101ddd1ea56SJ. Bruce Fields status = nfsd4_encode_fsloc_fsroot(xdr, rqstp, &exp->ex_path); 210281c3f413SJ.Bruce Fields if (status) 210381c3f413SJ.Bruce Fields return status; 2104ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2105ddd1ea56SJ. Bruce Fields if (!p) 210681c3f413SJ.Bruce Fields return nfserr_resource; 2107c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(fslocs->locations_count); 210881c3f413SJ.Bruce Fields for (i=0; i<fslocs->locations_count; i++) { 2109ddd1ea56SJ. Bruce Fields status = nfsd4_encode_fs_location4(xdr, &fslocs->locations[i]); 211081c3f413SJ.Bruce Fields if (status) 211181c3f413SJ.Bruce Fields return status; 211281c3f413SJ.Bruce Fields } 211381c3f413SJ.Bruce Fields return 0; 211481c3f413SJ.Bruce Fields } 21151da177e4SLinus Torvalds 21163d2544b1SJ. Bruce Fields static u32 nfs4_file_type(umode_t mode) 21173d2544b1SJ. Bruce Fields { 21183d2544b1SJ. Bruce Fields switch (mode & S_IFMT) { 21193d2544b1SJ. Bruce Fields case S_IFIFO: return NF4FIFO; 21203d2544b1SJ. Bruce Fields case S_IFCHR: return NF4CHR; 21213d2544b1SJ. Bruce Fields case S_IFDIR: return NF4DIR; 21223d2544b1SJ. Bruce Fields case S_IFBLK: return NF4BLK; 21233d2544b1SJ. Bruce Fields case S_IFLNK: return NF4LNK; 21243d2544b1SJ. Bruce Fields case S_IFREG: return NF4REG; 21253d2544b1SJ. Bruce Fields case S_IFSOCK: return NF4SOCK; 21263d2544b1SJ. Bruce Fields default: return NF4BAD; 21271da177e4SLinus Torvalds }; 21283d2544b1SJ. Bruce Fields } 21291da177e4SLinus Torvalds 2130b37ad28bSAl Viro static inline __be32 2131ddd1ea56SJ. Bruce Fields nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp, 2132ddd1ea56SJ. Bruce Fields struct nfs4_ace *ace) 21331da177e4SLinus Torvalds { 21343554116dSJ. Bruce Fields if (ace->whotype != NFS4_ACL_WHO_NAMED) 2135ddd1ea56SJ. Bruce Fields return nfs4_acl_write_who(xdr, ace->whotype); 21363554116dSJ. Bruce Fields else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) 2137ddd1ea56SJ. Bruce Fields return nfsd4_encode_group(xdr, rqstp, ace->who_gid); 2138ab8e4aeeSEric W. Biederman else 2139ddd1ea56SJ. Bruce Fields return nfsd4_encode_user(xdr, rqstp, ace->who_uid); 21401da177e4SLinus Torvalds } 21411da177e4SLinus Torvalds 214242ca0993SJ.Bruce Fields #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ 214342ca0993SJ.Bruce Fields FATTR4_WORD0_RDATTR_ERROR) 214442ca0993SJ.Bruce Fields #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID 214542ca0993SJ.Bruce Fields 214618032ca0SDavid Quigley #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 214718032ca0SDavid Quigley static inline __be32 2148ddd1ea56SJ. Bruce Fields nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp, 2149ddd1ea56SJ. Bruce Fields void *context, int len) 215018032ca0SDavid Quigley { 2151ddd1ea56SJ. Bruce Fields __be32 *p; 215218032ca0SDavid Quigley 2153ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, len + 4 + 4 + 4); 2154ddd1ea56SJ. Bruce Fields if (!p) 215518032ca0SDavid Quigley return nfserr_resource; 215618032ca0SDavid Quigley 215718032ca0SDavid Quigley /* 215818032ca0SDavid Quigley * For now we use a 0 here to indicate the null translation; in 215918032ca0SDavid Quigley * the future we may place a call to translation code here. 216018032ca0SDavid Quigley */ 2161c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* lfs */ 2162c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* pi */ 216318032ca0SDavid Quigley p = xdr_encode_opaque(p, context, len); 216418032ca0SDavid Quigley return 0; 216518032ca0SDavid Quigley } 216618032ca0SDavid Quigley #else 216718032ca0SDavid Quigley static inline __be32 2168ddd1ea56SJ. Bruce Fields nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp, 2169ddd1ea56SJ. Bruce Fields void *context, int len) 217018032ca0SDavid Quigley { return 0; } 217118032ca0SDavid Quigley #endif 217218032ca0SDavid Quigley 2173b37ad28bSAl Viro static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) 217442ca0993SJ.Bruce Fields { 217542ca0993SJ.Bruce Fields /* As per referral draft: */ 217642ca0993SJ.Bruce Fields if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS || 217742ca0993SJ.Bruce Fields *bmval1 & ~WORD1_ABSENT_FS_ATTRS) { 217842ca0993SJ.Bruce Fields if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR || 217942ca0993SJ.Bruce Fields *bmval0 & FATTR4_WORD0_FS_LOCATIONS) 218042ca0993SJ.Bruce Fields *rdattr_err = NFSERR_MOVED; 218142ca0993SJ.Bruce Fields else 218242ca0993SJ.Bruce Fields return nfserr_moved; 218342ca0993SJ.Bruce Fields } 218442ca0993SJ.Bruce Fields *bmval0 &= WORD0_ABSENT_FS_ATTRS; 218542ca0993SJ.Bruce Fields *bmval1 &= WORD1_ABSENT_FS_ATTRS; 218642ca0993SJ.Bruce Fields return 0; 218742ca0993SJ.Bruce Fields } 21881da177e4SLinus Torvalds 2189ae7095a7SJ. Bruce Fields 2190ae7095a7SJ. Bruce Fields static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) 2191ae7095a7SJ. Bruce Fields { 2192ae7095a7SJ. Bruce Fields struct path path = exp->ex_path; 2193ae7095a7SJ. Bruce Fields int err; 2194ae7095a7SJ. Bruce Fields 2195ae7095a7SJ. Bruce Fields path_get(&path); 2196ae7095a7SJ. Bruce Fields while (follow_up(&path)) { 2197ae7095a7SJ. Bruce Fields if (path.dentry != path.mnt->mnt_root) 2198ae7095a7SJ. Bruce Fields break; 2199ae7095a7SJ. Bruce Fields } 22003dadecceSAl Viro err = vfs_getattr(&path, stat); 2201ae7095a7SJ. Bruce Fields path_put(&path); 2202ae7095a7SJ. Bruce Fields return err; 2203ae7095a7SJ. Bruce Fields } 2204ae7095a7SJ. Bruce Fields 22051da177e4SLinus Torvalds /* 22061da177e4SLinus Torvalds * Note: @fhp can be NULL; in this case, we might have to compose the filehandle 22071da177e4SLinus Torvalds * ourselves. 22081da177e4SLinus Torvalds */ 2209da2ebce6SJeff Layton static __be32 2210d5184658SJ. Bruce Fields nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, 2211d5184658SJ. Bruce Fields struct svc_export *exp, 2212d5184658SJ. Bruce Fields struct dentry *dentry, u32 *bmval, 2213406a7ea9SFrank Filz struct svc_rqst *rqstp, int ignore_crossmnt) 22141da177e4SLinus Torvalds { 22151da177e4SLinus Torvalds u32 bmval0 = bmval[0]; 22161da177e4SLinus Torvalds u32 bmval1 = bmval[1]; 22177e705706SAndy Adamson u32 bmval2 = bmval[2]; 22181da177e4SLinus Torvalds struct kstat stat; 2219d50e6136SJ. Bruce Fields struct svc_fh *tempfh = NULL; 22201da177e4SLinus Torvalds struct kstatfs statfs; 2221ddd1ea56SJ. Bruce Fields __be32 *p; 22221fcea5b2SJ. Bruce Fields int starting_len = xdr->buf->len; 2223082d4bd7SJ. Bruce Fields int attrlen_offset; 2224082d4bd7SJ. Bruce Fields __be32 attrlen; 22251da177e4SLinus Torvalds u32 dummy; 22261da177e4SLinus Torvalds u64 dummy64; 222742ca0993SJ.Bruce Fields u32 rdattr_err = 0; 2228b37ad28bSAl Viro __be32 status; 2229b8dd7b9aSAl Viro int err; 22301da177e4SLinus Torvalds struct nfs4_acl *acl = NULL; 223118032ca0SDavid Quigley void *context = NULL; 223218032ca0SDavid Quigley int contextlen; 223318032ca0SDavid Quigley bool contextsupport = false; 22347e705706SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 22357e705706SAndy Adamson u32 minorversion = resp->cstate.minorversion; 2236ebabe9a9SChristoph Hellwig struct path path = { 2237ebabe9a9SChristoph Hellwig .mnt = exp->ex_path.mnt, 2238ebabe9a9SChristoph Hellwig .dentry = dentry, 2239ebabe9a9SChristoph Hellwig }; 22403d733711SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 22411da177e4SLinus Torvalds 22421da177e4SLinus Torvalds BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); 22437e705706SAndy Adamson BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); 22447e705706SAndy Adamson BUG_ON(bmval1 & ~nfsd_suppattrs1(minorversion)); 22457e705706SAndy Adamson BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion)); 22461da177e4SLinus Torvalds 224742ca0993SJ.Bruce Fields if (exp->ex_fslocs.migrated) { 22487e705706SAndy Adamson BUG_ON(bmval[2]); 224942ca0993SJ.Bruce Fields status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err); 225042ca0993SJ.Bruce Fields if (status) 225142ca0993SJ.Bruce Fields goto out; 225242ca0993SJ.Bruce Fields } 225342ca0993SJ.Bruce Fields 22543dadecceSAl Viro err = vfs_getattr(&path, &stat); 2255b8dd7b9aSAl Viro if (err) 22561da177e4SLinus Torvalds goto out_nfserr; 225712337901SChristoph Hellwig if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | 225812337901SChristoph Hellwig FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) || 22591da177e4SLinus Torvalds (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | 22601da177e4SLinus Torvalds FATTR4_WORD1_SPACE_TOTAL))) { 2261ebabe9a9SChristoph Hellwig err = vfs_statfs(&path, &statfs); 2262b8dd7b9aSAl Viro if (err) 22631da177e4SLinus Torvalds goto out_nfserr; 22641da177e4SLinus Torvalds } 22651da177e4SLinus Torvalds if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) { 2266d50e6136SJ. Bruce Fields tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); 2267d50e6136SJ. Bruce Fields status = nfserr_jukebox; 2268d50e6136SJ. Bruce Fields if (!tempfh) 2269d50e6136SJ. Bruce Fields goto out; 2270d50e6136SJ. Bruce Fields fh_init(tempfh, NFS4_FHSIZE); 2271d50e6136SJ. Bruce Fields status = fh_compose(tempfh, exp, dentry, NULL); 22721da177e4SLinus Torvalds if (status) 22731da177e4SLinus Torvalds goto out; 2274d50e6136SJ. Bruce Fields fhp = tempfh; 22751da177e4SLinus Torvalds } 22761da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACL) { 22770c9d65e7SAndreas Gruenbacher err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); 2278b8dd7b9aSAl Viro if (err == -EOPNOTSUPP) 22791da177e4SLinus Torvalds bmval0 &= ~FATTR4_WORD0_ACL; 2280b8dd7b9aSAl Viro else if (err == -EINVAL) { 22811da177e4SLinus Torvalds status = nfserr_attrnotsupp; 22821da177e4SLinus Torvalds goto out; 2283b8dd7b9aSAl Viro } else if (err != 0) 22841da177e4SLinus Torvalds goto out_nfserr; 22851da177e4SLinus Torvalds } 22862b44f1baSBenny Halevy 228718032ca0SDavid Quigley #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 228818032ca0SDavid Quigley if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) || 228918032ca0SDavid Quigley bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { 22902b0143b5SDavid Howells err = security_inode_getsecctx(d_inode(dentry), 229118032ca0SDavid Quigley &context, &contextlen); 229218032ca0SDavid Quigley contextsupport = (err == 0); 229318032ca0SDavid Quigley if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { 229418032ca0SDavid Quigley if (err == -EOPNOTSUPP) 229518032ca0SDavid Quigley bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL; 229618032ca0SDavid Quigley else if (err) 229718032ca0SDavid Quigley goto out_nfserr; 229818032ca0SDavid Quigley } 229918032ca0SDavid Quigley } 230018032ca0SDavid Quigley #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ 230118032ca0SDavid Quigley 23022b44f1baSBenny Halevy if (bmval2) { 2303ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 2304ddd1ea56SJ. Bruce Fields if (!p) 23051da177e4SLinus Torvalds goto out_resource; 2306c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(3); 2307c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(bmval0); 2308c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(bmval1); 2309c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(bmval2); 23102b44f1baSBenny Halevy } else if (bmval1) { 2311ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2312ddd1ea56SJ. Bruce Fields if (!p) 23132b44f1baSBenny Halevy goto out_resource; 2314c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(2); 2315c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(bmval0); 2316c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(bmval1); 23177e705706SAndy Adamson } else { 2318ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2319ddd1ea56SJ. Bruce Fields if (!p) 23202b44f1baSBenny Halevy goto out_resource; 2321c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 2322c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(bmval0); 23237e705706SAndy Adamson } 2324082d4bd7SJ. Bruce Fields 2325082d4bd7SJ. Bruce Fields attrlen_offset = xdr->buf->len; 2326ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2327ddd1ea56SJ. Bruce Fields if (!p) 2328ddd1ea56SJ. Bruce Fields goto out_resource; 2329082d4bd7SJ. Bruce Fields p++; /* to be backfilled later */ 23301da177e4SLinus Torvalds 23311da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { 23327e705706SAndy Adamson u32 word0 = nfsd_suppattrs0(minorversion); 23337e705706SAndy Adamson u32 word1 = nfsd_suppattrs1(minorversion); 23347e705706SAndy Adamson u32 word2 = nfsd_suppattrs2(minorversion); 23357e705706SAndy Adamson 23360c9d65e7SAndreas Gruenbacher if (!IS_POSIXACL(dentry->d_inode)) 233742ca0993SJ.Bruce Fields word0 &= ~FATTR4_WORD0_ACL; 233818032ca0SDavid Quigley if (!contextsupport) 233918032ca0SDavid Quigley word2 &= ~FATTR4_WORD2_SECURITY_LABEL; 23407e705706SAndy Adamson if (!word2) { 2341ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2342ddd1ea56SJ. Bruce Fields if (!p) 23432b44f1baSBenny Halevy goto out_resource; 2344c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(2); 2345c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(word0); 2346c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(word1); 23477e705706SAndy Adamson } else { 2348ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 2349ddd1ea56SJ. Bruce Fields if (!p) 23502b44f1baSBenny Halevy goto out_resource; 2351c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(3); 2352c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(word0); 2353c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(word1); 2354c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(word2); 23557e705706SAndy Adamson } 23561da177e4SLinus Torvalds } 23571da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_TYPE) { 2358ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2359ddd1ea56SJ. Bruce Fields if (!p) 23601da177e4SLinus Torvalds goto out_resource; 23613d2544b1SJ. Bruce Fields dummy = nfs4_file_type(stat.mode); 23626b6d8137SJ. Bruce Fields if (dummy == NF4BAD) { 23636b6d8137SJ. Bruce Fields status = nfserr_serverfault; 23646b6d8137SJ. Bruce Fields goto out; 23656b6d8137SJ. Bruce Fields } 2366c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(dummy); 23671da177e4SLinus Torvalds } 23681da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { 2369ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2370ddd1ea56SJ. Bruce Fields if (!p) 23711da177e4SLinus Torvalds goto out_resource; 237249640001SNeilBrown if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) 2373c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_FH_PERSISTENT); 237449640001SNeilBrown else 2375c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_FH_PERSISTENT| 2376c373b0a4SJ. Bruce Fields NFS4_FH_VOL_RENAME); 23771da177e4SLinus Torvalds } 23781da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CHANGE) { 2379ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2380ddd1ea56SJ. Bruce Fields if (!p) 23811da177e4SLinus Torvalds goto out_resource; 23822b0143b5SDavid Howells p = encode_change(p, &stat, d_inode(dentry)); 23831da177e4SLinus Torvalds } 23841da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SIZE) { 2385ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2386ddd1ea56SJ. Bruce Fields if (!p) 23871da177e4SLinus Torvalds goto out_resource; 2388b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, stat.size); 23891da177e4SLinus Torvalds } 23901da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) { 2391ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2392ddd1ea56SJ. Bruce Fields if (!p) 23931da177e4SLinus Torvalds goto out_resource; 2394c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 23951da177e4SLinus Torvalds } 23961da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) { 2397ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2398ddd1ea56SJ. Bruce Fields if (!p) 23991da177e4SLinus Torvalds goto out_resource; 2400c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 24011da177e4SLinus Torvalds } 24021da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_NAMED_ATTR) { 2403ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2404ddd1ea56SJ. Bruce Fields if (!p) 24051da177e4SLinus Torvalds goto out_resource; 2406c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 24071da177e4SLinus Torvalds } 24081da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FSID) { 2409ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 2410ddd1ea56SJ. Bruce Fields if (!p) 24111da177e4SLinus Torvalds goto out_resource; 241242ca0993SJ.Bruce Fields if (exp->ex_fslocs.migrated) { 2413b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MAJOR); 2414b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MINOR); 2415af6a4e28SNeilBrown } else switch(fsid_source(fhp)) { 2416af6a4e28SNeilBrown case FSIDSOURCE_FSID: 2417b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64)exp->ex_fsid); 2418b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64)0); 2419af6a4e28SNeilBrown break; 2420af6a4e28SNeilBrown case FSIDSOURCE_DEV: 2421c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 2422c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(MAJOR(stat.dev)); 2423c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 2424c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(MINOR(stat.dev)); 2425af6a4e28SNeilBrown break; 2426af6a4e28SNeilBrown case FSIDSOURCE_UUID: 242794eb3689SKinglong Mee p = xdr_encode_opaque_fixed(p, exp->ex_uuid, 242894eb3689SKinglong Mee EX_UUID_LEN); 2429af6a4e28SNeilBrown break; 24301da177e4SLinus Torvalds } 24311da177e4SLinus Torvalds } 24321da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { 2433ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2434ddd1ea56SJ. Bruce Fields if (!p) 24351da177e4SLinus Torvalds goto out_resource; 2436c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 24371da177e4SLinus Torvalds } 24381da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_LEASE_TIME) { 2439ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2440ddd1ea56SJ. Bruce Fields if (!p) 24411da177e4SLinus Torvalds goto out_resource; 2442c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(nn->nfsd4_lease); 24431da177e4SLinus Torvalds } 24441da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { 2445ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2446ddd1ea56SJ. Bruce Fields if (!p) 24471da177e4SLinus Torvalds goto out_resource; 2448c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(rdattr_err); 24491da177e4SLinus Torvalds } 24501da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACL) { 24511da177e4SLinus Torvalds struct nfs4_ace *ace; 24521da177e4SLinus Torvalds 24531da177e4SLinus Torvalds if (acl == NULL) { 2454ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2455ddd1ea56SJ. Bruce Fields if (!p) 24561da177e4SLinus Torvalds goto out_resource; 24571da177e4SLinus Torvalds 2458c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 24591da177e4SLinus Torvalds goto out_acl; 24601da177e4SLinus Torvalds } 2461ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2462ddd1ea56SJ. Bruce Fields if (!p) 24631da177e4SLinus Torvalds goto out_resource; 2464c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(acl->naces); 24651da177e4SLinus Torvalds 246628e05dd8SJ. Bruce Fields for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { 2467ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4*3); 2468ddd1ea56SJ. Bruce Fields if (!p) 24691da177e4SLinus Torvalds goto out_resource; 2470c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ace->type); 2471c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ace->flag); 2472c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ace->access_mask & 2473c373b0a4SJ. Bruce Fields NFS4_ACE_MASK_ALL); 2474ddd1ea56SJ. Bruce Fields status = nfsd4_encode_aclname(xdr, rqstp, ace); 24751da177e4SLinus Torvalds if (status) 24761da177e4SLinus Torvalds goto out; 24771da177e4SLinus Torvalds } 24781da177e4SLinus Torvalds } 24791da177e4SLinus Torvalds out_acl: 24801da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACLSUPPORT) { 2481ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2482ddd1ea56SJ. Bruce Fields if (!p) 24831da177e4SLinus Torvalds goto out_resource; 24840c9d65e7SAndreas Gruenbacher *p++ = cpu_to_be32(IS_POSIXACL(dentry->d_inode) ? 24851da177e4SLinus Torvalds ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0); 24861da177e4SLinus Torvalds } 24871da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CANSETTIME) { 2488ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2489ddd1ea56SJ. Bruce Fields if (!p) 24901da177e4SLinus Torvalds goto out_resource; 2491c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 24921da177e4SLinus Torvalds } 24931da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { 2494ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2495ddd1ea56SJ. Bruce Fields if (!p) 24961da177e4SLinus Torvalds goto out_resource; 2497c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 24981da177e4SLinus Torvalds } 24991da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { 2500ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2501ddd1ea56SJ. Bruce Fields if (!p) 25021da177e4SLinus Torvalds goto out_resource; 2503c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 25041da177e4SLinus Torvalds } 25051da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) { 2506ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2507ddd1ea56SJ. Bruce Fields if (!p) 25081da177e4SLinus Torvalds goto out_resource; 2509c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 25101da177e4SLinus Torvalds } 25111da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILEHANDLE) { 2512ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, fhp->fh_handle.fh_size + 4); 2513ddd1ea56SJ. Bruce Fields if (!p) 25141da177e4SLinus Torvalds goto out_resource; 25150c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, 25160c0c267bSJ. Bruce Fields fhp->fh_handle.fh_size); 25171da177e4SLinus Torvalds } 25181da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILEID) { 2519ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2520ddd1ea56SJ. Bruce Fields if (!p) 25211da177e4SLinus Torvalds goto out_resource; 2522b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, stat.ino); 25231da177e4SLinus Torvalds } 25241da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { 2525ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2526ddd1ea56SJ. Bruce Fields if (!p) 25271da177e4SLinus Torvalds goto out_resource; 2528b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) statfs.f_ffree); 25291da177e4SLinus Torvalds } 25301da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_FREE) { 2531ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2532ddd1ea56SJ. Bruce Fields if (!p) 25331da177e4SLinus Torvalds goto out_resource; 2534b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) statfs.f_ffree); 25351da177e4SLinus Torvalds } 25361da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { 2537ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2538ddd1ea56SJ. Bruce Fields if (!p) 25391da177e4SLinus Torvalds goto out_resource; 2540b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) statfs.f_files); 25411da177e4SLinus Torvalds } 254281c3f413SJ.Bruce Fields if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { 2543ddd1ea56SJ. Bruce Fields status = nfsd4_encode_fs_locations(xdr, rqstp, exp); 254481c3f413SJ.Bruce Fields if (status) 254581c3f413SJ.Bruce Fields goto out; 254681c3f413SJ.Bruce Fields } 25471da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { 2548ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2549ddd1ea56SJ. Bruce Fields if (!p) 25501da177e4SLinus Torvalds goto out_resource; 2551c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 25521da177e4SLinus Torvalds } 25531da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { 2554ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2555ddd1ea56SJ. Bruce Fields if (!p) 25561da177e4SLinus Torvalds goto out_resource; 2557b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, exp->ex_path.mnt->mnt_sb->s_maxbytes); 25581da177e4SLinus Torvalds } 25591da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXLINK) { 2560ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2561ddd1ea56SJ. Bruce Fields if (!p) 25621da177e4SLinus Torvalds goto out_resource; 2563c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(255); 25641da177e4SLinus Torvalds } 25651da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXNAME) { 2566ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2567ddd1ea56SJ. Bruce Fields if (!p) 25681da177e4SLinus Torvalds goto out_resource; 2569c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(statfs.f_namelen); 25701da177e4SLinus Torvalds } 25711da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXREAD) { 2572ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2573ddd1ea56SJ. Bruce Fields if (!p) 25741da177e4SLinus Torvalds goto out_resource; 2575b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp)); 25761da177e4SLinus Torvalds } 25771da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXWRITE) { 2578ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2579ddd1ea56SJ. Bruce Fields if (!p) 25801da177e4SLinus Torvalds goto out_resource; 2581b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp)); 25821da177e4SLinus Torvalds } 25831da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_MODE) { 2584ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2585ddd1ea56SJ. Bruce Fields if (!p) 25861da177e4SLinus Torvalds goto out_resource; 2587c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.mode & S_IALLUGO); 25881da177e4SLinus Torvalds } 25891da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_NO_TRUNC) { 2590ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2591ddd1ea56SJ. Bruce Fields if (!p) 25921da177e4SLinus Torvalds goto out_resource; 2593c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 25941da177e4SLinus Torvalds } 25951da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_NUMLINKS) { 2596ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2597ddd1ea56SJ. Bruce Fields if (!p) 25981da177e4SLinus Torvalds goto out_resource; 2599c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.nlink); 26001da177e4SLinus Torvalds } 26011da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_OWNER) { 2602ddd1ea56SJ. Bruce Fields status = nfsd4_encode_user(xdr, rqstp, stat.uid); 26031da177e4SLinus Torvalds if (status) 26041da177e4SLinus Torvalds goto out; 26051da177e4SLinus Torvalds } 26061da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { 2607ddd1ea56SJ. Bruce Fields status = nfsd4_encode_group(xdr, rqstp, stat.gid); 26081da177e4SLinus Torvalds if (status) 26091da177e4SLinus Torvalds goto out; 26101da177e4SLinus Torvalds } 26111da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_RAWDEV) { 2612ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2613ddd1ea56SJ. Bruce Fields if (!p) 26141da177e4SLinus Torvalds goto out_resource; 2615c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32((u32) MAJOR(stat.rdev)); 2616c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32((u32) MINOR(stat.rdev)); 26171da177e4SLinus Torvalds } 26181da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { 2619ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2620ddd1ea56SJ. Bruce Fields if (!p) 26211da177e4SLinus Torvalds goto out_resource; 26221da177e4SLinus Torvalds dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize; 2623b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, dummy64); 26241da177e4SLinus Torvalds } 26251da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_FREE) { 2626ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2627ddd1ea56SJ. Bruce Fields if (!p) 26281da177e4SLinus Torvalds goto out_resource; 26291da177e4SLinus Torvalds dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize; 2630b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, dummy64); 26311da177e4SLinus Torvalds } 26321da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { 2633ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2634ddd1ea56SJ. Bruce Fields if (!p) 26351da177e4SLinus Torvalds goto out_resource; 26361da177e4SLinus Torvalds dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize; 2637b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, dummy64); 26381da177e4SLinus Torvalds } 26391da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_USED) { 2640ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2641ddd1ea56SJ. Bruce Fields if (!p) 26421da177e4SLinus Torvalds goto out_resource; 26431da177e4SLinus Torvalds dummy64 = (u64)stat.blocks << 9; 2644b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, dummy64); 26451da177e4SLinus Torvalds } 26461da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { 2647ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2648ddd1ea56SJ. Bruce Fields if (!p) 26491da177e4SLinus Torvalds goto out_resource; 2650b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (s64)stat.atime.tv_sec); 2651c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.atime.tv_nsec); 26521da177e4SLinus Torvalds } 26531da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_DELTA) { 2654ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2655ddd1ea56SJ. Bruce Fields if (!p) 26561da177e4SLinus Torvalds goto out_resource; 2657c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 2658c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 2659c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 26601da177e4SLinus Torvalds } 26611da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_METADATA) { 2662ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2663ddd1ea56SJ. Bruce Fields if (!p) 26641da177e4SLinus Torvalds goto out_resource; 2665b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (s64)stat.ctime.tv_sec); 2666c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.ctime.tv_nsec); 26671da177e4SLinus Torvalds } 26681da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { 2669ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2670ddd1ea56SJ. Bruce Fields if (!p) 26711da177e4SLinus Torvalds goto out_resource; 2672b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (s64)stat.mtime.tv_sec); 2673c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.mtime.tv_nsec); 26741da177e4SLinus Torvalds } 26751da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { 2676ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2677ddd1ea56SJ. Bruce Fields if (!p) 26781da177e4SLinus Torvalds goto out_resource; 2679406a7ea9SFrank Filz /* 2680406a7ea9SFrank Filz * Get parent's attributes if not ignoring crossmount 2681406a7ea9SFrank Filz * and this is the root of a cross-mounted filesystem. 2682406a7ea9SFrank Filz */ 2683406a7ea9SFrank Filz if (ignore_crossmnt == 0 && 2684ae7095a7SJ. Bruce Fields dentry == exp->ex_path.mnt->mnt_root) 2685ae7095a7SJ. Bruce Fields get_parent_attributes(exp, &stat); 2686b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, stat.ino); 26871da177e4SLinus Torvalds } 26889cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 26899cf514ccSChristoph Hellwig if ((bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) || 26909cf514ccSChristoph Hellwig (bmval2 & FATTR4_WORD2_LAYOUT_TYPES)) { 26919cf514ccSChristoph Hellwig if (exp->ex_layout_type) { 26929cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 8); 26939cf514ccSChristoph Hellwig if (!p) 26949cf514ccSChristoph Hellwig goto out_resource; 26959cf514ccSChristoph Hellwig *p++ = cpu_to_be32(1); 26969cf514ccSChristoph Hellwig *p++ = cpu_to_be32(exp->ex_layout_type); 26979cf514ccSChristoph Hellwig } else { 26989cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 26999cf514ccSChristoph Hellwig if (!p) 27009cf514ccSChristoph Hellwig goto out_resource; 27019cf514ccSChristoph Hellwig *p++ = cpu_to_be32(0); 27029cf514ccSChristoph Hellwig } 27039cf514ccSChristoph Hellwig } 27049cf514ccSChristoph Hellwig 27059cf514ccSChristoph Hellwig if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) { 27069cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 27079cf514ccSChristoph Hellwig if (!p) 27089cf514ccSChristoph Hellwig goto out_resource; 27099cf514ccSChristoph Hellwig *p++ = cpu_to_be32(stat.blksize); 27109cf514ccSChristoph Hellwig } 27119cf514ccSChristoph Hellwig #endif /* CONFIG_NFSD_PNFS */ 271218032ca0SDavid Quigley if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { 2713ddd1ea56SJ. Bruce Fields status = nfsd4_encode_security_label(xdr, rqstp, context, 2714ddd1ea56SJ. Bruce Fields contextlen); 271518032ca0SDavid Quigley if (status) 271618032ca0SDavid Quigley goto out; 271718032ca0SDavid Quigley } 27188c18f205SBenny Halevy if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { 2719ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 2720ddd1ea56SJ. Bruce Fields if (!p) 2721de3997a7SJ. Bruce Fields goto out_resource; 2722c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(3); 2723c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD0); 2724c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD1); 2725c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD2); 27268c18f205SBenny Halevy } 27277e705706SAndy Adamson 2728082d4bd7SJ. Bruce Fields attrlen = htonl(xdr->buf->len - attrlen_offset - 4); 2729082d4bd7SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4); 27301da177e4SLinus Torvalds status = nfs_ok; 27311da177e4SLinus Torvalds 27321da177e4SLinus Torvalds out: 2733ba4e55bbSJ. Bruce Fields #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 273418032ca0SDavid Quigley if (context) 273518032ca0SDavid Quigley security_release_secctx(context, contextlen); 2736ba4e55bbSJ. Bruce Fields #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ 273728e05dd8SJ. Bruce Fields kfree(acl); 273818df11d0SYan, Zheng if (tempfh) { 2739d50e6136SJ. Bruce Fields fh_put(tempfh); 274018df11d0SYan, Zheng kfree(tempfh); 274118df11d0SYan, Zheng } 27421fcea5b2SJ. Bruce Fields if (status) 27431fcea5b2SJ. Bruce Fields xdr_truncate_encode(xdr, starting_len); 27441da177e4SLinus Torvalds return status; 27451da177e4SLinus Torvalds out_nfserr: 2746b8dd7b9aSAl Viro status = nfserrno(err); 27471da177e4SLinus Torvalds goto out; 27481da177e4SLinus Torvalds out_resource: 27491da177e4SLinus Torvalds status = nfserr_resource; 27501da177e4SLinus Torvalds goto out; 27511da177e4SLinus Torvalds } 27521da177e4SLinus Torvalds 27532825a7f9SJ. Bruce Fields static void svcxdr_init_encode_from_buffer(struct xdr_stream *xdr, 27542825a7f9SJ. Bruce Fields struct xdr_buf *buf, __be32 *p, int bytes) 27552825a7f9SJ. Bruce Fields { 27562825a7f9SJ. Bruce Fields xdr->scratch.iov_len = 0; 27572825a7f9SJ. Bruce Fields memset(buf, 0, sizeof(struct xdr_buf)); 27582825a7f9SJ. Bruce Fields buf->head[0].iov_base = p; 27592825a7f9SJ. Bruce Fields buf->head[0].iov_len = 0; 27602825a7f9SJ. Bruce Fields buf->len = 0; 27612825a7f9SJ. Bruce Fields xdr->buf = buf; 27622825a7f9SJ. Bruce Fields xdr->iov = buf->head; 27632825a7f9SJ. Bruce Fields xdr->p = p; 27642825a7f9SJ. Bruce Fields xdr->end = (void *)p + bytes; 27652825a7f9SJ. Bruce Fields buf->buflen = bytes; 27662825a7f9SJ. Bruce Fields } 27672825a7f9SJ. Bruce Fields 2768d5184658SJ. Bruce Fields __be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words, 2769d5184658SJ. Bruce Fields struct svc_fh *fhp, struct svc_export *exp, 2770d5184658SJ. Bruce Fields struct dentry *dentry, u32 *bmval, 2771d5184658SJ. Bruce Fields struct svc_rqst *rqstp, int ignore_crossmnt) 2772d5184658SJ. Bruce Fields { 27732825a7f9SJ. Bruce Fields struct xdr_buf dummy; 2774d5184658SJ. Bruce Fields struct xdr_stream xdr; 2775d5184658SJ. Bruce Fields __be32 ret; 2776d5184658SJ. Bruce Fields 27772825a7f9SJ. Bruce Fields svcxdr_init_encode_from_buffer(&xdr, &dummy, *p, words << 2); 2778d5184658SJ. Bruce Fields ret = nfsd4_encode_fattr(&xdr, fhp, exp, dentry, bmval, rqstp, 2779d5184658SJ. Bruce Fields ignore_crossmnt); 2780d5184658SJ. Bruce Fields *p = xdr.p; 2781d5184658SJ. Bruce Fields return ret; 2782d5184658SJ. Bruce Fields } 2783d5184658SJ. Bruce Fields 2784c0ce6ec8SJ. Bruce Fields static inline int attributes_need_mount(u32 *bmval) 2785c0ce6ec8SJ. Bruce Fields { 2786c0ce6ec8SJ. Bruce Fields if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME)) 2787c0ce6ec8SJ. Bruce Fields return 1; 2788c0ce6ec8SJ. Bruce Fields if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) 2789c0ce6ec8SJ. Bruce Fields return 1; 2790c0ce6ec8SJ. Bruce Fields return 0; 2791c0ce6ec8SJ. Bruce Fields } 2792c0ce6ec8SJ. Bruce Fields 2793b37ad28bSAl Viro static __be32 2794561f0ed4SJ. Bruce Fields nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd, 2795561f0ed4SJ. Bruce Fields const char *name, int namlen) 27961da177e4SLinus Torvalds { 27971da177e4SLinus Torvalds struct svc_export *exp = cd->rd_fhp->fh_export; 27981da177e4SLinus Torvalds struct dentry *dentry; 2799b37ad28bSAl Viro __be32 nfserr; 2800406a7ea9SFrank Filz int ignore_crossmnt = 0; 28011da177e4SLinus Torvalds 28021da177e4SLinus Torvalds dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); 28031da177e4SLinus Torvalds if (IS_ERR(dentry)) 28041da177e4SLinus Torvalds return nfserrno(PTR_ERR(dentry)); 28052b0143b5SDavid Howells if (d_really_is_negative(dentry)) { 2806b2c0cea6SJ. Bruce Fields /* 2807b2c0cea6SJ. Bruce Fields * nfsd_buffered_readdir drops the i_mutex between 2808b2c0cea6SJ. Bruce Fields * readdir and calling this callback, leaving a window 2809b2c0cea6SJ. Bruce Fields * where this directory entry could have gone away. 2810b2c0cea6SJ. Bruce Fields */ 2811b2c0cea6SJ. Bruce Fields dput(dentry); 2812b2c0cea6SJ. Bruce Fields return nfserr_noent; 2813b2c0cea6SJ. Bruce Fields } 28141da177e4SLinus Torvalds 28151da177e4SLinus Torvalds exp_get(exp); 2816406a7ea9SFrank Filz /* 2817406a7ea9SFrank Filz * In the case of a mountpoint, the client may be asking for 2818406a7ea9SFrank Filz * attributes that are only properties of the underlying filesystem 2819406a7ea9SFrank Filz * as opposed to the cross-mounted file system. In such a case, 2820406a7ea9SFrank Filz * we will not follow the cross mount and will fill the attribtutes 2821406a7ea9SFrank Filz * directly from the mountpoint dentry. 2822406a7ea9SFrank Filz */ 28233227fa41SJ. Bruce Fields if (nfsd_mountpoint(dentry, exp)) { 2824021d3a72SJ.Bruce Fields int err; 2825021d3a72SJ.Bruce Fields 28263227fa41SJ. Bruce Fields if (!(exp->ex_flags & NFSEXP_V4ROOT) 28273227fa41SJ. Bruce Fields && !attributes_need_mount(cd->rd_bmval)) { 28283227fa41SJ. Bruce Fields ignore_crossmnt = 1; 28293227fa41SJ. Bruce Fields goto out_encode; 28303227fa41SJ. Bruce Fields } 2831dcb488a3SAndy Adamson /* 2832dcb488a3SAndy Adamson * Why the heck aren't we just using nfsd_lookup?? 2833dcb488a3SAndy Adamson * Different "."/".." handling? Something else? 2834dcb488a3SAndy Adamson * At least, add a comment here to explain.... 2835dcb488a3SAndy Adamson */ 2836021d3a72SJ.Bruce Fields err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); 2837021d3a72SJ.Bruce Fields if (err) { 2838021d3a72SJ.Bruce Fields nfserr = nfserrno(err); 28391da177e4SLinus Torvalds goto out_put; 28401da177e4SLinus Torvalds } 2841dcb488a3SAndy Adamson nfserr = check_nfsd_access(exp, cd->rd_rqstp); 2842dcb488a3SAndy Adamson if (nfserr) 2843dcb488a3SAndy Adamson goto out_put; 28441da177e4SLinus Torvalds 28451da177e4SLinus Torvalds } 28463227fa41SJ. Bruce Fields out_encode: 2847561f0ed4SJ. Bruce Fields nfserr = nfsd4_encode_fattr(xdr, NULL, exp, dentry, cd->rd_bmval, 2848406a7ea9SFrank Filz cd->rd_rqstp, ignore_crossmnt); 28491da177e4SLinus Torvalds out_put: 28501da177e4SLinus Torvalds dput(dentry); 28511da177e4SLinus Torvalds exp_put(exp); 28521da177e4SLinus Torvalds return nfserr; 28531da177e4SLinus Torvalds } 28541da177e4SLinus Torvalds 28552ebbc012SAl Viro static __be32 * 2856561f0ed4SJ. Bruce Fields nfsd4_encode_rdattr_error(struct xdr_stream *xdr, __be32 nfserr) 28571da177e4SLinus Torvalds { 2858561f0ed4SJ. Bruce Fields __be32 *p; 2859561f0ed4SJ. Bruce Fields 2860c3a45617SKinglong Mee p = xdr_reserve_space(xdr, 20); 2861561f0ed4SJ. Bruce Fields if (!p) 28621da177e4SLinus Torvalds return NULL; 28631da177e4SLinus Torvalds *p++ = htonl(2); 28641da177e4SLinus Torvalds *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */ 28651da177e4SLinus Torvalds *p++ = htonl(0); /* bmval1 */ 28661da177e4SLinus Torvalds 286787915c64SJ. Bruce Fields *p++ = htonl(4); /* attribute length */ 28681da177e4SLinus Torvalds *p++ = nfserr; /* no htonl */ 28691da177e4SLinus Torvalds return p; 28701da177e4SLinus Torvalds } 28711da177e4SLinus Torvalds 28721da177e4SLinus Torvalds static int 2873a0ad13efSNeilBrown nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, 2874a0ad13efSNeilBrown loff_t offset, u64 ino, unsigned int d_type) 28751da177e4SLinus Torvalds { 2876a0ad13efSNeilBrown struct readdir_cd *ccd = ccdv; 28771da177e4SLinus Torvalds struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); 2878561f0ed4SJ. Bruce Fields struct xdr_stream *xdr = cd->xdr; 2879561f0ed4SJ. Bruce Fields int start_offset = xdr->buf->len; 2880561f0ed4SJ. Bruce Fields int cookie_offset; 2881aee37764SJ. Bruce Fields u32 name_and_cookie; 2882561f0ed4SJ. Bruce Fields int entry_bytes; 2883b37ad28bSAl Viro __be32 nfserr = nfserr_toosmall; 2884561f0ed4SJ. Bruce Fields __be64 wire_offset; 2885561f0ed4SJ. Bruce Fields __be32 *p; 28861da177e4SLinus Torvalds 28871da177e4SLinus Torvalds /* In nfsv4, "." and ".." never make it onto the wire.. */ 28881da177e4SLinus Torvalds if (name && isdotent(name, namlen)) { 28891da177e4SLinus Torvalds cd->common.err = nfs_ok; 28901da177e4SLinus Torvalds return 0; 28911da177e4SLinus Torvalds } 28921da177e4SLinus Torvalds 2893561f0ed4SJ. Bruce Fields if (cd->cookie_offset) { 2894561f0ed4SJ. Bruce Fields wire_offset = cpu_to_be64(offset); 2895561f0ed4SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, cd->cookie_offset, 2896561f0ed4SJ. Bruce Fields &wire_offset, 8); 2897561f0ed4SJ. Bruce Fields } 28981da177e4SLinus Torvalds 2899561f0ed4SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2900561f0ed4SJ. Bruce Fields if (!p) 29011da177e4SLinus Torvalds goto fail; 29021da177e4SLinus Torvalds *p++ = xdr_one; /* mark entry present */ 2903561f0ed4SJ. Bruce Fields cookie_offset = xdr->buf->len; 2904561f0ed4SJ. Bruce Fields p = xdr_reserve_space(xdr, 3*4 + namlen); 2905561f0ed4SJ. Bruce Fields if (!p) 2906561f0ed4SJ. Bruce Fields goto fail; 29071da177e4SLinus Torvalds p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */ 29081da177e4SLinus Torvalds p = xdr_encode_array(p, name, namlen); /* name length & name */ 29091da177e4SLinus Torvalds 2910561f0ed4SJ. Bruce Fields nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen); 29111da177e4SLinus Torvalds switch (nfserr) { 29121da177e4SLinus Torvalds case nfs_ok: 29131da177e4SLinus Torvalds break; 29141da177e4SLinus Torvalds case nfserr_resource: 29151da177e4SLinus Torvalds nfserr = nfserr_toosmall; 29161da177e4SLinus Torvalds goto fail; 2917b2c0cea6SJ. Bruce Fields case nfserr_noent: 2918f41c5ad2SKinglong Mee xdr_truncate_encode(xdr, start_offset); 2919b2c0cea6SJ. Bruce Fields goto skip_entry; 29201da177e4SLinus Torvalds default: 29211da177e4SLinus Torvalds /* 29221da177e4SLinus Torvalds * If the client requested the RDATTR_ERROR attribute, 29231da177e4SLinus Torvalds * we stuff the error code into this attribute 29241da177e4SLinus Torvalds * and continue. If this attribute was not requested, 29251da177e4SLinus Torvalds * then in accordance with the spec, we fail the 29261da177e4SLinus Torvalds * entire READDIR operation(!) 29271da177e4SLinus Torvalds */ 29281da177e4SLinus Torvalds if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) 29291da177e4SLinus Torvalds goto fail; 2930561f0ed4SJ. Bruce Fields p = nfsd4_encode_rdattr_error(xdr, nfserr); 293134081efcSFred Isaman if (p == NULL) { 293234081efcSFred Isaman nfserr = nfserr_toosmall; 29331da177e4SLinus Torvalds goto fail; 29341da177e4SLinus Torvalds } 293534081efcSFred Isaman } 2936561f0ed4SJ. Bruce Fields nfserr = nfserr_toosmall; 2937561f0ed4SJ. Bruce Fields entry_bytes = xdr->buf->len - start_offset; 2938561f0ed4SJ. Bruce Fields if (entry_bytes > cd->rd_maxcount) 2939561f0ed4SJ. Bruce Fields goto fail; 2940561f0ed4SJ. Bruce Fields cd->rd_maxcount -= entry_bytes; 2941aee37764SJ. Bruce Fields /* 2942aee37764SJ. Bruce Fields * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so 2943aee37764SJ. Bruce Fields * let's always let through the first entry, at least: 2944aee37764SJ. Bruce Fields */ 29450ec016e3SJ. Bruce Fields if (!cd->rd_dircount) 29460ec016e3SJ. Bruce Fields goto fail; 29470ec016e3SJ. Bruce Fields name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8; 2948aee37764SJ. Bruce Fields if (name_and_cookie > cd->rd_dircount && cd->cookie_offset) 2949aee37764SJ. Bruce Fields goto fail; 2950aee37764SJ. Bruce Fields cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie); 29510ec016e3SJ. Bruce Fields 2952561f0ed4SJ. Bruce Fields cd->cookie_offset = cookie_offset; 2953b2c0cea6SJ. Bruce Fields skip_entry: 29541da177e4SLinus Torvalds cd->common.err = nfs_ok; 29551da177e4SLinus Torvalds return 0; 29561da177e4SLinus Torvalds fail: 2957561f0ed4SJ. Bruce Fields xdr_truncate_encode(xdr, start_offset); 29581da177e4SLinus Torvalds cd->common.err = nfserr; 29591da177e4SLinus Torvalds return -EINVAL; 29601da177e4SLinus Torvalds } 29611da177e4SLinus Torvalds 2962d0a381ddSJ. Bruce Fields static __be32 2963d0a381ddSJ. Bruce Fields nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid) 2964e2f282b9SBenny Halevy { 2965bc749ca4SJ. Bruce Fields __be32 *p; 2966e2f282b9SBenny Halevy 2967d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, sizeof(stateid_t)); 2968d0a381ddSJ. Bruce Fields if (!p) 2969d0a381ddSJ. Bruce Fields return nfserr_resource; 2970c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sid->si_generation); 29710c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &sid->si_opaque, 29720c0c267bSJ. Bruce Fields sizeof(stateid_opaque_t)); 2973d0a381ddSJ. Bruce Fields return 0; 2974e2f282b9SBenny Halevy } 2975e2f282b9SBenny Halevy 2976695e12f8SBenny Halevy static __be32 2977b37ad28bSAl Viro nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) 29781da177e4SLinus Torvalds { 2979d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2980bc749ca4SJ. Bruce Fields __be32 *p; 29811da177e4SLinus Torvalds 29821da177e4SLinus Torvalds if (!nfserr) { 2983d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2984d0a381ddSJ. Bruce Fields if (!p) 2985d0a381ddSJ. Bruce Fields return nfserr_resource; 2986c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(access->ac_supported); 2987c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(access->ac_resp_access); 29881da177e4SLinus Torvalds } 2989695e12f8SBenny Halevy return nfserr; 29901da177e4SLinus Torvalds } 29911da177e4SLinus Torvalds 29921d1bc8f2SJ. Bruce Fields static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts) 29931d1bc8f2SJ. Bruce Fields { 2994d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 29951d1bc8f2SJ. Bruce Fields __be32 *p; 29961d1bc8f2SJ. Bruce Fields 29971d1bc8f2SJ. Bruce Fields if (!nfserr) { 2998d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8); 2999d0a381ddSJ. Bruce Fields if (!p) 3000d0a381ddSJ. Bruce Fields return nfserr_resource; 30010c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, bcts->sessionid.data, 30020c0c267bSJ. Bruce Fields NFS4_MAX_SESSIONID_LEN); 3003c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(bcts->dir); 30046e67b5d1SJ. Bruce Fields /* Sorry, we do not yet support RDMA over 4.1: */ 3005c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 30061d1bc8f2SJ. Bruce Fields } 30071d1bc8f2SJ. Bruce Fields return nfserr; 30081d1bc8f2SJ. Bruce Fields } 30091d1bc8f2SJ. Bruce Fields 3010695e12f8SBenny Halevy static __be32 3011b37ad28bSAl Viro nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) 30121da177e4SLinus Torvalds { 3013d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3014d0a381ddSJ. Bruce Fields 3015e2f282b9SBenny Halevy if (!nfserr) 3016d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &close->cl_stateid); 3017e2f282b9SBenny Halevy 3018695e12f8SBenny Halevy return nfserr; 30191da177e4SLinus Torvalds } 30201da177e4SLinus Torvalds 30211da177e4SLinus Torvalds 3022695e12f8SBenny Halevy static __be32 3023b37ad28bSAl Viro nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) 30241da177e4SLinus Torvalds { 3025d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3026bc749ca4SJ. Bruce Fields __be32 *p; 30271da177e4SLinus Torvalds 30281da177e4SLinus Torvalds if (!nfserr) { 3029d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE); 3030d0a381ddSJ. Bruce Fields if (!p) 3031d0a381ddSJ. Bruce Fields return nfserr_resource; 30320c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, commit->co_verf.data, 30330c0c267bSJ. Bruce Fields NFS4_VERIFIER_SIZE); 30341da177e4SLinus Torvalds } 3035695e12f8SBenny Halevy return nfserr; 30361da177e4SLinus Torvalds } 30371da177e4SLinus Torvalds 3038695e12f8SBenny Halevy static __be32 3039b37ad28bSAl Viro nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) 30401da177e4SLinus Torvalds { 3041d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3042bc749ca4SJ. Bruce Fields __be32 *p; 30431da177e4SLinus Torvalds 30441da177e4SLinus Torvalds if (!nfserr) { 3045d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 32); 3046d0a381ddSJ. Bruce Fields if (!p) 3047d0a381ddSJ. Bruce Fields return nfserr_resource; 3048d05d5744SJ. Bruce Fields p = encode_cinfo(p, &create->cr_cinfo); 3049c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(2); 3050c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(create->cr_bmval[0]); 3051c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(create->cr_bmval[1]); 30521da177e4SLinus Torvalds } 3053695e12f8SBenny Halevy return nfserr; 30541da177e4SLinus Torvalds } 30551da177e4SLinus Torvalds 3056b37ad28bSAl Viro static __be32 3057b37ad28bSAl Viro nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr) 30581da177e4SLinus Torvalds { 30591da177e4SLinus Torvalds struct svc_fh *fhp = getattr->ga_fhp; 3060d5184658SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 30611da177e4SLinus Torvalds 30621da177e4SLinus Torvalds if (nfserr) 30631da177e4SLinus Torvalds return nfserr; 30641da177e4SLinus Torvalds 3065d5184658SJ. Bruce Fields nfserr = nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry, 3066d5184658SJ. Bruce Fields getattr->ga_bmval, 3067406a7ea9SFrank Filz resp->rqstp, 0); 30681da177e4SLinus Torvalds return nfserr; 30691da177e4SLinus Torvalds } 30701da177e4SLinus Torvalds 3071695e12f8SBenny Halevy static __be32 3072695e12f8SBenny Halevy nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp) 30731da177e4SLinus Torvalds { 3074d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3075695e12f8SBenny Halevy struct svc_fh *fhp = *fhpp; 30761da177e4SLinus Torvalds unsigned int len; 3077bc749ca4SJ. Bruce Fields __be32 *p; 30781da177e4SLinus Torvalds 30791da177e4SLinus Torvalds if (!nfserr) { 30801da177e4SLinus Torvalds len = fhp->fh_handle.fh_size; 3081d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, len + 4); 3082d0a381ddSJ. Bruce Fields if (!p) 3083d0a381ddSJ. Bruce Fields return nfserr_resource; 30840c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, len); 30851da177e4SLinus Torvalds } 3086695e12f8SBenny Halevy return nfserr; 30871da177e4SLinus Torvalds } 30881da177e4SLinus Torvalds 30891da177e4SLinus Torvalds /* 30901da177e4SLinus Torvalds * Including all fields other than the name, a LOCK4denied structure requires 30911da177e4SLinus Torvalds * 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes. 30921da177e4SLinus Torvalds */ 3093d0a381ddSJ. Bruce Fields static __be32 3094d0a381ddSJ. Bruce Fields nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld) 30951da177e4SLinus Torvalds { 30967c13f344SJ. Bruce Fields struct xdr_netobj *conf = &ld->ld_owner; 3097bc749ca4SJ. Bruce Fields __be32 *p; 30981da177e4SLinus Torvalds 30998c7424cfSJ. Bruce Fields again: 3100d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 32 + XDR_LEN(conf->len)); 31018c7424cfSJ. Bruce Fields if (!p) { 31028c7424cfSJ. Bruce Fields /* 31038c7424cfSJ. Bruce Fields * Don't fail to return the result just because we can't 31048c7424cfSJ. Bruce Fields * return the conflicting open: 31058c7424cfSJ. Bruce Fields */ 31068c7424cfSJ. Bruce Fields if (conf->len) { 3107f98bac5aSKinglong Mee kfree(conf->data); 31088c7424cfSJ. Bruce Fields conf->len = 0; 31098c7424cfSJ. Bruce Fields conf->data = NULL; 31108c7424cfSJ. Bruce Fields goto again; 31118c7424cfSJ. Bruce Fields } 3112d0a381ddSJ. Bruce Fields return nfserr_resource; 31138c7424cfSJ. Bruce Fields } 3114b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, ld->ld_start); 3115b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, ld->ld_length); 3116c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ld->ld_type); 31177c13f344SJ. Bruce Fields if (conf->len) { 31180c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &ld->ld_clientid, 8); 31190c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, conf->data, conf->len); 3120f98bac5aSKinglong Mee kfree(conf->data); 31211da177e4SLinus Torvalds } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ 3122b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64)0); /* clientid */ 3123c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* length of owner name */ 31241da177e4SLinus Torvalds } 3125d0a381ddSJ. Bruce Fields return nfserr_denied; 31261da177e4SLinus Torvalds } 31271da177e4SLinus Torvalds 3128695e12f8SBenny Halevy static __be32 3129b37ad28bSAl Viro nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) 31301da177e4SLinus Torvalds { 3131d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3132d0a381ddSJ. Bruce Fields 3133e2f282b9SBenny Halevy if (!nfserr) 3134d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid); 3135e2f282b9SBenny Halevy else if (nfserr == nfserr_denied) 3136d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied); 3137f98bac5aSKinglong Mee 3138695e12f8SBenny Halevy return nfserr; 31391da177e4SLinus Torvalds } 31401da177e4SLinus Torvalds 3141695e12f8SBenny Halevy static __be32 3142b37ad28bSAl Viro nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) 31431da177e4SLinus Torvalds { 3144d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3145d0a381ddSJ. Bruce Fields 31461da177e4SLinus Torvalds if (nfserr == nfserr_denied) 3147d0a381ddSJ. Bruce Fields nfsd4_encode_lock_denied(xdr, &lockt->lt_denied); 3148695e12f8SBenny Halevy return nfserr; 31491da177e4SLinus Torvalds } 31501da177e4SLinus Torvalds 3151695e12f8SBenny Halevy static __be32 3152b37ad28bSAl Viro nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) 31531da177e4SLinus Torvalds { 3154d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3155d0a381ddSJ. Bruce Fields 3156e2f282b9SBenny Halevy if (!nfserr) 3157d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &locku->lu_stateid); 31581da177e4SLinus Torvalds 3159695e12f8SBenny Halevy return nfserr; 31601da177e4SLinus Torvalds } 31611da177e4SLinus Torvalds 31621da177e4SLinus Torvalds 3163695e12f8SBenny Halevy static __be32 3164b37ad28bSAl Viro nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) 31651da177e4SLinus Torvalds { 3166d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3167bc749ca4SJ. Bruce Fields __be32 *p; 31681da177e4SLinus Torvalds 31691da177e4SLinus Torvalds if (!nfserr) { 3170d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 20); 3171d0a381ddSJ. Bruce Fields if (!p) 3172d0a381ddSJ. Bruce Fields return nfserr_resource; 3173d05d5744SJ. Bruce Fields p = encode_cinfo(p, &link->li_cinfo); 31741da177e4SLinus Torvalds } 3175695e12f8SBenny Halevy return nfserr; 31761da177e4SLinus Torvalds } 31771da177e4SLinus Torvalds 31781da177e4SLinus Torvalds 3179695e12f8SBenny Halevy static __be32 3180b37ad28bSAl Viro nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) 31811da177e4SLinus Torvalds { 3182d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3183bc749ca4SJ. Bruce Fields __be32 *p; 31841da177e4SLinus Torvalds 31851da177e4SLinus Torvalds if (nfserr) 31861da177e4SLinus Torvalds goto out; 31871da177e4SLinus Torvalds 3188d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid); 3189d0a381ddSJ. Bruce Fields if (nfserr) 3190d0a381ddSJ. Bruce Fields goto out; 3191d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 40); 3192d0a381ddSJ. Bruce Fields if (!p) 3193d0a381ddSJ. Bruce Fields return nfserr_resource; 3194d05d5744SJ. Bruce Fields p = encode_cinfo(p, &open->op_cinfo); 3195c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_rflags); 3196c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(2); 3197c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_bmval[0]); 3198c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_bmval[1]); 3199c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_delegate_type); 32001da177e4SLinus Torvalds 32011da177e4SLinus Torvalds switch (open->op_delegate_type) { 32021da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_NONE: 32031da177e4SLinus Torvalds break; 32041da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_READ: 3205d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid); 3206d0a381ddSJ. Bruce Fields if (nfserr) 3207d0a381ddSJ. Bruce Fields return nfserr; 3208d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 20); 3209d0a381ddSJ. Bruce Fields if (!p) 3210d0a381ddSJ. Bruce Fields return nfserr_resource; 3211c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_recall); 32121da177e4SLinus Torvalds 32131da177e4SLinus Torvalds /* 32141da177e4SLinus Torvalds * TODO: ACE's in delegations 32151da177e4SLinus Torvalds */ 3216c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); 3217c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3218c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3219c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */ 32201da177e4SLinus Torvalds break; 32211da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_WRITE: 3222d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid); 3223d0a381ddSJ. Bruce Fields if (nfserr) 3224d0a381ddSJ. Bruce Fields return nfserr; 3225d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 32); 3226d0a381ddSJ. Bruce Fields if (!p) 3227d0a381ddSJ. Bruce Fields return nfserr_resource; 3228c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 32291da177e4SLinus Torvalds 32301da177e4SLinus Torvalds /* 32311da177e4SLinus Torvalds * TODO: space_limit's in delegations 32321da177e4SLinus Torvalds */ 3233c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_LIMIT_SIZE); 3234c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(~(u32)0); 3235c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(~(u32)0); 32361da177e4SLinus Torvalds 32371da177e4SLinus Torvalds /* 32381da177e4SLinus Torvalds * TODO: ACE's in delegations 32391da177e4SLinus Torvalds */ 3240c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); 3241c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3242c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3243c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */ 32441da177e4SLinus Torvalds break; 3245d24433cdSBenny Halevy case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */ 3246d24433cdSBenny Halevy switch (open->op_why_no_deleg) { 3247d24433cdSBenny Halevy case WND4_CONTENTION: 3248d24433cdSBenny Halevy case WND4_RESOURCE: 3249d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 3250d0a381ddSJ. Bruce Fields if (!p) 3251d0a381ddSJ. Bruce Fields return nfserr_resource; 3252c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_why_no_deleg); 3253c373b0a4SJ. Bruce Fields /* deleg signaling not supported yet: */ 3254c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3255d24433cdSBenny Halevy break; 3256d24433cdSBenny Halevy default: 3257d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 3258d0a381ddSJ. Bruce Fields if (!p) 3259d0a381ddSJ. Bruce Fields return nfserr_resource; 3260c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_why_no_deleg); 3261d24433cdSBenny Halevy } 3262d24433cdSBenny Halevy break; 32631da177e4SLinus Torvalds default: 32641da177e4SLinus Torvalds BUG(); 32651da177e4SLinus Torvalds } 32661da177e4SLinus Torvalds /* XXX save filehandle here */ 32671da177e4SLinus Torvalds out: 3268695e12f8SBenny Halevy return nfserr; 32691da177e4SLinus Torvalds } 32701da177e4SLinus Torvalds 3271695e12f8SBenny Halevy static __be32 3272b37ad28bSAl Viro nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) 32731da177e4SLinus Torvalds { 3274d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3275d0a381ddSJ. Bruce Fields 3276e2f282b9SBenny Halevy if (!nfserr) 3277d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid); 32781da177e4SLinus Torvalds 3279695e12f8SBenny Halevy return nfserr; 32801da177e4SLinus Torvalds } 32811da177e4SLinus Torvalds 3282695e12f8SBenny Halevy static __be32 3283b37ad28bSAl Viro nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) 32841da177e4SLinus Torvalds { 3285d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3286d0a381ddSJ. Bruce Fields 3287e2f282b9SBenny Halevy if (!nfserr) 3288d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &od->od_stateid); 32891da177e4SLinus Torvalds 3290695e12f8SBenny Halevy return nfserr; 32911da177e4SLinus Torvalds } 32921da177e4SLinus Torvalds 3293dc97618dSJ. Bruce Fields static __be32 nfsd4_encode_splice_read( 3294dc97618dSJ. Bruce Fields struct nfsd4_compoundres *resp, 3295dc97618dSJ. Bruce Fields struct nfsd4_read *read, 3296dc97618dSJ. Bruce Fields struct file *file, unsigned long maxcount) 32971da177e4SLinus Torvalds { 3298dc97618dSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 329934a78b48SJ. Bruce Fields struct xdr_buf *buf = xdr->buf; 3300dc97618dSJ. Bruce Fields u32 eof; 3301dc97618dSJ. Bruce Fields int space_left; 3302dc97618dSJ. Bruce Fields __be32 nfserr; 3303fec25fa4SJ. Bruce Fields __be32 *p = xdr->p - 2; 3304dc97618dSJ. Bruce Fields 3305d5d5c304SKinglong Mee /* Make sure there will be room for padding if needed */ 3306d5d5c304SKinglong Mee if (xdr->end - xdr->p < 1) 3307dc97618dSJ. Bruce Fields return nfserr_resource; 3308dc97618dSJ. Bruce Fields 3309dc97618dSJ. Bruce Fields nfserr = nfsd_splice_read(read->rd_rqstp, file, 3310dc97618dSJ. Bruce Fields read->rd_offset, &maxcount); 3311dc97618dSJ. Bruce Fields if (nfserr) { 3312dc97618dSJ. Bruce Fields /* 3313dc97618dSJ. Bruce Fields * nfsd_splice_actor may have already messed with the 3314dc97618dSJ. Bruce Fields * page length; reset it so as not to confuse 3315dc97618dSJ. Bruce Fields * xdr_truncate_encode: 3316dc97618dSJ. Bruce Fields */ 331734a78b48SJ. Bruce Fields buf->page_len = 0; 3318dc97618dSJ. Bruce Fields return nfserr; 3319dc97618dSJ. Bruce Fields } 3320dc97618dSJ. Bruce Fields 3321dc97618dSJ. Bruce Fields eof = (read->rd_offset + maxcount >= 33222b0143b5SDavid Howells d_inode(read->rd_fhp->fh_dentry)->i_size); 3323dc97618dSJ. Bruce Fields 3324fec25fa4SJ. Bruce Fields *(p++) = htonl(eof); 3325fec25fa4SJ. Bruce Fields *(p++) = htonl(maxcount); 3326dc97618dSJ. Bruce Fields 332734a78b48SJ. Bruce Fields buf->page_len = maxcount; 332834a78b48SJ. Bruce Fields buf->len += maxcount; 332915b23ef5SJ. Bruce Fields xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1) 333015b23ef5SJ. Bruce Fields / PAGE_SIZE; 3331dc97618dSJ. Bruce Fields 3332dc97618dSJ. Bruce Fields /* Use rest of head for padding and remaining ops: */ 333334a78b48SJ. Bruce Fields buf->tail[0].iov_base = xdr->p; 333434a78b48SJ. Bruce Fields buf->tail[0].iov_len = 0; 3335fec25fa4SJ. Bruce Fields xdr->iov = buf->tail; 3336dc97618dSJ. Bruce Fields if (maxcount&3) { 3337fec25fa4SJ. Bruce Fields int pad = 4 - (maxcount&3); 3338fec25fa4SJ. Bruce Fields 3339fec25fa4SJ. Bruce Fields *(xdr->p++) = 0; 3340fec25fa4SJ. Bruce Fields 334134a78b48SJ. Bruce Fields buf->tail[0].iov_base += maxcount&3; 3342fec25fa4SJ. Bruce Fields buf->tail[0].iov_len = pad; 3343fec25fa4SJ. Bruce Fields buf->len += pad; 3344dc97618dSJ. Bruce Fields } 3345dc97618dSJ. Bruce Fields 3346dc97618dSJ. Bruce Fields space_left = min_t(int, (void *)xdr->end - (void *)xdr->p, 334734a78b48SJ. Bruce Fields buf->buflen - buf->len); 334834a78b48SJ. Bruce Fields buf->buflen = buf->len + space_left; 3349dc97618dSJ. Bruce Fields xdr->end = (__be32 *)((void *)xdr->end + space_left); 3350dc97618dSJ. Bruce Fields 3351dc97618dSJ. Bruce Fields return 0; 3352dc97618dSJ. Bruce Fields } 3353dc97618dSJ. Bruce Fields 3354dc97618dSJ. Bruce Fields static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, 3355dc97618dSJ. Bruce Fields struct nfsd4_read *read, 3356dc97618dSJ. Bruce Fields struct file *file, unsigned long maxcount) 3357dc97618dSJ. Bruce Fields { 3358dc97618dSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 33591da177e4SLinus Torvalds u32 eof; 3360afc59400SJ. Bruce Fields int v; 3361dc97618dSJ. Bruce Fields int starting_len = xdr->buf->len - 8; 33621da177e4SLinus Torvalds long len; 3363b0420980SJ. Bruce Fields int thislen; 3364dc97618dSJ. Bruce Fields __be32 nfserr; 3365dc97618dSJ. Bruce Fields __be32 tmp; 3366bc749ca4SJ. Bruce Fields __be32 *p; 3367b0420980SJ. Bruce Fields u32 zzz = 0; 3368b0420980SJ. Bruce Fields int pad; 33691da177e4SLinus Torvalds 33701da177e4SLinus Torvalds len = maxcount; 33711da177e4SLinus Torvalds v = 0; 33726ff9897dSJ. Bruce Fields 33731055414fSKinglong Mee thislen = min_t(long, len, ((void *)xdr->end - (void *)xdr->p)); 3374b0420980SJ. Bruce Fields p = xdr_reserve_space(xdr, (thislen+3)&~3); 3375b0420980SJ. Bruce Fields WARN_ON_ONCE(!p); 3376b0420980SJ. Bruce Fields resp->rqstp->rq_vec[v].iov_base = p; 33776ff9897dSJ. Bruce Fields resp->rqstp->rq_vec[v].iov_len = thislen; 3378b0420980SJ. Bruce Fields v++; 3379b0420980SJ. Bruce Fields len -= thislen; 3380b0420980SJ. Bruce Fields 3381b0420980SJ. Bruce Fields while (len) { 3382b0420980SJ. Bruce Fields thislen = min_t(long, len, PAGE_SIZE); 3383b0420980SJ. Bruce Fields p = xdr_reserve_space(xdr, (thislen+3)&~3); 3384b0420980SJ. Bruce Fields WARN_ON_ONCE(!p); 3385b0420980SJ. Bruce Fields resp->rqstp->rq_vec[v].iov_base = p; 3386b0420980SJ. Bruce Fields resp->rqstp->rq_vec[v].iov_len = thislen; 33871da177e4SLinus Torvalds v++; 33886ff9897dSJ. Bruce Fields len -= thislen; 33891da177e4SLinus Torvalds } 33901da177e4SLinus Torvalds read->rd_vlen = v; 33911da177e4SLinus Torvalds 3392dc97618dSJ. Bruce Fields nfserr = nfsd_readv(file, read->rd_offset, resp->rqstp->rq_vec, 3393dc97618dSJ. Bruce Fields read->rd_vlen, &maxcount); 3394dc97618dSJ. Bruce Fields if (nfserr) 33951da177e4SLinus Torvalds return nfserr; 3396b0420980SJ. Bruce Fields xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3)); 3397dc97618dSJ. Bruce Fields 339844524359SNeilBrown eof = (read->rd_offset + maxcount >= 33992b0143b5SDavid Howells d_inode(read->rd_fhp->fh_dentry)->i_size); 34001da177e4SLinus Torvalds 3401dc97618dSJ. Bruce Fields tmp = htonl(eof); 3402dc97618dSJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4); 3403dc97618dSJ. Bruce Fields tmp = htonl(maxcount); 3404dc97618dSJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); 3405dc97618dSJ. Bruce Fields 3406b0420980SJ. Bruce Fields pad = (maxcount&3) ? 4 - (maxcount&3) : 0; 3407b0420980SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount, 3408b0420980SJ. Bruce Fields &zzz, pad); 34091da177e4SLinus Torvalds return 0; 3410dc97618dSJ. Bruce Fields 3411dc97618dSJ. Bruce Fields } 3412dc97618dSJ. Bruce Fields 3413dc97618dSJ. Bruce Fields static __be32 3414dc97618dSJ. Bruce Fields nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, 3415dc97618dSJ. Bruce Fields struct nfsd4_read *read) 3416dc97618dSJ. Bruce Fields { 3417dc97618dSJ. Bruce Fields unsigned long maxcount; 3418dc97618dSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3419dc97618dSJ. Bruce Fields struct file *file = read->rd_filp; 3420dc97618dSJ. Bruce Fields int starting_len = xdr->buf->len; 3421e749a462SChristoph Hellwig struct raparms *ra = NULL; 3422dc97618dSJ. Bruce Fields __be32 *p; 3423dc97618dSJ. Bruce Fields __be32 err; 3424dc97618dSJ. Bruce Fields 3425dc97618dSJ. Bruce Fields if (nfserr) 3426dc97618dSJ. Bruce Fields return nfserr; 3427dc97618dSJ. Bruce Fields 3428dc97618dSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */ 3429dc97618dSJ. Bruce Fields if (!p) { 3430779fb0f3SJeff Layton WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)); 3431dc97618dSJ. Bruce Fields return nfserr_resource; 3432dc97618dSJ. Bruce Fields } 3433779fb0f3SJeff Layton if (resp->xdr.buf->page_len && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) { 3434b0420980SJ. Bruce Fields WARN_ON_ONCE(1); 3435dc97618dSJ. Bruce Fields return nfserr_resource; 3436dc97618dSJ. Bruce Fields } 3437dc97618dSJ. Bruce Fields xdr_commit_encode(xdr); 3438dc97618dSJ. Bruce Fields 3439dc97618dSJ. Bruce Fields maxcount = svc_max_payload(resp->rqstp); 34403c7aa15dSKinglong Mee maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len)); 34413c7aa15dSKinglong Mee maxcount = min_t(unsigned long, maxcount, read->rd_length); 3442dc97618dSJ. Bruce Fields 3443*af90f707SChristoph Hellwig if (read->rd_tmp_file) 3444e749a462SChristoph Hellwig ra = nfsd_init_raparms(file); 3445dc97618dSJ. Bruce Fields 3446779fb0f3SJeff Layton if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) 3447dc97618dSJ. Bruce Fields err = nfsd4_encode_splice_read(resp, read, file, maxcount); 3448dc97618dSJ. Bruce Fields else 3449dc97618dSJ. Bruce Fields err = nfsd4_encode_readv(resp, read, file, maxcount); 3450dc97618dSJ. Bruce Fields 3451e749a462SChristoph Hellwig if (ra) 3452e749a462SChristoph Hellwig nfsd_put_raparams(file, ra); 3453dc97618dSJ. Bruce Fields 3454dc97618dSJ. Bruce Fields if (err) 3455dc97618dSJ. Bruce Fields xdr_truncate_encode(xdr, starting_len); 3456dc97618dSJ. Bruce Fields return err; 34571da177e4SLinus Torvalds } 34581da177e4SLinus Torvalds 3459b37ad28bSAl Viro static __be32 3460b37ad28bSAl Viro nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) 34611da177e4SLinus Torvalds { 34621da177e4SLinus Torvalds int maxcount; 3463476a7b1fSJ. Bruce Fields __be32 wire_count; 3464476a7b1fSJ. Bruce Fields int zero = 0; 3465ddd1ea56SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 34661fcea5b2SJ. Bruce Fields int length_offset = xdr->buf->len; 3467bc749ca4SJ. Bruce Fields __be32 *p; 34681da177e4SLinus Torvalds 34691da177e4SLinus Torvalds if (nfserr) 34701da177e4SLinus Torvalds return nfserr; 34712825a7f9SJ. Bruce Fields 34722825a7f9SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 34732825a7f9SJ. Bruce Fields if (!p) 34742825a7f9SJ. Bruce Fields return nfserr_resource; 34751da177e4SLinus Torvalds maxcount = PAGE_SIZE; 3476d0a381ddSJ. Bruce Fields 3477476a7b1fSJ. Bruce Fields p = xdr_reserve_space(xdr, maxcount); 3478476a7b1fSJ. Bruce Fields if (!p) 34794e21ac4bSJ. Bruce Fields return nfserr_resource; 34801da177e4SLinus Torvalds /* 34811da177e4SLinus Torvalds * XXX: By default, the ->readlink() VFS op will truncate symlinks 34821da177e4SLinus Torvalds * if they would overflow the buffer. Is this kosher in NFSv4? If 34831da177e4SLinus Torvalds * not, one easy fix is: if ->readlink() precisely fills the buffer, 34841da177e4SLinus Torvalds * assume that truncation occurred, and return NFS4ERR_RESOURCE. 34851da177e4SLinus Torvalds */ 3486476a7b1fSJ. Bruce Fields nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, 3487476a7b1fSJ. Bruce Fields (char *)p, &maxcount); 34881da177e4SLinus Torvalds if (nfserr == nfserr_isdir) 3489d3f627c8SJ. Bruce Fields nfserr = nfserr_inval; 3490d3f627c8SJ. Bruce Fields if (nfserr) { 34911fcea5b2SJ. Bruce Fields xdr_truncate_encode(xdr, length_offset); 34921da177e4SLinus Torvalds return nfserr; 3493d3f627c8SJ. Bruce Fields } 34941da177e4SLinus Torvalds 3495476a7b1fSJ. Bruce Fields wire_count = htonl(maxcount); 3496476a7b1fSJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4); 349769bbd9c7SAvi Kivity xdr_truncate_encode(xdr, length_offset + 4 + ALIGN(maxcount, 4)); 3498476a7b1fSJ. Bruce Fields if (maxcount & 3) 3499476a7b1fSJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount, 3500476a7b1fSJ. Bruce Fields &zero, 4 - (maxcount&3)); 35011da177e4SLinus Torvalds return 0; 35021da177e4SLinus Torvalds } 35031da177e4SLinus Torvalds 3504b37ad28bSAl Viro static __be32 3505b37ad28bSAl Viro nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir) 35061da177e4SLinus Torvalds { 35071da177e4SLinus Torvalds int maxcount; 3508561f0ed4SJ. Bruce Fields int bytes_left; 35091da177e4SLinus Torvalds loff_t offset; 3510561f0ed4SJ. Bruce Fields __be64 wire_offset; 3511ddd1ea56SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 35121fcea5b2SJ. Bruce Fields int starting_len = xdr->buf->len; 3513bc749ca4SJ. Bruce Fields __be32 *p; 35141da177e4SLinus Torvalds 35151da177e4SLinus Torvalds if (nfserr) 35161da177e4SLinus Torvalds return nfserr; 35171da177e4SLinus Torvalds 3518d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE); 3519d0a381ddSJ. Bruce Fields if (!p) 3520d0a381ddSJ. Bruce Fields return nfserr_resource; 35211da177e4SLinus Torvalds 35221da177e4SLinus Torvalds /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */ 3523c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3524c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 35254aea24b2SJ. Bruce Fields resp->xdr.buf->head[0].iov_len = ((char *)resp->xdr.p) 35264aea24b2SJ. Bruce Fields - (char *)resp->xdr.buf->head[0].iov_base; 35271da177e4SLinus Torvalds 35281da177e4SLinus Torvalds /* 3529561f0ed4SJ. Bruce Fields * Number of bytes left for directory entries allowing for the 3530561f0ed4SJ. Bruce Fields * final 8 bytes of the readdir and a following failed op: 35311da177e4SLinus Torvalds */ 3532561f0ed4SJ. Bruce Fields bytes_left = xdr->buf->buflen - xdr->buf->len 3533561f0ed4SJ. Bruce Fields - COMPOUND_ERR_SLACK_SPACE - 8; 3534561f0ed4SJ. Bruce Fields if (bytes_left < 0) { 3535561f0ed4SJ. Bruce Fields nfserr = nfserr_resource; 3536561f0ed4SJ. Bruce Fields goto err_no_verf; 3537561f0ed4SJ. Bruce Fields } 3538561f0ed4SJ. Bruce Fields maxcount = min_t(u32, readdir->rd_maxcount, INT_MAX); 3539561f0ed4SJ. Bruce Fields /* 3540561f0ed4SJ. Bruce Fields * Note the rfc defines rd_maxcount as the size of the 3541561f0ed4SJ. Bruce Fields * READDIR4resok structure, which includes the verifier above 3542561f0ed4SJ. Bruce Fields * and the 8 bytes encoded at the end of this function: 3543561f0ed4SJ. Bruce Fields */ 3544561f0ed4SJ. Bruce Fields if (maxcount < 16) { 35451da177e4SLinus Torvalds nfserr = nfserr_toosmall; 35461da177e4SLinus Torvalds goto err_no_verf; 35471da177e4SLinus Torvalds } 3548561f0ed4SJ. Bruce Fields maxcount = min_t(int, maxcount-16, bytes_left); 35491da177e4SLinus Torvalds 3550aee37764SJ. Bruce Fields /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */ 3551aee37764SJ. Bruce Fields if (!readdir->rd_dircount) 3552aee37764SJ. Bruce Fields readdir->rd_dircount = INT_MAX; 3553aee37764SJ. Bruce Fields 3554561f0ed4SJ. Bruce Fields readdir->xdr = xdr; 3555561f0ed4SJ. Bruce Fields readdir->rd_maxcount = maxcount; 35561da177e4SLinus Torvalds readdir->common.err = 0; 3557561f0ed4SJ. Bruce Fields readdir->cookie_offset = 0; 35581da177e4SLinus Torvalds 35591da177e4SLinus Torvalds offset = readdir->rd_cookie; 35601da177e4SLinus Torvalds nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, 35611da177e4SLinus Torvalds &offset, 35621da177e4SLinus Torvalds &readdir->common, nfsd4_encode_dirent); 35631da177e4SLinus Torvalds if (nfserr == nfs_ok && 35641da177e4SLinus Torvalds readdir->common.err == nfserr_toosmall && 3565561f0ed4SJ. Bruce Fields xdr->buf->len == starting_len + 8) { 3566561f0ed4SJ. Bruce Fields /* nothing encoded; which limit did we hit?: */ 3567561f0ed4SJ. Bruce Fields if (maxcount - 16 < bytes_left) 3568561f0ed4SJ. Bruce Fields /* It was the fault of rd_maxcount: */ 35691da177e4SLinus Torvalds nfserr = nfserr_toosmall; 3570561f0ed4SJ. Bruce Fields else 3571561f0ed4SJ. Bruce Fields /* We ran out of buffer space: */ 3572561f0ed4SJ. Bruce Fields nfserr = nfserr_resource; 3573561f0ed4SJ. Bruce Fields } 35741da177e4SLinus Torvalds if (nfserr) 35751da177e4SLinus Torvalds goto err_no_verf; 35761da177e4SLinus Torvalds 3577561f0ed4SJ. Bruce Fields if (readdir->cookie_offset) { 3578561f0ed4SJ. Bruce Fields wire_offset = cpu_to_be64(offset); 3579561f0ed4SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, readdir->cookie_offset, 3580561f0ed4SJ. Bruce Fields &wire_offset, 8); 3581561f0ed4SJ. Bruce Fields } 35821da177e4SLinus Torvalds 3583561f0ed4SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 3584561f0ed4SJ. Bruce Fields if (!p) { 3585561f0ed4SJ. Bruce Fields WARN_ON_ONCE(1); 3586561f0ed4SJ. Bruce Fields goto err_no_verf; 3587561f0ed4SJ. Bruce Fields } 35881da177e4SLinus Torvalds *p++ = 0; /* no more entries */ 35891da177e4SLinus Torvalds *p++ = htonl(readdir->common.err == nfserr_eof); 35901da177e4SLinus Torvalds 35911da177e4SLinus Torvalds return 0; 35921da177e4SLinus Torvalds err_no_verf: 35931fcea5b2SJ. Bruce Fields xdr_truncate_encode(xdr, starting_len); 35941da177e4SLinus Torvalds return nfserr; 35951da177e4SLinus Torvalds } 35961da177e4SLinus Torvalds 3597695e12f8SBenny Halevy static __be32 3598b37ad28bSAl Viro nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) 35991da177e4SLinus Torvalds { 3600d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3601bc749ca4SJ. Bruce Fields __be32 *p; 36021da177e4SLinus Torvalds 36031da177e4SLinus Torvalds if (!nfserr) { 3604d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 20); 3605d0a381ddSJ. Bruce Fields if (!p) 3606d0a381ddSJ. Bruce Fields return nfserr_resource; 3607d05d5744SJ. Bruce Fields p = encode_cinfo(p, &remove->rm_cinfo); 36081da177e4SLinus Torvalds } 3609695e12f8SBenny Halevy return nfserr; 36101da177e4SLinus Torvalds } 36111da177e4SLinus Torvalds 3612695e12f8SBenny Halevy static __be32 3613b37ad28bSAl Viro nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) 36141da177e4SLinus Torvalds { 3615d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3616bc749ca4SJ. Bruce Fields __be32 *p; 36171da177e4SLinus Torvalds 36181da177e4SLinus Torvalds if (!nfserr) { 3619d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 40); 3620d0a381ddSJ. Bruce Fields if (!p) 3621d0a381ddSJ. Bruce Fields return nfserr_resource; 3622d05d5744SJ. Bruce Fields p = encode_cinfo(p, &rename->rn_sinfo); 3623d05d5744SJ. Bruce Fields p = encode_cinfo(p, &rename->rn_tinfo); 36241da177e4SLinus Torvalds } 3625695e12f8SBenny Halevy return nfserr; 36261da177e4SLinus Torvalds } 36271da177e4SLinus Torvalds 3628695e12f8SBenny Halevy static __be32 3629d0a381ddSJ. Bruce Fields nfsd4_do_encode_secinfo(struct xdr_stream *xdr, 363022b6dee8SMi Jinlong __be32 nfserr, struct svc_export *exp) 3631dcb488a3SAndy Adamson { 3632676e4ebdSChuck Lever u32 i, nflavs, supported; 36334796f457SJ. Bruce Fields struct exp_flavor_info *flavs; 36344796f457SJ. Bruce Fields struct exp_flavor_info def_flavs[2]; 3635676e4ebdSChuck Lever __be32 *p, *flavorsp; 3636676e4ebdSChuck Lever static bool report = true; 3637dcb488a3SAndy Adamson 3638dcb488a3SAndy Adamson if (nfserr) 3639dcb488a3SAndy Adamson goto out; 3640d0a381ddSJ. Bruce Fields nfserr = nfserr_resource; 36414796f457SJ. Bruce Fields if (exp->ex_nflavors) { 36424796f457SJ. Bruce Fields flavs = exp->ex_flavors; 36434796f457SJ. Bruce Fields nflavs = exp->ex_nflavors; 36444796f457SJ. Bruce Fields } else { /* Handling of some defaults in absence of real secinfo: */ 36454796f457SJ. Bruce Fields flavs = def_flavs; 36464796f457SJ. Bruce Fields if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) { 36474796f457SJ. Bruce Fields nflavs = 2; 36484796f457SJ. Bruce Fields flavs[0].pseudoflavor = RPC_AUTH_UNIX; 36494796f457SJ. Bruce Fields flavs[1].pseudoflavor = RPC_AUTH_NULL; 36504796f457SJ. Bruce Fields } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) { 36514796f457SJ. Bruce Fields nflavs = 1; 36524796f457SJ. Bruce Fields flavs[0].pseudoflavor 36534796f457SJ. Bruce Fields = svcauth_gss_flavor(exp->ex_client); 36544796f457SJ. Bruce Fields } else { 36554796f457SJ. Bruce Fields nflavs = 1; 36564796f457SJ. Bruce Fields flavs[0].pseudoflavor 36574796f457SJ. Bruce Fields = exp->ex_client->flavour->flavour; 36584796f457SJ. Bruce Fields } 36594796f457SJ. Bruce Fields } 36604796f457SJ. Bruce Fields 3661676e4ebdSChuck Lever supported = 0; 3662d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 3663d0a381ddSJ. Bruce Fields if (!p) 3664d0a381ddSJ. Bruce Fields goto out; 3665676e4ebdSChuck Lever flavorsp = p++; /* to be backfilled later */ 3666676e4ebdSChuck Lever 36674796f457SJ. Bruce Fields for (i = 0; i < nflavs; i++) { 3668676e4ebdSChuck Lever rpc_authflavor_t pf = flavs[i].pseudoflavor; 3669a77c806fSChuck Lever struct rpcsec_gss_info info; 3670dcb488a3SAndy Adamson 3671676e4ebdSChuck Lever if (rpcauth_get_gssinfo(pf, &info) == 0) { 3672676e4ebdSChuck Lever supported++; 3673d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4 + 4 + 3674d0a381ddSJ. Bruce Fields XDR_LEN(info.oid.len) + 4 + 4); 3675d0a381ddSJ. Bruce Fields if (!p) 3676d0a381ddSJ. Bruce Fields goto out; 3677c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(RPC_AUTH_GSS); 36780c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, info.oid.data, info.oid.len); 3679c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(info.qop); 3680c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(info.service); 3681676e4ebdSChuck Lever } else if (pf < RPC_AUTH_MAXFLAVOR) { 3682676e4ebdSChuck Lever supported++; 3683d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 3684d0a381ddSJ. Bruce Fields if (!p) 3685d0a381ddSJ. Bruce Fields goto out; 3686c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(pf); 3687676e4ebdSChuck Lever } else { 3688676e4ebdSChuck Lever if (report) 3689676e4ebdSChuck Lever pr_warn("NFS: SECINFO: security flavor %u " 3690676e4ebdSChuck Lever "is not supported\n", pf); 3691dcb488a3SAndy Adamson } 3692dcb488a3SAndy Adamson } 3693a77c806fSChuck Lever 3694676e4ebdSChuck Lever if (nflavs != supported) 3695676e4ebdSChuck Lever report = false; 3696676e4ebdSChuck Lever *flavorsp = htonl(supported); 3697d0a381ddSJ. Bruce Fields nfserr = 0; 3698dcb488a3SAndy Adamson out: 3699dcb488a3SAndy Adamson if (exp) 3700dcb488a3SAndy Adamson exp_put(exp); 3701695e12f8SBenny Halevy return nfserr; 3702dcb488a3SAndy Adamson } 3703dcb488a3SAndy Adamson 370422b6dee8SMi Jinlong static __be32 370522b6dee8SMi Jinlong nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, 370622b6dee8SMi Jinlong struct nfsd4_secinfo *secinfo) 370722b6dee8SMi Jinlong { 3708d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3709d0a381ddSJ. Bruce Fields 3710d0a381ddSJ. Bruce Fields return nfsd4_do_encode_secinfo(xdr, nfserr, secinfo->si_exp); 371122b6dee8SMi Jinlong } 371222b6dee8SMi Jinlong 371322b6dee8SMi Jinlong static __be32 371422b6dee8SMi Jinlong nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, 371522b6dee8SMi Jinlong struct nfsd4_secinfo_no_name *secinfo) 371622b6dee8SMi Jinlong { 3717d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3718d0a381ddSJ. Bruce Fields 3719d0a381ddSJ. Bruce Fields return nfsd4_do_encode_secinfo(xdr, nfserr, secinfo->sin_exp); 372022b6dee8SMi Jinlong } 372122b6dee8SMi Jinlong 37221da177e4SLinus Torvalds /* 37231da177e4SLinus Torvalds * The SETATTR encode routine is special -- it always encodes a bitmap, 37241da177e4SLinus Torvalds * regardless of the error status. 37251da177e4SLinus Torvalds */ 3726695e12f8SBenny Halevy static __be32 3727b37ad28bSAl Viro nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) 37281da177e4SLinus Torvalds { 3729d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3730bc749ca4SJ. Bruce Fields __be32 *p; 37311da177e4SLinus Torvalds 3732d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 3733d0a381ddSJ. Bruce Fields if (!p) 3734d0a381ddSJ. Bruce Fields return nfserr_resource; 37351da177e4SLinus Torvalds if (nfserr) { 3736c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(3); 3737c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3738c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3739c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 37401da177e4SLinus Torvalds } 37411da177e4SLinus Torvalds else { 3742c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(3); 3743c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(setattr->sa_bmval[0]); 3744c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(setattr->sa_bmval[1]); 3745c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(setattr->sa_bmval[2]); 37461da177e4SLinus Torvalds } 3747695e12f8SBenny Halevy return nfserr; 37481da177e4SLinus Torvalds } 37491da177e4SLinus Torvalds 3750695e12f8SBenny Halevy static __be32 3751b37ad28bSAl Viro nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) 37521da177e4SLinus Torvalds { 3753d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3754bc749ca4SJ. Bruce Fields __be32 *p; 37551da177e4SLinus Torvalds 37561da177e4SLinus Torvalds if (!nfserr) { 3757d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8 + NFS4_VERIFIER_SIZE); 3758d0a381ddSJ. Bruce Fields if (!p) 3759d0a381ddSJ. Bruce Fields return nfserr_resource; 37600c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &scd->se_clientid, 8); 37610c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &scd->se_confirm, 37620c0c267bSJ. Bruce Fields NFS4_VERIFIER_SIZE); 37631da177e4SLinus Torvalds } 37641da177e4SLinus Torvalds else if (nfserr == nfserr_clid_inuse) { 3765d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 3766d0a381ddSJ. Bruce Fields if (!p) 3767d0a381ddSJ. Bruce Fields return nfserr_resource; 3768c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3769c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 37701da177e4SLinus Torvalds } 3771695e12f8SBenny Halevy return nfserr; 37721da177e4SLinus Torvalds } 37731da177e4SLinus Torvalds 3774695e12f8SBenny Halevy static __be32 3775b37ad28bSAl Viro nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) 37761da177e4SLinus Torvalds { 3777d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3778bc749ca4SJ. Bruce Fields __be32 *p; 37791da177e4SLinus Torvalds 37801da177e4SLinus Torvalds if (!nfserr) { 3781d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 3782d0a381ddSJ. Bruce Fields if (!p) 3783d0a381ddSJ. Bruce Fields return nfserr_resource; 3784c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(write->wr_bytes_written); 3785c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(write->wr_how_written); 37860c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, write->wr_verifier.data, 37870c0c267bSJ. Bruce Fields NFS4_VERIFIER_SIZE); 37881da177e4SLinus Torvalds } 3789695e12f8SBenny Halevy return nfserr; 37901da177e4SLinus Torvalds } 37911da177e4SLinus Torvalds 379257266a6eSJ. Bruce Fields static const u32 nfs4_minimal_spo_must_enforce[2] = { 379357266a6eSJ. Bruce Fields [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) | 379457266a6eSJ. Bruce Fields 1 << (OP_EXCHANGE_ID - 32) | 379557266a6eSJ. Bruce Fields 1 << (OP_CREATE_SESSION - 32) | 379657266a6eSJ. Bruce Fields 1 << (OP_DESTROY_SESSION - 32) | 379757266a6eSJ. Bruce Fields 1 << (OP_DESTROY_CLIENTID - 32) 379857266a6eSJ. Bruce Fields }; 379957266a6eSJ. Bruce Fields 3800695e12f8SBenny Halevy static __be32 380157b7b43bSJ. Bruce Fields nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, 38022db134ebSAndy Adamson struct nfsd4_exchange_id *exid) 38032db134ebSAndy Adamson { 3804d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3805bc749ca4SJ. Bruce Fields __be32 *p; 38060733d213SAndy Adamson char *major_id; 38070733d213SAndy Adamson char *server_scope; 38080733d213SAndy Adamson int major_id_sz; 38090733d213SAndy Adamson int server_scope_sz; 38100733d213SAndy Adamson uint64_t minor_id = 0; 38110733d213SAndy Adamson 38120733d213SAndy Adamson if (nfserr) 38132db134ebSAndy Adamson return nfserr; 38140733d213SAndy Adamson 38150733d213SAndy Adamson major_id = utsname()->nodename; 38160733d213SAndy Adamson major_id_sz = strlen(major_id); 38170733d213SAndy Adamson server_scope = utsname()->nodename; 38180733d213SAndy Adamson server_scope_sz = strlen(server_scope); 38190733d213SAndy Adamson 3820d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 38210733d213SAndy Adamson 8 /* eir_clientid */ + 38220733d213SAndy Adamson 4 /* eir_sequenceid */ + 38230733d213SAndy Adamson 4 /* eir_flags */ + 3824a8bb84bcSKinglong Mee 4 /* spr_how */); 3825d0a381ddSJ. Bruce Fields if (!p) 3826d0a381ddSJ. Bruce Fields return nfserr_resource; 38270733d213SAndy Adamson 38280c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &exid->clientid, 8); 3829c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(exid->seqid); 3830c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(exid->flags); 38310733d213SAndy Adamson 3832c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(exid->spa_how); 3833a8bb84bcSKinglong Mee 383457266a6eSJ. Bruce Fields switch (exid->spa_how) { 383557266a6eSJ. Bruce Fields case SP4_NONE: 383657266a6eSJ. Bruce Fields break; 383757266a6eSJ. Bruce Fields case SP4_MACH_CRED: 3838a8bb84bcSKinglong Mee /* spo_must_enforce, spo_must_allow */ 3839d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 3840d0a381ddSJ. Bruce Fields if (!p) 3841d0a381ddSJ. Bruce Fields return nfserr_resource; 3842a8bb84bcSKinglong Mee 384357266a6eSJ. Bruce Fields /* spo_must_enforce bitmap: */ 3844c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(2); 3845c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(nfs4_minimal_spo_must_enforce[0]); 3846c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(nfs4_minimal_spo_must_enforce[1]); 384757266a6eSJ. Bruce Fields /* empty spo_must_allow bitmap: */ 3848c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3849a8bb84bcSKinglong Mee 385057266a6eSJ. Bruce Fields break; 385157266a6eSJ. Bruce Fields default: 385257266a6eSJ. Bruce Fields WARN_ON_ONCE(1); 385357266a6eSJ. Bruce Fields } 38540733d213SAndy Adamson 3855d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 3856a8bb84bcSKinglong Mee 8 /* so_minor_id */ + 3857a8bb84bcSKinglong Mee 4 /* so_major_id.len */ + 3858a8bb84bcSKinglong Mee (XDR_QUADLEN(major_id_sz) * 4) + 3859a8bb84bcSKinglong Mee 4 /* eir_server_scope.len */ + 3860a8bb84bcSKinglong Mee (XDR_QUADLEN(server_scope_sz) * 4) + 3861a8bb84bcSKinglong Mee 4 /* eir_server_impl_id.count (0) */); 3862d0a381ddSJ. Bruce Fields if (!p) 3863d0a381ddSJ. Bruce Fields return nfserr_resource; 3864a8bb84bcSKinglong Mee 38650733d213SAndy Adamson /* The server_owner struct */ 3866b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, minor_id); /* Minor id */ 38670733d213SAndy Adamson /* major id */ 38680c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, major_id, major_id_sz); 38690733d213SAndy Adamson 38700733d213SAndy Adamson /* Server scope */ 38710c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, server_scope, server_scope_sz); 38720733d213SAndy Adamson 38730733d213SAndy Adamson /* Implementation id */ 3874c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* zero length nfs_impl_id4 array */ 38750733d213SAndy Adamson return 0; 38762db134ebSAndy Adamson } 38772db134ebSAndy Adamson 38782db134ebSAndy Adamson static __be32 387957b7b43bSJ. Bruce Fields nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, 38802db134ebSAndy Adamson struct nfsd4_create_session *sess) 38812db134ebSAndy Adamson { 3882d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3883bc749ca4SJ. Bruce Fields __be32 *p; 3884ec6b5d7bSAndy Adamson 3885ec6b5d7bSAndy Adamson if (nfserr) 38862db134ebSAndy Adamson return nfserr; 3887ec6b5d7bSAndy Adamson 3888d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 24); 3889d0a381ddSJ. Bruce Fields if (!p) 3890d0a381ddSJ. Bruce Fields return nfserr_resource; 38910c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, sess->sessionid.data, 38920c0c267bSJ. Bruce Fields NFS4_MAX_SESSIONID_LEN); 3893c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->seqid); 3894c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->flags); 3895ec6b5d7bSAndy Adamson 3896d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 28); 3897d0a381ddSJ. Bruce Fields if (!p) 3898d0a381ddSJ. Bruce Fields return nfserr_resource; 3899c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* headerpadsz */ 3900c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxreq_sz); 3901c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxresp_sz); 3902c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxresp_cached); 3903c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxops); 3904c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxreqs); 3905c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.nr_rdma_attrs); 3906ec6b5d7bSAndy Adamson 3907ec6b5d7bSAndy Adamson if (sess->fore_channel.nr_rdma_attrs) { 3908d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 3909d0a381ddSJ. Bruce Fields if (!p) 3910d0a381ddSJ. Bruce Fields return nfserr_resource; 3911c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.rdma_attrs); 3912ec6b5d7bSAndy Adamson } 3913ec6b5d7bSAndy Adamson 3914d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 28); 3915d0a381ddSJ. Bruce Fields if (!p) 3916d0a381ddSJ. Bruce Fields return nfserr_resource; 3917c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* headerpadsz */ 3918c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxreq_sz); 3919c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxresp_sz); 3920c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxresp_cached); 3921c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxops); 3922c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxreqs); 3923c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.nr_rdma_attrs); 3924ec6b5d7bSAndy Adamson 3925ec6b5d7bSAndy Adamson if (sess->back_channel.nr_rdma_attrs) { 3926d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 3927d0a381ddSJ. Bruce Fields if (!p) 3928d0a381ddSJ. Bruce Fields return nfserr_resource; 3929c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.rdma_attrs); 3930ec6b5d7bSAndy Adamson } 3931ec6b5d7bSAndy Adamson return 0; 39322db134ebSAndy Adamson } 39332db134ebSAndy Adamson 39342db134ebSAndy Adamson static __be32 393557b7b43bSJ. Bruce Fields nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, 39362db134ebSAndy Adamson struct nfsd4_sequence *seq) 39372db134ebSAndy Adamson { 3938d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3939bc749ca4SJ. Bruce Fields __be32 *p; 3940b85d4c01SBenny Halevy 3941b85d4c01SBenny Halevy if (nfserr) 39422db134ebSAndy Adamson return nfserr; 3943b85d4c01SBenny Halevy 3944d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20); 3945d0a381ddSJ. Bruce Fields if (!p) 3946d0a381ddSJ. Bruce Fields return nfserr_resource; 39470c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, seq->sessionid.data, 39480c0c267bSJ. Bruce Fields NFS4_MAX_SESSIONID_LEN); 3949c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->seqid); 3950c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->slotid); 3951b7d7ca35SJ. Bruce Fields /* Note slotid's are numbered from zero: */ 3952c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_highest_slotid */ 3953c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_target_highest_slotid */ 3954c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->status_flags); 3955b85d4c01SBenny Halevy 3956f5236013SJ. Bruce Fields resp->cstate.data_offset = xdr->buf->len; /* DRC cache data pointer */ 3957b85d4c01SBenny Halevy return 0; 39582db134ebSAndy Adamson } 39592db134ebSAndy Adamson 39602355c596SJ. Bruce Fields static __be32 396157b7b43bSJ. Bruce Fields nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, 396217456804SBryan Schumaker struct nfsd4_test_stateid *test_stateid) 396317456804SBryan Schumaker { 3964d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 396503cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid, *next; 396617456804SBryan Schumaker __be32 *p; 396717456804SBryan Schumaker 3968a11fcce1SJ. Bruce Fields if (nfserr) 3969a11fcce1SJ. Bruce Fields return nfserr; 3970a11fcce1SJ. Bruce Fields 3971d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4 + (4 * test_stateid->ts_num_ids)); 3972d0a381ddSJ. Bruce Fields if (!p) 3973d0a381ddSJ. Bruce Fields return nfserr_resource; 397417456804SBryan Schumaker *p++ = htonl(test_stateid->ts_num_ids); 397517456804SBryan Schumaker 397603cfb420SBryan Schumaker list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) { 397702f5fde5SAl Viro *p++ = stateid->ts_id_status; 397817456804SBryan Schumaker } 397917456804SBryan Schumaker 398017456804SBryan Schumaker return nfserr; 398117456804SBryan Schumaker } 398217456804SBryan Schumaker 39839cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 39849cf514ccSChristoph Hellwig static __be32 39859cf514ccSChristoph Hellwig nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, 39869cf514ccSChristoph Hellwig struct nfsd4_getdeviceinfo *gdev) 39879cf514ccSChristoph Hellwig { 39889cf514ccSChristoph Hellwig struct xdr_stream *xdr = &resp->xdr; 39899cf514ccSChristoph Hellwig const struct nfsd4_layout_ops *ops = 39909cf514ccSChristoph Hellwig nfsd4_layout_ops[gdev->gd_layout_type]; 39919cf514ccSChristoph Hellwig u32 starting_len = xdr->buf->len, needed_len; 39929cf514ccSChristoph Hellwig __be32 *p; 39939cf514ccSChristoph Hellwig 39949cf514ccSChristoph Hellwig dprintk("%s: err %d\n", __func__, nfserr); 39959cf514ccSChristoph Hellwig if (nfserr) 39969cf514ccSChristoph Hellwig goto out; 39979cf514ccSChristoph Hellwig 39989cf514ccSChristoph Hellwig nfserr = nfserr_resource; 39999cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 40009cf514ccSChristoph Hellwig if (!p) 40019cf514ccSChristoph Hellwig goto out; 40029cf514ccSChristoph Hellwig 40039cf514ccSChristoph Hellwig *p++ = cpu_to_be32(gdev->gd_layout_type); 40049cf514ccSChristoph Hellwig 40059cf514ccSChristoph Hellwig /* If maxcount is 0 then just update notifications */ 40069cf514ccSChristoph Hellwig if (gdev->gd_maxcount != 0) { 40079cf514ccSChristoph Hellwig nfserr = ops->encode_getdeviceinfo(xdr, gdev); 40089cf514ccSChristoph Hellwig if (nfserr) { 40099cf514ccSChristoph Hellwig /* 40109cf514ccSChristoph Hellwig * We don't bother to burden the layout drivers with 40119cf514ccSChristoph Hellwig * enforcing gd_maxcount, just tell the client to 40129cf514ccSChristoph Hellwig * come back with a bigger buffer if it's not enough. 40139cf514ccSChristoph Hellwig */ 40149cf514ccSChristoph Hellwig if (xdr->buf->len + 4 > gdev->gd_maxcount) 40159cf514ccSChristoph Hellwig goto toosmall; 40169cf514ccSChristoph Hellwig goto out; 40179cf514ccSChristoph Hellwig } 40189cf514ccSChristoph Hellwig } 40199cf514ccSChristoph Hellwig 40209cf514ccSChristoph Hellwig nfserr = nfserr_resource; 40219cf514ccSChristoph Hellwig if (gdev->gd_notify_types) { 40229cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4 + 4); 40239cf514ccSChristoph Hellwig if (!p) 40249cf514ccSChristoph Hellwig goto out; 40259cf514ccSChristoph Hellwig *p++ = cpu_to_be32(1); /* bitmap length */ 40269cf514ccSChristoph Hellwig *p++ = cpu_to_be32(gdev->gd_notify_types); 40279cf514ccSChristoph Hellwig } else { 40289cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 40299cf514ccSChristoph Hellwig if (!p) 40309cf514ccSChristoph Hellwig goto out; 40319cf514ccSChristoph Hellwig *p++ = 0; 40329cf514ccSChristoph Hellwig } 40339cf514ccSChristoph Hellwig 40349cf514ccSChristoph Hellwig nfserr = 0; 40359cf514ccSChristoph Hellwig out: 40369cf514ccSChristoph Hellwig kfree(gdev->gd_device); 40379cf514ccSChristoph Hellwig dprintk("%s: done: %d\n", __func__, be32_to_cpu(nfserr)); 40389cf514ccSChristoph Hellwig return nfserr; 40399cf514ccSChristoph Hellwig 40409cf514ccSChristoph Hellwig toosmall: 40419cf514ccSChristoph Hellwig dprintk("%s: maxcount too small\n", __func__); 40429cf514ccSChristoph Hellwig needed_len = xdr->buf->len + 4 /* notifications */; 40439cf514ccSChristoph Hellwig xdr_truncate_encode(xdr, starting_len); 40449cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 40459cf514ccSChristoph Hellwig if (!p) { 40469cf514ccSChristoph Hellwig nfserr = nfserr_resource; 40479cf514ccSChristoph Hellwig } else { 40489cf514ccSChristoph Hellwig *p++ = cpu_to_be32(needed_len); 40499cf514ccSChristoph Hellwig nfserr = nfserr_toosmall; 40509cf514ccSChristoph Hellwig } 40519cf514ccSChristoph Hellwig goto out; 40529cf514ccSChristoph Hellwig } 40539cf514ccSChristoph Hellwig 40549cf514ccSChristoph Hellwig static __be32 40559cf514ccSChristoph Hellwig nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr, 40569cf514ccSChristoph Hellwig struct nfsd4_layoutget *lgp) 40579cf514ccSChristoph Hellwig { 40589cf514ccSChristoph Hellwig struct xdr_stream *xdr = &resp->xdr; 40599cf514ccSChristoph Hellwig const struct nfsd4_layout_ops *ops = 40609cf514ccSChristoph Hellwig nfsd4_layout_ops[lgp->lg_layout_type]; 40619cf514ccSChristoph Hellwig __be32 *p; 40629cf514ccSChristoph Hellwig 40639cf514ccSChristoph Hellwig dprintk("%s: err %d\n", __func__, nfserr); 40649cf514ccSChristoph Hellwig if (nfserr) 40659cf514ccSChristoph Hellwig goto out; 40669cf514ccSChristoph Hellwig 40679cf514ccSChristoph Hellwig nfserr = nfserr_resource; 40689cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 36 + sizeof(stateid_opaque_t)); 40699cf514ccSChristoph Hellwig if (!p) 40709cf514ccSChristoph Hellwig goto out; 40719cf514ccSChristoph Hellwig 40729cf514ccSChristoph Hellwig *p++ = cpu_to_be32(1); /* we always set return-on-close */ 40739cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lgp->lg_sid.si_generation); 40749cf514ccSChristoph Hellwig p = xdr_encode_opaque_fixed(p, &lgp->lg_sid.si_opaque, 40759cf514ccSChristoph Hellwig sizeof(stateid_opaque_t)); 40769cf514ccSChristoph Hellwig 40779cf514ccSChristoph Hellwig *p++ = cpu_to_be32(1); /* we always return a single layout */ 40789cf514ccSChristoph Hellwig p = xdr_encode_hyper(p, lgp->lg_seg.offset); 40799cf514ccSChristoph Hellwig p = xdr_encode_hyper(p, lgp->lg_seg.length); 40809cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lgp->lg_seg.iomode); 40819cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lgp->lg_layout_type); 40829cf514ccSChristoph Hellwig 40839cf514ccSChristoph Hellwig nfserr = ops->encode_layoutget(xdr, lgp); 40849cf514ccSChristoph Hellwig out: 40859cf514ccSChristoph Hellwig kfree(lgp->lg_content); 40869cf514ccSChristoph Hellwig return nfserr; 40879cf514ccSChristoph Hellwig } 40889cf514ccSChristoph Hellwig 40899cf514ccSChristoph Hellwig static __be32 40909cf514ccSChristoph Hellwig nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr, 40919cf514ccSChristoph Hellwig struct nfsd4_layoutcommit *lcp) 40929cf514ccSChristoph Hellwig { 40939cf514ccSChristoph Hellwig struct xdr_stream *xdr = &resp->xdr; 40949cf514ccSChristoph Hellwig __be32 *p; 40959cf514ccSChristoph Hellwig 40969cf514ccSChristoph Hellwig if (nfserr) 40979cf514ccSChristoph Hellwig return nfserr; 40989cf514ccSChristoph Hellwig 40999cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 41009cf514ccSChristoph Hellwig if (!p) 41019cf514ccSChristoph Hellwig return nfserr_resource; 41029cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lcp->lc_size_chg); 41039cf514ccSChristoph Hellwig if (lcp->lc_size_chg) { 41049cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 8); 41059cf514ccSChristoph Hellwig if (!p) 41069cf514ccSChristoph Hellwig return nfserr_resource; 41079cf514ccSChristoph Hellwig p = xdr_encode_hyper(p, lcp->lc_newsize); 41089cf514ccSChristoph Hellwig } 41099cf514ccSChristoph Hellwig 41109cf514ccSChristoph Hellwig return nfs_ok; 41119cf514ccSChristoph Hellwig } 41129cf514ccSChristoph Hellwig 41139cf514ccSChristoph Hellwig static __be32 41149cf514ccSChristoph Hellwig nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, 41159cf514ccSChristoph Hellwig struct nfsd4_layoutreturn *lrp) 41169cf514ccSChristoph Hellwig { 41179cf514ccSChristoph Hellwig struct xdr_stream *xdr = &resp->xdr; 41189cf514ccSChristoph Hellwig __be32 *p; 41199cf514ccSChristoph Hellwig 41209cf514ccSChristoph Hellwig if (nfserr) 41219cf514ccSChristoph Hellwig return nfserr; 41229cf514ccSChristoph Hellwig 41239cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 41249cf514ccSChristoph Hellwig if (!p) 41259cf514ccSChristoph Hellwig return nfserr_resource; 41269cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lrp->lrs_present); 41279cf514ccSChristoph Hellwig if (lrp->lrs_present) 4128376675daSKinglong Mee return nfsd4_encode_stateid(xdr, &lrp->lr_sid); 41299cf514ccSChristoph Hellwig return nfs_ok; 41309cf514ccSChristoph Hellwig } 41319cf514ccSChristoph Hellwig #endif /* CONFIG_NFSD_PNFS */ 41329cf514ccSChristoph Hellwig 41332db134ebSAndy Adamson static __be32 413424bab491SAnna Schumaker nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, 413524bab491SAnna Schumaker struct nfsd4_seek *seek) 413624bab491SAnna Schumaker { 413724bab491SAnna Schumaker __be32 *p; 413824bab491SAnna Schumaker 413924bab491SAnna Schumaker if (nfserr) 414024bab491SAnna Schumaker return nfserr; 414124bab491SAnna Schumaker 414224bab491SAnna Schumaker p = xdr_reserve_space(&resp->xdr, 4 + 8); 414324bab491SAnna Schumaker *p++ = cpu_to_be32(seek->seek_eof); 414424bab491SAnna Schumaker p = xdr_encode_hyper(p, seek->seek_pos); 414524bab491SAnna Schumaker 414624bab491SAnna Schumaker return nfserr; 414724bab491SAnna Schumaker } 414824bab491SAnna Schumaker 414924bab491SAnna Schumaker static __be32 4150695e12f8SBenny Halevy nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) 4151695e12f8SBenny Halevy { 4152695e12f8SBenny Halevy return nfserr; 4153695e12f8SBenny Halevy } 4154695e12f8SBenny Halevy 4155695e12f8SBenny Halevy typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *); 4156695e12f8SBenny Halevy 41572db134ebSAndy Adamson /* 41582db134ebSAndy Adamson * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1 41592db134ebSAndy Adamson * since we don't need to filter out obsolete ops as this is 41602db134ebSAndy Adamson * done in the decoding phase. 41612db134ebSAndy Adamson */ 4162695e12f8SBenny Halevy static nfsd4_enc nfsd4_enc_ops[] = { 4163ad1060c8SJ. Bruce Fields [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access, 4164ad1060c8SJ. Bruce Fields [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close, 4165ad1060c8SJ. Bruce Fields [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit, 4166ad1060c8SJ. Bruce Fields [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create, 4167ad1060c8SJ. Bruce Fields [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop, 4168ad1060c8SJ. Bruce Fields [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop, 4169ad1060c8SJ. Bruce Fields [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr, 4170ad1060c8SJ. Bruce Fields [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh, 4171ad1060c8SJ. Bruce Fields [OP_LINK] = (nfsd4_enc)nfsd4_encode_link, 4172ad1060c8SJ. Bruce Fields [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock, 4173ad1060c8SJ. Bruce Fields [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt, 4174ad1060c8SJ. Bruce Fields [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku, 4175ad1060c8SJ. Bruce Fields [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop, 4176ad1060c8SJ. Bruce Fields [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop, 4177ad1060c8SJ. Bruce Fields [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop, 4178ad1060c8SJ. Bruce Fields [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open, 417984f09f46SBenny Halevy [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop, 4180ad1060c8SJ. Bruce Fields [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm, 4181ad1060c8SJ. Bruce Fields [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade, 4182ad1060c8SJ. Bruce Fields [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop, 4183ad1060c8SJ. Bruce Fields [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop, 4184ad1060c8SJ. Bruce Fields [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop, 4185ad1060c8SJ. Bruce Fields [OP_READ] = (nfsd4_enc)nfsd4_encode_read, 4186ad1060c8SJ. Bruce Fields [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir, 4187ad1060c8SJ. Bruce Fields [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink, 4188ad1060c8SJ. Bruce Fields [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove, 4189ad1060c8SJ. Bruce Fields [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename, 4190ad1060c8SJ. Bruce Fields [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop, 4191ad1060c8SJ. Bruce Fields [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop, 4192ad1060c8SJ. Bruce Fields [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop, 4193ad1060c8SJ. Bruce Fields [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo, 4194ad1060c8SJ. Bruce Fields [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr, 4195ad1060c8SJ. Bruce Fields [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid, 4196ad1060c8SJ. Bruce Fields [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop, 4197ad1060c8SJ. Bruce Fields [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop, 4198ad1060c8SJ. Bruce Fields [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write, 4199ad1060c8SJ. Bruce Fields [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop, 42002db134ebSAndy Adamson 42012db134ebSAndy Adamson /* NFSv4.1 operations */ 42022db134ebSAndy Adamson [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop, 42031d1bc8f2SJ. Bruce Fields [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session, 42042db134ebSAndy Adamson [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, 42052db134ebSAndy Adamson [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, 420643212cc7SKinglong Mee [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop, 420743212cc7SKinglong Mee [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, 42082db134ebSAndy Adamson [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 42099cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 42109cf514ccSChristoph Hellwig [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_getdeviceinfo, 42119cf514ccSChristoph Hellwig [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, 42129cf514ccSChristoph Hellwig [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_layoutcommit, 42139cf514ccSChristoph Hellwig [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_layoutget, 42149cf514ccSChristoph Hellwig [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_layoutreturn, 42159cf514ccSChristoph Hellwig #else 42162db134ebSAndy Adamson [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, 42172db134ebSAndy Adamson [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, 42182db134ebSAndy Adamson [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, 42192db134ebSAndy Adamson [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, 42202db134ebSAndy Adamson [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, 42219cf514ccSChristoph Hellwig #endif 422222b6dee8SMi Jinlong [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name, 42232db134ebSAndy Adamson [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, 42242db134ebSAndy Adamson [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, 422517456804SBryan Schumaker [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid, 42262db134ebSAndy Adamson [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 42272db134ebSAndy Adamson [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop, 42282db134ebSAndy Adamson [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop, 422987a15a80SAnna Schumaker 423087a15a80SAnna Schumaker /* NFSv4.2 operations */ 423187a15a80SAnna Schumaker [OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop, 423287a15a80SAnna Schumaker [OP_COPY] = (nfsd4_enc)nfsd4_encode_noop, 423387a15a80SAnna Schumaker [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_noop, 423487a15a80SAnna Schumaker [OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop, 423587a15a80SAnna Schumaker [OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop, 423687a15a80SAnna Schumaker [OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop, 423787a15a80SAnna Schumaker [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop, 423887a15a80SAnna Schumaker [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop, 423987a15a80SAnna Schumaker [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_noop, 424087a15a80SAnna Schumaker [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop, 424124bab491SAnna Schumaker [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek, 424287a15a80SAnna Schumaker [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop, 4243695e12f8SBenny Halevy }; 4244695e12f8SBenny Halevy 4245496c262cSAndy Adamson /* 4246a8095f7eSJ. Bruce Fields * Calculate whether we still have space to encode repsize bytes. 4247a8095f7eSJ. Bruce Fields * There are two considerations: 4248a8095f7eSJ. Bruce Fields * - For NFS versions >=4.1, the size of the reply must stay within 4249a8095f7eSJ. Bruce Fields * session limits 4250a8095f7eSJ. Bruce Fields * - For all NFS versions, we must stay within limited preallocated 4251a8095f7eSJ. Bruce Fields * buffer space. 4252496c262cSAndy Adamson * 4253a8095f7eSJ. Bruce Fields * This is called before the operation is processed, so can only provide 4254a8095f7eSJ. Bruce Fields * an upper estimate. For some nonidempotent operations (such as 4255a8095f7eSJ. Bruce Fields * getattr), it's not necessarily a problem if that estimate is wrong, 4256a8095f7eSJ. Bruce Fields * as we can fail it after processing without significant side effects. 4257496c262cSAndy Adamson */ 4258a8095f7eSJ. Bruce Fields __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize) 4259496c262cSAndy Adamson { 426067492c99SJ. Bruce Fields struct xdr_buf *buf = &resp->rqstp->rq_res; 4261a8095f7eSJ. Bruce Fields struct nfsd4_slot *slot = resp->cstate.slot; 4262496c262cSAndy Adamson 426347ee5298SJ. Bruce Fields if (buf->len + respsize <= buf->buflen) 426447ee5298SJ. Bruce Fields return nfs_ok; 426547ee5298SJ. Bruce Fields if (!nfsd4_has_session(&resp->cstate)) 426647ee5298SJ. Bruce Fields return nfserr_resource; 426747ee5298SJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) { 426847ee5298SJ. Bruce Fields WARN_ON_ONCE(1); 4269496c262cSAndy Adamson return nfserr_rep_too_big_to_cache; 4270ea8d7720SJ. Bruce Fields } 427147ee5298SJ. Bruce Fields return nfserr_rep_too_big; 4272496c262cSAndy Adamson } 4273496c262cSAndy Adamson 42741da177e4SLinus Torvalds void 42751da177e4SLinus Torvalds nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 42761da177e4SLinus Torvalds { 4277082d4bd7SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 42789411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = resp->cstate.replay_owner; 42795f4ab945SJ. Bruce Fields struct svc_rqst *rqstp = resp->rqstp; 4280082d4bd7SJ. Bruce Fields int post_err_offset; 428107d1f802SJ. Bruce Fields nfsd4_enc encoder; 4282bc749ca4SJ. Bruce Fields __be32 *p; 42831da177e4SLinus Torvalds 4284d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 4285d0a381ddSJ. Bruce Fields if (!p) { 4286d0a381ddSJ. Bruce Fields WARN_ON_ONCE(1); 4287d0a381ddSJ. Bruce Fields return; 4288d0a381ddSJ. Bruce Fields } 4289c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(op->opnum); 4290082d4bd7SJ. Bruce Fields post_err_offset = xdr->buf->len; 42911da177e4SLinus Torvalds 4292695e12f8SBenny Halevy if (op->opnum == OP_ILLEGAL) 4293695e12f8SBenny Halevy goto status; 4294695e12f8SBenny Halevy BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || 4295695e12f8SBenny Halevy !nfsd4_enc_ops[op->opnum]); 429607d1f802SJ. Bruce Fields encoder = nfsd4_enc_ops[op->opnum]; 429707d1f802SJ. Bruce Fields op->status = encoder(resp, op->status, &op->u); 42982825a7f9SJ. Bruce Fields xdr_commit_encode(xdr); 42992825a7f9SJ. Bruce Fields 4300067e1aceSJ. Bruce Fields /* nfsd4_check_resp_size guarantees enough room for error status */ 43015f4ab945SJ. Bruce Fields if (!op->status) { 43025f4ab945SJ. Bruce Fields int space_needed = 0; 43035f4ab945SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 43045f4ab945SJ. Bruce Fields space_needed = COMPOUND_ERR_SLACK_SPACE; 43055f4ab945SJ. Bruce Fields op->status = nfsd4_check_resp_size(resp, space_needed); 43065f4ab945SJ. Bruce Fields } 4307c8f13d97SJ. Bruce Fields if (op->status == nfserr_resource && nfsd4_has_session(&resp->cstate)) { 4308c8f13d97SJ. Bruce Fields struct nfsd4_slot *slot = resp->cstate.slot; 4309c8f13d97SJ. Bruce Fields 4310c8f13d97SJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) 4311c8f13d97SJ. Bruce Fields op->status = nfserr_rep_too_big_to_cache; 4312c8f13d97SJ. Bruce Fields else 4313c8f13d97SJ. Bruce Fields op->status = nfserr_rep_too_big; 4314c8f13d97SJ. Bruce Fields } 431507d1f802SJ. Bruce Fields if (op->status == nfserr_resource || 431607d1f802SJ. Bruce Fields op->status == nfserr_rep_too_big || 431707d1f802SJ. Bruce Fields op->status == nfserr_rep_too_big_to_cache) { 431807d1f802SJ. Bruce Fields /* 431907d1f802SJ. Bruce Fields * The operation may have already been encoded or 432007d1f802SJ. Bruce Fields * partially encoded. No op returns anything additional 432107d1f802SJ. Bruce Fields * in the case of one of these three errors, so we can 432207d1f802SJ. Bruce Fields * just truncate back to after the status. But it's a 432307d1f802SJ. Bruce Fields * bug if we had to do this on a non-idempotent op: 432407d1f802SJ. Bruce Fields */ 432507d1f802SJ. Bruce Fields warn_on_nonidempotent_op(op); 4326082d4bd7SJ. Bruce Fields xdr_truncate_encode(xdr, post_err_offset); 432707d1f802SJ. Bruce Fields } 43289411b1d4SJ. Bruce Fields if (so) { 4329082d4bd7SJ. Bruce Fields int len = xdr->buf->len - post_err_offset; 4330082d4bd7SJ. Bruce Fields 43319411b1d4SJ. Bruce Fields so->so_replay.rp_status = op->status; 4332082d4bd7SJ. Bruce Fields so->so_replay.rp_buflen = len; 4333082d4bd7SJ. Bruce Fields read_bytes_from_xdr_buf(xdr->buf, post_err_offset, 4334082d4bd7SJ. Bruce Fields so->so_replay.rp_buf, len); 43359411b1d4SJ. Bruce Fields } 4336695e12f8SBenny Halevy status: 4337082d4bd7SJ. Bruce Fields /* Note that op->status is already in network byte order: */ 4338082d4bd7SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4); 43391da177e4SLinus Torvalds } 43401da177e4SLinus Torvalds 43411da177e4SLinus Torvalds /* 43421da177e4SLinus Torvalds * Encode the reply stored in the stateowner reply cache 43431da177e4SLinus Torvalds * 43441da177e4SLinus Torvalds * XDR note: do not encode rp->rp_buflen: the buffer contains the 43451da177e4SLinus Torvalds * previously sent already encoded operation. 43461da177e4SLinus Torvalds */ 43471da177e4SLinus Torvalds void 4348d0a381ddSJ. Bruce Fields nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op) 43491da177e4SLinus Torvalds { 4350bc749ca4SJ. Bruce Fields __be32 *p; 43511da177e4SLinus Torvalds struct nfs4_replay *rp = op->replay; 43521da177e4SLinus Torvalds 43531da177e4SLinus Torvalds BUG_ON(!rp); 43541da177e4SLinus Torvalds 4355d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8 + rp->rp_buflen); 4356d0a381ddSJ. Bruce Fields if (!p) { 4357d0a381ddSJ. Bruce Fields WARN_ON_ONCE(1); 4358d0a381ddSJ. Bruce Fields return; 4359d0a381ddSJ. Bruce Fields } 4360c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(op->opnum); 43611da177e4SLinus Torvalds *p++ = rp->rp_status; /* already xdr'ed */ 43621da177e4SLinus Torvalds 43630c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, rp->rp_buf, rp->rp_buflen); 43641da177e4SLinus Torvalds } 43651da177e4SLinus Torvalds 43661da177e4SLinus Torvalds int 43672ebbc012SAl Viro nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) 43681da177e4SLinus Torvalds { 43691da177e4SLinus Torvalds return xdr_ressize_check(rqstp, p); 43701da177e4SLinus Torvalds } 43711da177e4SLinus Torvalds 43723e98abffSJ. Bruce Fields int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp) 43731da177e4SLinus Torvalds { 43743e98abffSJ. Bruce Fields struct svc_rqst *rqstp = rq; 43753e98abffSJ. Bruce Fields struct nfsd4_compoundargs *args = rqstp->rq_argp; 43763e98abffSJ. Bruce Fields 43771da177e4SLinus Torvalds if (args->ops != args->iops) { 43781da177e4SLinus Torvalds kfree(args->ops); 43791da177e4SLinus Torvalds args->ops = args->iops; 43801da177e4SLinus Torvalds } 43811da177e4SLinus Torvalds kfree(args->tmpp); 43821da177e4SLinus Torvalds args->tmpp = NULL; 43831da177e4SLinus Torvalds while (args->to_free) { 4384d5e23383SJ. Bruce Fields struct svcxdr_tmpbuf *tb = args->to_free; 43851da177e4SLinus Torvalds args->to_free = tb->next; 43861da177e4SLinus Torvalds kfree(tb); 43871da177e4SLinus Torvalds } 43883e98abffSJ. Bruce Fields return 1; 43891da177e4SLinus Torvalds } 43901da177e4SLinus Torvalds 43911da177e4SLinus Torvalds int 43922ebbc012SAl Viro nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) 43931da177e4SLinus Torvalds { 4394e874f9f8SJeff Layton if (rqstp->rq_arg.head[0].iov_len % 4) { 4395e874f9f8SJeff Layton /* client is nuts */ 4396e874f9f8SJeff Layton dprintk("%s: compound not properly padded! (peeraddr=%pISc xid=0x%x)", 4397e874f9f8SJeff Layton __func__, svc_addr(rqstp), be32_to_cpu(rqstp->rq_xid)); 4398e874f9f8SJeff Layton return 0; 4399e874f9f8SJeff Layton } 44001da177e4SLinus Torvalds args->p = p; 44011da177e4SLinus Torvalds args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; 44021da177e4SLinus Torvalds args->pagelist = rqstp->rq_arg.pages; 44031da177e4SLinus Torvalds args->pagelen = rqstp->rq_arg.page_len; 44041da177e4SLinus Torvalds args->tmpp = NULL; 44051da177e4SLinus Torvalds args->to_free = NULL; 44061da177e4SLinus Torvalds args->ops = args->iops; 44071da177e4SLinus Torvalds args->rqstp = rqstp; 44081da177e4SLinus Torvalds 44093e98abffSJ. Bruce Fields return !nfsd4_decode_compound(args); 44101da177e4SLinus Torvalds } 44111da177e4SLinus Torvalds 44121da177e4SLinus Torvalds int 44132ebbc012SAl Viro nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp) 44141da177e4SLinus Torvalds { 44151da177e4SLinus Torvalds /* 44161da177e4SLinus Torvalds * All that remains is to write the tag and operation count... 44171da177e4SLinus Torvalds */ 44186ac90391SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 44196ac90391SJ. Bruce Fields 44206ac90391SJ. Bruce Fields WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + 44216ac90391SJ. Bruce Fields buf->tail[0].iov_len); 4422dd97fddeSJ. Bruce Fields 44232825a7f9SJ. Bruce Fields rqstp->rq_next_page = resp->xdr.page_ptr + 1; 44242825a7f9SJ. Bruce Fields 44251da177e4SLinus Torvalds p = resp->tagp; 44261da177e4SLinus Torvalds *p++ = htonl(resp->taglen); 44271da177e4SLinus Torvalds memcpy(p, resp->tag, resp->taglen); 44281da177e4SLinus Torvalds p += XDR_QUADLEN(resp->taglen); 44291da177e4SLinus Torvalds *p++ = htonl(resp->opcnt); 44301da177e4SLinus Torvalds 4431b607664eSTrond Myklebust nfsd4_sequence_done(resp); 44321da177e4SLinus Torvalds return 1; 44331da177e4SLinus Torvalds } 44341da177e4SLinus Torvalds 44351da177e4SLinus Torvalds /* 44361da177e4SLinus Torvalds * Local variables: 44371da177e4SLinus Torvalds * c-basic-offset: 8 44381da177e4SLinus Torvalds * End: 44391da177e4SLinus Torvalds */ 4440