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 3647057abdSAndreas Gruenbacher #include <linux/fs_struct.h> 3796bcad50SChristoph Hellwig #include <linux/file.h> 385a0e3ad6STejun Heo #include <linux/slab.h> 391da177e4SLinus Torvalds #include <linux/namei.h> 40341eb184SBoaz Harrosh #include <linux/statfs.h> 410733d213SAndy Adamson #include <linux/utsname.h> 4217456804SBryan Schumaker #include <linux/pagemap.h> 434796f457SJ. Bruce Fields #include <linux/sunrpc/svcauth_gss.h> 449a74af21SBoaz Harrosh 452ca72e17SJ. Bruce Fields #include "idmap.h" 462ca72e17SJ. Bruce Fields #include "acl.h" 479a74af21SBoaz Harrosh #include "xdr4.h" 480a3adadeSJ. Bruce Fields #include "vfs.h" 4917456804SBryan Schumaker #include "state.h" 501091006cSJ. Bruce Fields #include "cache.h" 513d733711SStanislav Kinsbursky #include "netns.h" 529cf514ccSChristoph Hellwig #include "pnfs.h" 532ca72e17SJ. Bruce Fields 5418032ca0SDavid Quigley #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 5518032ca0SDavid Quigley #include <linux/security.h> 5618032ca0SDavid Quigley #endif 5718032ca0SDavid Quigley 5818032ca0SDavid Quigley 591da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_XDR 601da177e4SLinus Torvalds 615cf23dbbSJ. Bruce Fields const u32 nfsd_suppattrs[3][3] = { 62916d2d84SJ. Bruce Fields {NFSD4_SUPPORTED_ATTRS_WORD0, 63916d2d84SJ. Bruce Fields NFSD4_SUPPORTED_ATTRS_WORD1, 64916d2d84SJ. Bruce Fields NFSD4_SUPPORTED_ATTRS_WORD2}, 65916d2d84SJ. Bruce Fields 66916d2d84SJ. Bruce Fields {NFSD4_1_SUPPORTED_ATTRS_WORD0, 67916d2d84SJ. Bruce Fields NFSD4_1_SUPPORTED_ATTRS_WORD1, 68916d2d84SJ. Bruce Fields NFSD4_1_SUPPORTED_ATTRS_WORD2}, 69916d2d84SJ. Bruce Fields 70916d2d84SJ. Bruce Fields {NFSD4_1_SUPPORTED_ATTRS_WORD0, 71916d2d84SJ. Bruce Fields NFSD4_1_SUPPORTED_ATTRS_WORD1, 72916d2d84SJ. Bruce Fields NFSD4_2_SUPPORTED_ATTRS_WORD2}, 73916d2d84SJ. Bruce Fields }; 74916d2d84SJ. Bruce Fields 7542ca0993SJ.Bruce Fields /* 7642ca0993SJ.Bruce Fields * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing 7742ca0993SJ.Bruce Fields * directory in order to indicate to the client that a filesystem boundary is present 7842ca0993SJ.Bruce Fields * We use a fixed fsid for a referral 7942ca0993SJ.Bruce Fields */ 8042ca0993SJ.Bruce Fields #define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL 8142ca0993SJ.Bruce Fields #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL 8242ca0993SJ.Bruce Fields 83b37ad28bSAl Viro static __be32 84a36b1725SJ. Bruce Fields check_filename(char *str, int len) 851da177e4SLinus Torvalds { 861da177e4SLinus Torvalds int i; 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds if (len == 0) 891da177e4SLinus Torvalds return nfserr_inval; 901da177e4SLinus Torvalds if (isdotent(str, len)) 91a36b1725SJ. Bruce Fields return nfserr_badname; 921da177e4SLinus Torvalds for (i = 0; i < len; i++) 931da177e4SLinus Torvalds if (str[i] == '/') 94a36b1725SJ. Bruce Fields return nfserr_badname; 951da177e4SLinus Torvalds return 0; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds #define DECODE_HEAD \ 992ebbc012SAl Viro __be32 *p; \ 100b37ad28bSAl Viro __be32 status 1011da177e4SLinus Torvalds #define DECODE_TAIL \ 1021da177e4SLinus Torvalds status = 0; \ 1031da177e4SLinus Torvalds out: \ 1041da177e4SLinus Torvalds return status; \ 1051da177e4SLinus Torvalds xdr_error: \ 106817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 107817cb9d4SChuck Lever __FILE__, __LINE__); \ 1081da177e4SLinus Torvalds status = nfserr_bad_xdr; \ 1091da177e4SLinus Torvalds goto out 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds #define READMEM(x,nbytes) do { \ 1121da177e4SLinus Torvalds x = (char *)p; \ 1131da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1141da177e4SLinus Torvalds } while (0) 1151da177e4SLinus Torvalds #define SAVEMEM(x,nbytes) do { \ 1161da177e4SLinus Torvalds if (!(x = (p==argp->tmp || p == argp->tmpp) ? \ 1171da177e4SLinus Torvalds savemem(argp, p, nbytes) : \ 1181da177e4SLinus Torvalds (char *)p)) { \ 119817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 120817cb9d4SChuck Lever __FILE__, __LINE__); \ 1211da177e4SLinus Torvalds goto xdr_error; \ 1221da177e4SLinus Torvalds } \ 1231da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1241da177e4SLinus Torvalds } while (0) 1251da177e4SLinus Torvalds #define COPYMEM(x,nbytes) do { \ 1261da177e4SLinus Torvalds memcpy((x), p, nbytes); \ 1271da177e4SLinus Torvalds p += XDR_QUADLEN(nbytes); \ 1281da177e4SLinus Torvalds } while (0) 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds /* READ_BUF, read_buf(): nbytes must be <= PAGE_SIZE */ 1311da177e4SLinus Torvalds #define READ_BUF(nbytes) do { \ 1321da177e4SLinus Torvalds if (nbytes <= (u32)((char *)argp->end - (char *)argp->p)) { \ 1331da177e4SLinus Torvalds p = argp->p; \ 1341da177e4SLinus Torvalds argp->p += XDR_QUADLEN(nbytes); \ 1351da177e4SLinus Torvalds } else if (!(p = read_buf(argp, nbytes))) { \ 136817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", \ 137817cb9d4SChuck Lever __FILE__, __LINE__); \ 1381da177e4SLinus Torvalds goto xdr_error; \ 1391da177e4SLinus Torvalds } \ 1401da177e4SLinus Torvalds } while (0) 1411da177e4SLinus Torvalds 142590b7431SJ. Bruce Fields static void next_decode_page(struct nfsd4_compoundargs *argp) 143590b7431SJ. Bruce Fields { 144590b7431SJ. Bruce Fields argp->p = page_address(argp->pagelist[0]); 145365da4adSJ. Bruce Fields argp->pagelist++; 146590b7431SJ. Bruce Fields if (argp->pagelen < PAGE_SIZE) { 147590b7431SJ. Bruce Fields argp->end = argp->p + (argp->pagelen>>2); 148590b7431SJ. Bruce Fields argp->pagelen = 0; 149590b7431SJ. Bruce Fields } else { 150590b7431SJ. Bruce Fields argp->end = argp->p + (PAGE_SIZE>>2); 151590b7431SJ. Bruce Fields argp->pagelen -= PAGE_SIZE; 152590b7431SJ. Bruce Fields } 153590b7431SJ. Bruce Fields } 154590b7431SJ. Bruce Fields 155ca2a05aaSJ. Bruce Fields static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) 1561da177e4SLinus Torvalds { 1571da177e4SLinus Torvalds /* We want more bytes than seem to be available. 1581da177e4SLinus Torvalds * Maybe we need a new page, maybe we have just run out 1591da177e4SLinus Torvalds */ 160ca2a05aaSJ. Bruce Fields unsigned int avail = (char *)argp->end - (char *)argp->p; 1612ebbc012SAl Viro __be32 *p; 1621da177e4SLinus Torvalds if (avail + argp->pagelen < nbytes) 1631da177e4SLinus Torvalds return NULL; 1641da177e4SLinus Torvalds if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */ 1651da177e4SLinus Torvalds return NULL; 1661da177e4SLinus Torvalds /* ok, we can do it with the current plus the next page */ 1671da177e4SLinus Torvalds if (nbytes <= sizeof(argp->tmp)) 1681da177e4SLinus Torvalds p = argp->tmp; 1691da177e4SLinus Torvalds else { 1701da177e4SLinus Torvalds kfree(argp->tmpp); 1711da177e4SLinus Torvalds p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL); 1721da177e4SLinus Torvalds if (!p) 1731da177e4SLinus Torvalds return NULL; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds } 176ca2a05aaSJ. Bruce Fields /* 177ca2a05aaSJ. Bruce Fields * The following memcpy is safe because read_buf is always 178ca2a05aaSJ. Bruce Fields * called with nbytes > avail, and the two cases above both 179ca2a05aaSJ. Bruce Fields * guarantee p points to at least nbytes bytes. 180ca2a05aaSJ. Bruce Fields */ 1811da177e4SLinus Torvalds memcpy(p, argp->p, avail); 182590b7431SJ. Bruce Fields next_decode_page(argp); 1831da177e4SLinus Torvalds memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); 1841da177e4SLinus Torvalds argp->p += XDR_QUADLEN(nbytes - avail); 1851da177e4SLinus Torvalds return p; 1861da177e4SLinus Torvalds } 1871da177e4SLinus Torvalds 18860adfc50SAndy Adamson static int zero_clientid(clientid_t *clid) 18960adfc50SAndy Adamson { 19060adfc50SAndy Adamson return (clid->cl_boot == 0) && (clid->cl_id == 0); 19160adfc50SAndy Adamson } 19260adfc50SAndy Adamson 1932d8498dbSChristoph Hellwig /** 194d5e23383SJ. Bruce Fields * svcxdr_tmpalloc - allocate memory to be freed after compound processing 195ce043ac8SJ. Bruce Fields * @argp: NFSv4 compound argument structure 196ce043ac8SJ. Bruce Fields * @p: pointer to be freed (with kfree()) 1972d8498dbSChristoph Hellwig * 1982d8498dbSChristoph Hellwig * Marks @p to be freed when processing the compound operation 1992d8498dbSChristoph Hellwig * described in @argp finishes. 2002d8498dbSChristoph Hellwig */ 201d5e23383SJ. Bruce Fields static void * 202d5e23383SJ. Bruce Fields svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len) 2031da177e4SLinus Torvalds { 204d5e23383SJ. Bruce Fields struct svcxdr_tmpbuf *tb; 2051da177e4SLinus Torvalds 206d5e23383SJ. Bruce Fields tb = kmalloc(sizeof(*tb) + len, GFP_KERNEL); 2071da177e4SLinus Torvalds if (!tb) 208d5e23383SJ. Bruce Fields return NULL; 2091da177e4SLinus Torvalds tb->next = argp->to_free; 2101da177e4SLinus Torvalds argp->to_free = tb; 211d5e23383SJ. Bruce Fields return tb->buf; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 21429c353b3SJ. Bruce Fields /* 21529c353b3SJ. Bruce Fields * For xdr strings that need to be passed to other kernel api's 21629c353b3SJ. Bruce Fields * as null-terminated strings. 21729c353b3SJ. Bruce Fields * 21829c353b3SJ. Bruce Fields * Note null-terminating in place usually isn't safe since the 21929c353b3SJ. Bruce Fields * buffer might end on a page boundary. 22029c353b3SJ. Bruce Fields */ 22129c353b3SJ. Bruce Fields static char * 22229c353b3SJ. Bruce Fields svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len) 22329c353b3SJ. Bruce Fields { 224d5e23383SJ. Bruce Fields char *p = svcxdr_tmpalloc(argp, len + 1); 22529c353b3SJ. Bruce Fields 22629c353b3SJ. Bruce Fields if (!p) 22729c353b3SJ. Bruce Fields return NULL; 22829c353b3SJ. Bruce Fields memcpy(p, buf, len); 22929c353b3SJ. Bruce Fields p[len] = '\0'; 23029c353b3SJ. Bruce Fields return p; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2332d8498dbSChristoph Hellwig /** 2342d8498dbSChristoph Hellwig * savemem - duplicate a chunk of memory for later processing 2352d8498dbSChristoph Hellwig * @argp: NFSv4 compound argument structure to be freed with 2362d8498dbSChristoph Hellwig * @p: pointer to be duplicated 2372d8498dbSChristoph Hellwig * @nbytes: length to be duplicated 2382d8498dbSChristoph Hellwig * 2392d8498dbSChristoph Hellwig * Returns a pointer to a copy of @nbytes bytes of memory at @p 2402d8498dbSChristoph Hellwig * that are preserved until processing of the NFSv4 compound 2412d8498dbSChristoph Hellwig * operation described by @argp finishes. 2422d8498dbSChristoph Hellwig */ 2432ebbc012SAl Viro static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) 2441da177e4SLinus Torvalds { 245d5e23383SJ. Bruce Fields void *ret; 246d5e23383SJ. Bruce Fields 247d5e23383SJ. Bruce Fields ret = svcxdr_tmpalloc(argp, nbytes); 248d5e23383SJ. Bruce Fields if (!ret) 249a4db5fe5SJ. Bruce Fields return NULL; 250d5e23383SJ. Bruce Fields memcpy(ret, p, nbytes); 251d5e23383SJ. Bruce Fields return ret; 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2544c94e13eSChristoph Hellwig /* 2554c94e13eSChristoph Hellwig * We require the high 32 bits of 'seconds' to be 0, and 2564c94e13eSChristoph Hellwig * we ignore all 32 bits of 'nseconds'. 2574c94e13eSChristoph Hellwig */ 2584c94e13eSChristoph Hellwig static __be32 2594c94e13eSChristoph Hellwig nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec *tv) 2604c94e13eSChristoph Hellwig { 2614c94e13eSChristoph Hellwig DECODE_HEAD; 2624c94e13eSChristoph Hellwig u64 sec; 2634c94e13eSChristoph Hellwig 2644c94e13eSChristoph Hellwig READ_BUF(12); 2654c94e13eSChristoph Hellwig p = xdr_decode_hyper(p, &sec); 2664c94e13eSChristoph Hellwig tv->tv_sec = sec; 2674c94e13eSChristoph Hellwig tv->tv_nsec = be32_to_cpup(p++); 2684c94e13eSChristoph Hellwig if (tv->tv_nsec >= (u32)1000000000) 2694c94e13eSChristoph Hellwig return nfserr_inval; 2704c94e13eSChristoph Hellwig 2714c94e13eSChristoph Hellwig DECODE_TAIL; 2724c94e13eSChristoph Hellwig } 2734c94e13eSChristoph Hellwig 274b37ad28bSAl Viro static __be32 2751da177e4SLinus Torvalds nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) 2761da177e4SLinus Torvalds { 2771da177e4SLinus Torvalds u32 bmlen; 2781da177e4SLinus Torvalds DECODE_HEAD; 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds bmval[0] = 0; 2811da177e4SLinus Torvalds bmval[1] = 0; 2827e705706SAndy Adamson bmval[2] = 0; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds READ_BUF(4); 28506553991SJ. Bruce Fields bmlen = be32_to_cpup(p++); 2861da177e4SLinus Torvalds if (bmlen > 1000) 2871da177e4SLinus Torvalds goto xdr_error; 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds READ_BUF(bmlen << 2); 2901da177e4SLinus Torvalds if (bmlen > 0) 29106553991SJ. Bruce Fields bmval[0] = be32_to_cpup(p++); 2921da177e4SLinus Torvalds if (bmlen > 1) 29306553991SJ. Bruce Fields bmval[1] = be32_to_cpup(p++); 2947e705706SAndy Adamson if (bmlen > 2) 29506553991SJ. Bruce Fields bmval[2] = be32_to_cpup(p++); 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds DECODE_TAIL; 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds 300b37ad28bSAl Viro static __be32 3013c8e0316SYu Zhiguo nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, 30218032ca0SDavid Quigley struct iattr *iattr, struct nfs4_acl **acl, 30347057abdSAndreas Gruenbacher struct xdr_netobj *label, int *umask) 3041da177e4SLinus Torvalds { 3051da177e4SLinus Torvalds int expected_len, len = 0; 3061da177e4SLinus Torvalds u32 dummy32; 3071da177e4SLinus Torvalds char *buf; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds DECODE_HEAD; 3101da177e4SLinus Torvalds iattr->ia_valid = 0; 3111da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, bmval))) 3121da177e4SLinus Torvalds return status; 3131da177e4SLinus Torvalds 314e864c189SJ. Bruce Fields if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 315e864c189SJ. Bruce Fields || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 316e864c189SJ. Bruce Fields || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) { 317e864c189SJ. Bruce Fields if (nfsd_attrs_supported(argp->minorversion, bmval)) 318e864c189SJ. Bruce Fields return nfserr_inval; 319e864c189SJ. Bruce Fields return nfserr_attrnotsupp; 320e864c189SJ. Bruce Fields } 321e864c189SJ. Bruce Fields 3221da177e4SLinus Torvalds READ_BUF(4); 32306553991SJ. Bruce Fields expected_len = be32_to_cpup(p++); 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds if (bmval[0] & FATTR4_WORD0_SIZE) { 3261da177e4SLinus Torvalds READ_BUF(8); 3271da177e4SLinus Torvalds len += 8; 328542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &iattr->ia_size); 3291da177e4SLinus Torvalds iattr->ia_valid |= ATTR_SIZE; 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds if (bmval[0] & FATTR4_WORD0_ACL) { 33264a817cfSJ. Bruce Fields u32 nace; 33328e05dd8SJ. Bruce Fields struct nfs4_ace *ace; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds READ_BUF(4); len += 4; 33606553991SJ. Bruce Fields nace = be32_to_cpup(p++); 3371da177e4SLinus Torvalds 33828e05dd8SJ. Bruce Fields if (nace > NFS4_ACL_MAX) 339798df338SJ. Bruce Fields return nfserr_fbig; 34028e05dd8SJ. Bruce Fields 341d5e23383SJ. Bruce Fields *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace)); 342eba1c99cSKinglong Mee if (*acl == NULL) 343eba1c99cSKinglong Mee return nfserr_jukebox; 344eba1c99cSKinglong Mee 34528e05dd8SJ. Bruce Fields (*acl)->naces = nace; 34628e05dd8SJ. Bruce Fields for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { 3471da177e4SLinus Torvalds READ_BUF(16); len += 16; 34806553991SJ. Bruce Fields ace->type = be32_to_cpup(p++); 34906553991SJ. Bruce Fields ace->flag = be32_to_cpup(p++); 35006553991SJ. Bruce Fields ace->access_mask = be32_to_cpup(p++); 35106553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 3521da177e4SLinus Torvalds READ_BUF(dummy32); 3531da177e4SLinus Torvalds len += XDR_QUADLEN(dummy32) << 2; 3541da177e4SLinus Torvalds READMEM(buf, dummy32); 35528e05dd8SJ. Bruce Fields ace->whotype = nfs4_acl_get_whotype(buf, dummy32); 3563c726023SJ. Bruce Fields status = nfs_ok; 35728e05dd8SJ. Bruce Fields if (ace->whotype != NFS4_ACL_WHO_NAMED) 358ab8e4aeeSEric W. Biederman ; 35928e05dd8SJ. Bruce Fields else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) 3603c726023SJ. Bruce Fields status = nfsd_map_name_to_gid(argp->rqstp, 361ab8e4aeeSEric W. Biederman buf, dummy32, &ace->who_gid); 3621da177e4SLinus Torvalds else 3633c726023SJ. Bruce Fields status = nfsd_map_name_to_uid(argp->rqstp, 364ab8e4aeeSEric W. Biederman buf, dummy32, &ace->who_uid); 3653c726023SJ. Bruce Fields if (status) 3663c726023SJ. Bruce Fields return status; 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds } else 3691da177e4SLinus Torvalds *acl = NULL; 3701da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_MODE) { 3711da177e4SLinus Torvalds READ_BUF(4); 3721da177e4SLinus Torvalds len += 4; 37306553991SJ. Bruce Fields iattr->ia_mode = be32_to_cpup(p++); 3741da177e4SLinus Torvalds iattr->ia_mode &= (S_IFMT | S_IALLUGO); 3751da177e4SLinus Torvalds iattr->ia_valid |= ATTR_MODE; 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_OWNER) { 3781da177e4SLinus Torvalds READ_BUF(4); 3791da177e4SLinus Torvalds len += 4; 38006553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 3811da177e4SLinus Torvalds READ_BUF(dummy32); 3821da177e4SLinus Torvalds len += (XDR_QUADLEN(dummy32) << 2); 3831da177e4SLinus Torvalds READMEM(buf, dummy32); 38447c85291SNeilBrown if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) 38547c85291SNeilBrown return status; 3861da177e4SLinus Torvalds iattr->ia_valid |= ATTR_UID; 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) { 3891da177e4SLinus Torvalds READ_BUF(4); 3901da177e4SLinus Torvalds len += 4; 39106553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 3921da177e4SLinus Torvalds READ_BUF(dummy32); 3931da177e4SLinus Torvalds len += (XDR_QUADLEN(dummy32) << 2); 3941da177e4SLinus Torvalds READMEM(buf, dummy32); 39547c85291SNeilBrown if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) 39647c85291SNeilBrown return status; 3971da177e4SLinus Torvalds iattr->ia_valid |= ATTR_GID; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) { 4001da177e4SLinus Torvalds READ_BUF(4); 4011da177e4SLinus Torvalds len += 4; 40206553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 4031da177e4SLinus Torvalds switch (dummy32) { 4041da177e4SLinus Torvalds case NFS4_SET_TO_CLIENT_TIME: 4051da177e4SLinus Torvalds len += 12; 4064c94e13eSChristoph Hellwig status = nfsd4_decode_time(argp, &iattr->ia_atime); 4074c94e13eSChristoph Hellwig if (status) 4084c94e13eSChristoph Hellwig return status; 4091da177e4SLinus Torvalds iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); 4101da177e4SLinus Torvalds break; 4111da177e4SLinus Torvalds case NFS4_SET_TO_SERVER_TIME: 4121da177e4SLinus Torvalds iattr->ia_valid |= ATTR_ATIME; 4131da177e4SLinus Torvalds break; 4141da177e4SLinus Torvalds default: 4151da177e4SLinus Torvalds goto xdr_error; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { 4191da177e4SLinus Torvalds READ_BUF(4); 4201da177e4SLinus Torvalds len += 4; 42106553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 4221da177e4SLinus Torvalds switch (dummy32) { 4231da177e4SLinus Torvalds case NFS4_SET_TO_CLIENT_TIME: 4241da177e4SLinus Torvalds len += 12; 4254c94e13eSChristoph Hellwig status = nfsd4_decode_time(argp, &iattr->ia_mtime); 4264c94e13eSChristoph Hellwig if (status) 4274c94e13eSChristoph Hellwig return status; 4281da177e4SLinus Torvalds iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); 4291da177e4SLinus Torvalds break; 4301da177e4SLinus Torvalds case NFS4_SET_TO_SERVER_TIME: 4311da177e4SLinus Torvalds iattr->ia_valid |= ATTR_MTIME; 4321da177e4SLinus Torvalds break; 4331da177e4SLinus Torvalds default: 4341da177e4SLinus Torvalds goto xdr_error; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds } 43718032ca0SDavid Quigley 43818032ca0SDavid Quigley label->len = 0; 43918032ca0SDavid Quigley #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 44018032ca0SDavid Quigley if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { 44118032ca0SDavid Quigley READ_BUF(4); 44218032ca0SDavid Quigley len += 4; 44306553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); /* lfs: we don't use it */ 44418032ca0SDavid Quigley READ_BUF(4); 44518032ca0SDavid Quigley len += 4; 44606553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); /* pi: we don't use it either */ 44718032ca0SDavid Quigley READ_BUF(4); 44818032ca0SDavid Quigley len += 4; 44906553991SJ. Bruce Fields dummy32 = be32_to_cpup(p++); 45018032ca0SDavid Quigley READ_BUF(dummy32); 4511ec8c0c4SKinglong Mee if (dummy32 > NFS4_MAXLABELLEN) 45218032ca0SDavid Quigley return nfserr_badlabel; 45318032ca0SDavid Quigley len += (XDR_QUADLEN(dummy32) << 2); 45418032ca0SDavid Quigley READMEM(buf, dummy32); 45529c353b3SJ. Bruce Fields label->len = dummy32; 45629c353b3SJ. Bruce Fields label->data = svcxdr_dupstr(argp, buf, dummy32); 45718032ca0SDavid Quigley if (!label->data) 45818032ca0SDavid Quigley return nfserr_jukebox; 45918032ca0SDavid Quigley } 46018032ca0SDavid Quigley #endif 46147057abdSAndreas Gruenbacher if (bmval[2] & FATTR4_WORD2_MODE_UMASK) { 46247057abdSAndreas Gruenbacher if (!umask) 46347057abdSAndreas Gruenbacher goto xdr_error; 46447057abdSAndreas Gruenbacher READ_BUF(8); 46547057abdSAndreas Gruenbacher len += 8; 46647057abdSAndreas Gruenbacher dummy32 = be32_to_cpup(p++); 46747057abdSAndreas Gruenbacher iattr->ia_mode = dummy32 & (S_IFMT | S_IALLUGO); 46847057abdSAndreas Gruenbacher dummy32 = be32_to_cpup(p++); 46947057abdSAndreas Gruenbacher *umask = dummy32 & S_IRWXUGO; 47047057abdSAndreas Gruenbacher iattr->ia_valid |= ATTR_MODE; 47147057abdSAndreas Gruenbacher } 472e864c189SJ. Bruce Fields if (len != expected_len) 4731da177e4SLinus Torvalds goto xdr_error; 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds DECODE_TAIL; 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds 478b37ad28bSAl Viro static __be32 479e31a1b66SBenny Halevy nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid) 480e31a1b66SBenny Halevy { 481e31a1b66SBenny Halevy DECODE_HEAD; 482e31a1b66SBenny Halevy 483e31a1b66SBenny Halevy READ_BUF(sizeof(stateid_t)); 48406553991SJ. Bruce Fields sid->si_generation = be32_to_cpup(p++); 485e31a1b66SBenny Halevy COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); 486e31a1b66SBenny Halevy 487e31a1b66SBenny Halevy DECODE_TAIL; 488e31a1b66SBenny Halevy } 489e31a1b66SBenny Halevy 490e31a1b66SBenny Halevy static __be32 4911da177e4SLinus Torvalds nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access) 4921da177e4SLinus Torvalds { 4931da177e4SLinus Torvalds DECODE_HEAD; 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds READ_BUF(4); 49606553991SJ. Bruce Fields access->ac_req_access = be32_to_cpup(p++); 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds DECODE_TAIL; 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds 501acb2887eSJ. Bruce Fields static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) 502acb2887eSJ. Bruce Fields { 503acb2887eSJ. Bruce Fields DECODE_HEAD; 50412fc3e92SJ. Bruce Fields u32 dummy, uid, gid; 505acb2887eSJ. Bruce Fields char *machine_name; 506acb2887eSJ. Bruce Fields int i; 507acb2887eSJ. Bruce Fields int nr_secflavs; 508acb2887eSJ. Bruce Fields 509acb2887eSJ. Bruce Fields /* callback_sec_params4 */ 510acb2887eSJ. Bruce Fields READ_BUF(4); 51106553991SJ. Bruce Fields nr_secflavs = be32_to_cpup(p++); 51257569a70SJ. Bruce Fields if (nr_secflavs) 51312fc3e92SJ. Bruce Fields cbs->flavor = (u32)(-1); 51457569a70SJ. Bruce Fields else 51557569a70SJ. Bruce Fields /* Is this legal? Be generous, take it to mean AUTH_NONE: */ 51657569a70SJ. Bruce Fields cbs->flavor = 0; 517acb2887eSJ. Bruce Fields for (i = 0; i < nr_secflavs; ++i) { 518acb2887eSJ. Bruce Fields READ_BUF(4); 51906553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 520acb2887eSJ. Bruce Fields switch (dummy) { 521acb2887eSJ. Bruce Fields case RPC_AUTH_NULL: 522acb2887eSJ. Bruce Fields /* Nothing to read */ 52312fc3e92SJ. Bruce Fields if (cbs->flavor == (u32)(-1)) 52412fc3e92SJ. Bruce Fields cbs->flavor = RPC_AUTH_NULL; 525acb2887eSJ. Bruce Fields break; 526acb2887eSJ. Bruce Fields case RPC_AUTH_UNIX: 527acb2887eSJ. Bruce Fields READ_BUF(8); 528acb2887eSJ. Bruce Fields /* stamp */ 52906553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 530acb2887eSJ. Bruce Fields 531acb2887eSJ. Bruce Fields /* machine name */ 53206553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 533acb2887eSJ. Bruce Fields READ_BUF(dummy); 534acb2887eSJ. Bruce Fields SAVEMEM(machine_name, dummy); 535acb2887eSJ. Bruce Fields 536acb2887eSJ. Bruce Fields /* uid, gid */ 537acb2887eSJ. Bruce Fields READ_BUF(8); 53806553991SJ. Bruce Fields uid = be32_to_cpup(p++); 53906553991SJ. Bruce Fields gid = be32_to_cpup(p++); 540acb2887eSJ. Bruce Fields 541acb2887eSJ. Bruce Fields /* more gids */ 542acb2887eSJ. Bruce Fields READ_BUF(4); 54306553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 544acb2887eSJ. Bruce Fields READ_BUF(dummy * 4); 54512fc3e92SJ. Bruce Fields if (cbs->flavor == (u32)(-1)) { 54603bc6d1cSEric W. Biederman kuid_t kuid = make_kuid(&init_user_ns, uid); 54703bc6d1cSEric W. Biederman kgid_t kgid = make_kgid(&init_user_ns, gid); 54803bc6d1cSEric W. Biederman if (uid_valid(kuid) && gid_valid(kgid)) { 54903bc6d1cSEric W. Biederman cbs->uid = kuid; 55003bc6d1cSEric W. Biederman cbs->gid = kgid; 55112fc3e92SJ. Bruce Fields cbs->flavor = RPC_AUTH_UNIX; 55203bc6d1cSEric W. Biederman } else { 55303bc6d1cSEric W. Biederman dprintk("RPC_AUTH_UNIX with invalid" 55403bc6d1cSEric W. Biederman "uid or gid ignoring!\n"); 55503bc6d1cSEric W. Biederman } 55612fc3e92SJ. Bruce Fields } 557acb2887eSJ. Bruce Fields break; 558acb2887eSJ. Bruce Fields case RPC_AUTH_GSS: 559acb2887eSJ. Bruce Fields dprintk("RPC_AUTH_GSS callback secflavor " 560acb2887eSJ. Bruce Fields "not supported!\n"); 561acb2887eSJ. Bruce Fields READ_BUF(8); 562acb2887eSJ. Bruce Fields /* gcbp_service */ 56306553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 564acb2887eSJ. Bruce Fields /* gcbp_handle_from_server */ 56506553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 566acb2887eSJ. Bruce Fields READ_BUF(dummy); 567acb2887eSJ. Bruce Fields p += XDR_QUADLEN(dummy); 568acb2887eSJ. Bruce Fields /* gcbp_handle_from_client */ 569acb2887eSJ. Bruce Fields READ_BUF(4); 57006553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 571acb2887eSJ. Bruce Fields READ_BUF(dummy); 572acb2887eSJ. Bruce Fields break; 573acb2887eSJ. Bruce Fields default: 574acb2887eSJ. Bruce Fields dprintk("Illegal callback secflavor\n"); 575acb2887eSJ. Bruce Fields return nfserr_inval; 576acb2887eSJ. Bruce Fields } 577acb2887eSJ. Bruce Fields } 578acb2887eSJ. Bruce Fields DECODE_TAIL; 579acb2887eSJ. Bruce Fields } 580acb2887eSJ. Bruce Fields 581cb73a9f4SJ. Bruce Fields static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) 582cb73a9f4SJ. Bruce Fields { 583cb73a9f4SJ. Bruce Fields DECODE_HEAD; 584cb73a9f4SJ. Bruce Fields 585cb73a9f4SJ. Bruce Fields READ_BUF(4); 58606553991SJ. Bruce Fields bc->bc_cb_program = be32_to_cpup(p++); 587cb73a9f4SJ. Bruce Fields nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); 588cb73a9f4SJ. Bruce Fields 589cb73a9f4SJ. Bruce Fields DECODE_TAIL; 590cb73a9f4SJ. Bruce Fields } 591cb73a9f4SJ. Bruce Fields 5921d1bc8f2SJ. Bruce Fields static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) 5931d1bc8f2SJ. Bruce Fields { 5941d1bc8f2SJ. Bruce Fields DECODE_HEAD; 5951d1bc8f2SJ. Bruce Fields 5961d1bc8f2SJ. Bruce Fields READ_BUF(NFS4_MAX_SESSIONID_LEN + 8); 5971d1bc8f2SJ. Bruce Fields COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); 59806553991SJ. Bruce Fields bcts->dir = be32_to_cpup(p++); 5996ce2357fSBryan Schumaker /* XXX: skipping ctsa_use_conn_in_rdma_mode. Perhaps Tom Tucker 6006ce2357fSBryan Schumaker * could help us figure out we should be using it. */ 6011d1bc8f2SJ. Bruce Fields DECODE_TAIL; 6021d1bc8f2SJ. Bruce Fields } 6031d1bc8f2SJ. Bruce Fields 604b37ad28bSAl Viro static __be32 6051da177e4SLinus Torvalds nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) 6061da177e4SLinus Torvalds { 6071da177e4SLinus Torvalds DECODE_HEAD; 6081da177e4SLinus Torvalds 609e31a1b66SBenny Halevy READ_BUF(4); 61006553991SJ. Bruce Fields close->cl_seqid = be32_to_cpup(p++); 611e31a1b66SBenny Halevy return nfsd4_decode_stateid(argp, &close->cl_stateid); 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds DECODE_TAIL; 6141da177e4SLinus Torvalds } 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds 617b37ad28bSAl Viro static __be32 6181da177e4SLinus Torvalds nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit) 6191da177e4SLinus Torvalds { 6201da177e4SLinus Torvalds DECODE_HEAD; 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds READ_BUF(12); 623542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &commit->co_offset); 62406553991SJ. Bruce Fields commit->co_count = be32_to_cpup(p++); 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds DECODE_TAIL; 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 629b37ad28bSAl Viro static __be32 6301da177e4SLinus Torvalds nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create) 6311da177e4SLinus Torvalds { 6321da177e4SLinus Torvalds DECODE_HEAD; 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds READ_BUF(4); 63506553991SJ. Bruce Fields create->cr_type = be32_to_cpup(p++); 6361da177e4SLinus Torvalds switch (create->cr_type) { 6371da177e4SLinus Torvalds case NF4LNK: 6381da177e4SLinus Torvalds READ_BUF(4); 6397fb84306SJ. Bruce Fields create->cr_datalen = be32_to_cpup(p++); 6407fb84306SJ. Bruce Fields READ_BUF(create->cr_datalen); 64129c353b3SJ. Bruce Fields create->cr_data = svcxdr_dupstr(argp, p, create->cr_datalen); 6427fb84306SJ. Bruce Fields if (!create->cr_data) 64376f47128SJ. Bruce Fields return nfserr_jukebox; 6441da177e4SLinus Torvalds break; 6451da177e4SLinus Torvalds case NF4BLK: 6461da177e4SLinus Torvalds case NF4CHR: 6471da177e4SLinus Torvalds READ_BUF(8); 64806553991SJ. Bruce Fields create->cr_specdata1 = be32_to_cpup(p++); 64906553991SJ. Bruce Fields create->cr_specdata2 = be32_to_cpup(p++); 6501da177e4SLinus Torvalds break; 6511da177e4SLinus Torvalds case NF4SOCK: 6521da177e4SLinus Torvalds case NF4FIFO: 6531da177e4SLinus Torvalds case NF4DIR: 6541da177e4SLinus Torvalds default: 6551da177e4SLinus Torvalds break; 6561da177e4SLinus Torvalds } 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds READ_BUF(4); 65906553991SJ. Bruce Fields create->cr_namelen = be32_to_cpup(p++); 6601da177e4SLinus Torvalds READ_BUF(create->cr_namelen); 6611da177e4SLinus Torvalds SAVEMEM(create->cr_name, create->cr_namelen); 662a36b1725SJ. Bruce Fields if ((status = check_filename(create->cr_name, create->cr_namelen))) 6631da177e4SLinus Torvalds return status; 6641da177e4SLinus Torvalds 6653c8e0316SYu Zhiguo status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, 66647057abdSAndreas Gruenbacher &create->cr_acl, &create->cr_label, 66747057abdSAndreas Gruenbacher ¤t->fs->umask); 668c0d6fc8aSBenny Halevy if (status) 6691da177e4SLinus Torvalds goto out; 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds DECODE_TAIL; 6721da177e4SLinus Torvalds } 6731da177e4SLinus Torvalds 674b37ad28bSAl Viro static inline __be32 6751da177e4SLinus Torvalds nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr) 6761da177e4SLinus Torvalds { 677e31a1b66SBenny Halevy return nfsd4_decode_stateid(argp, &dr->dr_stateid); 6781da177e4SLinus Torvalds } 6791da177e4SLinus Torvalds 680b37ad28bSAl Viro static inline __be32 6811da177e4SLinus Torvalds nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) 6821da177e4SLinus Torvalds { 6831da177e4SLinus Torvalds return nfsd4_decode_bitmap(argp, getattr->ga_bmval); 6841da177e4SLinus Torvalds } 6851da177e4SLinus Torvalds 686b37ad28bSAl Viro static __be32 6871da177e4SLinus Torvalds nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) 6881da177e4SLinus Torvalds { 6891da177e4SLinus Torvalds DECODE_HEAD; 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds READ_BUF(4); 69206553991SJ. Bruce Fields link->li_namelen = be32_to_cpup(p++); 6931da177e4SLinus Torvalds READ_BUF(link->li_namelen); 6941da177e4SLinus Torvalds SAVEMEM(link->li_name, link->li_namelen); 695a36b1725SJ. Bruce Fields if ((status = check_filename(link->li_name, link->li_namelen))) 6961da177e4SLinus Torvalds return status; 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds DECODE_TAIL; 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds 701b37ad28bSAl Viro static __be32 7021da177e4SLinus Torvalds nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) 7031da177e4SLinus Torvalds { 7041da177e4SLinus Torvalds DECODE_HEAD; 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds /* 7071da177e4SLinus Torvalds * type, reclaim(boolean), offset, length, new_lock_owner(boolean) 7081da177e4SLinus Torvalds */ 7091da177e4SLinus Torvalds READ_BUF(28); 71006553991SJ. Bruce Fields lock->lk_type = be32_to_cpup(p++); 7111da177e4SLinus Torvalds if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT)) 7121da177e4SLinus Torvalds goto xdr_error; 71306553991SJ. Bruce Fields lock->lk_reclaim = be32_to_cpup(p++); 714542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &lock->lk_offset); 715542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &lock->lk_length); 71606553991SJ. Bruce Fields lock->lk_is_new = be32_to_cpup(p++); 7171da177e4SLinus Torvalds 7181da177e4SLinus Torvalds if (lock->lk_is_new) { 719e31a1b66SBenny Halevy READ_BUF(4); 72006553991SJ. Bruce Fields lock->lk_new_open_seqid = be32_to_cpup(p++); 721e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid); 722e31a1b66SBenny Halevy if (status) 723e31a1b66SBenny Halevy return status; 724e31a1b66SBenny Halevy READ_BUF(8 + sizeof(clientid_t)); 72506553991SJ. Bruce Fields lock->lk_new_lock_seqid = be32_to_cpup(p++); 7261da177e4SLinus Torvalds COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t)); 72706553991SJ. Bruce Fields lock->lk_new_owner.len = be32_to_cpup(p++); 7281da177e4SLinus Torvalds READ_BUF(lock->lk_new_owner.len); 7291da177e4SLinus Torvalds READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len); 7301da177e4SLinus Torvalds } else { 731e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid); 732e31a1b66SBenny Halevy if (status) 733e31a1b66SBenny Halevy return status; 734e31a1b66SBenny Halevy READ_BUF(4); 73506553991SJ. Bruce Fields lock->lk_old_lock_seqid = be32_to_cpup(p++); 7361da177e4SLinus Torvalds } 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds DECODE_TAIL; 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 741b37ad28bSAl Viro static __be32 7421da177e4SLinus Torvalds nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) 7431da177e4SLinus Torvalds { 7441da177e4SLinus Torvalds DECODE_HEAD; 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds READ_BUF(32); 74706553991SJ. Bruce Fields lockt->lt_type = be32_to_cpup(p++); 7481da177e4SLinus Torvalds if((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT)) 7491da177e4SLinus Torvalds goto xdr_error; 750542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &lockt->lt_offset); 751542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &lockt->lt_length); 7521da177e4SLinus Torvalds COPYMEM(&lockt->lt_clientid, 8); 75306553991SJ. Bruce Fields lockt->lt_owner.len = be32_to_cpup(p++); 7541da177e4SLinus Torvalds READ_BUF(lockt->lt_owner.len); 7551da177e4SLinus Torvalds READMEM(lockt->lt_owner.data, lockt->lt_owner.len); 7561da177e4SLinus Torvalds 7571da177e4SLinus Torvalds DECODE_TAIL; 7581da177e4SLinus Torvalds } 7591da177e4SLinus Torvalds 760b37ad28bSAl Viro static __be32 7611da177e4SLinus Torvalds nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) 7621da177e4SLinus Torvalds { 7631da177e4SLinus Torvalds DECODE_HEAD; 7641da177e4SLinus Torvalds 765e31a1b66SBenny Halevy READ_BUF(8); 76606553991SJ. Bruce Fields locku->lu_type = be32_to_cpup(p++); 7671da177e4SLinus Torvalds if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT)) 7681da177e4SLinus Torvalds goto xdr_error; 76906553991SJ. Bruce Fields locku->lu_seqid = be32_to_cpup(p++); 770e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &locku->lu_stateid); 771e31a1b66SBenny Halevy if (status) 772e31a1b66SBenny Halevy return status; 773e31a1b66SBenny Halevy READ_BUF(16); 774542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &locku->lu_offset); 775542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &locku->lu_length); 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds DECODE_TAIL; 7781da177e4SLinus Torvalds } 7791da177e4SLinus Torvalds 780b37ad28bSAl Viro static __be32 7811da177e4SLinus Torvalds nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) 7821da177e4SLinus Torvalds { 7831da177e4SLinus Torvalds DECODE_HEAD; 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds READ_BUF(4); 78606553991SJ. Bruce Fields lookup->lo_len = be32_to_cpup(p++); 7871da177e4SLinus Torvalds READ_BUF(lookup->lo_len); 7881da177e4SLinus Torvalds SAVEMEM(lookup->lo_name, lookup->lo_len); 789a36b1725SJ. Bruce Fields if ((status = check_filename(lookup->lo_name, lookup->lo_len))) 7901da177e4SLinus Torvalds return status; 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds DECODE_TAIL; 7931da177e4SLinus Torvalds } 7941da177e4SLinus Torvalds 7952c8bd7e0SBenny Halevy static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when) 79604f9e664SJ. Bruce Fields { 79704f9e664SJ. Bruce Fields __be32 *p; 79804f9e664SJ. Bruce Fields u32 w; 79904f9e664SJ. Bruce Fields 80004f9e664SJ. Bruce Fields READ_BUF(4); 80106553991SJ. Bruce Fields w = be32_to_cpup(p++); 8022c8bd7e0SBenny Halevy *share_access = w & NFS4_SHARE_ACCESS_MASK; 8032c8bd7e0SBenny Halevy *deleg_want = w & NFS4_SHARE_WANT_MASK; 8042c8bd7e0SBenny Halevy if (deleg_when) 8052c8bd7e0SBenny Halevy *deleg_when = w & NFS4_SHARE_WHEN_MASK; 8062c8bd7e0SBenny Halevy 80704f9e664SJ. Bruce Fields switch (w & NFS4_SHARE_ACCESS_MASK) { 80804f9e664SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 80904f9e664SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 81004f9e664SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 81104f9e664SJ. Bruce Fields break; 81204f9e664SJ. Bruce Fields default: 81304f9e664SJ. Bruce Fields return nfserr_bad_xdr; 81404f9e664SJ. Bruce Fields } 815fc0d14feSBenny Halevy w &= ~NFS4_SHARE_ACCESS_MASK; 81604f9e664SJ. Bruce Fields if (!w) 81704f9e664SJ. Bruce Fields return nfs_ok; 81804f9e664SJ. Bruce Fields if (!argp->minorversion) 81904f9e664SJ. Bruce Fields return nfserr_bad_xdr; 82004f9e664SJ. Bruce Fields switch (w & NFS4_SHARE_WANT_MASK) { 82104f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_NO_PREFERENCE: 82204f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_READ_DELEG: 82304f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_WRITE_DELEG: 82404f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_ANY_DELEG: 82504f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_NO_DELEG: 82604f9e664SJ. Bruce Fields case NFS4_SHARE_WANT_CANCEL: 82704f9e664SJ. Bruce Fields break; 82804f9e664SJ. Bruce Fields default: 82904f9e664SJ. Bruce Fields return nfserr_bad_xdr; 83004f9e664SJ. Bruce Fields } 83192bac8c5SBenny Halevy w &= ~NFS4_SHARE_WANT_MASK; 83204f9e664SJ. Bruce Fields if (!w) 83304f9e664SJ. Bruce Fields return nfs_ok; 8342c8bd7e0SBenny Halevy 8352c8bd7e0SBenny Halevy if (!deleg_when) /* open_downgrade */ 8362c8bd7e0SBenny Halevy return nfserr_inval; 83704f9e664SJ. Bruce Fields switch (w) { 83804f9e664SJ. Bruce Fields case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL: 83904f9e664SJ. Bruce Fields case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED: 840c668fc6dSBenny Halevy case (NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL | 841c668fc6dSBenny Halevy NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED): 84204f9e664SJ. Bruce Fields return nfs_ok; 84304f9e664SJ. Bruce Fields } 84404f9e664SJ. Bruce Fields xdr_error: 84504f9e664SJ. Bruce Fields return nfserr_bad_xdr; 84604f9e664SJ. Bruce Fields } 84704f9e664SJ. Bruce Fields 84804f9e664SJ. Bruce Fields static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x) 84904f9e664SJ. Bruce Fields { 85004f9e664SJ. Bruce Fields __be32 *p; 85104f9e664SJ. Bruce Fields 85204f9e664SJ. Bruce Fields READ_BUF(4); 85306553991SJ. Bruce Fields *x = be32_to_cpup(p++); 85404f9e664SJ. Bruce Fields /* Note: unlinke access bits, deny bits may be zero. */ 85501cd4afaSDan Carpenter if (*x & ~NFS4_SHARE_DENY_BOTH) 85604f9e664SJ. Bruce Fields return nfserr_bad_xdr; 85704f9e664SJ. Bruce Fields return nfs_ok; 85804f9e664SJ. Bruce Fields xdr_error: 85904f9e664SJ. Bruce Fields return nfserr_bad_xdr; 86004f9e664SJ. Bruce Fields } 86104f9e664SJ. Bruce Fields 862a084daf5SJ. Bruce Fields static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o) 863a084daf5SJ. Bruce Fields { 864a084daf5SJ. Bruce Fields __be32 *p; 865a084daf5SJ. Bruce Fields 866a084daf5SJ. Bruce Fields READ_BUF(4); 86706553991SJ. Bruce Fields o->len = be32_to_cpup(p++); 868a084daf5SJ. Bruce Fields 869a084daf5SJ. Bruce Fields if (o->len == 0 || o->len > NFS4_OPAQUE_LIMIT) 870a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 871a084daf5SJ. Bruce Fields 872a084daf5SJ. Bruce Fields READ_BUF(o->len); 873a084daf5SJ. Bruce Fields SAVEMEM(o->data, o->len); 874a084daf5SJ. Bruce Fields return nfs_ok; 875a084daf5SJ. Bruce Fields xdr_error: 876a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 877a084daf5SJ. Bruce Fields } 878a084daf5SJ. Bruce Fields 879b37ad28bSAl Viro static __be32 8801da177e4SLinus Torvalds nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) 8811da177e4SLinus Torvalds { 8821da177e4SLinus Torvalds DECODE_HEAD; 8832c8bd7e0SBenny Halevy u32 dummy; 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds memset(open->op_bmval, 0, sizeof(open->op_bmval)); 8861da177e4SLinus Torvalds open->op_iattr.ia_valid = 0; 887fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 8881da177e4SLinus Torvalds 8899d313b17SJ. Bruce Fields open->op_xdr_error = 0; 8901da177e4SLinus Torvalds /* seqid, share_access, share_deny, clientid, ownerlen */ 89104f9e664SJ. Bruce Fields READ_BUF(4); 89206553991SJ. Bruce Fields open->op_seqid = be32_to_cpup(p++); 8932c8bd7e0SBenny Halevy /* decode, yet ignore deleg_when until supported */ 8942c8bd7e0SBenny Halevy status = nfsd4_decode_share_access(argp, &open->op_share_access, 8952c8bd7e0SBenny Halevy &open->op_deleg_want, &dummy); 89604f9e664SJ. Bruce Fields if (status) 89704f9e664SJ. Bruce Fields goto xdr_error; 89804f9e664SJ. Bruce Fields status = nfsd4_decode_share_deny(argp, &open->op_share_deny); 89904f9e664SJ. Bruce Fields if (status) 90004f9e664SJ. Bruce Fields goto xdr_error; 901a084daf5SJ. Bruce Fields READ_BUF(sizeof(clientid_t)); 9021da177e4SLinus Torvalds COPYMEM(&open->op_clientid, sizeof(clientid_t)); 903a084daf5SJ. Bruce Fields status = nfsd4_decode_opaque(argp, &open->op_owner); 904a084daf5SJ. Bruce Fields if (status) 905a084daf5SJ. Bruce Fields goto xdr_error; 906a084daf5SJ. Bruce Fields READ_BUF(4); 90706553991SJ. Bruce Fields open->op_create = be32_to_cpup(p++); 9081da177e4SLinus Torvalds switch (open->op_create) { 9091da177e4SLinus Torvalds case NFS4_OPEN_NOCREATE: 9101da177e4SLinus Torvalds break; 9111da177e4SLinus Torvalds case NFS4_OPEN_CREATE: 91247057abdSAndreas Gruenbacher current->fs->umask = 0; 9131da177e4SLinus Torvalds READ_BUF(4); 91406553991SJ. Bruce Fields open->op_createmode = be32_to_cpup(p++); 9151da177e4SLinus Torvalds switch (open->op_createmode) { 9161da177e4SLinus Torvalds case NFS4_CREATE_UNCHECKED: 9171da177e4SLinus Torvalds case NFS4_CREATE_GUARDED: 918c0d6fc8aSBenny Halevy status = nfsd4_decode_fattr(argp, open->op_bmval, 91947057abdSAndreas Gruenbacher &open->op_iattr, &open->op_acl, &open->op_label, 92047057abdSAndreas Gruenbacher ¤t->fs->umask); 921c0d6fc8aSBenny Halevy if (status) 9221da177e4SLinus Torvalds goto out; 9231da177e4SLinus Torvalds break; 9241da177e4SLinus Torvalds case NFS4_CREATE_EXCLUSIVE: 925ab4684d1SChuck Lever READ_BUF(NFS4_VERIFIER_SIZE); 926ab4684d1SChuck Lever COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); 9271da177e4SLinus Torvalds break; 92879fb54abSBenny Halevy case NFS4_CREATE_EXCLUSIVE4_1: 92979fb54abSBenny Halevy if (argp->minorversion < 1) 93079fb54abSBenny Halevy goto xdr_error; 931ab4684d1SChuck Lever READ_BUF(NFS4_VERIFIER_SIZE); 932ab4684d1SChuck Lever COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); 93379fb54abSBenny Halevy status = nfsd4_decode_fattr(argp, open->op_bmval, 93447057abdSAndreas Gruenbacher &open->op_iattr, &open->op_acl, &open->op_label, 93547057abdSAndreas Gruenbacher ¤t->fs->umask); 93679fb54abSBenny Halevy if (status) 93779fb54abSBenny Halevy goto out; 93879fb54abSBenny Halevy break; 9391da177e4SLinus Torvalds default: 9401da177e4SLinus Torvalds goto xdr_error; 9411da177e4SLinus Torvalds } 9421da177e4SLinus Torvalds break; 9431da177e4SLinus Torvalds default: 9441da177e4SLinus Torvalds goto xdr_error; 9451da177e4SLinus Torvalds } 9461da177e4SLinus Torvalds 9471da177e4SLinus Torvalds /* open_claim */ 9481da177e4SLinus Torvalds READ_BUF(4); 94906553991SJ. Bruce Fields open->op_claim_type = be32_to_cpup(p++); 9501da177e4SLinus Torvalds switch (open->op_claim_type) { 9511da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_NULL: 9521da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_PREV: 9531da177e4SLinus Torvalds READ_BUF(4); 95406553991SJ. Bruce Fields open->op_fname.len = be32_to_cpup(p++); 9551da177e4SLinus Torvalds READ_BUF(open->op_fname.len); 9561da177e4SLinus Torvalds SAVEMEM(open->op_fname.data, open->op_fname.len); 957a36b1725SJ. Bruce Fields if ((status = check_filename(open->op_fname.data, open->op_fname.len))) 9581da177e4SLinus Torvalds return status; 9591da177e4SLinus Torvalds break; 9601da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_PREVIOUS: 9611da177e4SLinus Torvalds READ_BUF(4); 96206553991SJ. Bruce Fields open->op_delegate_type = be32_to_cpup(p++); 9631da177e4SLinus Torvalds break; 9641da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_CUR: 965e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); 966e31a1b66SBenny Halevy if (status) 967e31a1b66SBenny Halevy return status; 968e31a1b66SBenny Halevy READ_BUF(4); 96906553991SJ. Bruce Fields open->op_fname.len = be32_to_cpup(p++); 9701da177e4SLinus Torvalds READ_BUF(open->op_fname.len); 9711da177e4SLinus Torvalds SAVEMEM(open->op_fname.data, open->op_fname.len); 972a36b1725SJ. Bruce Fields if ((status = check_filename(open->op_fname.data, open->op_fname.len))) 9731da177e4SLinus Torvalds return status; 9741da177e4SLinus Torvalds break; 9758b289b2cSJ. Bruce Fields case NFS4_OPEN_CLAIM_FH: 9768b289b2cSJ. Bruce Fields case NFS4_OPEN_CLAIM_DELEG_PREV_FH: 9778b289b2cSJ. Bruce Fields if (argp->minorversion < 1) 9788b289b2cSJ. Bruce Fields goto xdr_error; 9798b289b2cSJ. Bruce Fields /* void */ 9808b289b2cSJ. Bruce Fields break; 9818b289b2cSJ. Bruce Fields case NFS4_OPEN_CLAIM_DELEG_CUR_FH: 9828b289b2cSJ. Bruce Fields if (argp->minorversion < 1) 9838b289b2cSJ. Bruce Fields goto xdr_error; 9848b289b2cSJ. Bruce Fields status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); 9858b289b2cSJ. Bruce Fields if (status) 9868b289b2cSJ. Bruce Fields return status; 9878b289b2cSJ. Bruce Fields break; 9881da177e4SLinus Torvalds default: 9891da177e4SLinus Torvalds goto xdr_error; 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds 9921da177e4SLinus Torvalds DECODE_TAIL; 9931da177e4SLinus Torvalds } 9941da177e4SLinus Torvalds 995b37ad28bSAl Viro static __be32 9961da177e4SLinus Torvalds nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) 9971da177e4SLinus Torvalds { 9981da177e4SLinus Torvalds DECODE_HEAD; 9991da177e4SLinus Torvalds 1000e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 1001e1a90ebdSAnna Schumaker return nfserr_notsupp; 1002e1a90ebdSAnna Schumaker 1003e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); 1004e31a1b66SBenny Halevy if (status) 1005e31a1b66SBenny Halevy return status; 1006e31a1b66SBenny Halevy READ_BUF(4); 100706553991SJ. Bruce Fields open_conf->oc_seqid = be32_to_cpup(p++); 10081da177e4SLinus Torvalds 10091da177e4SLinus Torvalds DECODE_TAIL; 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds 1012b37ad28bSAl Viro static __be32 10131da177e4SLinus Torvalds nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down) 10141da177e4SLinus Torvalds { 10151da177e4SLinus Torvalds DECODE_HEAD; 10161da177e4SLinus Torvalds 1017e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &open_down->od_stateid); 1018e31a1b66SBenny Halevy if (status) 1019e31a1b66SBenny Halevy return status; 102004f9e664SJ. Bruce Fields READ_BUF(4); 102106553991SJ. Bruce Fields open_down->od_seqid = be32_to_cpup(p++); 10222c8bd7e0SBenny Halevy status = nfsd4_decode_share_access(argp, &open_down->od_share_access, 10232c8bd7e0SBenny Halevy &open_down->od_deleg_want, NULL); 102404f9e664SJ. Bruce Fields if (status) 102504f9e664SJ. Bruce Fields return status; 102604f9e664SJ. Bruce Fields status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny); 102704f9e664SJ. Bruce Fields if (status) 102804f9e664SJ. Bruce Fields return status; 10291da177e4SLinus Torvalds DECODE_TAIL; 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds 1032b37ad28bSAl Viro static __be32 10331da177e4SLinus Torvalds nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) 10341da177e4SLinus Torvalds { 10351da177e4SLinus Torvalds DECODE_HEAD; 10361da177e4SLinus Torvalds 10371da177e4SLinus Torvalds READ_BUF(4); 103806553991SJ. Bruce Fields putfh->pf_fhlen = be32_to_cpup(p++); 10391da177e4SLinus Torvalds if (putfh->pf_fhlen > NFS4_FHSIZE) 10401da177e4SLinus Torvalds goto xdr_error; 10411da177e4SLinus Torvalds READ_BUF(putfh->pf_fhlen); 10421da177e4SLinus Torvalds SAVEMEM(putfh->pf_fhval, putfh->pf_fhlen); 10431da177e4SLinus Torvalds 10441da177e4SLinus Torvalds DECODE_TAIL; 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds 1047b37ad28bSAl Viro static __be32 1048e1a90ebdSAnna Schumaker nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p) 1049e1a90ebdSAnna Schumaker { 1050e1a90ebdSAnna Schumaker if (argp->minorversion == 0) 1051e1a90ebdSAnna Schumaker return nfs_ok; 1052e1a90ebdSAnna Schumaker return nfserr_notsupp; 1053e1a90ebdSAnna Schumaker } 1054e1a90ebdSAnna Schumaker 1055e1a90ebdSAnna Schumaker static __be32 10561da177e4SLinus Torvalds nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) 10571da177e4SLinus Torvalds { 10581da177e4SLinus Torvalds DECODE_HEAD; 10591da177e4SLinus Torvalds 1060e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &read->rd_stateid); 1061e31a1b66SBenny Halevy if (status) 1062e31a1b66SBenny Halevy return status; 1063e31a1b66SBenny Halevy READ_BUF(12); 1064542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &read->rd_offset); 106506553991SJ. Bruce Fields read->rd_length = be32_to_cpup(p++); 10661da177e4SLinus Torvalds 10671da177e4SLinus Torvalds DECODE_TAIL; 10681da177e4SLinus Torvalds } 10691da177e4SLinus Torvalds 1070b37ad28bSAl Viro static __be32 10711da177e4SLinus Torvalds nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir) 10721da177e4SLinus Torvalds { 10731da177e4SLinus Torvalds DECODE_HEAD; 10741da177e4SLinus Torvalds 10751da177e4SLinus Torvalds READ_BUF(24); 1076542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &readdir->rd_cookie); 10771da177e4SLinus Torvalds COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data)); 107806553991SJ. Bruce Fields readdir->rd_dircount = be32_to_cpup(p++); 107906553991SJ. Bruce Fields readdir->rd_maxcount = be32_to_cpup(p++); 10801da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval))) 10811da177e4SLinus Torvalds goto out; 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds DECODE_TAIL; 10841da177e4SLinus Torvalds } 10851da177e4SLinus Torvalds 1086b37ad28bSAl Viro static __be32 10871da177e4SLinus Torvalds nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove) 10881da177e4SLinus Torvalds { 10891da177e4SLinus Torvalds DECODE_HEAD; 10901da177e4SLinus Torvalds 10911da177e4SLinus Torvalds READ_BUF(4); 109206553991SJ. Bruce Fields remove->rm_namelen = be32_to_cpup(p++); 10931da177e4SLinus Torvalds READ_BUF(remove->rm_namelen); 10941da177e4SLinus Torvalds SAVEMEM(remove->rm_name, remove->rm_namelen); 1095a36b1725SJ. Bruce Fields if ((status = check_filename(remove->rm_name, remove->rm_namelen))) 10961da177e4SLinus Torvalds return status; 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds DECODE_TAIL; 10991da177e4SLinus Torvalds } 11001da177e4SLinus Torvalds 1101b37ad28bSAl Viro static __be32 11021da177e4SLinus Torvalds nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename) 11031da177e4SLinus Torvalds { 11041da177e4SLinus Torvalds DECODE_HEAD; 11051da177e4SLinus Torvalds 11061da177e4SLinus Torvalds READ_BUF(4); 110706553991SJ. Bruce Fields rename->rn_snamelen = be32_to_cpup(p++); 11084aed9c46SJ. Bruce Fields READ_BUF(rename->rn_snamelen); 11091da177e4SLinus Torvalds SAVEMEM(rename->rn_sname, rename->rn_snamelen); 11104aed9c46SJ. Bruce Fields READ_BUF(4); 111106553991SJ. Bruce Fields rename->rn_tnamelen = be32_to_cpup(p++); 11121da177e4SLinus Torvalds READ_BUF(rename->rn_tnamelen); 11131da177e4SLinus Torvalds SAVEMEM(rename->rn_tname, rename->rn_tnamelen); 1114a36b1725SJ. Bruce Fields if ((status = check_filename(rename->rn_sname, rename->rn_snamelen))) 11151da177e4SLinus Torvalds return status; 1116a36b1725SJ. Bruce Fields if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen))) 11171da177e4SLinus Torvalds return status; 11181da177e4SLinus Torvalds 11191da177e4SLinus Torvalds DECODE_TAIL; 11201da177e4SLinus Torvalds } 11211da177e4SLinus Torvalds 1122b37ad28bSAl Viro static __be32 11231da177e4SLinus Torvalds nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) 11241da177e4SLinus Torvalds { 11251da177e4SLinus Torvalds DECODE_HEAD; 11261da177e4SLinus Torvalds 1127e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 1128e1a90ebdSAnna Schumaker return nfserr_notsupp; 1129e1a90ebdSAnna Schumaker 11301da177e4SLinus Torvalds READ_BUF(sizeof(clientid_t)); 11311da177e4SLinus Torvalds COPYMEM(clientid, sizeof(clientid_t)); 11321da177e4SLinus Torvalds 11331da177e4SLinus Torvalds DECODE_TAIL; 11341da177e4SLinus Torvalds } 11351da177e4SLinus Torvalds 1136b37ad28bSAl Viro static __be32 1137dcb488a3SAndy Adamson nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, 1138dcb488a3SAndy Adamson struct nfsd4_secinfo *secinfo) 1139dcb488a3SAndy Adamson { 1140dcb488a3SAndy Adamson DECODE_HEAD; 1141dcb488a3SAndy Adamson 1142dcb488a3SAndy Adamson READ_BUF(4); 114306553991SJ. Bruce Fields secinfo->si_namelen = be32_to_cpup(p++); 1144dcb488a3SAndy Adamson READ_BUF(secinfo->si_namelen); 1145dcb488a3SAndy Adamson SAVEMEM(secinfo->si_name, secinfo->si_namelen); 1146a36b1725SJ. Bruce Fields status = check_filename(secinfo->si_name, secinfo->si_namelen); 1147dcb488a3SAndy Adamson if (status) 1148dcb488a3SAndy Adamson return status; 1149dcb488a3SAndy Adamson DECODE_TAIL; 1150dcb488a3SAndy Adamson } 1151dcb488a3SAndy Adamson 1152dcb488a3SAndy Adamson static __be32 115304f4ad16SJ. Bruce Fields nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, 115404f4ad16SJ. Bruce Fields struct nfsd4_secinfo_no_name *sin) 115504f4ad16SJ. Bruce Fields { 115604f4ad16SJ. Bruce Fields DECODE_HEAD; 115704f4ad16SJ. Bruce Fields 115804f4ad16SJ. Bruce Fields READ_BUF(4); 115906553991SJ. Bruce Fields sin->sin_style = be32_to_cpup(p++); 116004f4ad16SJ. Bruce Fields DECODE_TAIL; 116104f4ad16SJ. Bruce Fields } 116204f4ad16SJ. Bruce Fields 116304f4ad16SJ. Bruce Fields static __be32 11641da177e4SLinus Torvalds nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) 11651da177e4SLinus Torvalds { 1166e31a1b66SBenny Halevy __be32 status; 11671da177e4SLinus Torvalds 1168e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); 1169e31a1b66SBenny Halevy if (status) 1170e31a1b66SBenny Halevy return status; 11713c8e0316SYu Zhiguo return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, 117247057abdSAndreas Gruenbacher &setattr->sa_acl, &setattr->sa_label, NULL); 11731da177e4SLinus Torvalds } 11741da177e4SLinus Torvalds 1175b37ad28bSAl Viro static __be32 11761da177e4SLinus Torvalds nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid) 11771da177e4SLinus Torvalds { 11781da177e4SLinus Torvalds DECODE_HEAD; 11791da177e4SLinus Torvalds 1180e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 1181e1a90ebdSAnna Schumaker return nfserr_notsupp; 1182e1a90ebdSAnna Schumaker 1183ab4684d1SChuck Lever READ_BUF(NFS4_VERIFIER_SIZE); 1184ab4684d1SChuck Lever COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE); 11851da177e4SLinus Torvalds 1186a084daf5SJ. Bruce Fields status = nfsd4_decode_opaque(argp, &setclientid->se_name); 1187a084daf5SJ. Bruce Fields if (status) 1188a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 1189a084daf5SJ. Bruce Fields READ_BUF(8); 119006553991SJ. Bruce Fields setclientid->se_callback_prog = be32_to_cpup(p++); 119106553991SJ. Bruce Fields setclientid->se_callback_netid_len = be32_to_cpup(p++); 11924aed9c46SJ. Bruce Fields READ_BUF(setclientid->se_callback_netid_len); 11931da177e4SLinus Torvalds SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len); 11944aed9c46SJ. Bruce Fields READ_BUF(4); 119506553991SJ. Bruce Fields setclientid->se_callback_addr_len = be32_to_cpup(p++); 11961da177e4SLinus Torvalds 11974aed9c46SJ. Bruce Fields READ_BUF(setclientid->se_callback_addr_len); 11981da177e4SLinus Torvalds SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len); 11994aed9c46SJ. Bruce Fields READ_BUF(4); 120006553991SJ. Bruce Fields setclientid->se_callback_ident = be32_to_cpup(p++); 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds DECODE_TAIL; 12031da177e4SLinus Torvalds } 12041da177e4SLinus Torvalds 1205b37ad28bSAl Viro static __be32 12061da177e4SLinus Torvalds nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c) 12071da177e4SLinus Torvalds { 12081da177e4SLinus Torvalds DECODE_HEAD; 12091da177e4SLinus Torvalds 1210e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 1211e1a90ebdSAnna Schumaker return nfserr_notsupp; 1212e1a90ebdSAnna Schumaker 1213ab4684d1SChuck Lever READ_BUF(8 + NFS4_VERIFIER_SIZE); 12141da177e4SLinus Torvalds COPYMEM(&scd_c->sc_clientid, 8); 1215ab4684d1SChuck Lever COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE); 12161da177e4SLinus Torvalds 12171da177e4SLinus Torvalds DECODE_TAIL; 12181da177e4SLinus Torvalds } 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds /* Also used for NVERIFY */ 1221b37ad28bSAl Viro static __be32 12221da177e4SLinus Torvalds nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) 12231da177e4SLinus Torvalds { 12241da177e4SLinus Torvalds DECODE_HEAD; 12251da177e4SLinus Torvalds 12261da177e4SLinus Torvalds if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) 12271da177e4SLinus Torvalds goto out; 12281da177e4SLinus Torvalds 12291da177e4SLinus Torvalds /* For convenience's sake, we compare raw xdr'd attributes in 1230e5f95703SJ. Bruce Fields * nfsd4_proc_verify */ 1231e5f95703SJ. Bruce Fields 12321da177e4SLinus Torvalds READ_BUF(4); 123306553991SJ. Bruce Fields verify->ve_attrlen = be32_to_cpup(p++); 12341da177e4SLinus Torvalds READ_BUF(verify->ve_attrlen); 12351da177e4SLinus Torvalds SAVEMEM(verify->ve_attrval, verify->ve_attrlen); 12361da177e4SLinus Torvalds 12371da177e4SLinus Torvalds DECODE_TAIL; 12381da177e4SLinus Torvalds } 12391da177e4SLinus Torvalds 1240b37ad28bSAl Viro static __be32 12411da177e4SLinus Torvalds nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) 12421da177e4SLinus Torvalds { 12431da177e4SLinus Torvalds int avail; 12441da177e4SLinus Torvalds int len; 12451da177e4SLinus Torvalds DECODE_HEAD; 12461da177e4SLinus Torvalds 1247e31a1b66SBenny Halevy status = nfsd4_decode_stateid(argp, &write->wr_stateid); 1248e31a1b66SBenny Halevy if (status) 1249e31a1b66SBenny Halevy return status; 1250e31a1b66SBenny Halevy READ_BUF(16); 1251542d1ab3SJ. Bruce Fields p = xdr_decode_hyper(p, &write->wr_offset); 125206553991SJ. Bruce Fields write->wr_stable_how = be32_to_cpup(p++); 125354bbb7d2SKinglong Mee if (write->wr_stable_how > NFS_FILE_SYNC) 12541da177e4SLinus Torvalds goto xdr_error; 125506553991SJ. Bruce Fields write->wr_buflen = be32_to_cpup(p++); 12561da177e4SLinus Torvalds 12571da177e4SLinus Torvalds /* Sorry .. no magic macros for this.. * 12581da177e4SLinus Torvalds * READ_BUF(write->wr_buflen); 12591da177e4SLinus Torvalds * SAVEMEM(write->wr_buf, write->wr_buflen); 12601da177e4SLinus Torvalds */ 12611da177e4SLinus Torvalds avail = (char*)argp->end - (char*)argp->p; 12621da177e4SLinus Torvalds if (avail + argp->pagelen < write->wr_buflen) { 1263817cb9d4SChuck Lever dprintk("NFSD: xdr error (%s:%d)\n", 1264817cb9d4SChuck Lever __FILE__, __LINE__); 12651da177e4SLinus Torvalds goto xdr_error; 12661da177e4SLinus Torvalds } 126770cc7f75SJ. Bruce Fields write->wr_head.iov_base = p; 126870cc7f75SJ. Bruce Fields write->wr_head.iov_len = avail; 126970cc7f75SJ. Bruce Fields write->wr_pagelist = argp->pagelist; 12705a80a54dSJ. Bruce Fields 12715a80a54dSJ. Bruce Fields len = XDR_QUADLEN(write->wr_buflen) << 2; 12725a80a54dSJ. Bruce Fields if (len >= avail) { 12735a80a54dSJ. Bruce Fields int pages; 12745a80a54dSJ. Bruce Fields 12755a80a54dSJ. Bruce Fields len -= avail; 12765a80a54dSJ. Bruce Fields 12775a80a54dSJ. Bruce Fields pages = len >> PAGE_SHIFT; 12785a80a54dSJ. Bruce Fields argp->pagelist += pages; 12795a80a54dSJ. Bruce Fields argp->pagelen -= pages * PAGE_SIZE; 12805a80a54dSJ. Bruce Fields len -= pages * PAGE_SIZE; 12815a80a54dSJ. Bruce Fields 12825a80a54dSJ. Bruce Fields argp->p = (__be32 *)page_address(argp->pagelist[0]); 1283365da4adSJ. Bruce Fields argp->pagelist++; 12845a80a54dSJ. Bruce Fields argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); 12851da177e4SLinus Torvalds } 12865a80a54dSJ. Bruce Fields argp->p += XDR_QUADLEN(len); 12871da177e4SLinus Torvalds 12881da177e4SLinus Torvalds DECODE_TAIL; 12891da177e4SLinus Torvalds } 12901da177e4SLinus Torvalds 1291b37ad28bSAl Viro static __be32 12921da177e4SLinus Torvalds nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner) 12931da177e4SLinus Torvalds { 12941da177e4SLinus Torvalds DECODE_HEAD; 12951da177e4SLinus Torvalds 1296e1a90ebdSAnna Schumaker if (argp->minorversion >= 1) 1297e1a90ebdSAnna Schumaker return nfserr_notsupp; 1298e1a90ebdSAnna Schumaker 12991da177e4SLinus Torvalds READ_BUF(12); 13001da177e4SLinus Torvalds COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); 130106553991SJ. Bruce Fields rlockowner->rl_owner.len = be32_to_cpup(p++); 13021da177e4SLinus Torvalds READ_BUF(rlockowner->rl_owner.len); 13031da177e4SLinus Torvalds READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len); 13041da177e4SLinus Torvalds 130560adfc50SAndy Adamson if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid)) 130660adfc50SAndy Adamson return nfserr_inval; 13071da177e4SLinus Torvalds DECODE_TAIL; 13081da177e4SLinus Torvalds } 13091da177e4SLinus Torvalds 1310b37ad28bSAl Viro static __be32 13112db134ebSAndy Adamson nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, 13120733d213SAndy Adamson struct nfsd4_exchange_id *exid) 13132db134ebSAndy Adamson { 13145afa040bSMi Jinlong int dummy, tmp; 13150733d213SAndy Adamson DECODE_HEAD; 13160733d213SAndy Adamson 13170733d213SAndy Adamson READ_BUF(NFS4_VERIFIER_SIZE); 13180733d213SAndy Adamson COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE); 13190733d213SAndy Adamson 1320a084daf5SJ. Bruce Fields status = nfsd4_decode_opaque(argp, &exid->clname); 1321a084daf5SJ. Bruce Fields if (status) 1322a084daf5SJ. Bruce Fields return nfserr_bad_xdr; 13230733d213SAndy Adamson 13240733d213SAndy Adamson READ_BUF(4); 132506553991SJ. Bruce Fields exid->flags = be32_to_cpup(p++); 13260733d213SAndy Adamson 13270733d213SAndy Adamson /* Ignore state_protect4_a */ 13280733d213SAndy Adamson READ_BUF(4); 132906553991SJ. Bruce Fields exid->spa_how = be32_to_cpup(p++); 13300733d213SAndy Adamson switch (exid->spa_how) { 13310733d213SAndy Adamson case SP4_NONE: 13320733d213SAndy Adamson break; 13330733d213SAndy Adamson case SP4_MACH_CRED: 13340733d213SAndy Adamson /* spo_must_enforce */ 1335ed941643SAndrew Elble status = nfsd4_decode_bitmap(argp, 1336ed941643SAndrew Elble exid->spo_must_enforce); 1337ed941643SAndrew Elble if (status) 1338ed941643SAndrew Elble goto out; 13390733d213SAndy Adamson /* spo_must_allow */ 1340ed941643SAndrew Elble status = nfsd4_decode_bitmap(argp, exid->spo_must_allow); 1341ed941643SAndrew Elble if (status) 1342ed941643SAndrew Elble goto out; 13430733d213SAndy Adamson break; 13440733d213SAndy Adamson case SP4_SSV: 13450733d213SAndy Adamson /* ssp_ops */ 13460733d213SAndy Adamson READ_BUF(4); 134706553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13480733d213SAndy Adamson READ_BUF(dummy * 4); 13490733d213SAndy Adamson p += dummy; 13500733d213SAndy Adamson 13510733d213SAndy Adamson READ_BUF(4); 135206553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13530733d213SAndy Adamson READ_BUF(dummy * 4); 13540733d213SAndy Adamson p += dummy; 13550733d213SAndy Adamson 13560733d213SAndy Adamson /* ssp_hash_algs<> */ 13570733d213SAndy Adamson READ_BUF(4); 135806553991SJ. Bruce Fields tmp = be32_to_cpup(p++); 13595afa040bSMi Jinlong while (tmp--) { 13600733d213SAndy Adamson READ_BUF(4); 136106553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13620733d213SAndy Adamson READ_BUF(dummy); 13630733d213SAndy Adamson p += XDR_QUADLEN(dummy); 13645afa040bSMi Jinlong } 13655afa040bSMi Jinlong 13665afa040bSMi Jinlong /* ssp_encr_algs<> */ 13675afa040bSMi Jinlong READ_BUF(4); 136806553991SJ. Bruce Fields tmp = be32_to_cpup(p++); 13695afa040bSMi Jinlong while (tmp--) { 13705afa040bSMi Jinlong READ_BUF(4); 137106553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13725afa040bSMi Jinlong READ_BUF(dummy); 13735afa040bSMi Jinlong p += XDR_QUADLEN(dummy); 13745afa040bSMi Jinlong } 13750733d213SAndy Adamson 13760733d213SAndy Adamson /* ssp_window and ssp_num_gss_handles */ 13770733d213SAndy Adamson READ_BUF(8); 137806553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 137906553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13800733d213SAndy Adamson break; 13810733d213SAndy Adamson default: 13820733d213SAndy Adamson goto xdr_error; 13830733d213SAndy Adamson } 13840733d213SAndy Adamson 13850733d213SAndy Adamson /* Ignore Implementation ID */ 13860733d213SAndy Adamson READ_BUF(4); /* nfs_impl_id4 array length */ 138706553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13880733d213SAndy Adamson 13890733d213SAndy Adamson if (dummy > 1) 13900733d213SAndy Adamson goto xdr_error; 13910733d213SAndy Adamson 13920733d213SAndy Adamson if (dummy == 1) { 13930733d213SAndy Adamson /* nii_domain */ 13940733d213SAndy Adamson READ_BUF(4); 139506553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 13960733d213SAndy Adamson READ_BUF(dummy); 13970733d213SAndy Adamson p += XDR_QUADLEN(dummy); 13980733d213SAndy Adamson 13990733d213SAndy Adamson /* nii_name */ 14000733d213SAndy Adamson READ_BUF(4); 140106553991SJ. Bruce Fields dummy = be32_to_cpup(p++); 14020733d213SAndy Adamson READ_BUF(dummy); 14030733d213SAndy Adamson p += XDR_QUADLEN(dummy); 14040733d213SAndy Adamson 14050733d213SAndy Adamson /* nii_date */ 14060733d213SAndy Adamson READ_BUF(12); 14070733d213SAndy Adamson p += 3; 14080733d213SAndy Adamson } 14090733d213SAndy Adamson DECODE_TAIL; 14102db134ebSAndy Adamson } 14112db134ebSAndy Adamson 14122db134ebSAndy Adamson static __be32 14132db134ebSAndy Adamson nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, 14142db134ebSAndy Adamson struct nfsd4_create_session *sess) 14152db134ebSAndy Adamson { 1416ec6b5d7bSAndy Adamson DECODE_HEAD; 1417ec6b5d7bSAndy Adamson u32 dummy; 1418ec6b5d7bSAndy Adamson 1419ec6b5d7bSAndy Adamson READ_BUF(16); 1420ec6b5d7bSAndy Adamson COPYMEM(&sess->clientid, 8); 142106553991SJ. Bruce Fields sess->seqid = be32_to_cpup(p++); 142206553991SJ. Bruce Fields sess->flags = be32_to_cpup(p++); 1423ec6b5d7bSAndy Adamson 1424ec6b5d7bSAndy Adamson /* Fore channel attrs */ 1425ec6b5d7bSAndy Adamson READ_BUF(28); 142606553991SJ. Bruce Fields dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */ 142706553991SJ. Bruce Fields sess->fore_channel.maxreq_sz = be32_to_cpup(p++); 142806553991SJ. Bruce Fields sess->fore_channel.maxresp_sz = be32_to_cpup(p++); 142906553991SJ. Bruce Fields sess->fore_channel.maxresp_cached = be32_to_cpup(p++); 143006553991SJ. Bruce Fields sess->fore_channel.maxops = be32_to_cpup(p++); 143106553991SJ. Bruce Fields sess->fore_channel.maxreqs = be32_to_cpup(p++); 143206553991SJ. Bruce Fields sess->fore_channel.nr_rdma_attrs = be32_to_cpup(p++); 1433ec6b5d7bSAndy Adamson if (sess->fore_channel.nr_rdma_attrs == 1) { 1434ec6b5d7bSAndy Adamson READ_BUF(4); 143506553991SJ. Bruce Fields sess->fore_channel.rdma_attrs = be32_to_cpup(p++); 1436ec6b5d7bSAndy Adamson } else if (sess->fore_channel.nr_rdma_attrs > 1) { 1437ec6b5d7bSAndy Adamson dprintk("Too many fore channel attr bitmaps!\n"); 1438ec6b5d7bSAndy Adamson goto xdr_error; 1439ec6b5d7bSAndy Adamson } 1440ec6b5d7bSAndy Adamson 1441ec6b5d7bSAndy Adamson /* Back channel attrs */ 1442ec6b5d7bSAndy Adamson READ_BUF(28); 144306553991SJ. Bruce Fields dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */ 144406553991SJ. Bruce Fields sess->back_channel.maxreq_sz = be32_to_cpup(p++); 144506553991SJ. Bruce Fields sess->back_channel.maxresp_sz = be32_to_cpup(p++); 144606553991SJ. Bruce Fields sess->back_channel.maxresp_cached = be32_to_cpup(p++); 144706553991SJ. Bruce Fields sess->back_channel.maxops = be32_to_cpup(p++); 144806553991SJ. Bruce Fields sess->back_channel.maxreqs = be32_to_cpup(p++); 144906553991SJ. Bruce Fields sess->back_channel.nr_rdma_attrs = be32_to_cpup(p++); 1450ec6b5d7bSAndy Adamson if (sess->back_channel.nr_rdma_attrs == 1) { 1451ec6b5d7bSAndy Adamson READ_BUF(4); 145206553991SJ. Bruce Fields sess->back_channel.rdma_attrs = be32_to_cpup(p++); 1453ec6b5d7bSAndy Adamson } else if (sess->back_channel.nr_rdma_attrs > 1) { 1454ec6b5d7bSAndy Adamson dprintk("Too many back channel attr bitmaps!\n"); 1455ec6b5d7bSAndy Adamson goto xdr_error; 1456ec6b5d7bSAndy Adamson } 1457ec6b5d7bSAndy Adamson 1458acb2887eSJ. Bruce Fields READ_BUF(4); 145906553991SJ. Bruce Fields sess->callback_prog = be32_to_cpup(p++); 1460acb2887eSJ. Bruce Fields nfsd4_decode_cb_sec(argp, &sess->cb_sec); 1461ec6b5d7bSAndy Adamson DECODE_TAIL; 14622db134ebSAndy Adamson } 14632db134ebSAndy Adamson 14642db134ebSAndy Adamson static __be32 14652db134ebSAndy Adamson nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp, 14662db134ebSAndy Adamson struct nfsd4_destroy_session *destroy_session) 14672db134ebSAndy Adamson { 1468e10e0cfcSBenny Halevy DECODE_HEAD; 1469e10e0cfcSBenny Halevy READ_BUF(NFS4_MAX_SESSIONID_LEN); 1470e10e0cfcSBenny Halevy COPYMEM(destroy_session->sessionid.data, NFS4_MAX_SESSIONID_LEN); 1471e10e0cfcSBenny Halevy 1472e10e0cfcSBenny Halevy DECODE_TAIL; 14732db134ebSAndy Adamson } 14742db134ebSAndy Adamson 14752db134ebSAndy Adamson static __be32 1476e1ca12dfSBryan Schumaker nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, 1477e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 1478e1ca12dfSBryan Schumaker { 1479e1ca12dfSBryan Schumaker DECODE_HEAD; 1480e1ca12dfSBryan Schumaker 1481e1ca12dfSBryan Schumaker READ_BUF(sizeof(stateid_t)); 148206553991SJ. Bruce Fields free_stateid->fr_stateid.si_generation = be32_to_cpup(p++); 1483e1ca12dfSBryan Schumaker COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t)); 1484e1ca12dfSBryan Schumaker 1485e1ca12dfSBryan Schumaker DECODE_TAIL; 1486e1ca12dfSBryan Schumaker } 1487e1ca12dfSBryan Schumaker 1488e1ca12dfSBryan Schumaker static __be32 14892db134ebSAndy Adamson nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, 14902db134ebSAndy Adamson struct nfsd4_sequence *seq) 14912db134ebSAndy Adamson { 1492b85d4c01SBenny Halevy DECODE_HEAD; 1493b85d4c01SBenny Halevy 1494b85d4c01SBenny Halevy READ_BUF(NFS4_MAX_SESSIONID_LEN + 16); 1495b85d4c01SBenny Halevy COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); 149606553991SJ. Bruce Fields seq->seqid = be32_to_cpup(p++); 149706553991SJ. Bruce Fields seq->slotid = be32_to_cpup(p++); 149806553991SJ. Bruce Fields seq->maxslots = be32_to_cpup(p++); 149906553991SJ. Bruce Fields seq->cachethis = be32_to_cpup(p++); 1500b85d4c01SBenny Halevy 1501b85d4c01SBenny Halevy DECODE_TAIL; 15022db134ebSAndy Adamson } 15032db134ebSAndy Adamson 150417456804SBryan Schumaker static __be32 150517456804SBryan Schumaker nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid) 150617456804SBryan Schumaker { 150717456804SBryan Schumaker int i; 150803cfb420SBryan Schumaker __be32 *p, status; 150903cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 151017456804SBryan Schumaker 151117456804SBryan Schumaker READ_BUF(4); 151217456804SBryan Schumaker test_stateid->ts_num_ids = ntohl(*p++); 151317456804SBryan Schumaker 151403cfb420SBryan Schumaker INIT_LIST_HEAD(&test_stateid->ts_stateid_list); 151517456804SBryan Schumaker 151617456804SBryan Schumaker for (i = 0; i < test_stateid->ts_num_ids; i++) { 1517d5e23383SJ. Bruce Fields stateid = svcxdr_tmpalloc(argp, sizeof(*stateid)); 151803cfb420SBryan Schumaker if (!stateid) { 1519afcf6792SAl Viro status = nfserrno(-ENOMEM); 152003cfb420SBryan Schumaker goto out; 152103cfb420SBryan Schumaker } 152203cfb420SBryan Schumaker 152303cfb420SBryan Schumaker INIT_LIST_HEAD(&stateid->ts_id_list); 152403cfb420SBryan Schumaker list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list); 152503cfb420SBryan Schumaker 152603cfb420SBryan Schumaker status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid); 152717456804SBryan Schumaker if (status) 152803cfb420SBryan Schumaker goto out; 152917456804SBryan Schumaker } 153017456804SBryan Schumaker 153117456804SBryan Schumaker status = 0; 153217456804SBryan Schumaker out: 153317456804SBryan Schumaker return status; 153417456804SBryan Schumaker xdr_error: 153517456804SBryan Schumaker dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__); 153617456804SBryan Schumaker status = nfserr_bad_xdr; 153717456804SBryan Schumaker goto out; 153817456804SBryan Schumaker } 153917456804SBryan Schumaker 1540345c2842SMi Jinlong static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc) 1541345c2842SMi Jinlong { 1542345c2842SMi Jinlong DECODE_HEAD; 1543345c2842SMi Jinlong 1544345c2842SMi Jinlong READ_BUF(8); 1545345c2842SMi Jinlong COPYMEM(&dc->clientid, 8); 1546345c2842SMi Jinlong 1547345c2842SMi Jinlong DECODE_TAIL; 1548345c2842SMi Jinlong } 1549345c2842SMi Jinlong 15504dc6ec00SJ. Bruce Fields static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc) 15514dc6ec00SJ. Bruce Fields { 15524dc6ec00SJ. Bruce Fields DECODE_HEAD; 15534dc6ec00SJ. Bruce Fields 15544dc6ec00SJ. Bruce Fields READ_BUF(4); 155506553991SJ. Bruce Fields rc->rca_one_fs = be32_to_cpup(p++); 15564dc6ec00SJ. Bruce Fields 15574dc6ec00SJ. Bruce Fields DECODE_TAIL; 15584dc6ec00SJ. Bruce Fields } 15594dc6ec00SJ. Bruce Fields 15609cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 15619cf514ccSChristoph Hellwig static __be32 15629cf514ccSChristoph Hellwig nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, 15639cf514ccSChristoph Hellwig struct nfsd4_getdeviceinfo *gdev) 15649cf514ccSChristoph Hellwig { 15659cf514ccSChristoph Hellwig DECODE_HEAD; 15669cf514ccSChristoph Hellwig u32 num, i; 15679cf514ccSChristoph Hellwig 15689cf514ccSChristoph Hellwig READ_BUF(sizeof(struct nfsd4_deviceid) + 3 * 4); 15699cf514ccSChristoph Hellwig COPYMEM(&gdev->gd_devid, sizeof(struct nfsd4_deviceid)); 15709cf514ccSChristoph Hellwig gdev->gd_layout_type = be32_to_cpup(p++); 15719cf514ccSChristoph Hellwig gdev->gd_maxcount = be32_to_cpup(p++); 15729cf514ccSChristoph Hellwig num = be32_to_cpup(p++); 15739cf514ccSChristoph Hellwig if (num) { 15749cf514ccSChristoph Hellwig READ_BUF(4 * num); 15759cf514ccSChristoph Hellwig gdev->gd_notify_types = be32_to_cpup(p++); 15769cf514ccSChristoph Hellwig for (i = 1; i < num; i++) { 15779cf514ccSChristoph Hellwig if (be32_to_cpup(p++)) { 15789cf514ccSChristoph Hellwig status = nfserr_inval; 15799cf514ccSChristoph Hellwig goto out; 15809cf514ccSChristoph Hellwig } 15819cf514ccSChristoph Hellwig } 15829cf514ccSChristoph Hellwig } 15839cf514ccSChristoph Hellwig DECODE_TAIL; 15849cf514ccSChristoph Hellwig } 15859cf514ccSChristoph Hellwig 15869cf514ccSChristoph Hellwig static __be32 15879cf514ccSChristoph Hellwig nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, 15889cf514ccSChristoph Hellwig struct nfsd4_layoutget *lgp) 15899cf514ccSChristoph Hellwig { 15909cf514ccSChristoph Hellwig DECODE_HEAD; 15919cf514ccSChristoph Hellwig 15929cf514ccSChristoph Hellwig READ_BUF(36); 15939cf514ccSChristoph Hellwig lgp->lg_signal = be32_to_cpup(p++); 15949cf514ccSChristoph Hellwig lgp->lg_layout_type = be32_to_cpup(p++); 15959cf514ccSChristoph Hellwig lgp->lg_seg.iomode = be32_to_cpup(p++); 15969cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lgp->lg_seg.offset); 15979cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lgp->lg_seg.length); 15989cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lgp->lg_minlength); 1599db59c0efSKinglong Mee 1600db59c0efSKinglong Mee status = nfsd4_decode_stateid(argp, &lgp->lg_sid); 1601db59c0efSKinglong Mee if (status) 1602db59c0efSKinglong Mee return status; 1603db59c0efSKinglong Mee 16049cf514ccSChristoph Hellwig READ_BUF(4); 16059cf514ccSChristoph Hellwig lgp->lg_maxcount = be32_to_cpup(p++); 16069cf514ccSChristoph Hellwig 16079cf514ccSChristoph Hellwig DECODE_TAIL; 16089cf514ccSChristoph Hellwig } 16099cf514ccSChristoph Hellwig 16109cf514ccSChristoph Hellwig static __be32 16119cf514ccSChristoph Hellwig nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, 16129cf514ccSChristoph Hellwig struct nfsd4_layoutcommit *lcp) 16139cf514ccSChristoph Hellwig { 16149cf514ccSChristoph Hellwig DECODE_HEAD; 16159cf514ccSChristoph Hellwig u32 timechange; 16169cf514ccSChristoph Hellwig 16179cf514ccSChristoph Hellwig READ_BUF(20); 16189cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lcp->lc_seg.offset); 16199cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lcp->lc_seg.length); 16209cf514ccSChristoph Hellwig lcp->lc_reclaim = be32_to_cpup(p++); 1621db59c0efSKinglong Mee 1622db59c0efSKinglong Mee status = nfsd4_decode_stateid(argp, &lcp->lc_sid); 1623db59c0efSKinglong Mee if (status) 1624db59c0efSKinglong Mee return status; 1625db59c0efSKinglong Mee 16269cf514ccSChristoph Hellwig READ_BUF(4); 16279cf514ccSChristoph Hellwig lcp->lc_newoffset = be32_to_cpup(p++); 16289cf514ccSChristoph Hellwig if (lcp->lc_newoffset) { 16299cf514ccSChristoph Hellwig READ_BUF(8); 16309cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lcp->lc_last_wr); 16319cf514ccSChristoph Hellwig } else 16329cf514ccSChristoph Hellwig lcp->lc_last_wr = 0; 16339cf514ccSChristoph Hellwig READ_BUF(4); 16349cf514ccSChristoph Hellwig timechange = be32_to_cpup(p++); 16359cf514ccSChristoph Hellwig if (timechange) { 16369cf514ccSChristoph Hellwig status = nfsd4_decode_time(argp, &lcp->lc_mtime); 16379cf514ccSChristoph Hellwig if (status) 16389cf514ccSChristoph Hellwig return status; 16399cf514ccSChristoph Hellwig } else { 16409cf514ccSChristoph Hellwig lcp->lc_mtime.tv_nsec = UTIME_NOW; 16419cf514ccSChristoph Hellwig } 16429cf514ccSChristoph Hellwig READ_BUF(8); 16439cf514ccSChristoph Hellwig lcp->lc_layout_type = be32_to_cpup(p++); 16449cf514ccSChristoph Hellwig 16459cf514ccSChristoph Hellwig /* 16469cf514ccSChristoph Hellwig * Save the layout update in XDR format and let the layout driver deal 16479cf514ccSChristoph Hellwig * with it later. 16489cf514ccSChristoph Hellwig */ 16499cf514ccSChristoph Hellwig lcp->lc_up_len = be32_to_cpup(p++); 16509cf514ccSChristoph Hellwig if (lcp->lc_up_len > 0) { 16519cf514ccSChristoph Hellwig READ_BUF(lcp->lc_up_len); 16529cf514ccSChristoph Hellwig READMEM(lcp->lc_up_layout, lcp->lc_up_len); 16539cf514ccSChristoph Hellwig } 16549cf514ccSChristoph Hellwig 16559cf514ccSChristoph Hellwig DECODE_TAIL; 16569cf514ccSChristoph Hellwig } 16579cf514ccSChristoph Hellwig 16589cf514ccSChristoph Hellwig static __be32 16599cf514ccSChristoph Hellwig nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, 16609cf514ccSChristoph Hellwig struct nfsd4_layoutreturn *lrp) 16619cf514ccSChristoph Hellwig { 16629cf514ccSChristoph Hellwig DECODE_HEAD; 16639cf514ccSChristoph Hellwig 16649cf514ccSChristoph Hellwig READ_BUF(16); 16659cf514ccSChristoph Hellwig lrp->lr_reclaim = be32_to_cpup(p++); 16669cf514ccSChristoph Hellwig lrp->lr_layout_type = be32_to_cpup(p++); 16679cf514ccSChristoph Hellwig lrp->lr_seg.iomode = be32_to_cpup(p++); 16689cf514ccSChristoph Hellwig lrp->lr_return_type = be32_to_cpup(p++); 16699cf514ccSChristoph Hellwig if (lrp->lr_return_type == RETURN_FILE) { 16709cf514ccSChristoph Hellwig READ_BUF(16); 16719cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lrp->lr_seg.offset); 16729cf514ccSChristoph Hellwig p = xdr_decode_hyper(p, &lrp->lr_seg.length); 1673db59c0efSKinglong Mee 1674db59c0efSKinglong Mee status = nfsd4_decode_stateid(argp, &lrp->lr_sid); 1675db59c0efSKinglong Mee if (status) 1676db59c0efSKinglong Mee return status; 1677db59c0efSKinglong Mee 16789cf514ccSChristoph Hellwig READ_BUF(4); 16799cf514ccSChristoph Hellwig lrp->lrf_body_len = be32_to_cpup(p++); 16809cf514ccSChristoph Hellwig if (lrp->lrf_body_len > 0) { 16819cf514ccSChristoph Hellwig READ_BUF(lrp->lrf_body_len); 16829cf514ccSChristoph Hellwig READMEM(lrp->lrf_body, lrp->lrf_body_len); 16839cf514ccSChristoph Hellwig } 16849cf514ccSChristoph Hellwig } else { 16859cf514ccSChristoph Hellwig lrp->lr_seg.offset = 0; 16869cf514ccSChristoph Hellwig lrp->lr_seg.length = NFS4_MAX_UINT64; 16879cf514ccSChristoph Hellwig } 16889cf514ccSChristoph Hellwig 16899cf514ccSChristoph Hellwig DECODE_TAIL; 16909cf514ccSChristoph Hellwig } 16919cf514ccSChristoph Hellwig #endif /* CONFIG_NFSD_PNFS */ 16929cf514ccSChristoph Hellwig 16932db134ebSAndy Adamson static __be32 169495d871f0SAnna Schumaker nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, 169595d871f0SAnna Schumaker struct nfsd4_fallocate *fallocate) 169695d871f0SAnna Schumaker { 169795d871f0SAnna Schumaker DECODE_HEAD; 169895d871f0SAnna Schumaker 169995d871f0SAnna Schumaker status = nfsd4_decode_stateid(argp, &fallocate->falloc_stateid); 170095d871f0SAnna Schumaker if (status) 170195d871f0SAnna Schumaker return status; 170295d871f0SAnna Schumaker 170395d871f0SAnna Schumaker READ_BUF(16); 170495d871f0SAnna Schumaker p = xdr_decode_hyper(p, &fallocate->falloc_offset); 170595d871f0SAnna Schumaker xdr_decode_hyper(p, &fallocate->falloc_length); 170695d871f0SAnna Schumaker 170795d871f0SAnna Schumaker DECODE_TAIL; 170895d871f0SAnna Schumaker } 170995d871f0SAnna Schumaker 171095d871f0SAnna Schumaker static __be32 1711ffa0160aSChristoph Hellwig nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone) 1712ffa0160aSChristoph Hellwig { 1713ffa0160aSChristoph Hellwig DECODE_HEAD; 1714ffa0160aSChristoph Hellwig 1715ffa0160aSChristoph Hellwig status = nfsd4_decode_stateid(argp, &clone->cl_src_stateid); 1716ffa0160aSChristoph Hellwig if (status) 1717ffa0160aSChristoph Hellwig return status; 1718ffa0160aSChristoph Hellwig status = nfsd4_decode_stateid(argp, &clone->cl_dst_stateid); 1719ffa0160aSChristoph Hellwig if (status) 1720ffa0160aSChristoph Hellwig return status; 1721ffa0160aSChristoph Hellwig 1722ffa0160aSChristoph Hellwig READ_BUF(8 + 8 + 8); 1723ffa0160aSChristoph Hellwig p = xdr_decode_hyper(p, &clone->cl_src_pos); 1724ffa0160aSChristoph Hellwig p = xdr_decode_hyper(p, &clone->cl_dst_pos); 1725ffa0160aSChristoph Hellwig p = xdr_decode_hyper(p, &clone->cl_count); 1726ffa0160aSChristoph Hellwig DECODE_TAIL; 1727ffa0160aSChristoph Hellwig } 1728ffa0160aSChristoph Hellwig 1729ffa0160aSChristoph Hellwig static __be32 173029ae7f9dSAnna Schumaker nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) 173129ae7f9dSAnna Schumaker { 173229ae7f9dSAnna Schumaker DECODE_HEAD; 173329ae7f9dSAnna Schumaker unsigned int tmp; 173429ae7f9dSAnna Schumaker 173529ae7f9dSAnna Schumaker status = nfsd4_decode_stateid(argp, ©->cp_src_stateid); 173629ae7f9dSAnna Schumaker if (status) 173729ae7f9dSAnna Schumaker return status; 173829ae7f9dSAnna Schumaker status = nfsd4_decode_stateid(argp, ©->cp_dst_stateid); 173929ae7f9dSAnna Schumaker if (status) 174029ae7f9dSAnna Schumaker return status; 174129ae7f9dSAnna Schumaker 174229ae7f9dSAnna Schumaker READ_BUF(8 + 8 + 8 + 4 + 4 + 4); 174329ae7f9dSAnna Schumaker p = xdr_decode_hyper(p, ©->cp_src_pos); 174429ae7f9dSAnna Schumaker p = xdr_decode_hyper(p, ©->cp_dst_pos); 174529ae7f9dSAnna Schumaker p = xdr_decode_hyper(p, ©->cp_count); 174629ae7f9dSAnna Schumaker copy->cp_consecutive = be32_to_cpup(p++); 174729ae7f9dSAnna Schumaker copy->cp_synchronous = be32_to_cpup(p++); 174829ae7f9dSAnna Schumaker tmp = be32_to_cpup(p); /* Source server list not supported */ 174929ae7f9dSAnna Schumaker 175029ae7f9dSAnna Schumaker DECODE_TAIL; 175129ae7f9dSAnna Schumaker } 175229ae7f9dSAnna Schumaker 175329ae7f9dSAnna Schumaker static __be32 175424bab491SAnna Schumaker nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) 175524bab491SAnna Schumaker { 175624bab491SAnna Schumaker DECODE_HEAD; 175724bab491SAnna Schumaker 175824bab491SAnna Schumaker status = nfsd4_decode_stateid(argp, &seek->seek_stateid); 175924bab491SAnna Schumaker if (status) 176024bab491SAnna Schumaker return status; 176124bab491SAnna Schumaker 176224bab491SAnna Schumaker READ_BUF(8 + 4); 176324bab491SAnna Schumaker p = xdr_decode_hyper(p, &seek->seek_offset); 176424bab491SAnna Schumaker seek->seek_whence = be32_to_cpup(p); 176524bab491SAnna Schumaker 176624bab491SAnna Schumaker DECODE_TAIL; 176724bab491SAnna Schumaker } 176824bab491SAnna Schumaker 176924bab491SAnna Schumaker static __be32 1770347e0ad9SBenny Halevy nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p) 1771347e0ad9SBenny Halevy { 1772347e0ad9SBenny Halevy return nfs_ok; 1773347e0ad9SBenny Halevy } 1774347e0ad9SBenny Halevy 17753c375c6fSBenny Halevy static __be32 17763c375c6fSBenny Halevy nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p) 17773c375c6fSBenny Halevy { 17781e685ec2SBenny Halevy return nfserr_notsupp; 17793c375c6fSBenny Halevy } 17803c375c6fSBenny Halevy 1781347e0ad9SBenny Halevy typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *); 1782347e0ad9SBenny Halevy 1783347e0ad9SBenny Halevy static nfsd4_dec nfsd4_dec_ops[] = { 1784ad1060c8SJ. Bruce Fields [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, 1785ad1060c8SJ. Bruce Fields [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, 1786ad1060c8SJ. Bruce Fields [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, 1787ad1060c8SJ. Bruce Fields [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, 1788ad1060c8SJ. Bruce Fields [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, 1789ad1060c8SJ. Bruce Fields [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, 1790ad1060c8SJ. Bruce Fields [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, 1791ad1060c8SJ. Bruce Fields [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, 1792ad1060c8SJ. Bruce Fields [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, 1793ad1060c8SJ. Bruce Fields [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, 1794ad1060c8SJ. Bruce Fields [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, 1795ad1060c8SJ. Bruce Fields [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, 1796ad1060c8SJ. Bruce Fields [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, 1797ad1060c8SJ. Bruce Fields [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, 1798ad1060c8SJ. Bruce Fields [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, 1799ad1060c8SJ. Bruce Fields [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, 1800ad1060c8SJ. Bruce Fields [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, 1801ad1060c8SJ. Bruce Fields [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, 1802ad1060c8SJ. Bruce Fields [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, 1803ad1060c8SJ. Bruce Fields [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, 1804e1a90ebdSAnna Schumaker [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh, 1805ad1060c8SJ. Bruce Fields [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, 1806ad1060c8SJ. Bruce Fields [OP_READ] = (nfsd4_dec)nfsd4_decode_read, 1807ad1060c8SJ. Bruce Fields [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, 1808ad1060c8SJ. Bruce Fields [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, 1809ad1060c8SJ. Bruce Fields [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, 1810ad1060c8SJ. Bruce Fields [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, 1811ad1060c8SJ. Bruce Fields [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew, 1812ad1060c8SJ. Bruce Fields [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, 1813ad1060c8SJ. Bruce Fields [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, 1814ad1060c8SJ. Bruce Fields [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, 1815ad1060c8SJ. Bruce Fields [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, 1816ad1060c8SJ. Bruce Fields [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid, 1817ad1060c8SJ. Bruce Fields [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm, 1818ad1060c8SJ. Bruce Fields [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, 1819ad1060c8SJ. Bruce Fields [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, 1820ad1060c8SJ. Bruce Fields [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, 18212db134ebSAndy Adamson 18222db134ebSAndy Adamson /* new operations for NFSv4.1 */ 1823cb73a9f4SJ. Bruce Fields [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, 18241d1bc8f2SJ. Bruce Fields [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, 18259064caaeSRandy Dunlap [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, 18269064caaeSRandy Dunlap [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, 18279064caaeSRandy Dunlap [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, 1828e1ca12dfSBryan Schumaker [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid, 18299064caaeSRandy Dunlap [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, 18309cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 18319cf514ccSChristoph Hellwig [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_getdeviceinfo, 18329cf514ccSChristoph Hellwig [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, 18339cf514ccSChristoph Hellwig [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_layoutcommit, 18349cf514ccSChristoph Hellwig [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_layoutget, 18359cf514ccSChristoph Hellwig [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_layoutreturn, 18369cf514ccSChristoph Hellwig #else 18379064caaeSRandy Dunlap [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, 18389064caaeSRandy Dunlap [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, 18399064caaeSRandy Dunlap [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, 18409064caaeSRandy Dunlap [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, 18419064caaeSRandy Dunlap [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, 18429cf514ccSChristoph Hellwig #endif 184304f4ad16SJ. Bruce Fields [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name, 18449064caaeSRandy Dunlap [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, 18459064caaeSRandy Dunlap [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, 184617456804SBryan Schumaker [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid, 18479064caaeSRandy Dunlap [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, 1848345c2842SMi Jinlong [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid, 18494dc6ec00SJ. Bruce Fields [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, 185087a15a80SAnna Schumaker 185187a15a80SAnna Schumaker /* new operations for NFSv4.2 */ 185295d871f0SAnna Schumaker [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate, 185329ae7f9dSAnna Schumaker [OP_COPY] = (nfsd4_dec)nfsd4_decode_copy, 185487a15a80SAnna Schumaker [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp, 1855b0cb9085SAnna Schumaker [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate, 185687a15a80SAnna Schumaker [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp, 185787a15a80SAnna Schumaker [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp, 185887a15a80SAnna Schumaker [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp, 185987a15a80SAnna Schumaker [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_notsupp, 186087a15a80SAnna Schumaker [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_notsupp, 186187a15a80SAnna Schumaker [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp, 186224bab491SAnna Schumaker [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek, 186387a15a80SAnna Schumaker [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp, 1864ffa0160aSChristoph Hellwig [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone, 18652db134ebSAndy Adamson }; 18662db134ebSAndy Adamson 1867e1a90ebdSAnna Schumaker static inline bool 1868e1a90ebdSAnna Schumaker nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op) 1869e1a90ebdSAnna Schumaker { 18708217d146SAnna Schumaker if (op->opnum < FIRST_NFS4_OP) 1871e1a90ebdSAnna Schumaker return false; 18728217d146SAnna Schumaker else if (argp->minorversion == 0 && op->opnum > LAST_NFS40_OP) 1873e1a90ebdSAnna Schumaker return false; 18748217d146SAnna Schumaker else if (argp->minorversion == 1 && op->opnum > LAST_NFS41_OP) 18758217d146SAnna Schumaker return false; 18768217d146SAnna Schumaker else if (argp->minorversion == 2 && op->opnum > LAST_NFS42_OP) 1877e1a90ebdSAnna Schumaker return false; 1878e1a90ebdSAnna Schumaker return true; 1879e1a90ebdSAnna Schumaker } 1880f2feb96bSBenny Halevy 1881347e0ad9SBenny Halevy static __be32 18821da177e4SLinus Torvalds nfsd4_decode_compound(struct nfsd4_compoundargs *argp) 18831da177e4SLinus Torvalds { 18841da177e4SLinus Torvalds DECODE_HEAD; 18851da177e4SLinus Torvalds struct nfsd4_op *op; 18861091006cSJ. Bruce Fields bool cachethis = false; 1887a5cddc88SJ. Bruce Fields int auth_slack= argp->rqstp->rq_auth_slack; 1888a5cddc88SJ. Bruce Fields int max_reply = auth_slack + 8; /* opcnt, status */ 1889b0e35fdaSJ. Bruce Fields int readcount = 0; 1890b0e35fdaSJ. Bruce Fields int readbytes = 0; 18911da177e4SLinus Torvalds int i; 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds READ_BUF(4); 189406553991SJ. Bruce Fields argp->taglen = be32_to_cpup(p++); 18954aed9c46SJ. Bruce Fields READ_BUF(argp->taglen); 18961da177e4SLinus Torvalds SAVEMEM(argp->tag, argp->taglen); 18974aed9c46SJ. Bruce Fields READ_BUF(8); 189806553991SJ. Bruce Fields argp->minorversion = be32_to_cpup(p++); 189906553991SJ. Bruce Fields argp->opcnt = be32_to_cpup(p++); 19004f0cefbfSJ. Bruce Fields max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2); 19011da177e4SLinus Torvalds 19021da177e4SLinus Torvalds if (argp->taglen > NFSD4_MAX_TAGLEN) 19031da177e4SLinus Torvalds goto xdr_error; 19041da177e4SLinus Torvalds if (argp->opcnt > 100) 19051da177e4SLinus Torvalds goto xdr_error; 19061da177e4SLinus Torvalds 1907e8c96f8cSTobias Klauser if (argp->opcnt > ARRAY_SIZE(argp->iops)) { 19085d6031caSJ. Bruce Fields argp->ops = kzalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); 19091da177e4SLinus Torvalds if (!argp->ops) { 19101da177e4SLinus Torvalds argp->ops = argp->iops; 1911817cb9d4SChuck Lever dprintk("nfsd: couldn't allocate room for COMPOUND\n"); 19121da177e4SLinus Torvalds goto xdr_error; 19131da177e4SLinus Torvalds } 19141da177e4SLinus Torvalds } 19151da177e4SLinus Torvalds 1916e1a90ebdSAnna Schumaker if (argp->minorversion > NFSD_SUPPORTED_MINOR_VERSION) 191730cff1ffSBenny Halevy argp->opcnt = 0; 191830cff1ffSBenny Halevy 19191da177e4SLinus Torvalds for (i = 0; i < argp->opcnt; i++) { 19201da177e4SLinus Torvalds op = &argp->ops[i]; 19211da177e4SLinus Torvalds op->replay = NULL; 19221da177e4SLinus Torvalds 19238a61b18cSJ. Bruce Fields READ_BUF(4); 192406553991SJ. Bruce Fields op->opnum = be32_to_cpup(p++); 19251da177e4SLinus Torvalds 1926e1a90ebdSAnna Schumaker if (nfsd4_opnum_in_range(argp, op)) 1927e1a90ebdSAnna Schumaker op->status = nfsd4_dec_ops[op->opnum](argp, &op->u); 1928347e0ad9SBenny Halevy else { 19291da177e4SLinus Torvalds op->opnum = OP_ILLEGAL; 19301da177e4SLinus Torvalds op->status = nfserr_op_illegal; 19311da177e4SLinus Torvalds } 19321091006cSJ. Bruce Fields /* 19331091006cSJ. Bruce Fields * We'll try to cache the result in the DRC if any one 19341091006cSJ. Bruce Fields * op in the compound wants to be cached: 19351091006cSJ. Bruce Fields */ 19361091006cSJ. Bruce Fields cachethis |= nfsd4_cache_this_op(op); 19376ff40decSJ. Bruce Fields 1938b0e35fdaSJ. Bruce Fields if (op->opnum == OP_READ) { 1939b0e35fdaSJ. Bruce Fields readcount++; 1940b0e35fdaSJ. Bruce Fields readbytes += nfsd4_max_reply(argp->rqstp, op); 1941b0e35fdaSJ. Bruce Fields } else 19424f0cefbfSJ. Bruce Fields max_reply += nfsd4_max_reply(argp->rqstp, op); 1943f7b43d0cSJ. Bruce Fields /* 19447323f0d2SKinglong Mee * OP_LOCK and OP_LOCKT may return a conflicting lock. 19457323f0d2SKinglong Mee * (Special case because it will just skip encoding this 19467323f0d2SKinglong Mee * if it runs out of xdr buffer space, and it is the only 19477323f0d2SKinglong Mee * operation that behaves this way.) 1948f7b43d0cSJ. Bruce Fields */ 19497323f0d2SKinglong Mee if (op->opnum == OP_LOCK || op->opnum == OP_LOCKT) 1950f7b43d0cSJ. Bruce Fields max_reply += NFS4_OPAQUE_LIMIT; 1951e372ba60SJ. Bruce Fields 1952e372ba60SJ. Bruce Fields if (op->status) { 1953e372ba60SJ. Bruce Fields argp->opcnt = i+1; 1954e372ba60SJ. Bruce Fields break; 1955e372ba60SJ. Bruce Fields } 19561da177e4SLinus Torvalds } 19571091006cSJ. Bruce Fields /* Sessions make the DRC unnecessary: */ 19581091006cSJ. Bruce Fields if (argp->minorversion) 19591091006cSJ. Bruce Fields cachethis = false; 1960b0e35fdaSJ. Bruce Fields svc_reserve(argp->rqstp, max_reply + readbytes); 19611091006cSJ. Bruce Fields argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; 19621da177e4SLinus Torvalds 1963a5cddc88SJ. Bruce Fields if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack) 1964779fb0f3SJeff Layton clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags); 1965b0e35fdaSJ. Bruce Fields 19661da177e4SLinus Torvalds DECODE_TAIL; 19671da177e4SLinus Torvalds } 19681da177e4SLinus Torvalds 1969b8800921SNeilBrown static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode, 1970b8800921SNeilBrown struct svc_export *exp) 1971c654b8a9SJ. Bruce Fields { 1972b8800921SNeilBrown if (exp->ex_flags & NFSEXP_V4ROOT) { 1973b8800921SNeilBrown *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time)); 1974b8800921SNeilBrown *p++ = 0; 1975b8800921SNeilBrown } else if (IS_I_VERSION(inode)) { 1976d05d5744SJ. Bruce Fields p = xdr_encode_hyper(p, inode->i_version); 1977c654b8a9SJ. Bruce Fields } else { 1978d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(stat->ctime.tv_sec); 1979d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(stat->ctime.tv_nsec); 1980c654b8a9SJ. Bruce Fields } 1981d05d5744SJ. Bruce Fields return p; 1982c654b8a9SJ. Bruce Fields } 1983c654b8a9SJ. Bruce Fields 1984d05d5744SJ. Bruce Fields static __be32 *encode_cinfo(__be32 *p, struct nfsd4_change_info *c) 1985c654b8a9SJ. Bruce Fields { 1986d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->atomic); 1987c654b8a9SJ. Bruce Fields if (c->change_supported) { 1988d05d5744SJ. Bruce Fields p = xdr_encode_hyper(p, c->before_change); 1989d05d5744SJ. Bruce Fields p = xdr_encode_hyper(p, c->after_change); 1990c654b8a9SJ. Bruce Fields } else { 1991d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->before_ctime_sec); 1992d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->before_ctime_nsec); 1993d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->after_ctime_sec); 1994d05d5744SJ. Bruce Fields *p++ = cpu_to_be32(c->after_ctime_nsec); 1995c654b8a9SJ. Bruce Fields } 1996d05d5744SJ. Bruce Fields return p; 1997c654b8a9SJ. Bruce Fields } 19981da177e4SLinus Torvalds 199981c3f413SJ.Bruce Fields /* Encode as an array of strings the string given with components 2000e7a0444aSWeston Andros Adamson * separated @sep, escaped with esc_enter and esc_exit. 200181c3f413SJ.Bruce Fields */ 2002ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep, 2003ddd1ea56SJ. Bruce Fields char *components, char esc_enter, 2004ddd1ea56SJ. Bruce Fields char esc_exit) 200581c3f413SJ.Bruce Fields { 2006ddd1ea56SJ. Bruce Fields __be32 *p; 2007082d4bd7SJ. Bruce Fields __be32 pathlen; 2008082d4bd7SJ. Bruce Fields int pathlen_offset; 200981c3f413SJ.Bruce Fields int strlen, count=0; 2010e7a0444aSWeston Andros Adamson char *str, *end, *next; 201181c3f413SJ.Bruce Fields 201281c3f413SJ.Bruce Fields dprintk("nfsd4_encode_components(%s)\n", components); 2013082d4bd7SJ. Bruce Fields 2014082d4bd7SJ. Bruce Fields pathlen_offset = xdr->buf->len; 2015ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2016ddd1ea56SJ. Bruce Fields if (!p) 201781c3f413SJ.Bruce Fields return nfserr_resource; 2018082d4bd7SJ. Bruce Fields p++; /* We will fill this in with @count later */ 2019082d4bd7SJ. Bruce Fields 202081c3f413SJ.Bruce Fields end = str = components; 202181c3f413SJ.Bruce Fields while (*end) { 2022e7a0444aSWeston Andros Adamson bool found_esc = false; 2023e7a0444aSWeston Andros Adamson 2024e7a0444aSWeston Andros Adamson /* try to parse as esc_start, ..., esc_end, sep */ 2025e7a0444aSWeston Andros Adamson if (*str == esc_enter) { 2026e7a0444aSWeston Andros Adamson for (; *end && (*end != esc_exit); end++) 2027e7a0444aSWeston Andros Adamson /* find esc_exit or end of string */; 2028e7a0444aSWeston Andros Adamson next = end + 1; 2029e7a0444aSWeston Andros Adamson if (*end && (!*next || *next == sep)) { 2030e7a0444aSWeston Andros Adamson str++; 2031e7a0444aSWeston Andros Adamson found_esc = true; 2032e7a0444aSWeston Andros Adamson } 2033e7a0444aSWeston Andros Adamson } 2034e7a0444aSWeston Andros Adamson 2035e7a0444aSWeston Andros Adamson if (!found_esc) 203681c3f413SJ.Bruce Fields for (; *end && (*end != sep); end++) 2037e7a0444aSWeston Andros Adamson /* find sep or end of string */; 2038e7a0444aSWeston Andros Adamson 203981c3f413SJ.Bruce Fields strlen = end - str; 204081c3f413SJ.Bruce Fields if (strlen) { 2041ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, strlen + 4); 2042ddd1ea56SJ. Bruce Fields if (!p) 204381c3f413SJ.Bruce Fields return nfserr_resource; 20440c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, str, strlen); 204581c3f413SJ.Bruce Fields count++; 204681c3f413SJ.Bruce Fields } 204781c3f413SJ.Bruce Fields else 204881c3f413SJ.Bruce Fields end++; 20495a64e569SBenjamin Coddington if (found_esc) 20505a64e569SBenjamin Coddington end = next; 20515a64e569SBenjamin Coddington 205281c3f413SJ.Bruce Fields str = end; 205381c3f413SJ.Bruce Fields } 2054bf7491f1SBenjamin Coddington pathlen = htonl(count); 2055082d4bd7SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4); 205681c3f413SJ.Bruce Fields return 0; 205781c3f413SJ.Bruce Fields } 205881c3f413SJ.Bruce Fields 2059e7a0444aSWeston Andros Adamson /* Encode as an array of strings the string given with components 2060e7a0444aSWeston Andros Adamson * separated @sep. 2061e7a0444aSWeston Andros Adamson */ 2062ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_components(struct xdr_stream *xdr, char sep, 2063ddd1ea56SJ. Bruce Fields char *components) 2064e7a0444aSWeston Andros Adamson { 2065ddd1ea56SJ. Bruce Fields return nfsd4_encode_components_esc(xdr, sep, components, 0, 0); 2066e7a0444aSWeston Andros Adamson } 2067e7a0444aSWeston Andros Adamson 206881c3f413SJ.Bruce Fields /* 206981c3f413SJ.Bruce Fields * encode a location element of a fs_locations structure 207081c3f413SJ.Bruce Fields */ 2071ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_fs_location4(struct xdr_stream *xdr, 2072ddd1ea56SJ. Bruce Fields struct nfsd4_fs_location *location) 207381c3f413SJ.Bruce Fields { 2074b37ad28bSAl Viro __be32 status; 207581c3f413SJ.Bruce Fields 2076ddd1ea56SJ. Bruce Fields status = nfsd4_encode_components_esc(xdr, ':', location->hosts, 2077e7a0444aSWeston Andros Adamson '[', ']'); 207881c3f413SJ.Bruce Fields if (status) 207981c3f413SJ.Bruce Fields return status; 2080ddd1ea56SJ. Bruce Fields status = nfsd4_encode_components(xdr, '/', location->path); 208181c3f413SJ.Bruce Fields if (status) 208281c3f413SJ.Bruce Fields return status; 208381c3f413SJ.Bruce Fields return 0; 208481c3f413SJ.Bruce Fields } 208581c3f413SJ.Bruce Fields 208681c3f413SJ.Bruce Fields /* 2087ed748aacSTrond Myklebust * Encode a path in RFC3530 'pathname4' format 208881c3f413SJ.Bruce Fields */ 2089ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_path(struct xdr_stream *xdr, 2090ddd1ea56SJ. Bruce Fields const struct path *root, 2091ddd1ea56SJ. Bruce Fields const struct path *path) 209281c3f413SJ.Bruce Fields { 2093301f0268SAl Viro struct path cur = *path; 2094ddd1ea56SJ. Bruce Fields __be32 *p; 2095ed748aacSTrond Myklebust struct dentry **components = NULL; 2096ed748aacSTrond Myklebust unsigned int ncomponents = 0; 2097ed748aacSTrond Myklebust __be32 err = nfserr_jukebox; 209881c3f413SJ.Bruce Fields 2099ed748aacSTrond Myklebust dprintk("nfsd4_encode_components("); 210081c3f413SJ.Bruce Fields 2101ed748aacSTrond Myklebust path_get(&cur); 2102ed748aacSTrond Myklebust /* First walk the path up to the nfsd root, and store the 2103ed748aacSTrond Myklebust * dentries/path components in an array. 2104ed748aacSTrond Myklebust */ 2105ed748aacSTrond Myklebust for (;;) { 2106b77a4b2eSKinglong Mee if (path_equal(&cur, root)) 2107ed748aacSTrond Myklebust break; 2108ed748aacSTrond Myklebust if (cur.dentry == cur.mnt->mnt_root) { 2109ed748aacSTrond Myklebust if (follow_up(&cur)) 2110ed748aacSTrond Myklebust continue; 2111ed748aacSTrond Myklebust goto out_free; 211281c3f413SJ.Bruce Fields } 2113ed748aacSTrond Myklebust if ((ncomponents & 15) == 0) { 2114ed748aacSTrond Myklebust struct dentry **new; 2115ed748aacSTrond Myklebust new = krealloc(components, 2116ed748aacSTrond Myklebust sizeof(*new) * (ncomponents + 16), 2117ed748aacSTrond Myklebust GFP_KERNEL); 2118ed748aacSTrond Myklebust if (!new) 2119ed748aacSTrond Myklebust goto out_free; 2120ed748aacSTrond Myklebust components = new; 2121ed748aacSTrond Myklebust } 2122ed748aacSTrond Myklebust components[ncomponents++] = cur.dentry; 2123ed748aacSTrond Myklebust cur.dentry = dget_parent(cur.dentry); 2124ed748aacSTrond Myklebust } 2125ddd1ea56SJ. Bruce Fields err = nfserr_resource; 2126ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2127ddd1ea56SJ. Bruce Fields if (!p) 2128ed748aacSTrond Myklebust goto out_free; 2129c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ncomponents); 2130ed748aacSTrond Myklebust 2131ed748aacSTrond Myklebust while (ncomponents) { 2132ed748aacSTrond Myklebust struct dentry *dentry = components[ncomponents - 1]; 2133301f0268SAl Viro unsigned int len; 2134ed748aacSTrond Myklebust 2135301f0268SAl Viro spin_lock(&dentry->d_lock); 2136301f0268SAl Viro len = dentry->d_name.len; 2137ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, len + 4); 2138ddd1ea56SJ. Bruce Fields if (!p) { 2139301f0268SAl Viro spin_unlock(&dentry->d_lock); 2140ed748aacSTrond Myklebust goto out_free; 2141301f0268SAl Viro } 21420c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, dentry->d_name.name, len); 2143a455589fSAl Viro dprintk("/%pd", dentry); 2144301f0268SAl Viro spin_unlock(&dentry->d_lock); 2145ed748aacSTrond Myklebust dput(dentry); 2146ed748aacSTrond Myklebust ncomponents--; 2147ed748aacSTrond Myklebust } 2148ed748aacSTrond Myklebust 2149ed748aacSTrond Myklebust err = 0; 2150ed748aacSTrond Myklebust out_free: 2151ed748aacSTrond Myklebust dprintk(")\n"); 2152ed748aacSTrond Myklebust while (ncomponents) 2153ed748aacSTrond Myklebust dput(components[--ncomponents]); 2154ed748aacSTrond Myklebust kfree(components); 2155ed748aacSTrond Myklebust path_put(&cur); 2156ed748aacSTrond Myklebust return err; 2157ed748aacSTrond Myklebust } 2158ed748aacSTrond Myklebust 2159ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_fsloc_fsroot(struct xdr_stream *xdr, 2160ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, const struct path *path) 2161ed748aacSTrond Myklebust { 2162ed748aacSTrond Myklebust struct svc_export *exp_ps; 2163ed748aacSTrond Myklebust __be32 res; 2164ed748aacSTrond Myklebust 2165ed748aacSTrond Myklebust exp_ps = rqst_find_fsidzero_export(rqstp); 2166ed748aacSTrond Myklebust if (IS_ERR(exp_ps)) 2167ed748aacSTrond Myklebust return nfserrno(PTR_ERR(exp_ps)); 2168ddd1ea56SJ. Bruce Fields res = nfsd4_encode_path(xdr, &exp_ps->ex_path, path); 2169ed748aacSTrond Myklebust exp_put(exp_ps); 2170ed748aacSTrond Myklebust return res; 217181c3f413SJ.Bruce Fields } 217281c3f413SJ.Bruce Fields 217381c3f413SJ.Bruce Fields /* 217481c3f413SJ.Bruce Fields * encode a fs_locations structure 217581c3f413SJ.Bruce Fields */ 2176ddd1ea56SJ. Bruce Fields static __be32 nfsd4_encode_fs_locations(struct xdr_stream *xdr, 2177ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, struct svc_export *exp) 217881c3f413SJ.Bruce Fields { 2179b37ad28bSAl Viro __be32 status; 2180cc45f017SAl Viro int i; 2181ddd1ea56SJ. Bruce Fields __be32 *p; 218281c3f413SJ.Bruce Fields struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; 218381c3f413SJ.Bruce Fields 2184ddd1ea56SJ. Bruce Fields status = nfsd4_encode_fsloc_fsroot(xdr, rqstp, &exp->ex_path); 218581c3f413SJ.Bruce Fields if (status) 218681c3f413SJ.Bruce Fields return status; 2187ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2188ddd1ea56SJ. Bruce Fields if (!p) 218981c3f413SJ.Bruce Fields return nfserr_resource; 2190c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(fslocs->locations_count); 219181c3f413SJ.Bruce Fields for (i=0; i<fslocs->locations_count; i++) { 2192ddd1ea56SJ. Bruce Fields status = nfsd4_encode_fs_location4(xdr, &fslocs->locations[i]); 219381c3f413SJ.Bruce Fields if (status) 219481c3f413SJ.Bruce Fields return status; 219581c3f413SJ.Bruce Fields } 219681c3f413SJ.Bruce Fields return 0; 219781c3f413SJ.Bruce Fields } 21981da177e4SLinus Torvalds 21993d2544b1SJ. Bruce Fields static u32 nfs4_file_type(umode_t mode) 22003d2544b1SJ. Bruce Fields { 22013d2544b1SJ. Bruce Fields switch (mode & S_IFMT) { 22023d2544b1SJ. Bruce Fields case S_IFIFO: return NF4FIFO; 22033d2544b1SJ. Bruce Fields case S_IFCHR: return NF4CHR; 22043d2544b1SJ. Bruce Fields case S_IFDIR: return NF4DIR; 22053d2544b1SJ. Bruce Fields case S_IFBLK: return NF4BLK; 22063d2544b1SJ. Bruce Fields case S_IFLNK: return NF4LNK; 22073d2544b1SJ. Bruce Fields case S_IFREG: return NF4REG; 22083d2544b1SJ. Bruce Fields case S_IFSOCK: return NF4SOCK; 22093d2544b1SJ. Bruce Fields default: return NF4BAD; 22101da177e4SLinus Torvalds }; 22113d2544b1SJ. Bruce Fields } 22121da177e4SLinus Torvalds 2213b37ad28bSAl Viro static inline __be32 2214ddd1ea56SJ. Bruce Fields nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp, 2215ddd1ea56SJ. Bruce Fields struct nfs4_ace *ace) 22161da177e4SLinus Torvalds { 22173554116dSJ. Bruce Fields if (ace->whotype != NFS4_ACL_WHO_NAMED) 2218ddd1ea56SJ. Bruce Fields return nfs4_acl_write_who(xdr, ace->whotype); 22193554116dSJ. Bruce Fields else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) 2220ddd1ea56SJ. Bruce Fields return nfsd4_encode_group(xdr, rqstp, ace->who_gid); 2221ab8e4aeeSEric W. Biederman else 2222ddd1ea56SJ. Bruce Fields return nfsd4_encode_user(xdr, rqstp, ace->who_uid); 22231da177e4SLinus Torvalds } 22241da177e4SLinus Torvalds 22256896f15aSKinglong Mee static inline __be32 22268a4c3926SJeff Layton nfsd4_encode_layout_types(struct xdr_stream *xdr, u32 layout_types) 22276896f15aSKinglong Mee { 22286896f15aSKinglong Mee __be32 *p; 22298a4c3926SJeff Layton unsigned long i = hweight_long(layout_types); 22306896f15aSKinglong Mee 22318a4c3926SJeff Layton p = xdr_reserve_space(xdr, 4 + 4 * i); 22326896f15aSKinglong Mee if (!p) 22336896f15aSKinglong Mee return nfserr_resource; 22348a4c3926SJeff Layton 22358a4c3926SJeff Layton *p++ = cpu_to_be32(i); 22368a4c3926SJeff Layton 22378a4c3926SJeff Layton for (i = LAYOUT_NFSV4_1_FILES; i < LAYOUT_TYPE_MAX; ++i) 22388a4c3926SJeff Layton if (layout_types & (1 << i)) 22398a4c3926SJeff Layton *p++ = cpu_to_be32(i); 22406896f15aSKinglong Mee 22416896f15aSKinglong Mee return 0; 22426896f15aSKinglong Mee } 22436896f15aSKinglong Mee 224442ca0993SJ.Bruce Fields #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ 224542ca0993SJ.Bruce Fields FATTR4_WORD0_RDATTR_ERROR) 224642ca0993SJ.Bruce Fields #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID 2247c2227a39SKinglong Mee #define WORD2_ABSENT_FS_ATTRS 0 224842ca0993SJ.Bruce Fields 224918032ca0SDavid Quigley #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 225018032ca0SDavid Quigley static inline __be32 2251ddd1ea56SJ. Bruce Fields nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp, 2252ddd1ea56SJ. Bruce Fields void *context, int len) 225318032ca0SDavid Quigley { 2254ddd1ea56SJ. Bruce Fields __be32 *p; 225518032ca0SDavid Quigley 2256ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, len + 4 + 4 + 4); 2257ddd1ea56SJ. Bruce Fields if (!p) 225818032ca0SDavid Quigley return nfserr_resource; 225918032ca0SDavid Quigley 226018032ca0SDavid Quigley /* 226118032ca0SDavid Quigley * For now we use a 0 here to indicate the null translation; in 226218032ca0SDavid Quigley * the future we may place a call to translation code here. 226318032ca0SDavid Quigley */ 2264c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* lfs */ 2265c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* pi */ 226618032ca0SDavid Quigley p = xdr_encode_opaque(p, context, len); 226718032ca0SDavid Quigley return 0; 226818032ca0SDavid Quigley } 226918032ca0SDavid Quigley #else 227018032ca0SDavid Quigley static inline __be32 2271ddd1ea56SJ. Bruce Fields nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp, 2272ddd1ea56SJ. Bruce Fields void *context, int len) 227318032ca0SDavid Quigley { return 0; } 227418032ca0SDavid Quigley #endif 227518032ca0SDavid Quigley 2276c2227a39SKinglong Mee static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err) 227742ca0993SJ.Bruce Fields { 227842ca0993SJ.Bruce Fields /* As per referral draft: */ 227942ca0993SJ.Bruce Fields if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS || 228042ca0993SJ.Bruce Fields *bmval1 & ~WORD1_ABSENT_FS_ATTRS) { 228142ca0993SJ.Bruce Fields if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR || 228242ca0993SJ.Bruce Fields *bmval0 & FATTR4_WORD0_FS_LOCATIONS) 228342ca0993SJ.Bruce Fields *rdattr_err = NFSERR_MOVED; 228442ca0993SJ.Bruce Fields else 228542ca0993SJ.Bruce Fields return nfserr_moved; 228642ca0993SJ.Bruce Fields } 228742ca0993SJ.Bruce Fields *bmval0 &= WORD0_ABSENT_FS_ATTRS; 228842ca0993SJ.Bruce Fields *bmval1 &= WORD1_ABSENT_FS_ATTRS; 2289c2227a39SKinglong Mee *bmval2 &= WORD2_ABSENT_FS_ATTRS; 229042ca0993SJ.Bruce Fields return 0; 229142ca0993SJ.Bruce Fields } 22921da177e4SLinus Torvalds 2293ae7095a7SJ. Bruce Fields 2294ae7095a7SJ. Bruce Fields static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) 2295ae7095a7SJ. Bruce Fields { 2296ae7095a7SJ. Bruce Fields struct path path = exp->ex_path; 2297ae7095a7SJ. Bruce Fields int err; 2298ae7095a7SJ. Bruce Fields 2299ae7095a7SJ. Bruce Fields path_get(&path); 2300ae7095a7SJ. Bruce Fields while (follow_up(&path)) { 2301ae7095a7SJ. Bruce Fields if (path.dentry != path.mnt->mnt_root) 2302ae7095a7SJ. Bruce Fields break; 2303ae7095a7SJ. Bruce Fields } 2304a528d35eSDavid Howells err = vfs_getattr(&path, stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); 2305ae7095a7SJ. Bruce Fields path_put(&path); 2306ae7095a7SJ. Bruce Fields return err; 2307ae7095a7SJ. Bruce Fields } 2308ae7095a7SJ. Bruce Fields 230975976de6SKinglong Mee static __be32 231075976de6SKinglong Mee nfsd4_encode_bitmap(struct xdr_stream *xdr, u32 bmval0, u32 bmval1, u32 bmval2) 231175976de6SKinglong Mee { 231275976de6SKinglong Mee __be32 *p; 231375976de6SKinglong Mee 231475976de6SKinglong Mee if (bmval2) { 231575976de6SKinglong Mee p = xdr_reserve_space(xdr, 16); 231675976de6SKinglong Mee if (!p) 231775976de6SKinglong Mee goto out_resource; 231875976de6SKinglong Mee *p++ = cpu_to_be32(3); 231975976de6SKinglong Mee *p++ = cpu_to_be32(bmval0); 232075976de6SKinglong Mee *p++ = cpu_to_be32(bmval1); 232175976de6SKinglong Mee *p++ = cpu_to_be32(bmval2); 232275976de6SKinglong Mee } else if (bmval1) { 232375976de6SKinglong Mee p = xdr_reserve_space(xdr, 12); 232475976de6SKinglong Mee if (!p) 232575976de6SKinglong Mee goto out_resource; 232675976de6SKinglong Mee *p++ = cpu_to_be32(2); 232775976de6SKinglong Mee *p++ = cpu_to_be32(bmval0); 232875976de6SKinglong Mee *p++ = cpu_to_be32(bmval1); 232975976de6SKinglong Mee } else { 233075976de6SKinglong Mee p = xdr_reserve_space(xdr, 8); 233175976de6SKinglong Mee if (!p) 233275976de6SKinglong Mee goto out_resource; 233375976de6SKinglong Mee *p++ = cpu_to_be32(1); 233475976de6SKinglong Mee *p++ = cpu_to_be32(bmval0); 233575976de6SKinglong Mee } 233675976de6SKinglong Mee 233775976de6SKinglong Mee return 0; 233875976de6SKinglong Mee out_resource: 233975976de6SKinglong Mee return nfserr_resource; 234075976de6SKinglong Mee } 234175976de6SKinglong Mee 23421da177e4SLinus Torvalds /* 23431da177e4SLinus Torvalds * Note: @fhp can be NULL; in this case, we might have to compose the filehandle 23441da177e4SLinus Torvalds * ourselves. 23451da177e4SLinus Torvalds */ 2346da2ebce6SJeff Layton static __be32 2347d5184658SJ. Bruce Fields nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, 2348d5184658SJ. Bruce Fields struct svc_export *exp, 2349d5184658SJ. Bruce Fields struct dentry *dentry, u32 *bmval, 2350406a7ea9SFrank Filz struct svc_rqst *rqstp, int ignore_crossmnt) 23511da177e4SLinus Torvalds { 23521da177e4SLinus Torvalds u32 bmval0 = bmval[0]; 23531da177e4SLinus Torvalds u32 bmval1 = bmval[1]; 23547e705706SAndy Adamson u32 bmval2 = bmval[2]; 23551da177e4SLinus Torvalds struct kstat stat; 2356d50e6136SJ. Bruce Fields struct svc_fh *tempfh = NULL; 23571da177e4SLinus Torvalds struct kstatfs statfs; 2358ddd1ea56SJ. Bruce Fields __be32 *p; 23591fcea5b2SJ. Bruce Fields int starting_len = xdr->buf->len; 2360082d4bd7SJ. Bruce Fields int attrlen_offset; 2361082d4bd7SJ. Bruce Fields __be32 attrlen; 23621da177e4SLinus Torvalds u32 dummy; 23631da177e4SLinus Torvalds u64 dummy64; 236442ca0993SJ.Bruce Fields u32 rdattr_err = 0; 2365b37ad28bSAl Viro __be32 status; 2366b8dd7b9aSAl Viro int err; 23671da177e4SLinus Torvalds struct nfs4_acl *acl = NULL; 236818032ca0SDavid Quigley void *context = NULL; 236918032ca0SDavid Quigley int contextlen; 237018032ca0SDavid Quigley bool contextsupport = false; 23717e705706SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 23727e705706SAndy Adamson u32 minorversion = resp->cstate.minorversion; 2373ebabe9a9SChristoph Hellwig struct path path = { 2374ebabe9a9SChristoph Hellwig .mnt = exp->ex_path.mnt, 2375ebabe9a9SChristoph Hellwig .dentry = dentry, 2376ebabe9a9SChristoph Hellwig }; 23773d733711SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 23781da177e4SLinus Torvalds 23791da177e4SLinus Torvalds BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); 2380916d2d84SJ. Bruce Fields BUG_ON(!nfsd_attrs_supported(minorversion, bmval)); 23811da177e4SLinus Torvalds 238242ca0993SJ.Bruce Fields if (exp->ex_fslocs.migrated) { 2383c2227a39SKinglong Mee status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err); 238442ca0993SJ.Bruce Fields if (status) 238542ca0993SJ.Bruce Fields goto out; 238642ca0993SJ.Bruce Fields } 238742ca0993SJ.Bruce Fields 2388a528d35eSDavid Howells err = vfs_getattr(&path, &stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); 2389b8dd7b9aSAl Viro if (err) 23901da177e4SLinus Torvalds goto out_nfserr; 239112337901SChristoph Hellwig if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | 239212337901SChristoph Hellwig FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) || 23931da177e4SLinus Torvalds (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | 23941da177e4SLinus Torvalds FATTR4_WORD1_SPACE_TOTAL))) { 2395ebabe9a9SChristoph Hellwig err = vfs_statfs(&path, &statfs); 2396b8dd7b9aSAl Viro if (err) 23971da177e4SLinus Torvalds goto out_nfserr; 23981da177e4SLinus Torvalds } 23991da177e4SLinus Torvalds if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) { 2400d50e6136SJ. Bruce Fields tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); 2401d50e6136SJ. Bruce Fields status = nfserr_jukebox; 2402d50e6136SJ. Bruce Fields if (!tempfh) 2403d50e6136SJ. Bruce Fields goto out; 2404d50e6136SJ. Bruce Fields fh_init(tempfh, NFS4_FHSIZE); 2405d50e6136SJ. Bruce Fields status = fh_compose(tempfh, exp, dentry, NULL); 24061da177e4SLinus Torvalds if (status) 24071da177e4SLinus Torvalds goto out; 2408d50e6136SJ. Bruce Fields fhp = tempfh; 24091da177e4SLinus Torvalds } 24101da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACL) { 24110c9d65e7SAndreas Gruenbacher err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); 2412b8dd7b9aSAl Viro if (err == -EOPNOTSUPP) 24131da177e4SLinus Torvalds bmval0 &= ~FATTR4_WORD0_ACL; 2414b8dd7b9aSAl Viro else if (err == -EINVAL) { 24151da177e4SLinus Torvalds status = nfserr_attrnotsupp; 24161da177e4SLinus Torvalds goto out; 2417b8dd7b9aSAl Viro } else if (err != 0) 24181da177e4SLinus Torvalds goto out_nfserr; 24191da177e4SLinus Torvalds } 24202b44f1baSBenny Halevy 242118032ca0SDavid Quigley #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 2422c2227a39SKinglong Mee if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) || 2423c2227a39SKinglong Mee bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { 242432ddd944SJ. Bruce Fields if (exp->ex_flags & NFSEXP_SECURITY_LABEL) 24252b0143b5SDavid Howells err = security_inode_getsecctx(d_inode(dentry), 242618032ca0SDavid Quigley &context, &contextlen); 242732ddd944SJ. Bruce Fields else 242832ddd944SJ. Bruce Fields err = -EOPNOTSUPP; 242918032ca0SDavid Quigley contextsupport = (err == 0); 243018032ca0SDavid Quigley if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { 243118032ca0SDavid Quigley if (err == -EOPNOTSUPP) 243218032ca0SDavid Quigley bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL; 243318032ca0SDavid Quigley else if (err) 243418032ca0SDavid Quigley goto out_nfserr; 243518032ca0SDavid Quigley } 243618032ca0SDavid Quigley } 243718032ca0SDavid Quigley #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ 243818032ca0SDavid Quigley 243975976de6SKinglong Mee status = nfsd4_encode_bitmap(xdr, bmval0, bmval1, bmval2); 244075976de6SKinglong Mee if (status) 244175976de6SKinglong Mee goto out; 2442082d4bd7SJ. Bruce Fields 2443082d4bd7SJ. Bruce Fields attrlen_offset = xdr->buf->len; 2444ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2445ddd1ea56SJ. Bruce Fields if (!p) 2446ddd1ea56SJ. Bruce Fields goto out_resource; 2447082d4bd7SJ. Bruce Fields p++; /* to be backfilled later */ 24481da177e4SLinus Torvalds 24491da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { 2450dcd20869SJ. Bruce Fields u32 supp[3]; 2451dcd20869SJ. Bruce Fields 2452dcd20869SJ. Bruce Fields memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp)); 24537e705706SAndy Adamson 24540c9d65e7SAndreas Gruenbacher if (!IS_POSIXACL(dentry->d_inode)) 2455916d2d84SJ. Bruce Fields supp[0] &= ~FATTR4_WORD0_ACL; 245618032ca0SDavid Quigley if (!contextsupport) 2457916d2d84SJ. Bruce Fields supp[2] &= ~FATTR4_WORD2_SECURITY_LABEL; 2458916d2d84SJ. Bruce Fields if (!supp[2]) { 2459ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2460ddd1ea56SJ. Bruce Fields if (!p) 24612b44f1baSBenny Halevy goto out_resource; 2462c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(2); 2463916d2d84SJ. Bruce Fields *p++ = cpu_to_be32(supp[0]); 2464916d2d84SJ. Bruce Fields *p++ = cpu_to_be32(supp[1]); 24657e705706SAndy Adamson } else { 2466ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 2467ddd1ea56SJ. Bruce Fields if (!p) 24682b44f1baSBenny Halevy goto out_resource; 2469c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(3); 2470916d2d84SJ. Bruce Fields *p++ = cpu_to_be32(supp[0]); 2471916d2d84SJ. Bruce Fields *p++ = cpu_to_be32(supp[1]); 2472916d2d84SJ. Bruce Fields *p++ = cpu_to_be32(supp[2]); 24737e705706SAndy Adamson } 24741da177e4SLinus Torvalds } 24751da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_TYPE) { 2476ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2477ddd1ea56SJ. Bruce Fields if (!p) 24781da177e4SLinus Torvalds goto out_resource; 24793d2544b1SJ. Bruce Fields dummy = nfs4_file_type(stat.mode); 24806b6d8137SJ. Bruce Fields if (dummy == NF4BAD) { 24816b6d8137SJ. Bruce Fields status = nfserr_serverfault; 24826b6d8137SJ. Bruce Fields goto out; 24836b6d8137SJ. Bruce Fields } 2484c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(dummy); 24851da177e4SLinus Torvalds } 24861da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { 2487ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2488ddd1ea56SJ. Bruce Fields if (!p) 24891da177e4SLinus Torvalds goto out_resource; 249049640001SNeilBrown if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) 2491c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_FH_PERSISTENT); 249249640001SNeilBrown else 2493c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_FH_PERSISTENT| 2494c373b0a4SJ. Bruce Fields NFS4_FH_VOL_RENAME); 24951da177e4SLinus Torvalds } 24961da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CHANGE) { 2497ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2498ddd1ea56SJ. Bruce Fields if (!p) 24991da177e4SLinus Torvalds goto out_resource; 2500b8800921SNeilBrown p = encode_change(p, &stat, d_inode(dentry), exp); 25011da177e4SLinus Torvalds } 25021da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SIZE) { 2503ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2504ddd1ea56SJ. Bruce Fields if (!p) 25051da177e4SLinus Torvalds goto out_resource; 2506b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, stat.size); 25071da177e4SLinus Torvalds } 25081da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) { 2509ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2510ddd1ea56SJ. Bruce Fields if (!p) 25111da177e4SLinus Torvalds goto out_resource; 2512c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 25131da177e4SLinus Torvalds } 25141da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) { 2515ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2516ddd1ea56SJ. Bruce Fields if (!p) 25171da177e4SLinus Torvalds goto out_resource; 2518c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 25191da177e4SLinus Torvalds } 25201da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_NAMED_ATTR) { 2521ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2522ddd1ea56SJ. Bruce Fields if (!p) 25231da177e4SLinus Torvalds goto out_resource; 2524c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 25251da177e4SLinus Torvalds } 25261da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FSID) { 2527ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 2528ddd1ea56SJ. Bruce Fields if (!p) 25291da177e4SLinus Torvalds goto out_resource; 253042ca0993SJ.Bruce Fields if (exp->ex_fslocs.migrated) { 2531b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MAJOR); 2532b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MINOR); 2533af6a4e28SNeilBrown } else switch(fsid_source(fhp)) { 2534af6a4e28SNeilBrown case FSIDSOURCE_FSID: 2535b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64)exp->ex_fsid); 2536b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64)0); 2537af6a4e28SNeilBrown break; 2538af6a4e28SNeilBrown case FSIDSOURCE_DEV: 2539c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 2540c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(MAJOR(stat.dev)); 2541c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 2542c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(MINOR(stat.dev)); 2543af6a4e28SNeilBrown break; 2544af6a4e28SNeilBrown case FSIDSOURCE_UUID: 254594eb3689SKinglong Mee p = xdr_encode_opaque_fixed(p, exp->ex_uuid, 254694eb3689SKinglong Mee EX_UUID_LEN); 2547af6a4e28SNeilBrown break; 25481da177e4SLinus Torvalds } 25491da177e4SLinus Torvalds } 25501da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { 2551ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2552ddd1ea56SJ. Bruce Fields if (!p) 25531da177e4SLinus Torvalds goto out_resource; 2554c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 25551da177e4SLinus Torvalds } 25561da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_LEASE_TIME) { 2557ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2558ddd1ea56SJ. Bruce Fields if (!p) 25591da177e4SLinus Torvalds goto out_resource; 2560c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(nn->nfsd4_lease); 25611da177e4SLinus Torvalds } 25621da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { 2563ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2564ddd1ea56SJ. Bruce Fields if (!p) 25651da177e4SLinus Torvalds goto out_resource; 2566c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(rdattr_err); 25671da177e4SLinus Torvalds } 25681da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACL) { 25691da177e4SLinus Torvalds struct nfs4_ace *ace; 25701da177e4SLinus Torvalds 25711da177e4SLinus Torvalds if (acl == NULL) { 2572ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2573ddd1ea56SJ. Bruce Fields if (!p) 25741da177e4SLinus Torvalds goto out_resource; 25751da177e4SLinus Torvalds 2576c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 25771da177e4SLinus Torvalds goto out_acl; 25781da177e4SLinus Torvalds } 2579ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2580ddd1ea56SJ. Bruce Fields if (!p) 25811da177e4SLinus Torvalds goto out_resource; 2582c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(acl->naces); 25831da177e4SLinus Torvalds 258428e05dd8SJ. Bruce Fields for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { 2585ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4*3); 2586ddd1ea56SJ. Bruce Fields if (!p) 25871da177e4SLinus Torvalds goto out_resource; 2588c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ace->type); 2589c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ace->flag); 2590c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ace->access_mask & 2591c373b0a4SJ. Bruce Fields NFS4_ACE_MASK_ALL); 2592ddd1ea56SJ. Bruce Fields status = nfsd4_encode_aclname(xdr, rqstp, ace); 25931da177e4SLinus Torvalds if (status) 25941da177e4SLinus Torvalds goto out; 25951da177e4SLinus Torvalds } 25961da177e4SLinus Torvalds } 25971da177e4SLinus Torvalds out_acl: 25981da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_ACLSUPPORT) { 2599ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2600ddd1ea56SJ. Bruce Fields if (!p) 26011da177e4SLinus Torvalds goto out_resource; 26020c9d65e7SAndreas Gruenbacher *p++ = cpu_to_be32(IS_POSIXACL(dentry->d_inode) ? 26031da177e4SLinus Torvalds ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0); 26041da177e4SLinus Torvalds } 26051da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CANSETTIME) { 2606ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2607ddd1ea56SJ. Bruce Fields if (!p) 26081da177e4SLinus Torvalds goto out_resource; 2609c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 26101da177e4SLinus Torvalds } 26111da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { 2612ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2613ddd1ea56SJ. Bruce Fields if (!p) 26141da177e4SLinus Torvalds goto out_resource; 2615c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 26161da177e4SLinus Torvalds } 26171da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { 2618ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2619ddd1ea56SJ. Bruce Fields if (!p) 26201da177e4SLinus Torvalds goto out_resource; 2621c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 26221da177e4SLinus Torvalds } 26231da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) { 2624ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2625ddd1ea56SJ. Bruce Fields if (!p) 26261da177e4SLinus Torvalds goto out_resource; 2627c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 26281da177e4SLinus Torvalds } 26291da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILEHANDLE) { 2630ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, fhp->fh_handle.fh_size + 4); 2631ddd1ea56SJ. Bruce Fields if (!p) 26321da177e4SLinus Torvalds goto out_resource; 26330c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, 26340c0c267bSJ. Bruce Fields fhp->fh_handle.fh_size); 26351da177e4SLinus Torvalds } 26361da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILEID) { 2637ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2638ddd1ea56SJ. Bruce Fields if (!p) 26391da177e4SLinus Torvalds goto out_resource; 2640b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, stat.ino); 26411da177e4SLinus Torvalds } 26421da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { 2643ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2644ddd1ea56SJ. Bruce Fields if (!p) 26451da177e4SLinus Torvalds goto out_resource; 2646b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) statfs.f_ffree); 26471da177e4SLinus Torvalds } 26481da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_FREE) { 2649ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2650ddd1ea56SJ. Bruce Fields if (!p) 26511da177e4SLinus Torvalds goto out_resource; 2652b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) statfs.f_ffree); 26531da177e4SLinus Torvalds } 26541da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { 2655ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2656ddd1ea56SJ. Bruce Fields if (!p) 26571da177e4SLinus Torvalds goto out_resource; 2658b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) statfs.f_files); 26591da177e4SLinus Torvalds } 266081c3f413SJ.Bruce Fields if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { 2661ddd1ea56SJ. Bruce Fields status = nfsd4_encode_fs_locations(xdr, rqstp, exp); 266281c3f413SJ.Bruce Fields if (status) 266381c3f413SJ.Bruce Fields goto out; 266481c3f413SJ.Bruce Fields } 26651da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { 2666ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2667ddd1ea56SJ. Bruce Fields if (!p) 26681da177e4SLinus Torvalds goto out_resource; 2669c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 26701da177e4SLinus Torvalds } 26711da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { 2672ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2673ddd1ea56SJ. Bruce Fields if (!p) 26741da177e4SLinus Torvalds goto out_resource; 2675b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, exp->ex_path.mnt->mnt_sb->s_maxbytes); 26761da177e4SLinus Torvalds } 26771da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXLINK) { 2678ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2679ddd1ea56SJ. Bruce Fields if (!p) 26801da177e4SLinus Torvalds goto out_resource; 2681c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(255); 26821da177e4SLinus Torvalds } 26831da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXNAME) { 2684ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2685ddd1ea56SJ. Bruce Fields if (!p) 26861da177e4SLinus Torvalds goto out_resource; 2687c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(statfs.f_namelen); 26881da177e4SLinus Torvalds } 26891da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXREAD) { 2690ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2691ddd1ea56SJ. Bruce Fields if (!p) 26921da177e4SLinus Torvalds goto out_resource; 2693b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp)); 26941da177e4SLinus Torvalds } 26951da177e4SLinus Torvalds if (bmval0 & FATTR4_WORD0_MAXWRITE) { 2696ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2697ddd1ea56SJ. Bruce Fields if (!p) 26981da177e4SLinus Torvalds goto out_resource; 2699b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp)); 27001da177e4SLinus Torvalds } 27011da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_MODE) { 2702ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2703ddd1ea56SJ. Bruce Fields if (!p) 27041da177e4SLinus Torvalds goto out_resource; 2705c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.mode & S_IALLUGO); 27061da177e4SLinus Torvalds } 27071da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_NO_TRUNC) { 2708ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2709ddd1ea56SJ. Bruce Fields if (!p) 27101da177e4SLinus Torvalds goto out_resource; 2711c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 27121da177e4SLinus Torvalds } 27131da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_NUMLINKS) { 2714ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 2715ddd1ea56SJ. Bruce Fields if (!p) 27161da177e4SLinus Torvalds goto out_resource; 2717c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.nlink); 27181da177e4SLinus Torvalds } 27191da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_OWNER) { 2720ddd1ea56SJ. Bruce Fields status = nfsd4_encode_user(xdr, rqstp, stat.uid); 27211da177e4SLinus Torvalds if (status) 27221da177e4SLinus Torvalds goto out; 27231da177e4SLinus Torvalds } 27241da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { 2725ddd1ea56SJ. Bruce Fields status = nfsd4_encode_group(xdr, rqstp, stat.gid); 27261da177e4SLinus Torvalds if (status) 27271da177e4SLinus Torvalds goto out; 27281da177e4SLinus Torvalds } 27291da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_RAWDEV) { 2730ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2731ddd1ea56SJ. Bruce Fields if (!p) 27321da177e4SLinus Torvalds goto out_resource; 2733c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32((u32) MAJOR(stat.rdev)); 2734c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32((u32) MINOR(stat.rdev)); 27351da177e4SLinus Torvalds } 27361da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { 2737ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2738ddd1ea56SJ. Bruce Fields if (!p) 27391da177e4SLinus Torvalds goto out_resource; 27401da177e4SLinus Torvalds dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize; 2741b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, dummy64); 27421da177e4SLinus Torvalds } 27431da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_FREE) { 2744ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2745ddd1ea56SJ. Bruce Fields if (!p) 27461da177e4SLinus Torvalds goto out_resource; 27471da177e4SLinus Torvalds dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize; 2748b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, dummy64); 27491da177e4SLinus Torvalds } 27501da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { 2751ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2752ddd1ea56SJ. Bruce Fields if (!p) 27531da177e4SLinus Torvalds goto out_resource; 27541da177e4SLinus Torvalds dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize; 2755b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, dummy64); 27561da177e4SLinus Torvalds } 27571da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_SPACE_USED) { 2758ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2759ddd1ea56SJ. Bruce Fields if (!p) 27601da177e4SLinus Torvalds goto out_resource; 27611da177e4SLinus Torvalds dummy64 = (u64)stat.blocks << 9; 2762b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, dummy64); 27631da177e4SLinus Torvalds } 27641da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { 2765ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2766ddd1ea56SJ. Bruce Fields if (!p) 27671da177e4SLinus Torvalds goto out_resource; 2768b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (s64)stat.atime.tv_sec); 2769c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.atime.tv_nsec); 27701da177e4SLinus Torvalds } 27711da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_DELTA) { 2772ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2773ddd1ea56SJ. Bruce Fields if (!p) 27741da177e4SLinus Torvalds goto out_resource; 2775c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 2776c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(1); 2777c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 27781da177e4SLinus Torvalds } 27791da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_METADATA) { 2780ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2781ddd1ea56SJ. Bruce Fields if (!p) 27821da177e4SLinus Torvalds goto out_resource; 2783b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (s64)stat.ctime.tv_sec); 2784c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.ctime.tv_nsec); 27851da177e4SLinus Torvalds } 27861da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { 2787ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 12); 2788ddd1ea56SJ. Bruce Fields if (!p) 27891da177e4SLinus Torvalds goto out_resource; 2790b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (s64)stat.mtime.tv_sec); 2791c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(stat.mtime.tv_nsec); 27921da177e4SLinus Torvalds } 27931da177e4SLinus Torvalds if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { 27940a2050d7SKinglong Mee struct kstat parent_stat; 27950a2050d7SKinglong Mee u64 ino = stat.ino; 27960a2050d7SKinglong Mee 2797ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 2798ddd1ea56SJ. Bruce Fields if (!p) 27991da177e4SLinus Torvalds goto out_resource; 2800406a7ea9SFrank Filz /* 2801406a7ea9SFrank Filz * Get parent's attributes if not ignoring crossmount 2802406a7ea9SFrank Filz * and this is the root of a cross-mounted filesystem. 2803406a7ea9SFrank Filz */ 2804406a7ea9SFrank Filz if (ignore_crossmnt == 0 && 28050a2050d7SKinglong Mee dentry == exp->ex_path.mnt->mnt_root) { 28060a2050d7SKinglong Mee err = get_parent_attributes(exp, &parent_stat); 28070a2050d7SKinglong Mee if (err) 28080a2050d7SKinglong Mee goto out_nfserr; 28090a2050d7SKinglong Mee ino = parent_stat.ino; 28100a2050d7SKinglong Mee } 28110a2050d7SKinglong Mee p = xdr_encode_hyper(p, ino); 28121da177e4SLinus Torvalds } 28139cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 28146896f15aSKinglong Mee if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) { 28158a4c3926SJeff Layton status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types); 28166896f15aSKinglong Mee if (status) 28176896f15aSKinglong Mee goto out; 28189cf514ccSChristoph Hellwig } 28196896f15aSKinglong Mee 28206896f15aSKinglong Mee if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) { 28218a4c3926SJeff Layton status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types); 28226896f15aSKinglong Mee if (status) 28236896f15aSKinglong Mee goto out; 28249cf514ccSChristoph Hellwig } 28259cf514ccSChristoph Hellwig 28269cf514ccSChristoph Hellwig if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) { 28279cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 28289cf514ccSChristoph Hellwig if (!p) 28299cf514ccSChristoph Hellwig goto out_resource; 28309cf514ccSChristoph Hellwig *p++ = cpu_to_be32(stat.blksize); 28319cf514ccSChristoph Hellwig } 28329cf514ccSChristoph Hellwig #endif /* CONFIG_NFSD_PNFS */ 28338c18f205SBenny Halevy if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { 283475976de6SKinglong Mee status = nfsd4_encode_bitmap(xdr, NFSD_SUPPATTR_EXCLCREAT_WORD0, 283575976de6SKinglong Mee NFSD_SUPPATTR_EXCLCREAT_WORD1, 283675976de6SKinglong Mee NFSD_SUPPATTR_EXCLCREAT_WORD2); 283775976de6SKinglong Mee if (status) 283875976de6SKinglong Mee goto out; 28398c18f205SBenny Halevy } 28407e705706SAndy Adamson 28417d580722SKinglong Mee if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { 28427d580722SKinglong Mee status = nfsd4_encode_security_label(xdr, rqstp, context, 28437d580722SKinglong Mee contextlen); 28447d580722SKinglong Mee if (status) 28457d580722SKinglong Mee goto out; 28467d580722SKinglong Mee } 28477d580722SKinglong Mee 2848082d4bd7SJ. Bruce Fields attrlen = htonl(xdr->buf->len - attrlen_offset - 4); 2849082d4bd7SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4); 28501da177e4SLinus Torvalds status = nfs_ok; 28511da177e4SLinus Torvalds 28521da177e4SLinus Torvalds out: 2853ba4e55bbSJ. Bruce Fields #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 285418032ca0SDavid Quigley if (context) 285518032ca0SDavid Quigley security_release_secctx(context, contextlen); 2856ba4e55bbSJ. Bruce Fields #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ 285728e05dd8SJ. Bruce Fields kfree(acl); 285818df11d0SYan, Zheng if (tempfh) { 2859d50e6136SJ. Bruce Fields fh_put(tempfh); 286018df11d0SYan, Zheng kfree(tempfh); 286118df11d0SYan, Zheng } 28621fcea5b2SJ. Bruce Fields if (status) 28631fcea5b2SJ. Bruce Fields xdr_truncate_encode(xdr, starting_len); 28641da177e4SLinus Torvalds return status; 28651da177e4SLinus Torvalds out_nfserr: 2866b8dd7b9aSAl Viro status = nfserrno(err); 28671da177e4SLinus Torvalds goto out; 28681da177e4SLinus Torvalds out_resource: 28691da177e4SLinus Torvalds status = nfserr_resource; 28701da177e4SLinus Torvalds goto out; 28711da177e4SLinus Torvalds } 28721da177e4SLinus Torvalds 28732825a7f9SJ. Bruce Fields static void svcxdr_init_encode_from_buffer(struct xdr_stream *xdr, 28742825a7f9SJ. Bruce Fields struct xdr_buf *buf, __be32 *p, int bytes) 28752825a7f9SJ. Bruce Fields { 28762825a7f9SJ. Bruce Fields xdr->scratch.iov_len = 0; 28772825a7f9SJ. Bruce Fields memset(buf, 0, sizeof(struct xdr_buf)); 28782825a7f9SJ. Bruce Fields buf->head[0].iov_base = p; 28792825a7f9SJ. Bruce Fields buf->head[0].iov_len = 0; 28802825a7f9SJ. Bruce Fields buf->len = 0; 28812825a7f9SJ. Bruce Fields xdr->buf = buf; 28822825a7f9SJ. Bruce Fields xdr->iov = buf->head; 28832825a7f9SJ. Bruce Fields xdr->p = p; 28842825a7f9SJ. Bruce Fields xdr->end = (void *)p + bytes; 28852825a7f9SJ. Bruce Fields buf->buflen = bytes; 28862825a7f9SJ. Bruce Fields } 28872825a7f9SJ. Bruce Fields 2888d5184658SJ. Bruce Fields __be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words, 2889d5184658SJ. Bruce Fields struct svc_fh *fhp, struct svc_export *exp, 2890d5184658SJ. Bruce Fields struct dentry *dentry, u32 *bmval, 2891d5184658SJ. Bruce Fields struct svc_rqst *rqstp, int ignore_crossmnt) 2892d5184658SJ. Bruce Fields { 28932825a7f9SJ. Bruce Fields struct xdr_buf dummy; 2894d5184658SJ. Bruce Fields struct xdr_stream xdr; 2895d5184658SJ. Bruce Fields __be32 ret; 2896d5184658SJ. Bruce Fields 28972825a7f9SJ. Bruce Fields svcxdr_init_encode_from_buffer(&xdr, &dummy, *p, words << 2); 2898d5184658SJ. Bruce Fields ret = nfsd4_encode_fattr(&xdr, fhp, exp, dentry, bmval, rqstp, 2899d5184658SJ. Bruce Fields ignore_crossmnt); 2900d5184658SJ. Bruce Fields *p = xdr.p; 2901d5184658SJ. Bruce Fields return ret; 2902d5184658SJ. Bruce Fields } 2903d5184658SJ. Bruce Fields 2904c0ce6ec8SJ. Bruce Fields static inline int attributes_need_mount(u32 *bmval) 2905c0ce6ec8SJ. Bruce Fields { 2906c0ce6ec8SJ. Bruce Fields if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME)) 2907c0ce6ec8SJ. Bruce Fields return 1; 2908c0ce6ec8SJ. Bruce Fields if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) 2909c0ce6ec8SJ. Bruce Fields return 1; 2910c0ce6ec8SJ. Bruce Fields return 0; 2911c0ce6ec8SJ. Bruce Fields } 2912c0ce6ec8SJ. Bruce Fields 2913b37ad28bSAl Viro static __be32 2914561f0ed4SJ. Bruce Fields nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd, 2915561f0ed4SJ. Bruce Fields const char *name, int namlen) 29161da177e4SLinus Torvalds { 29171da177e4SLinus Torvalds struct svc_export *exp = cd->rd_fhp->fh_export; 29181da177e4SLinus Torvalds struct dentry *dentry; 2919b37ad28bSAl Viro __be32 nfserr; 2920406a7ea9SFrank Filz int ignore_crossmnt = 0; 29211da177e4SLinus Torvalds 2922bbddca8eSNeilBrown dentry = lookup_one_len_unlocked(name, cd->rd_fhp->fh_dentry, namlen); 29231da177e4SLinus Torvalds if (IS_ERR(dentry)) 29241da177e4SLinus Torvalds return nfserrno(PTR_ERR(dentry)); 29252b0143b5SDavid Howells if (d_really_is_negative(dentry)) { 2926b2c0cea6SJ. Bruce Fields /* 2927bbddca8eSNeilBrown * we're not holding the i_mutex here, so there's 2928bbddca8eSNeilBrown * a window where this directory entry could have gone 2929bbddca8eSNeilBrown * away. 2930b2c0cea6SJ. Bruce Fields */ 2931b2c0cea6SJ. Bruce Fields dput(dentry); 2932b2c0cea6SJ. Bruce Fields return nfserr_noent; 2933b2c0cea6SJ. Bruce Fields } 29341da177e4SLinus Torvalds 29351da177e4SLinus Torvalds exp_get(exp); 2936406a7ea9SFrank Filz /* 2937406a7ea9SFrank Filz * In the case of a mountpoint, the client may be asking for 2938406a7ea9SFrank Filz * attributes that are only properties of the underlying filesystem 2939406a7ea9SFrank Filz * as opposed to the cross-mounted file system. In such a case, 2940406a7ea9SFrank Filz * we will not follow the cross mount and will fill the attribtutes 2941406a7ea9SFrank Filz * directly from the mountpoint dentry. 2942406a7ea9SFrank Filz */ 29433227fa41SJ. Bruce Fields if (nfsd_mountpoint(dentry, exp)) { 2944021d3a72SJ.Bruce Fields int err; 2945021d3a72SJ.Bruce Fields 29463227fa41SJ. Bruce Fields if (!(exp->ex_flags & NFSEXP_V4ROOT) 29473227fa41SJ. Bruce Fields && !attributes_need_mount(cd->rd_bmval)) { 29483227fa41SJ. Bruce Fields ignore_crossmnt = 1; 29493227fa41SJ. Bruce Fields goto out_encode; 29503227fa41SJ. Bruce Fields } 2951dcb488a3SAndy Adamson /* 2952dcb488a3SAndy Adamson * Why the heck aren't we just using nfsd_lookup?? 2953dcb488a3SAndy Adamson * Different "."/".." handling? Something else? 2954dcb488a3SAndy Adamson * At least, add a comment here to explain.... 2955dcb488a3SAndy Adamson */ 2956021d3a72SJ.Bruce Fields err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); 2957021d3a72SJ.Bruce Fields if (err) { 2958021d3a72SJ.Bruce Fields nfserr = nfserrno(err); 29591da177e4SLinus Torvalds goto out_put; 29601da177e4SLinus Torvalds } 2961dcb488a3SAndy Adamson nfserr = check_nfsd_access(exp, cd->rd_rqstp); 2962dcb488a3SAndy Adamson if (nfserr) 2963dcb488a3SAndy Adamson goto out_put; 29641da177e4SLinus Torvalds 29651da177e4SLinus Torvalds } 29663227fa41SJ. Bruce Fields out_encode: 2967561f0ed4SJ. Bruce Fields nfserr = nfsd4_encode_fattr(xdr, NULL, exp, dentry, cd->rd_bmval, 2968406a7ea9SFrank Filz cd->rd_rqstp, ignore_crossmnt); 29691da177e4SLinus Torvalds out_put: 29701da177e4SLinus Torvalds dput(dentry); 29711da177e4SLinus Torvalds exp_put(exp); 29721da177e4SLinus Torvalds return nfserr; 29731da177e4SLinus Torvalds } 29741da177e4SLinus Torvalds 29752ebbc012SAl Viro static __be32 * 2976561f0ed4SJ. Bruce Fields nfsd4_encode_rdattr_error(struct xdr_stream *xdr, __be32 nfserr) 29771da177e4SLinus Torvalds { 2978561f0ed4SJ. Bruce Fields __be32 *p; 2979561f0ed4SJ. Bruce Fields 2980c3a45617SKinglong Mee p = xdr_reserve_space(xdr, 20); 2981561f0ed4SJ. Bruce Fields if (!p) 29821da177e4SLinus Torvalds return NULL; 29831da177e4SLinus Torvalds *p++ = htonl(2); 29841da177e4SLinus Torvalds *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */ 29851da177e4SLinus Torvalds *p++ = htonl(0); /* bmval1 */ 29861da177e4SLinus Torvalds 298787915c64SJ. Bruce Fields *p++ = htonl(4); /* attribute length */ 29881da177e4SLinus Torvalds *p++ = nfserr; /* no htonl */ 29891da177e4SLinus Torvalds return p; 29901da177e4SLinus Torvalds } 29911da177e4SLinus Torvalds 29921da177e4SLinus Torvalds static int 2993a0ad13efSNeilBrown nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, 2994a0ad13efSNeilBrown loff_t offset, u64 ino, unsigned int d_type) 29951da177e4SLinus Torvalds { 2996a0ad13efSNeilBrown struct readdir_cd *ccd = ccdv; 29971da177e4SLinus Torvalds struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); 2998561f0ed4SJ. Bruce Fields struct xdr_stream *xdr = cd->xdr; 2999561f0ed4SJ. Bruce Fields int start_offset = xdr->buf->len; 3000561f0ed4SJ. Bruce Fields int cookie_offset; 3001aee37764SJ. Bruce Fields u32 name_and_cookie; 3002561f0ed4SJ. Bruce Fields int entry_bytes; 3003b37ad28bSAl Viro __be32 nfserr = nfserr_toosmall; 3004561f0ed4SJ. Bruce Fields __be64 wire_offset; 3005561f0ed4SJ. Bruce Fields __be32 *p; 30061da177e4SLinus Torvalds 30071da177e4SLinus Torvalds /* In nfsv4, "." and ".." never make it onto the wire.. */ 30081da177e4SLinus Torvalds if (name && isdotent(name, namlen)) { 30091da177e4SLinus Torvalds cd->common.err = nfs_ok; 30101da177e4SLinus Torvalds return 0; 30111da177e4SLinus Torvalds } 30121da177e4SLinus Torvalds 3013561f0ed4SJ. Bruce Fields if (cd->cookie_offset) { 3014561f0ed4SJ. Bruce Fields wire_offset = cpu_to_be64(offset); 3015561f0ed4SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, cd->cookie_offset, 3016561f0ed4SJ. Bruce Fields &wire_offset, 8); 3017561f0ed4SJ. Bruce Fields } 30181da177e4SLinus Torvalds 3019561f0ed4SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 3020561f0ed4SJ. Bruce Fields if (!p) 30211da177e4SLinus Torvalds goto fail; 30221da177e4SLinus Torvalds *p++ = xdr_one; /* mark entry present */ 3023561f0ed4SJ. Bruce Fields cookie_offset = xdr->buf->len; 3024561f0ed4SJ. Bruce Fields p = xdr_reserve_space(xdr, 3*4 + namlen); 3025561f0ed4SJ. Bruce Fields if (!p) 3026561f0ed4SJ. Bruce Fields goto fail; 30271da177e4SLinus Torvalds p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */ 30281da177e4SLinus Torvalds p = xdr_encode_array(p, name, namlen); /* name length & name */ 30291da177e4SLinus Torvalds 3030561f0ed4SJ. Bruce Fields nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen); 30311da177e4SLinus Torvalds switch (nfserr) { 30321da177e4SLinus Torvalds case nfs_ok: 30331da177e4SLinus Torvalds break; 30341da177e4SLinus Torvalds case nfserr_resource: 30351da177e4SLinus Torvalds nfserr = nfserr_toosmall; 30361da177e4SLinus Torvalds goto fail; 3037b2c0cea6SJ. Bruce Fields case nfserr_noent: 3038f41c5ad2SKinglong Mee xdr_truncate_encode(xdr, start_offset); 3039b2c0cea6SJ. Bruce Fields goto skip_entry; 30401da177e4SLinus Torvalds default: 30411da177e4SLinus Torvalds /* 30421da177e4SLinus Torvalds * If the client requested the RDATTR_ERROR attribute, 30431da177e4SLinus Torvalds * we stuff the error code into this attribute 30441da177e4SLinus Torvalds * and continue. If this attribute was not requested, 30451da177e4SLinus Torvalds * then in accordance with the spec, we fail the 30461da177e4SLinus Torvalds * entire READDIR operation(!) 30471da177e4SLinus Torvalds */ 30481da177e4SLinus Torvalds if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) 30491da177e4SLinus Torvalds goto fail; 3050561f0ed4SJ. Bruce Fields p = nfsd4_encode_rdattr_error(xdr, nfserr); 305134081efcSFred Isaman if (p == NULL) { 305234081efcSFred Isaman nfserr = nfserr_toosmall; 30531da177e4SLinus Torvalds goto fail; 30541da177e4SLinus Torvalds } 305534081efcSFred Isaman } 3056561f0ed4SJ. Bruce Fields nfserr = nfserr_toosmall; 3057561f0ed4SJ. Bruce Fields entry_bytes = xdr->buf->len - start_offset; 3058561f0ed4SJ. Bruce Fields if (entry_bytes > cd->rd_maxcount) 3059561f0ed4SJ. Bruce Fields goto fail; 3060561f0ed4SJ. Bruce Fields cd->rd_maxcount -= entry_bytes; 3061aee37764SJ. Bruce Fields /* 3062aee37764SJ. Bruce Fields * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so 3063aee37764SJ. Bruce Fields * let's always let through the first entry, at least: 3064aee37764SJ. Bruce Fields */ 30650ec016e3SJ. Bruce Fields if (!cd->rd_dircount) 30660ec016e3SJ. Bruce Fields goto fail; 30670ec016e3SJ. Bruce Fields name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8; 3068aee37764SJ. Bruce Fields if (name_and_cookie > cd->rd_dircount && cd->cookie_offset) 3069aee37764SJ. Bruce Fields goto fail; 3070aee37764SJ. Bruce Fields cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie); 30710ec016e3SJ. Bruce Fields 3072561f0ed4SJ. Bruce Fields cd->cookie_offset = cookie_offset; 3073b2c0cea6SJ. Bruce Fields skip_entry: 30741da177e4SLinus Torvalds cd->common.err = nfs_ok; 30751da177e4SLinus Torvalds return 0; 30761da177e4SLinus Torvalds fail: 3077561f0ed4SJ. Bruce Fields xdr_truncate_encode(xdr, start_offset); 30781da177e4SLinus Torvalds cd->common.err = nfserr; 30791da177e4SLinus Torvalds return -EINVAL; 30801da177e4SLinus Torvalds } 30811da177e4SLinus Torvalds 3082d0a381ddSJ. Bruce Fields static __be32 3083d0a381ddSJ. Bruce Fields nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid) 3084e2f282b9SBenny Halevy { 3085bc749ca4SJ. Bruce Fields __be32 *p; 3086e2f282b9SBenny Halevy 3087d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, sizeof(stateid_t)); 3088d0a381ddSJ. Bruce Fields if (!p) 3089d0a381ddSJ. Bruce Fields return nfserr_resource; 3090c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sid->si_generation); 30910c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &sid->si_opaque, 30920c0c267bSJ. Bruce Fields sizeof(stateid_opaque_t)); 3093d0a381ddSJ. Bruce Fields return 0; 3094e2f282b9SBenny Halevy } 3095e2f282b9SBenny Halevy 3096695e12f8SBenny Halevy static __be32 3097b37ad28bSAl Viro nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) 30981da177e4SLinus Torvalds { 3099d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3100bc749ca4SJ. Bruce Fields __be32 *p; 31011da177e4SLinus Torvalds 31021da177e4SLinus Torvalds if (!nfserr) { 3103d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 3104d0a381ddSJ. Bruce Fields if (!p) 3105d0a381ddSJ. Bruce Fields return nfserr_resource; 3106c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(access->ac_supported); 3107c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(access->ac_resp_access); 31081da177e4SLinus Torvalds } 3109695e12f8SBenny Halevy return nfserr; 31101da177e4SLinus Torvalds } 31111da177e4SLinus Torvalds 31121d1bc8f2SJ. Bruce Fields static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts) 31131d1bc8f2SJ. Bruce Fields { 3114d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 31151d1bc8f2SJ. Bruce Fields __be32 *p; 31161d1bc8f2SJ. Bruce Fields 31171d1bc8f2SJ. Bruce Fields if (!nfserr) { 3118d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8); 3119d0a381ddSJ. Bruce Fields if (!p) 3120d0a381ddSJ. Bruce Fields return nfserr_resource; 31210c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, bcts->sessionid.data, 31220c0c267bSJ. Bruce Fields NFS4_MAX_SESSIONID_LEN); 3123c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(bcts->dir); 31244ce85c8cSChuck Lever /* Upshifting from TCP to RDMA is not supported */ 3125c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 31261d1bc8f2SJ. Bruce Fields } 31271d1bc8f2SJ. Bruce Fields return nfserr; 31281d1bc8f2SJ. Bruce Fields } 31291d1bc8f2SJ. Bruce Fields 3130695e12f8SBenny Halevy static __be32 3131b37ad28bSAl Viro nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) 31321da177e4SLinus Torvalds { 3133d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3134d0a381ddSJ. Bruce Fields 3135e2f282b9SBenny Halevy if (!nfserr) 3136d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &close->cl_stateid); 3137e2f282b9SBenny Halevy 3138695e12f8SBenny Halevy return nfserr; 31391da177e4SLinus Torvalds } 31401da177e4SLinus Torvalds 31411da177e4SLinus Torvalds 3142695e12f8SBenny Halevy static __be32 3143b37ad28bSAl Viro nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) 31441da177e4SLinus Torvalds { 3145d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3146bc749ca4SJ. Bruce Fields __be32 *p; 31471da177e4SLinus Torvalds 31481da177e4SLinus Torvalds if (!nfserr) { 3149d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE); 3150d0a381ddSJ. Bruce Fields if (!p) 3151d0a381ddSJ. Bruce Fields return nfserr_resource; 31520c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, commit->co_verf.data, 31530c0c267bSJ. Bruce Fields NFS4_VERIFIER_SIZE); 31541da177e4SLinus Torvalds } 3155695e12f8SBenny Halevy return nfserr; 31561da177e4SLinus Torvalds } 31571da177e4SLinus Torvalds 3158695e12f8SBenny Halevy static __be32 3159b37ad28bSAl Viro nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) 31601da177e4SLinus Torvalds { 3161d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3162bc749ca4SJ. Bruce Fields __be32 *p; 31631da177e4SLinus Torvalds 31641da177e4SLinus Torvalds if (!nfserr) { 316575976de6SKinglong Mee p = xdr_reserve_space(xdr, 20); 3166d0a381ddSJ. Bruce Fields if (!p) 3167d0a381ddSJ. Bruce Fields return nfserr_resource; 316875976de6SKinglong Mee encode_cinfo(p, &create->cr_cinfo); 316975976de6SKinglong Mee nfserr = nfsd4_encode_bitmap(xdr, create->cr_bmval[0], 317075976de6SKinglong Mee create->cr_bmval[1], create->cr_bmval[2]); 31711da177e4SLinus Torvalds } 3172695e12f8SBenny Halevy return nfserr; 31731da177e4SLinus Torvalds } 31741da177e4SLinus Torvalds 3175b37ad28bSAl Viro static __be32 3176b37ad28bSAl Viro nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr) 31771da177e4SLinus Torvalds { 31781da177e4SLinus Torvalds struct svc_fh *fhp = getattr->ga_fhp; 3179d5184658SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 31801da177e4SLinus Torvalds 31811da177e4SLinus Torvalds if (nfserr) 31821da177e4SLinus Torvalds return nfserr; 31831da177e4SLinus Torvalds 3184d5184658SJ. Bruce Fields nfserr = nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry, 3185d5184658SJ. Bruce Fields getattr->ga_bmval, 3186406a7ea9SFrank Filz resp->rqstp, 0); 31871da177e4SLinus Torvalds return nfserr; 31881da177e4SLinus Torvalds } 31891da177e4SLinus Torvalds 3190695e12f8SBenny Halevy static __be32 3191695e12f8SBenny Halevy nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp) 31921da177e4SLinus Torvalds { 3193d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3194695e12f8SBenny Halevy struct svc_fh *fhp = *fhpp; 31951da177e4SLinus Torvalds unsigned int len; 3196bc749ca4SJ. Bruce Fields __be32 *p; 31971da177e4SLinus Torvalds 31981da177e4SLinus Torvalds if (!nfserr) { 31991da177e4SLinus Torvalds len = fhp->fh_handle.fh_size; 3200d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, len + 4); 3201d0a381ddSJ. Bruce Fields if (!p) 3202d0a381ddSJ. Bruce Fields return nfserr_resource; 32030c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, len); 32041da177e4SLinus Torvalds } 3205695e12f8SBenny Halevy return nfserr; 32061da177e4SLinus Torvalds } 32071da177e4SLinus Torvalds 32081da177e4SLinus Torvalds /* 32091da177e4SLinus Torvalds * Including all fields other than the name, a LOCK4denied structure requires 32101da177e4SLinus Torvalds * 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes. 32111da177e4SLinus Torvalds */ 3212d0a381ddSJ. Bruce Fields static __be32 3213d0a381ddSJ. Bruce Fields nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld) 32141da177e4SLinus Torvalds { 32157c13f344SJ. Bruce Fields struct xdr_netobj *conf = &ld->ld_owner; 3216bc749ca4SJ. Bruce Fields __be32 *p; 32171da177e4SLinus Torvalds 32188c7424cfSJ. Bruce Fields again: 3219d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 32 + XDR_LEN(conf->len)); 32208c7424cfSJ. Bruce Fields if (!p) { 32218c7424cfSJ. Bruce Fields /* 32228c7424cfSJ. Bruce Fields * Don't fail to return the result just because we can't 32238c7424cfSJ. Bruce Fields * return the conflicting open: 32248c7424cfSJ. Bruce Fields */ 32258c7424cfSJ. Bruce Fields if (conf->len) { 3226f98bac5aSKinglong Mee kfree(conf->data); 32278c7424cfSJ. Bruce Fields conf->len = 0; 32288c7424cfSJ. Bruce Fields conf->data = NULL; 32298c7424cfSJ. Bruce Fields goto again; 32308c7424cfSJ. Bruce Fields } 3231d0a381ddSJ. Bruce Fields return nfserr_resource; 32328c7424cfSJ. Bruce Fields } 3233b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, ld->ld_start); 3234b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, ld->ld_length); 3235c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(ld->ld_type); 32367c13f344SJ. Bruce Fields if (conf->len) { 32370c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &ld->ld_clientid, 8); 32380c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, conf->data, conf->len); 3239f98bac5aSKinglong Mee kfree(conf->data); 32401da177e4SLinus Torvalds } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ 3241b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, (u64)0); /* clientid */ 3242c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* length of owner name */ 32431da177e4SLinus Torvalds } 3244d0a381ddSJ. Bruce Fields return nfserr_denied; 32451da177e4SLinus Torvalds } 32461da177e4SLinus Torvalds 3247695e12f8SBenny Halevy static __be32 3248b37ad28bSAl Viro nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) 32491da177e4SLinus Torvalds { 3250d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3251d0a381ddSJ. Bruce Fields 3252e2f282b9SBenny Halevy if (!nfserr) 3253d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid); 3254e2f282b9SBenny Halevy else if (nfserr == nfserr_denied) 3255d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied); 3256f98bac5aSKinglong Mee 3257695e12f8SBenny Halevy return nfserr; 32581da177e4SLinus Torvalds } 32591da177e4SLinus Torvalds 3260695e12f8SBenny Halevy static __be32 3261b37ad28bSAl Viro nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) 32621da177e4SLinus Torvalds { 3263d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3264d0a381ddSJ. Bruce Fields 32651da177e4SLinus Torvalds if (nfserr == nfserr_denied) 3266d0a381ddSJ. Bruce Fields nfsd4_encode_lock_denied(xdr, &lockt->lt_denied); 3267695e12f8SBenny Halevy return nfserr; 32681da177e4SLinus Torvalds } 32691da177e4SLinus Torvalds 3270695e12f8SBenny Halevy static __be32 3271b37ad28bSAl Viro nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) 32721da177e4SLinus Torvalds { 3273d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3274d0a381ddSJ. Bruce Fields 3275e2f282b9SBenny Halevy if (!nfserr) 3276d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &locku->lu_stateid); 32771da177e4SLinus Torvalds 3278695e12f8SBenny Halevy return nfserr; 32791da177e4SLinus Torvalds } 32801da177e4SLinus Torvalds 32811da177e4SLinus Torvalds 3282695e12f8SBenny Halevy static __be32 3283b37ad28bSAl Viro nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) 32841da177e4SLinus Torvalds { 3285d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3286bc749ca4SJ. Bruce Fields __be32 *p; 32871da177e4SLinus Torvalds 32881da177e4SLinus Torvalds if (!nfserr) { 3289d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 20); 3290d0a381ddSJ. Bruce Fields if (!p) 3291d0a381ddSJ. Bruce Fields return nfserr_resource; 3292d05d5744SJ. Bruce Fields p = encode_cinfo(p, &link->li_cinfo); 32931da177e4SLinus Torvalds } 3294695e12f8SBenny Halevy return nfserr; 32951da177e4SLinus Torvalds } 32961da177e4SLinus Torvalds 32971da177e4SLinus Torvalds 3298695e12f8SBenny Halevy static __be32 3299b37ad28bSAl Viro nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) 33001da177e4SLinus Torvalds { 3301d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3302bc749ca4SJ. Bruce Fields __be32 *p; 33031da177e4SLinus Torvalds 33041da177e4SLinus Torvalds if (nfserr) 33051da177e4SLinus Torvalds goto out; 33061da177e4SLinus Torvalds 3307d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid); 3308d0a381ddSJ. Bruce Fields if (nfserr) 3309d0a381ddSJ. Bruce Fields goto out; 331075976de6SKinglong Mee p = xdr_reserve_space(xdr, 24); 3311d0a381ddSJ. Bruce Fields if (!p) 3312d0a381ddSJ. Bruce Fields return nfserr_resource; 3313d05d5744SJ. Bruce Fields p = encode_cinfo(p, &open->op_cinfo); 3314c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_rflags); 33151da177e4SLinus Torvalds 331675976de6SKinglong Mee nfserr = nfsd4_encode_bitmap(xdr, open->op_bmval[0], open->op_bmval[1], 331775976de6SKinglong Mee open->op_bmval[2]); 331875976de6SKinglong Mee if (nfserr) 331975976de6SKinglong Mee goto out; 332075976de6SKinglong Mee 332175976de6SKinglong Mee p = xdr_reserve_space(xdr, 4); 332275976de6SKinglong Mee if (!p) 332375976de6SKinglong Mee return nfserr_resource; 332475976de6SKinglong Mee 332575976de6SKinglong Mee *p++ = cpu_to_be32(open->op_delegate_type); 33261da177e4SLinus Torvalds switch (open->op_delegate_type) { 33271da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_NONE: 33281da177e4SLinus Torvalds break; 33291da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_READ: 3330d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid); 3331d0a381ddSJ. Bruce Fields if (nfserr) 3332d0a381ddSJ. Bruce Fields return nfserr; 3333d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 20); 3334d0a381ddSJ. Bruce Fields if (!p) 3335d0a381ddSJ. Bruce Fields return nfserr_resource; 3336c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_recall); 33371da177e4SLinus Torvalds 33381da177e4SLinus Torvalds /* 33391da177e4SLinus Torvalds * TODO: ACE's in delegations 33401da177e4SLinus Torvalds */ 3341c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); 3342c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3343c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3344c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */ 33451da177e4SLinus Torvalds break; 33461da177e4SLinus Torvalds case NFS4_OPEN_DELEGATE_WRITE: 3347d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid); 3348d0a381ddSJ. Bruce Fields if (nfserr) 3349d0a381ddSJ. Bruce Fields return nfserr; 3350d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 32); 3351d0a381ddSJ. Bruce Fields if (!p) 3352d0a381ddSJ. Bruce Fields return nfserr_resource; 3353c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 33541da177e4SLinus Torvalds 33551da177e4SLinus Torvalds /* 33561da177e4SLinus Torvalds * TODO: space_limit's in delegations 33571da177e4SLinus Torvalds */ 3358c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_LIMIT_SIZE); 3359c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(~(u32)0); 3360c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(~(u32)0); 33611da177e4SLinus Torvalds 33621da177e4SLinus Torvalds /* 33631da177e4SLinus Torvalds * TODO: ACE's in delegations 33641da177e4SLinus Torvalds */ 3365c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); 3366c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3367c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3368c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */ 33691da177e4SLinus Torvalds break; 3370d24433cdSBenny Halevy case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */ 3371d24433cdSBenny Halevy switch (open->op_why_no_deleg) { 3372d24433cdSBenny Halevy case WND4_CONTENTION: 3373d24433cdSBenny Halevy case WND4_RESOURCE: 3374d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 3375d0a381ddSJ. Bruce Fields if (!p) 3376d0a381ddSJ. Bruce Fields return nfserr_resource; 3377c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_why_no_deleg); 3378c373b0a4SJ. Bruce Fields /* deleg signaling not supported yet: */ 3379c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3380d24433cdSBenny Halevy break; 3381d24433cdSBenny Halevy default: 3382d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 3383d0a381ddSJ. Bruce Fields if (!p) 3384d0a381ddSJ. Bruce Fields return nfserr_resource; 3385c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(open->op_why_no_deleg); 3386d24433cdSBenny Halevy } 3387d24433cdSBenny Halevy break; 33881da177e4SLinus Torvalds default: 33891da177e4SLinus Torvalds BUG(); 33901da177e4SLinus Torvalds } 33911da177e4SLinus Torvalds /* XXX save filehandle here */ 33921da177e4SLinus Torvalds out: 3393695e12f8SBenny Halevy return nfserr; 33941da177e4SLinus Torvalds } 33951da177e4SLinus Torvalds 3396695e12f8SBenny Halevy static __be32 3397b37ad28bSAl Viro nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) 33981da177e4SLinus Torvalds { 3399d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3400d0a381ddSJ. Bruce Fields 3401e2f282b9SBenny Halevy if (!nfserr) 3402d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid); 34031da177e4SLinus Torvalds 3404695e12f8SBenny Halevy return nfserr; 34051da177e4SLinus Torvalds } 34061da177e4SLinus Torvalds 3407695e12f8SBenny Halevy static __be32 3408b37ad28bSAl Viro nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) 34091da177e4SLinus Torvalds { 3410d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3411d0a381ddSJ. Bruce Fields 3412e2f282b9SBenny Halevy if (!nfserr) 3413d0a381ddSJ. Bruce Fields nfserr = nfsd4_encode_stateid(xdr, &od->od_stateid); 34141da177e4SLinus Torvalds 3415695e12f8SBenny Halevy return nfserr; 34161da177e4SLinus Torvalds } 34171da177e4SLinus Torvalds 3418dc97618dSJ. Bruce Fields static __be32 nfsd4_encode_splice_read( 3419dc97618dSJ. Bruce Fields struct nfsd4_compoundres *resp, 3420dc97618dSJ. Bruce Fields struct nfsd4_read *read, 3421dc97618dSJ. Bruce Fields struct file *file, unsigned long maxcount) 34221da177e4SLinus Torvalds { 3423dc97618dSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 342434a78b48SJ. Bruce Fields struct xdr_buf *buf = xdr->buf; 3425dc97618dSJ. Bruce Fields u32 eof; 3426ac503e4aSBenjamin Coddington long len; 3427dc97618dSJ. Bruce Fields int space_left; 3428dc97618dSJ. Bruce Fields __be32 nfserr; 3429fec25fa4SJ. Bruce Fields __be32 *p = xdr->p - 2; 3430dc97618dSJ. Bruce Fields 3431d5d5c304SKinglong Mee /* Make sure there will be room for padding if needed */ 3432d5d5c304SKinglong Mee if (xdr->end - xdr->p < 1) 3433dc97618dSJ. Bruce Fields return nfserr_resource; 3434dc97618dSJ. Bruce Fields 3435ac503e4aSBenjamin Coddington len = maxcount; 3436dc97618dSJ. Bruce Fields nfserr = nfsd_splice_read(read->rd_rqstp, file, 3437dc97618dSJ. Bruce Fields read->rd_offset, &maxcount); 3438dc97618dSJ. Bruce Fields if (nfserr) { 3439dc97618dSJ. Bruce Fields /* 3440dc97618dSJ. Bruce Fields * nfsd_splice_actor may have already messed with the 3441dc97618dSJ. Bruce Fields * page length; reset it so as not to confuse 3442dc97618dSJ. Bruce Fields * xdr_truncate_encode: 3443dc97618dSJ. Bruce Fields */ 344434a78b48SJ. Bruce Fields buf->page_len = 0; 3445dc97618dSJ. Bruce Fields return nfserr; 3446dc97618dSJ. Bruce Fields } 3447dc97618dSJ. Bruce Fields 3448ac503e4aSBenjamin Coddington eof = nfsd_eof_on_read(len, maxcount, read->rd_offset, 34492b0143b5SDavid Howells d_inode(read->rd_fhp->fh_dentry)->i_size); 3450dc97618dSJ. Bruce Fields 3451fec25fa4SJ. Bruce Fields *(p++) = htonl(eof); 3452fec25fa4SJ. Bruce Fields *(p++) = htonl(maxcount); 3453dc97618dSJ. Bruce Fields 345434a78b48SJ. Bruce Fields buf->page_len = maxcount; 345534a78b48SJ. Bruce Fields buf->len += maxcount; 345615b23ef5SJ. Bruce Fields xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1) 345715b23ef5SJ. Bruce Fields / PAGE_SIZE; 3458dc97618dSJ. Bruce Fields 3459dc97618dSJ. Bruce Fields /* Use rest of head for padding and remaining ops: */ 346034a78b48SJ. Bruce Fields buf->tail[0].iov_base = xdr->p; 346134a78b48SJ. Bruce Fields buf->tail[0].iov_len = 0; 3462fec25fa4SJ. Bruce Fields xdr->iov = buf->tail; 3463dc97618dSJ. Bruce Fields if (maxcount&3) { 3464fec25fa4SJ. Bruce Fields int pad = 4 - (maxcount&3); 3465fec25fa4SJ. Bruce Fields 3466fec25fa4SJ. Bruce Fields *(xdr->p++) = 0; 3467fec25fa4SJ. Bruce Fields 346834a78b48SJ. Bruce Fields buf->tail[0].iov_base += maxcount&3; 3469fec25fa4SJ. Bruce Fields buf->tail[0].iov_len = pad; 3470fec25fa4SJ. Bruce Fields buf->len += pad; 3471dc97618dSJ. Bruce Fields } 3472dc97618dSJ. Bruce Fields 3473dc97618dSJ. Bruce Fields space_left = min_t(int, (void *)xdr->end - (void *)xdr->p, 347434a78b48SJ. Bruce Fields buf->buflen - buf->len); 347534a78b48SJ. Bruce Fields buf->buflen = buf->len + space_left; 3476dc97618dSJ. Bruce Fields xdr->end = (__be32 *)((void *)xdr->end + space_left); 3477dc97618dSJ. Bruce Fields 3478dc97618dSJ. Bruce Fields return 0; 3479dc97618dSJ. Bruce Fields } 3480dc97618dSJ. Bruce Fields 3481dc97618dSJ. Bruce Fields static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, 3482dc97618dSJ. Bruce Fields struct nfsd4_read *read, 3483dc97618dSJ. Bruce Fields struct file *file, unsigned long maxcount) 3484dc97618dSJ. Bruce Fields { 3485dc97618dSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 34861da177e4SLinus Torvalds u32 eof; 3487afc59400SJ. Bruce Fields int v; 3488dc97618dSJ. Bruce Fields int starting_len = xdr->buf->len - 8; 34891da177e4SLinus Torvalds long len; 3490b0420980SJ. Bruce Fields int thislen; 3491dc97618dSJ. Bruce Fields __be32 nfserr; 3492dc97618dSJ. Bruce Fields __be32 tmp; 3493bc749ca4SJ. Bruce Fields __be32 *p; 3494b0420980SJ. Bruce Fields u32 zzz = 0; 3495b0420980SJ. Bruce Fields int pad; 34961da177e4SLinus Torvalds 34971da177e4SLinus Torvalds len = maxcount; 34981da177e4SLinus Torvalds v = 0; 34996ff9897dSJ. Bruce Fields 35001055414fSKinglong Mee thislen = min_t(long, len, ((void *)xdr->end - (void *)xdr->p)); 3501b0420980SJ. Bruce Fields p = xdr_reserve_space(xdr, (thislen+3)&~3); 3502b0420980SJ. Bruce Fields WARN_ON_ONCE(!p); 3503b0420980SJ. Bruce Fields resp->rqstp->rq_vec[v].iov_base = p; 35046ff9897dSJ. Bruce Fields resp->rqstp->rq_vec[v].iov_len = thislen; 3505b0420980SJ. Bruce Fields v++; 3506b0420980SJ. Bruce Fields len -= thislen; 3507b0420980SJ. Bruce Fields 3508b0420980SJ. Bruce Fields while (len) { 3509b0420980SJ. Bruce Fields thislen = min_t(long, len, PAGE_SIZE); 3510b0420980SJ. Bruce Fields p = xdr_reserve_space(xdr, (thislen+3)&~3); 3511b0420980SJ. Bruce Fields WARN_ON_ONCE(!p); 3512b0420980SJ. Bruce Fields resp->rqstp->rq_vec[v].iov_base = p; 3513b0420980SJ. Bruce Fields resp->rqstp->rq_vec[v].iov_len = thislen; 35141da177e4SLinus Torvalds v++; 35156ff9897dSJ. Bruce Fields len -= thislen; 35161da177e4SLinus Torvalds } 35171da177e4SLinus Torvalds read->rd_vlen = v; 35181da177e4SLinus Torvalds 3519ac503e4aSBenjamin Coddington len = maxcount; 3520dc97618dSJ. Bruce Fields nfserr = nfsd_readv(file, read->rd_offset, resp->rqstp->rq_vec, 3521dc97618dSJ. Bruce Fields read->rd_vlen, &maxcount); 3522dc97618dSJ. Bruce Fields if (nfserr) 35231da177e4SLinus Torvalds return nfserr; 3524b0420980SJ. Bruce Fields xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3)); 3525dc97618dSJ. Bruce Fields 3526ac503e4aSBenjamin Coddington eof = nfsd_eof_on_read(len, maxcount, read->rd_offset, 35272b0143b5SDavid Howells d_inode(read->rd_fhp->fh_dentry)->i_size); 35281da177e4SLinus Torvalds 3529dc97618dSJ. Bruce Fields tmp = htonl(eof); 3530dc97618dSJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4); 3531dc97618dSJ. Bruce Fields tmp = htonl(maxcount); 3532dc97618dSJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); 3533dc97618dSJ. Bruce Fields 3534b0420980SJ. Bruce Fields pad = (maxcount&3) ? 4 - (maxcount&3) : 0; 3535b0420980SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount, 3536b0420980SJ. Bruce Fields &zzz, pad); 35371da177e4SLinus Torvalds return 0; 3538dc97618dSJ. Bruce Fields 3539dc97618dSJ. Bruce Fields } 3540dc97618dSJ. Bruce Fields 3541dc97618dSJ. Bruce Fields static __be32 3542dc97618dSJ. Bruce Fields nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, 3543dc97618dSJ. Bruce Fields struct nfsd4_read *read) 3544dc97618dSJ. Bruce Fields { 3545dc97618dSJ. Bruce Fields unsigned long maxcount; 3546dc97618dSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3547dc97618dSJ. Bruce Fields struct file *file = read->rd_filp; 3548dc97618dSJ. Bruce Fields int starting_len = xdr->buf->len; 3549e749a462SChristoph Hellwig struct raparms *ra = NULL; 3550dc97618dSJ. Bruce Fields __be32 *p; 3551dc97618dSJ. Bruce Fields 3552dc97618dSJ. Bruce Fields if (nfserr) 355396bcad50SChristoph Hellwig goto out; 3554dc97618dSJ. Bruce Fields 3555dc97618dSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */ 3556dc97618dSJ. Bruce Fields if (!p) { 3557779fb0f3SJeff Layton WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)); 355896bcad50SChristoph Hellwig nfserr = nfserr_resource; 355996bcad50SChristoph Hellwig goto out; 3560dc97618dSJ. Bruce Fields } 356168e8bb03SChristoph Hellwig if (resp->xdr.buf->page_len && 356268e8bb03SChristoph Hellwig test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) { 3563b0420980SJ. Bruce Fields WARN_ON_ONCE(1); 356496bcad50SChristoph Hellwig nfserr = nfserr_resource; 356596bcad50SChristoph Hellwig goto out; 3566dc97618dSJ. Bruce Fields } 3567dc97618dSJ. Bruce Fields xdr_commit_encode(xdr); 3568dc97618dSJ. Bruce Fields 3569dc97618dSJ. Bruce Fields maxcount = svc_max_payload(resp->rqstp); 357068e8bb03SChristoph Hellwig maxcount = min_t(unsigned long, maxcount, 357168e8bb03SChristoph Hellwig (xdr->buf->buflen - xdr->buf->len)); 35723c7aa15dSKinglong Mee maxcount = min_t(unsigned long, maxcount, read->rd_length); 3573dc97618dSJ. Bruce Fields 3574af90f707SChristoph Hellwig if (read->rd_tmp_file) 3575e749a462SChristoph Hellwig ra = nfsd_init_raparms(file); 3576dc97618dSJ. Bruce Fields 357768e8bb03SChristoph Hellwig if (file->f_op->splice_read && 357868e8bb03SChristoph Hellwig test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) 357996bcad50SChristoph Hellwig nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount); 3580dc97618dSJ. Bruce Fields else 358196bcad50SChristoph Hellwig nfserr = nfsd4_encode_readv(resp, read, file, maxcount); 3582dc97618dSJ. Bruce Fields 3583e749a462SChristoph Hellwig if (ra) 3584e749a462SChristoph Hellwig nfsd_put_raparams(file, ra); 3585dc97618dSJ. Bruce Fields 358696bcad50SChristoph Hellwig if (nfserr) 3587dc97618dSJ. Bruce Fields xdr_truncate_encode(xdr, starting_len); 358896bcad50SChristoph Hellwig 358996bcad50SChristoph Hellwig out: 359096bcad50SChristoph Hellwig if (file) 359196bcad50SChristoph Hellwig fput(file); 359296bcad50SChristoph Hellwig return nfserr; 35931da177e4SLinus Torvalds } 35941da177e4SLinus Torvalds 3595b37ad28bSAl Viro static __be32 3596b37ad28bSAl Viro nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) 35971da177e4SLinus Torvalds { 35981da177e4SLinus Torvalds int maxcount; 3599476a7b1fSJ. Bruce Fields __be32 wire_count; 3600476a7b1fSJ. Bruce Fields int zero = 0; 3601ddd1ea56SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 36021fcea5b2SJ. Bruce Fields int length_offset = xdr->buf->len; 3603bc749ca4SJ. Bruce Fields __be32 *p; 36041da177e4SLinus Torvalds 36051da177e4SLinus Torvalds if (nfserr) 36061da177e4SLinus Torvalds return nfserr; 36072825a7f9SJ. Bruce Fields 36082825a7f9SJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 36092825a7f9SJ. Bruce Fields if (!p) 36102825a7f9SJ. Bruce Fields return nfserr_resource; 36111da177e4SLinus Torvalds maxcount = PAGE_SIZE; 3612d0a381ddSJ. Bruce Fields 3613476a7b1fSJ. Bruce Fields p = xdr_reserve_space(xdr, maxcount); 3614476a7b1fSJ. Bruce Fields if (!p) 36154e21ac4bSJ. Bruce Fields return nfserr_resource; 36161da177e4SLinus Torvalds /* 3617fd4a0edfSMiklos Szeredi * XXX: By default, vfs_readlink() will truncate symlinks if they 3618fd4a0edfSMiklos Szeredi * would overflow the buffer. Is this kosher in NFSv4? If not, one 3619fd4a0edfSMiklos Szeredi * easy fix is: if vfs_readlink() precisely fills the buffer, assume 3620fd4a0edfSMiklos Szeredi * that truncation occurred, and return NFS4ERR_RESOURCE. 36211da177e4SLinus Torvalds */ 3622476a7b1fSJ. Bruce Fields nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, 3623476a7b1fSJ. Bruce Fields (char *)p, &maxcount); 36241da177e4SLinus Torvalds if (nfserr == nfserr_isdir) 3625d3f627c8SJ. Bruce Fields nfserr = nfserr_inval; 3626d3f627c8SJ. Bruce Fields if (nfserr) { 36271fcea5b2SJ. Bruce Fields xdr_truncate_encode(xdr, length_offset); 36281da177e4SLinus Torvalds return nfserr; 3629d3f627c8SJ. Bruce Fields } 36301da177e4SLinus Torvalds 3631476a7b1fSJ. Bruce Fields wire_count = htonl(maxcount); 3632476a7b1fSJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4); 363369bbd9c7SAvi Kivity xdr_truncate_encode(xdr, length_offset + 4 + ALIGN(maxcount, 4)); 3634476a7b1fSJ. Bruce Fields if (maxcount & 3) 3635476a7b1fSJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount, 3636476a7b1fSJ. Bruce Fields &zero, 4 - (maxcount&3)); 36371da177e4SLinus Torvalds return 0; 36381da177e4SLinus Torvalds } 36391da177e4SLinus Torvalds 3640b37ad28bSAl Viro static __be32 3641b37ad28bSAl Viro nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir) 36421da177e4SLinus Torvalds { 36431da177e4SLinus Torvalds int maxcount; 3644561f0ed4SJ. Bruce Fields int bytes_left; 36451da177e4SLinus Torvalds loff_t offset; 3646561f0ed4SJ. Bruce Fields __be64 wire_offset; 3647ddd1ea56SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 36481fcea5b2SJ. Bruce Fields int starting_len = xdr->buf->len; 3649bc749ca4SJ. Bruce Fields __be32 *p; 36501da177e4SLinus Torvalds 36511da177e4SLinus Torvalds if (nfserr) 36521da177e4SLinus Torvalds return nfserr; 36531da177e4SLinus Torvalds 3654d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE); 3655d0a381ddSJ. Bruce Fields if (!p) 3656d0a381ddSJ. Bruce Fields return nfserr_resource; 36571da177e4SLinus Torvalds 36581da177e4SLinus Torvalds /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */ 3659c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3660c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 36614aea24b2SJ. Bruce Fields resp->xdr.buf->head[0].iov_len = ((char *)resp->xdr.p) 36624aea24b2SJ. Bruce Fields - (char *)resp->xdr.buf->head[0].iov_base; 36631da177e4SLinus Torvalds 36641da177e4SLinus Torvalds /* 3665561f0ed4SJ. Bruce Fields * Number of bytes left for directory entries allowing for the 3666561f0ed4SJ. Bruce Fields * final 8 bytes of the readdir and a following failed op: 36671da177e4SLinus Torvalds */ 3668561f0ed4SJ. Bruce Fields bytes_left = xdr->buf->buflen - xdr->buf->len 3669561f0ed4SJ. Bruce Fields - COMPOUND_ERR_SLACK_SPACE - 8; 3670561f0ed4SJ. Bruce Fields if (bytes_left < 0) { 3671561f0ed4SJ. Bruce Fields nfserr = nfserr_resource; 3672561f0ed4SJ. Bruce Fields goto err_no_verf; 3673561f0ed4SJ. Bruce Fields } 3674561f0ed4SJ. Bruce Fields maxcount = min_t(u32, readdir->rd_maxcount, INT_MAX); 3675561f0ed4SJ. Bruce Fields /* 3676561f0ed4SJ. Bruce Fields * Note the rfc defines rd_maxcount as the size of the 3677561f0ed4SJ. Bruce Fields * READDIR4resok structure, which includes the verifier above 3678561f0ed4SJ. Bruce Fields * and the 8 bytes encoded at the end of this function: 3679561f0ed4SJ. Bruce Fields */ 3680561f0ed4SJ. Bruce Fields if (maxcount < 16) { 36811da177e4SLinus Torvalds nfserr = nfserr_toosmall; 36821da177e4SLinus Torvalds goto err_no_verf; 36831da177e4SLinus Torvalds } 3684561f0ed4SJ. Bruce Fields maxcount = min_t(int, maxcount-16, bytes_left); 36851da177e4SLinus Torvalds 3686aee37764SJ. Bruce Fields /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */ 3687aee37764SJ. Bruce Fields if (!readdir->rd_dircount) 3688aee37764SJ. Bruce Fields readdir->rd_dircount = INT_MAX; 3689aee37764SJ. Bruce Fields 3690561f0ed4SJ. Bruce Fields readdir->xdr = xdr; 3691561f0ed4SJ. Bruce Fields readdir->rd_maxcount = maxcount; 36921da177e4SLinus Torvalds readdir->common.err = 0; 3693561f0ed4SJ. Bruce Fields readdir->cookie_offset = 0; 36941da177e4SLinus Torvalds 36951da177e4SLinus Torvalds offset = readdir->rd_cookie; 36961da177e4SLinus Torvalds nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, 36971da177e4SLinus Torvalds &offset, 36981da177e4SLinus Torvalds &readdir->common, nfsd4_encode_dirent); 36991da177e4SLinus Torvalds if (nfserr == nfs_ok && 37001da177e4SLinus Torvalds readdir->common.err == nfserr_toosmall && 3701561f0ed4SJ. Bruce Fields xdr->buf->len == starting_len + 8) { 3702561f0ed4SJ. Bruce Fields /* nothing encoded; which limit did we hit?: */ 3703561f0ed4SJ. Bruce Fields if (maxcount - 16 < bytes_left) 3704561f0ed4SJ. Bruce Fields /* It was the fault of rd_maxcount: */ 37051da177e4SLinus Torvalds nfserr = nfserr_toosmall; 3706561f0ed4SJ. Bruce Fields else 3707561f0ed4SJ. Bruce Fields /* We ran out of buffer space: */ 3708561f0ed4SJ. Bruce Fields nfserr = nfserr_resource; 3709561f0ed4SJ. Bruce Fields } 37101da177e4SLinus Torvalds if (nfserr) 37111da177e4SLinus Torvalds goto err_no_verf; 37121da177e4SLinus Torvalds 3713561f0ed4SJ. Bruce Fields if (readdir->cookie_offset) { 3714561f0ed4SJ. Bruce Fields wire_offset = cpu_to_be64(offset); 3715561f0ed4SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, readdir->cookie_offset, 3716561f0ed4SJ. Bruce Fields &wire_offset, 8); 3717561f0ed4SJ. Bruce Fields } 37181da177e4SLinus Torvalds 3719561f0ed4SJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 3720561f0ed4SJ. Bruce Fields if (!p) { 3721561f0ed4SJ. Bruce Fields WARN_ON_ONCE(1); 3722561f0ed4SJ. Bruce Fields goto err_no_verf; 3723561f0ed4SJ. Bruce Fields } 37241da177e4SLinus Torvalds *p++ = 0; /* no more entries */ 37251da177e4SLinus Torvalds *p++ = htonl(readdir->common.err == nfserr_eof); 37261da177e4SLinus Torvalds 37271da177e4SLinus Torvalds return 0; 37281da177e4SLinus Torvalds err_no_verf: 37291fcea5b2SJ. Bruce Fields xdr_truncate_encode(xdr, starting_len); 37301da177e4SLinus Torvalds return nfserr; 37311da177e4SLinus Torvalds } 37321da177e4SLinus Torvalds 3733695e12f8SBenny Halevy static __be32 3734b37ad28bSAl Viro nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) 37351da177e4SLinus Torvalds { 3736d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3737bc749ca4SJ. Bruce Fields __be32 *p; 37381da177e4SLinus Torvalds 37391da177e4SLinus Torvalds if (!nfserr) { 3740d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 20); 3741d0a381ddSJ. Bruce Fields if (!p) 3742d0a381ddSJ. Bruce Fields return nfserr_resource; 3743d05d5744SJ. Bruce Fields p = encode_cinfo(p, &remove->rm_cinfo); 37441da177e4SLinus Torvalds } 3745695e12f8SBenny Halevy return nfserr; 37461da177e4SLinus Torvalds } 37471da177e4SLinus Torvalds 3748695e12f8SBenny Halevy static __be32 3749b37ad28bSAl Viro nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) 37501da177e4SLinus Torvalds { 3751d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3752bc749ca4SJ. Bruce Fields __be32 *p; 37531da177e4SLinus Torvalds 37541da177e4SLinus Torvalds if (!nfserr) { 3755d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 40); 3756d0a381ddSJ. Bruce Fields if (!p) 3757d0a381ddSJ. Bruce Fields return nfserr_resource; 3758d05d5744SJ. Bruce Fields p = encode_cinfo(p, &rename->rn_sinfo); 3759d05d5744SJ. Bruce Fields p = encode_cinfo(p, &rename->rn_tinfo); 37601da177e4SLinus Torvalds } 3761695e12f8SBenny Halevy return nfserr; 37621da177e4SLinus Torvalds } 37631da177e4SLinus Torvalds 3764695e12f8SBenny Halevy static __be32 3765d0a381ddSJ. Bruce Fields nfsd4_do_encode_secinfo(struct xdr_stream *xdr, 376622b6dee8SMi Jinlong __be32 nfserr, struct svc_export *exp) 3767dcb488a3SAndy Adamson { 3768676e4ebdSChuck Lever u32 i, nflavs, supported; 37694796f457SJ. Bruce Fields struct exp_flavor_info *flavs; 37704796f457SJ. Bruce Fields struct exp_flavor_info def_flavs[2]; 3771676e4ebdSChuck Lever __be32 *p, *flavorsp; 3772676e4ebdSChuck Lever static bool report = true; 3773dcb488a3SAndy Adamson 3774dcb488a3SAndy Adamson if (nfserr) 3775dcb488a3SAndy Adamson goto out; 3776d0a381ddSJ. Bruce Fields nfserr = nfserr_resource; 37774796f457SJ. Bruce Fields if (exp->ex_nflavors) { 37784796f457SJ. Bruce Fields flavs = exp->ex_flavors; 37794796f457SJ. Bruce Fields nflavs = exp->ex_nflavors; 37804796f457SJ. Bruce Fields } else { /* Handling of some defaults in absence of real secinfo: */ 37814796f457SJ. Bruce Fields flavs = def_flavs; 37824796f457SJ. Bruce Fields if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) { 37834796f457SJ. Bruce Fields nflavs = 2; 37844796f457SJ. Bruce Fields flavs[0].pseudoflavor = RPC_AUTH_UNIX; 37854796f457SJ. Bruce Fields flavs[1].pseudoflavor = RPC_AUTH_NULL; 37864796f457SJ. Bruce Fields } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) { 37874796f457SJ. Bruce Fields nflavs = 1; 37884796f457SJ. Bruce Fields flavs[0].pseudoflavor 37894796f457SJ. Bruce Fields = svcauth_gss_flavor(exp->ex_client); 37904796f457SJ. Bruce Fields } else { 37914796f457SJ. Bruce Fields nflavs = 1; 37924796f457SJ. Bruce Fields flavs[0].pseudoflavor 37934796f457SJ. Bruce Fields = exp->ex_client->flavour->flavour; 37944796f457SJ. Bruce Fields } 37954796f457SJ. Bruce Fields } 37964796f457SJ. Bruce Fields 3797676e4ebdSChuck Lever supported = 0; 3798d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 3799d0a381ddSJ. Bruce Fields if (!p) 3800d0a381ddSJ. Bruce Fields goto out; 3801676e4ebdSChuck Lever flavorsp = p++; /* to be backfilled later */ 3802676e4ebdSChuck Lever 38034796f457SJ. Bruce Fields for (i = 0; i < nflavs; i++) { 3804676e4ebdSChuck Lever rpc_authflavor_t pf = flavs[i].pseudoflavor; 3805a77c806fSChuck Lever struct rpcsec_gss_info info; 3806dcb488a3SAndy Adamson 3807676e4ebdSChuck Lever if (rpcauth_get_gssinfo(pf, &info) == 0) { 3808676e4ebdSChuck Lever supported++; 3809d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4 + 4 + 3810d0a381ddSJ. Bruce Fields XDR_LEN(info.oid.len) + 4 + 4); 3811d0a381ddSJ. Bruce Fields if (!p) 3812d0a381ddSJ. Bruce Fields goto out; 3813c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(RPC_AUTH_GSS); 38140c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, info.oid.data, info.oid.len); 3815c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(info.qop); 3816c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(info.service); 3817676e4ebdSChuck Lever } else if (pf < RPC_AUTH_MAXFLAVOR) { 3818676e4ebdSChuck Lever supported++; 3819d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 3820d0a381ddSJ. Bruce Fields if (!p) 3821d0a381ddSJ. Bruce Fields goto out; 3822c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(pf); 3823676e4ebdSChuck Lever } else { 3824676e4ebdSChuck Lever if (report) 3825676e4ebdSChuck Lever pr_warn("NFS: SECINFO: security flavor %u " 3826676e4ebdSChuck Lever "is not supported\n", pf); 3827dcb488a3SAndy Adamson } 3828dcb488a3SAndy Adamson } 3829a77c806fSChuck Lever 3830676e4ebdSChuck Lever if (nflavs != supported) 3831676e4ebdSChuck Lever report = false; 3832676e4ebdSChuck Lever *flavorsp = htonl(supported); 3833d0a381ddSJ. Bruce Fields nfserr = 0; 3834dcb488a3SAndy Adamson out: 3835dcb488a3SAndy Adamson if (exp) 3836dcb488a3SAndy Adamson exp_put(exp); 3837695e12f8SBenny Halevy return nfserr; 3838dcb488a3SAndy Adamson } 3839dcb488a3SAndy Adamson 384022b6dee8SMi Jinlong static __be32 384122b6dee8SMi Jinlong nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, 384222b6dee8SMi Jinlong struct nfsd4_secinfo *secinfo) 384322b6dee8SMi Jinlong { 3844d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3845d0a381ddSJ. Bruce Fields 3846d0a381ddSJ. Bruce Fields return nfsd4_do_encode_secinfo(xdr, nfserr, secinfo->si_exp); 384722b6dee8SMi Jinlong } 384822b6dee8SMi Jinlong 384922b6dee8SMi Jinlong static __be32 385022b6dee8SMi Jinlong nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, 385122b6dee8SMi Jinlong struct nfsd4_secinfo_no_name *secinfo) 385222b6dee8SMi Jinlong { 3853d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3854d0a381ddSJ. Bruce Fields 3855d0a381ddSJ. Bruce Fields return nfsd4_do_encode_secinfo(xdr, nfserr, secinfo->sin_exp); 385622b6dee8SMi Jinlong } 385722b6dee8SMi Jinlong 38581da177e4SLinus Torvalds /* 38591da177e4SLinus Torvalds * The SETATTR encode routine is special -- it always encodes a bitmap, 38601da177e4SLinus Torvalds * regardless of the error status. 38611da177e4SLinus Torvalds */ 3862695e12f8SBenny Halevy static __be32 3863b37ad28bSAl Viro nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) 38641da177e4SLinus Torvalds { 3865d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3866bc749ca4SJ. Bruce Fields __be32 *p; 38671da177e4SLinus Torvalds 3868d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 3869d0a381ddSJ. Bruce Fields if (!p) 3870d0a381ddSJ. Bruce Fields return nfserr_resource; 38711da177e4SLinus Torvalds if (nfserr) { 3872c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(3); 3873c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3874c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3875c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 38761da177e4SLinus Torvalds } 38771da177e4SLinus Torvalds else { 3878c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(3); 3879c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(setattr->sa_bmval[0]); 3880c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(setattr->sa_bmval[1]); 3881c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(setattr->sa_bmval[2]); 38821da177e4SLinus Torvalds } 3883695e12f8SBenny Halevy return nfserr; 38841da177e4SLinus Torvalds } 38851da177e4SLinus Torvalds 3886695e12f8SBenny Halevy static __be32 3887b37ad28bSAl Viro nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) 38881da177e4SLinus Torvalds { 3889d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3890bc749ca4SJ. Bruce Fields __be32 *p; 38911da177e4SLinus Torvalds 38921da177e4SLinus Torvalds if (!nfserr) { 3893d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8 + NFS4_VERIFIER_SIZE); 3894d0a381ddSJ. Bruce Fields if (!p) 3895d0a381ddSJ. Bruce Fields return nfserr_resource; 38960c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &scd->se_clientid, 8); 38970c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &scd->se_confirm, 38980c0c267bSJ. Bruce Fields NFS4_VERIFIER_SIZE); 38991da177e4SLinus Torvalds } 39001da177e4SLinus Torvalds else if (nfserr == nfserr_clid_inuse) { 3901d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 3902d0a381ddSJ. Bruce Fields if (!p) 3903d0a381ddSJ. Bruce Fields return nfserr_resource; 3904c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 3905c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); 39061da177e4SLinus Torvalds } 3907695e12f8SBenny Halevy return nfserr; 39081da177e4SLinus Torvalds } 39091da177e4SLinus Torvalds 3910695e12f8SBenny Halevy static __be32 3911b37ad28bSAl Viro nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) 39121da177e4SLinus Torvalds { 3913d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3914bc749ca4SJ. Bruce Fields __be32 *p; 39151da177e4SLinus Torvalds 39161da177e4SLinus Torvalds if (!nfserr) { 3917d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 16); 3918d0a381ddSJ. Bruce Fields if (!p) 3919d0a381ddSJ. Bruce Fields return nfserr_resource; 3920c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(write->wr_bytes_written); 3921c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(write->wr_how_written); 39220c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, write->wr_verifier.data, 39230c0c267bSJ. Bruce Fields NFS4_VERIFIER_SIZE); 39241da177e4SLinus Torvalds } 3925695e12f8SBenny Halevy return nfserr; 39261da177e4SLinus Torvalds } 39271da177e4SLinus Torvalds 3928695e12f8SBenny Halevy static __be32 392957b7b43bSJ. Bruce Fields nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, 39302db134ebSAndy Adamson struct nfsd4_exchange_id *exid) 39312db134ebSAndy Adamson { 3932d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3933bc749ca4SJ. Bruce Fields __be32 *p; 39340733d213SAndy Adamson char *major_id; 39350733d213SAndy Adamson char *server_scope; 39360733d213SAndy Adamson int major_id_sz; 39370733d213SAndy Adamson int server_scope_sz; 3938ed941643SAndrew Elble int status = 0; 39390733d213SAndy Adamson uint64_t minor_id = 0; 39400733d213SAndy Adamson 39410733d213SAndy Adamson if (nfserr) 39422db134ebSAndy Adamson return nfserr; 39430733d213SAndy Adamson 39440733d213SAndy Adamson major_id = utsname()->nodename; 39450733d213SAndy Adamson major_id_sz = strlen(major_id); 39460733d213SAndy Adamson server_scope = utsname()->nodename; 39470733d213SAndy Adamson server_scope_sz = strlen(server_scope); 39480733d213SAndy Adamson 3949d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 39500733d213SAndy Adamson 8 /* eir_clientid */ + 39510733d213SAndy Adamson 4 /* eir_sequenceid */ + 39520733d213SAndy Adamson 4 /* eir_flags */ + 3953a8bb84bcSKinglong Mee 4 /* spr_how */); 3954d0a381ddSJ. Bruce Fields if (!p) 3955d0a381ddSJ. Bruce Fields return nfserr_resource; 39560733d213SAndy Adamson 39570c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, &exid->clientid, 8); 3958c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(exid->seqid); 3959c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(exid->flags); 39600733d213SAndy Adamson 3961c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(exid->spa_how); 3962a8bb84bcSKinglong Mee 396357266a6eSJ. Bruce Fields switch (exid->spa_how) { 396457266a6eSJ. Bruce Fields case SP4_NONE: 396557266a6eSJ. Bruce Fields break; 396657266a6eSJ. Bruce Fields case SP4_MACH_CRED: 396757266a6eSJ. Bruce Fields /* spo_must_enforce bitmap: */ 3968ed941643SAndrew Elble status = nfsd4_encode_bitmap(xdr, 3969ed941643SAndrew Elble exid->spo_must_enforce[0], 3970ed941643SAndrew Elble exid->spo_must_enforce[1], 3971ed941643SAndrew Elble exid->spo_must_enforce[2]); 3972ed941643SAndrew Elble if (status) 3973ed941643SAndrew Elble goto out; 3974ed941643SAndrew Elble /* spo_must_allow bitmap: */ 3975ed941643SAndrew Elble status = nfsd4_encode_bitmap(xdr, 3976ed941643SAndrew Elble exid->spo_must_allow[0], 3977ed941643SAndrew Elble exid->spo_must_allow[1], 3978ed941643SAndrew Elble exid->spo_must_allow[2]); 3979ed941643SAndrew Elble if (status) 3980ed941643SAndrew Elble goto out; 398157266a6eSJ. Bruce Fields break; 398257266a6eSJ. Bruce Fields default: 398357266a6eSJ. Bruce Fields WARN_ON_ONCE(1); 398457266a6eSJ. Bruce Fields } 39850733d213SAndy Adamson 3986d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 3987a8bb84bcSKinglong Mee 8 /* so_minor_id */ + 3988a8bb84bcSKinglong Mee 4 /* so_major_id.len */ + 3989a8bb84bcSKinglong Mee (XDR_QUADLEN(major_id_sz) * 4) + 3990a8bb84bcSKinglong Mee 4 /* eir_server_scope.len */ + 3991a8bb84bcSKinglong Mee (XDR_QUADLEN(server_scope_sz) * 4) + 3992a8bb84bcSKinglong Mee 4 /* eir_server_impl_id.count (0) */); 3993d0a381ddSJ. Bruce Fields if (!p) 3994d0a381ddSJ. Bruce Fields return nfserr_resource; 3995a8bb84bcSKinglong Mee 39960733d213SAndy Adamson /* The server_owner struct */ 3997b64c7f3bSJ. Bruce Fields p = xdr_encode_hyper(p, minor_id); /* Minor id */ 39980733d213SAndy Adamson /* major id */ 39990c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, major_id, major_id_sz); 40000733d213SAndy Adamson 40010733d213SAndy Adamson /* Server scope */ 40020c0c267bSJ. Bruce Fields p = xdr_encode_opaque(p, server_scope, server_scope_sz); 40030733d213SAndy Adamson 40040733d213SAndy Adamson /* Implementation id */ 4005c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* zero length nfs_impl_id4 array */ 40060733d213SAndy Adamson return 0; 4007ed941643SAndrew Elble out: 4008ed941643SAndrew Elble return status; 40092db134ebSAndy Adamson } 40102db134ebSAndy Adamson 40112db134ebSAndy Adamson static __be32 401257b7b43bSJ. Bruce Fields nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, 40132db134ebSAndy Adamson struct nfsd4_create_session *sess) 40142db134ebSAndy Adamson { 4015d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 4016bc749ca4SJ. Bruce Fields __be32 *p; 4017ec6b5d7bSAndy Adamson 4018ec6b5d7bSAndy Adamson if (nfserr) 40192db134ebSAndy Adamson return nfserr; 4020ec6b5d7bSAndy Adamson 4021d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 24); 4022d0a381ddSJ. Bruce Fields if (!p) 4023d0a381ddSJ. Bruce Fields return nfserr_resource; 40240c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, sess->sessionid.data, 40250c0c267bSJ. Bruce Fields NFS4_MAX_SESSIONID_LEN); 4026c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->seqid); 4027c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->flags); 4028ec6b5d7bSAndy Adamson 4029d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 28); 4030d0a381ddSJ. Bruce Fields if (!p) 4031d0a381ddSJ. Bruce Fields return nfserr_resource; 4032c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* headerpadsz */ 4033c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxreq_sz); 4034c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxresp_sz); 4035c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxresp_cached); 4036c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxops); 4037c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.maxreqs); 4038c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.nr_rdma_attrs); 4039ec6b5d7bSAndy Adamson 4040ec6b5d7bSAndy Adamson if (sess->fore_channel.nr_rdma_attrs) { 4041d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 4042d0a381ddSJ. Bruce Fields if (!p) 4043d0a381ddSJ. Bruce Fields return nfserr_resource; 4044c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->fore_channel.rdma_attrs); 4045ec6b5d7bSAndy Adamson } 4046ec6b5d7bSAndy Adamson 4047d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 28); 4048d0a381ddSJ. Bruce Fields if (!p) 4049d0a381ddSJ. Bruce Fields return nfserr_resource; 4050c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(0); /* headerpadsz */ 4051c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxreq_sz); 4052c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxresp_sz); 4053c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxresp_cached); 4054c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxops); 4055c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.maxreqs); 4056c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.nr_rdma_attrs); 4057ec6b5d7bSAndy Adamson 4058ec6b5d7bSAndy Adamson if (sess->back_channel.nr_rdma_attrs) { 4059d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4); 4060d0a381ddSJ. Bruce Fields if (!p) 4061d0a381ddSJ. Bruce Fields return nfserr_resource; 4062c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(sess->back_channel.rdma_attrs); 4063ec6b5d7bSAndy Adamson } 4064ec6b5d7bSAndy Adamson return 0; 40652db134ebSAndy Adamson } 40662db134ebSAndy Adamson 40672db134ebSAndy Adamson static __be32 406857b7b43bSJ. Bruce Fields nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, 40692db134ebSAndy Adamson struct nfsd4_sequence *seq) 40702db134ebSAndy Adamson { 4071d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 4072bc749ca4SJ. Bruce Fields __be32 *p; 4073b85d4c01SBenny Halevy 4074b85d4c01SBenny Halevy if (nfserr) 40752db134ebSAndy Adamson return nfserr; 4076b85d4c01SBenny Halevy 4077d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20); 4078d0a381ddSJ. Bruce Fields if (!p) 4079d0a381ddSJ. Bruce Fields return nfserr_resource; 40800c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, seq->sessionid.data, 40810c0c267bSJ. Bruce Fields NFS4_MAX_SESSIONID_LEN); 4082c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->seqid); 4083c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->slotid); 4084b7d7ca35SJ. Bruce Fields /* Note slotid's are numbered from zero: */ 4085c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_highest_slotid */ 4086c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_target_highest_slotid */ 4087c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(seq->status_flags); 4088b85d4c01SBenny Halevy 4089f5236013SJ. Bruce Fields resp->cstate.data_offset = xdr->buf->len; /* DRC cache data pointer */ 4090b85d4c01SBenny Halevy return 0; 40912db134ebSAndy Adamson } 40922db134ebSAndy Adamson 40932355c596SJ. Bruce Fields static __be32 409457b7b43bSJ. Bruce Fields nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, 409517456804SBryan Schumaker struct nfsd4_test_stateid *test_stateid) 409617456804SBryan Schumaker { 4097d0a381ddSJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 409803cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid, *next; 409917456804SBryan Schumaker __be32 *p; 410017456804SBryan Schumaker 4101a11fcce1SJ. Bruce Fields if (nfserr) 4102a11fcce1SJ. Bruce Fields return nfserr; 4103a11fcce1SJ. Bruce Fields 4104d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 4 + (4 * test_stateid->ts_num_ids)); 4105d0a381ddSJ. Bruce Fields if (!p) 4106d0a381ddSJ. Bruce Fields return nfserr_resource; 410717456804SBryan Schumaker *p++ = htonl(test_stateid->ts_num_ids); 410817456804SBryan Schumaker 410903cfb420SBryan Schumaker list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) { 411002f5fde5SAl Viro *p++ = stateid->ts_id_status; 411117456804SBryan Schumaker } 411217456804SBryan Schumaker 411317456804SBryan Schumaker return nfserr; 411417456804SBryan Schumaker } 411517456804SBryan Schumaker 41169cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 41179cf514ccSChristoph Hellwig static __be32 41189cf514ccSChristoph Hellwig nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, 41199cf514ccSChristoph Hellwig struct nfsd4_getdeviceinfo *gdev) 41209cf514ccSChristoph Hellwig { 41219cf514ccSChristoph Hellwig struct xdr_stream *xdr = &resp->xdr; 4122*f961e3f2SJ. Bruce Fields const struct nfsd4_layout_ops *ops; 41239cf514ccSChristoph Hellwig u32 starting_len = xdr->buf->len, needed_len; 41249cf514ccSChristoph Hellwig __be32 *p; 41259cf514ccSChristoph Hellwig 4126bec782b4SJeff Layton dprintk("%s: err %d\n", __func__, be32_to_cpu(nfserr)); 41279cf514ccSChristoph Hellwig if (nfserr) 41289cf514ccSChristoph Hellwig goto out; 41299cf514ccSChristoph Hellwig 41309cf514ccSChristoph Hellwig nfserr = nfserr_resource; 41319cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 41329cf514ccSChristoph Hellwig if (!p) 41339cf514ccSChristoph Hellwig goto out; 41349cf514ccSChristoph Hellwig 41359cf514ccSChristoph Hellwig *p++ = cpu_to_be32(gdev->gd_layout_type); 41369cf514ccSChristoph Hellwig 41379cf514ccSChristoph Hellwig /* If maxcount is 0 then just update notifications */ 41389cf514ccSChristoph Hellwig if (gdev->gd_maxcount != 0) { 4139*f961e3f2SJ. Bruce Fields ops = nfsd4_layout_ops[gdev->gd_layout_type]; 41409cf514ccSChristoph Hellwig nfserr = ops->encode_getdeviceinfo(xdr, gdev); 41419cf514ccSChristoph Hellwig if (nfserr) { 41429cf514ccSChristoph Hellwig /* 41439cf514ccSChristoph Hellwig * We don't bother to burden the layout drivers with 41449cf514ccSChristoph Hellwig * enforcing gd_maxcount, just tell the client to 41459cf514ccSChristoph Hellwig * come back with a bigger buffer if it's not enough. 41469cf514ccSChristoph Hellwig */ 41479cf514ccSChristoph Hellwig if (xdr->buf->len + 4 > gdev->gd_maxcount) 41489cf514ccSChristoph Hellwig goto toosmall; 41499cf514ccSChristoph Hellwig goto out; 41509cf514ccSChristoph Hellwig } 41519cf514ccSChristoph Hellwig } 41529cf514ccSChristoph Hellwig 41539cf514ccSChristoph Hellwig nfserr = nfserr_resource; 41549cf514ccSChristoph Hellwig if (gdev->gd_notify_types) { 41559cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4 + 4); 41569cf514ccSChristoph Hellwig if (!p) 41579cf514ccSChristoph Hellwig goto out; 41589cf514ccSChristoph Hellwig *p++ = cpu_to_be32(1); /* bitmap length */ 41599cf514ccSChristoph Hellwig *p++ = cpu_to_be32(gdev->gd_notify_types); 41609cf514ccSChristoph Hellwig } else { 41619cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 41629cf514ccSChristoph Hellwig if (!p) 41639cf514ccSChristoph Hellwig goto out; 41649cf514ccSChristoph Hellwig *p++ = 0; 41659cf514ccSChristoph Hellwig } 41669cf514ccSChristoph Hellwig 41679cf514ccSChristoph Hellwig nfserr = 0; 41689cf514ccSChristoph Hellwig out: 41699cf514ccSChristoph Hellwig kfree(gdev->gd_device); 41709cf514ccSChristoph Hellwig dprintk("%s: done: %d\n", __func__, be32_to_cpu(nfserr)); 41719cf514ccSChristoph Hellwig return nfserr; 41729cf514ccSChristoph Hellwig 41739cf514ccSChristoph Hellwig toosmall: 41749cf514ccSChristoph Hellwig dprintk("%s: maxcount too small\n", __func__); 41759cf514ccSChristoph Hellwig needed_len = xdr->buf->len + 4 /* notifications */; 41769cf514ccSChristoph Hellwig xdr_truncate_encode(xdr, starting_len); 41779cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 41789cf514ccSChristoph Hellwig if (!p) { 41799cf514ccSChristoph Hellwig nfserr = nfserr_resource; 41809cf514ccSChristoph Hellwig } else { 41819cf514ccSChristoph Hellwig *p++ = cpu_to_be32(needed_len); 41829cf514ccSChristoph Hellwig nfserr = nfserr_toosmall; 41839cf514ccSChristoph Hellwig } 41849cf514ccSChristoph Hellwig goto out; 41859cf514ccSChristoph Hellwig } 41869cf514ccSChristoph Hellwig 41879cf514ccSChristoph Hellwig static __be32 41889cf514ccSChristoph Hellwig nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr, 41899cf514ccSChristoph Hellwig struct nfsd4_layoutget *lgp) 41909cf514ccSChristoph Hellwig { 41919cf514ccSChristoph Hellwig struct xdr_stream *xdr = &resp->xdr; 4192*f961e3f2SJ. Bruce Fields const struct nfsd4_layout_ops *ops; 41939cf514ccSChristoph Hellwig __be32 *p; 41949cf514ccSChristoph Hellwig 41959cf514ccSChristoph Hellwig dprintk("%s: err %d\n", __func__, nfserr); 41969cf514ccSChristoph Hellwig if (nfserr) 41979cf514ccSChristoph Hellwig goto out; 41989cf514ccSChristoph Hellwig 41999cf514ccSChristoph Hellwig nfserr = nfserr_resource; 42009cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 36 + sizeof(stateid_opaque_t)); 42019cf514ccSChristoph Hellwig if (!p) 42029cf514ccSChristoph Hellwig goto out; 42039cf514ccSChristoph Hellwig 42049cf514ccSChristoph Hellwig *p++ = cpu_to_be32(1); /* we always set return-on-close */ 42059cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lgp->lg_sid.si_generation); 42069cf514ccSChristoph Hellwig p = xdr_encode_opaque_fixed(p, &lgp->lg_sid.si_opaque, 42079cf514ccSChristoph Hellwig sizeof(stateid_opaque_t)); 42089cf514ccSChristoph Hellwig 42099cf514ccSChristoph Hellwig *p++ = cpu_to_be32(1); /* we always return a single layout */ 42109cf514ccSChristoph Hellwig p = xdr_encode_hyper(p, lgp->lg_seg.offset); 42119cf514ccSChristoph Hellwig p = xdr_encode_hyper(p, lgp->lg_seg.length); 42129cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lgp->lg_seg.iomode); 42139cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lgp->lg_layout_type); 42149cf514ccSChristoph Hellwig 4215*f961e3f2SJ. Bruce Fields ops = nfsd4_layout_ops[lgp->lg_layout_type]; 42169cf514ccSChristoph Hellwig nfserr = ops->encode_layoutget(xdr, lgp); 42179cf514ccSChristoph Hellwig out: 42189cf514ccSChristoph Hellwig kfree(lgp->lg_content); 42199cf514ccSChristoph Hellwig return nfserr; 42209cf514ccSChristoph Hellwig } 42219cf514ccSChristoph Hellwig 42229cf514ccSChristoph Hellwig static __be32 42239cf514ccSChristoph Hellwig nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr, 42249cf514ccSChristoph Hellwig struct nfsd4_layoutcommit *lcp) 42259cf514ccSChristoph Hellwig { 42269cf514ccSChristoph Hellwig struct xdr_stream *xdr = &resp->xdr; 42279cf514ccSChristoph Hellwig __be32 *p; 42289cf514ccSChristoph Hellwig 42299cf514ccSChristoph Hellwig if (nfserr) 42309cf514ccSChristoph Hellwig return nfserr; 42319cf514ccSChristoph Hellwig 42329cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 42339cf514ccSChristoph Hellwig if (!p) 42349cf514ccSChristoph Hellwig return nfserr_resource; 42359cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lcp->lc_size_chg); 42369cf514ccSChristoph Hellwig if (lcp->lc_size_chg) { 42379cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 8); 42389cf514ccSChristoph Hellwig if (!p) 42399cf514ccSChristoph Hellwig return nfserr_resource; 42409cf514ccSChristoph Hellwig p = xdr_encode_hyper(p, lcp->lc_newsize); 42419cf514ccSChristoph Hellwig } 42429cf514ccSChristoph Hellwig 42439cf514ccSChristoph Hellwig return nfs_ok; 42449cf514ccSChristoph Hellwig } 42459cf514ccSChristoph Hellwig 42469cf514ccSChristoph Hellwig static __be32 42479cf514ccSChristoph Hellwig nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, 42489cf514ccSChristoph Hellwig struct nfsd4_layoutreturn *lrp) 42499cf514ccSChristoph Hellwig { 42509cf514ccSChristoph Hellwig struct xdr_stream *xdr = &resp->xdr; 42519cf514ccSChristoph Hellwig __be32 *p; 42529cf514ccSChristoph Hellwig 42539cf514ccSChristoph Hellwig if (nfserr) 42549cf514ccSChristoph Hellwig return nfserr; 42559cf514ccSChristoph Hellwig 42569cf514ccSChristoph Hellwig p = xdr_reserve_space(xdr, 4); 42579cf514ccSChristoph Hellwig if (!p) 42589cf514ccSChristoph Hellwig return nfserr_resource; 42599cf514ccSChristoph Hellwig *p++ = cpu_to_be32(lrp->lrs_present); 42609cf514ccSChristoph Hellwig if (lrp->lrs_present) 4261376675daSKinglong Mee return nfsd4_encode_stateid(xdr, &lrp->lr_sid); 42629cf514ccSChristoph Hellwig return nfs_ok; 42639cf514ccSChristoph Hellwig } 42649cf514ccSChristoph Hellwig #endif /* CONFIG_NFSD_PNFS */ 42659cf514ccSChristoph Hellwig 42662db134ebSAndy Adamson static __be32 426729ae7f9dSAnna Schumaker nfsd42_encode_write_res(struct nfsd4_compoundres *resp, struct nfsd42_write_res *write) 426829ae7f9dSAnna Schumaker { 426929ae7f9dSAnna Schumaker __be32 *p; 427029ae7f9dSAnna Schumaker 427129ae7f9dSAnna Schumaker p = xdr_reserve_space(&resp->xdr, 4 + 8 + 4 + NFS4_VERIFIER_SIZE); 427229ae7f9dSAnna Schumaker if (!p) 427329ae7f9dSAnna Schumaker return nfserr_resource; 427429ae7f9dSAnna Schumaker 427529ae7f9dSAnna Schumaker *p++ = cpu_to_be32(0); 427629ae7f9dSAnna Schumaker p = xdr_encode_hyper(p, write->wr_bytes_written); 427729ae7f9dSAnna Schumaker *p++ = cpu_to_be32(write->wr_stable_how); 427829ae7f9dSAnna Schumaker p = xdr_encode_opaque_fixed(p, write->wr_verifier.data, 427929ae7f9dSAnna Schumaker NFS4_VERIFIER_SIZE); 428029ae7f9dSAnna Schumaker return nfs_ok; 428129ae7f9dSAnna Schumaker } 428229ae7f9dSAnna Schumaker 428329ae7f9dSAnna Schumaker static __be32 428429ae7f9dSAnna Schumaker nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, 428529ae7f9dSAnna Schumaker struct nfsd4_copy *copy) 428629ae7f9dSAnna Schumaker { 428729ae7f9dSAnna Schumaker __be32 *p; 428829ae7f9dSAnna Schumaker 428929ae7f9dSAnna Schumaker if (!nfserr) { 429029ae7f9dSAnna Schumaker nfserr = nfsd42_encode_write_res(resp, ©->cp_res); 429129ae7f9dSAnna Schumaker if (nfserr) 429229ae7f9dSAnna Schumaker return nfserr; 429329ae7f9dSAnna Schumaker 429429ae7f9dSAnna Schumaker p = xdr_reserve_space(&resp->xdr, 4 + 4); 429529ae7f9dSAnna Schumaker *p++ = cpu_to_be32(copy->cp_consecutive); 429629ae7f9dSAnna Schumaker *p++ = cpu_to_be32(copy->cp_synchronous); 429729ae7f9dSAnna Schumaker } 429829ae7f9dSAnna Schumaker return nfserr; 429929ae7f9dSAnna Schumaker } 430029ae7f9dSAnna Schumaker 430129ae7f9dSAnna Schumaker static __be32 430224bab491SAnna Schumaker nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, 430324bab491SAnna Schumaker struct nfsd4_seek *seek) 430424bab491SAnna Schumaker { 430524bab491SAnna Schumaker __be32 *p; 430624bab491SAnna Schumaker 430724bab491SAnna Schumaker if (nfserr) 430824bab491SAnna Schumaker return nfserr; 430924bab491SAnna Schumaker 431024bab491SAnna Schumaker p = xdr_reserve_space(&resp->xdr, 4 + 8); 431124bab491SAnna Schumaker *p++ = cpu_to_be32(seek->seek_eof); 431224bab491SAnna Schumaker p = xdr_encode_hyper(p, seek->seek_pos); 431324bab491SAnna Schumaker 431424bab491SAnna Schumaker return nfserr; 431524bab491SAnna Schumaker } 431624bab491SAnna Schumaker 431724bab491SAnna Schumaker static __be32 4318695e12f8SBenny Halevy nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) 4319695e12f8SBenny Halevy { 4320695e12f8SBenny Halevy return nfserr; 4321695e12f8SBenny Halevy } 4322695e12f8SBenny Halevy 4323695e12f8SBenny Halevy typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *); 4324695e12f8SBenny Halevy 43252db134ebSAndy Adamson /* 43262db134ebSAndy Adamson * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1 43272db134ebSAndy Adamson * since we don't need to filter out obsolete ops as this is 43282db134ebSAndy Adamson * done in the decoding phase. 43292db134ebSAndy Adamson */ 4330695e12f8SBenny Halevy static nfsd4_enc nfsd4_enc_ops[] = { 4331ad1060c8SJ. Bruce Fields [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access, 4332ad1060c8SJ. Bruce Fields [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close, 4333ad1060c8SJ. Bruce Fields [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit, 4334ad1060c8SJ. Bruce Fields [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create, 4335ad1060c8SJ. Bruce Fields [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop, 4336ad1060c8SJ. Bruce Fields [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop, 4337ad1060c8SJ. Bruce Fields [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr, 4338ad1060c8SJ. Bruce Fields [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh, 4339ad1060c8SJ. Bruce Fields [OP_LINK] = (nfsd4_enc)nfsd4_encode_link, 4340ad1060c8SJ. Bruce Fields [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock, 4341ad1060c8SJ. Bruce Fields [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt, 4342ad1060c8SJ. Bruce Fields [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku, 4343ad1060c8SJ. Bruce Fields [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop, 4344ad1060c8SJ. Bruce Fields [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop, 4345ad1060c8SJ. Bruce Fields [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop, 4346ad1060c8SJ. Bruce Fields [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open, 434784f09f46SBenny Halevy [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop, 4348ad1060c8SJ. Bruce Fields [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm, 4349ad1060c8SJ. Bruce Fields [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade, 4350ad1060c8SJ. Bruce Fields [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop, 4351ad1060c8SJ. Bruce Fields [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop, 4352ad1060c8SJ. Bruce Fields [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop, 4353ad1060c8SJ. Bruce Fields [OP_READ] = (nfsd4_enc)nfsd4_encode_read, 4354ad1060c8SJ. Bruce Fields [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir, 4355ad1060c8SJ. Bruce Fields [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink, 4356ad1060c8SJ. Bruce Fields [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove, 4357ad1060c8SJ. Bruce Fields [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename, 4358ad1060c8SJ. Bruce Fields [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop, 4359ad1060c8SJ. Bruce Fields [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop, 4360ad1060c8SJ. Bruce Fields [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop, 4361ad1060c8SJ. Bruce Fields [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo, 4362ad1060c8SJ. Bruce Fields [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr, 4363ad1060c8SJ. Bruce Fields [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid, 4364ad1060c8SJ. Bruce Fields [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop, 4365ad1060c8SJ. Bruce Fields [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop, 4366ad1060c8SJ. Bruce Fields [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write, 4367ad1060c8SJ. Bruce Fields [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop, 43682db134ebSAndy Adamson 43692db134ebSAndy Adamson /* NFSv4.1 operations */ 43702db134ebSAndy Adamson [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop, 43711d1bc8f2SJ. Bruce Fields [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session, 43722db134ebSAndy Adamson [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, 43732db134ebSAndy Adamson [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, 437443212cc7SKinglong Mee [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop, 437543212cc7SKinglong Mee [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, 43762db134ebSAndy Adamson [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 43779cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 43789cf514ccSChristoph Hellwig [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_getdeviceinfo, 43799cf514ccSChristoph Hellwig [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, 43809cf514ccSChristoph Hellwig [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_layoutcommit, 43819cf514ccSChristoph Hellwig [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_layoutget, 43829cf514ccSChristoph Hellwig [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_layoutreturn, 43839cf514ccSChristoph Hellwig #else 43842db134ebSAndy Adamson [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, 43852db134ebSAndy Adamson [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, 43862db134ebSAndy Adamson [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, 43872db134ebSAndy Adamson [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, 43882db134ebSAndy Adamson [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, 43899cf514ccSChristoph Hellwig #endif 439022b6dee8SMi Jinlong [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name, 43912db134ebSAndy Adamson [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, 43922db134ebSAndy Adamson [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, 439317456804SBryan Schumaker [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid, 43942db134ebSAndy Adamson [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 43952db134ebSAndy Adamson [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop, 43962db134ebSAndy Adamson [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop, 439787a15a80SAnna Schumaker 439887a15a80SAnna Schumaker /* NFSv4.2 operations */ 439987a15a80SAnna Schumaker [OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop, 440029ae7f9dSAnna Schumaker [OP_COPY] = (nfsd4_enc)nfsd4_encode_copy, 440187a15a80SAnna Schumaker [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_noop, 440287a15a80SAnna Schumaker [OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop, 440387a15a80SAnna Schumaker [OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop, 440487a15a80SAnna Schumaker [OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop, 440587a15a80SAnna Schumaker [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop, 440687a15a80SAnna Schumaker [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop, 440787a15a80SAnna Schumaker [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_noop, 440887a15a80SAnna Schumaker [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop, 440924bab491SAnna Schumaker [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek, 441087a15a80SAnna Schumaker [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop, 4411ffa0160aSChristoph Hellwig [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop, 4412695e12f8SBenny Halevy }; 4413695e12f8SBenny Halevy 4414496c262cSAndy Adamson /* 4415a8095f7eSJ. Bruce Fields * Calculate whether we still have space to encode repsize bytes. 4416a8095f7eSJ. Bruce Fields * There are two considerations: 4417a8095f7eSJ. Bruce Fields * - For NFS versions >=4.1, the size of the reply must stay within 4418a8095f7eSJ. Bruce Fields * session limits 4419a8095f7eSJ. Bruce Fields * - For all NFS versions, we must stay within limited preallocated 4420a8095f7eSJ. Bruce Fields * buffer space. 4421496c262cSAndy Adamson * 4422a8095f7eSJ. Bruce Fields * This is called before the operation is processed, so can only provide 4423a8095f7eSJ. Bruce Fields * an upper estimate. For some nonidempotent operations (such as 4424a8095f7eSJ. Bruce Fields * getattr), it's not necessarily a problem if that estimate is wrong, 4425a8095f7eSJ. Bruce Fields * as we can fail it after processing without significant side effects. 4426496c262cSAndy Adamson */ 4427a8095f7eSJ. Bruce Fields __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize) 4428496c262cSAndy Adamson { 442967492c99SJ. Bruce Fields struct xdr_buf *buf = &resp->rqstp->rq_res; 4430a8095f7eSJ. Bruce Fields struct nfsd4_slot *slot = resp->cstate.slot; 4431496c262cSAndy Adamson 443247ee5298SJ. Bruce Fields if (buf->len + respsize <= buf->buflen) 443347ee5298SJ. Bruce Fields return nfs_ok; 443447ee5298SJ. Bruce Fields if (!nfsd4_has_session(&resp->cstate)) 443547ee5298SJ. Bruce Fields return nfserr_resource; 443647ee5298SJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) { 443747ee5298SJ. Bruce Fields WARN_ON_ONCE(1); 4438496c262cSAndy Adamson return nfserr_rep_too_big_to_cache; 4439ea8d7720SJ. Bruce Fields } 444047ee5298SJ. Bruce Fields return nfserr_rep_too_big; 4441496c262cSAndy Adamson } 4442496c262cSAndy Adamson 44431da177e4SLinus Torvalds void 44441da177e4SLinus Torvalds nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 44451da177e4SLinus Torvalds { 4446082d4bd7SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 44479411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = resp->cstate.replay_owner; 44485f4ab945SJ. Bruce Fields struct svc_rqst *rqstp = resp->rqstp; 4449082d4bd7SJ. Bruce Fields int post_err_offset; 445007d1f802SJ. Bruce Fields nfsd4_enc encoder; 4451bc749ca4SJ. Bruce Fields __be32 *p; 44521da177e4SLinus Torvalds 4453d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8); 4454d0a381ddSJ. Bruce Fields if (!p) { 4455d0a381ddSJ. Bruce Fields WARN_ON_ONCE(1); 4456d0a381ddSJ. Bruce Fields return; 4457d0a381ddSJ. Bruce Fields } 4458c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(op->opnum); 4459082d4bd7SJ. Bruce Fields post_err_offset = xdr->buf->len; 44601da177e4SLinus Torvalds 4461695e12f8SBenny Halevy if (op->opnum == OP_ILLEGAL) 4462695e12f8SBenny Halevy goto status; 4463695e12f8SBenny Halevy BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || 4464695e12f8SBenny Halevy !nfsd4_enc_ops[op->opnum]); 446507d1f802SJ. Bruce Fields encoder = nfsd4_enc_ops[op->opnum]; 446607d1f802SJ. Bruce Fields op->status = encoder(resp, op->status, &op->u); 44672825a7f9SJ. Bruce Fields xdr_commit_encode(xdr); 44682825a7f9SJ. Bruce Fields 4469067e1aceSJ. Bruce Fields /* nfsd4_check_resp_size guarantees enough room for error status */ 44705f4ab945SJ. Bruce Fields if (!op->status) { 44715f4ab945SJ. Bruce Fields int space_needed = 0; 44725f4ab945SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 44735f4ab945SJ. Bruce Fields space_needed = COMPOUND_ERR_SLACK_SPACE; 44745f4ab945SJ. Bruce Fields op->status = nfsd4_check_resp_size(resp, space_needed); 44755f4ab945SJ. Bruce Fields } 4476c8f13d97SJ. Bruce Fields if (op->status == nfserr_resource && nfsd4_has_session(&resp->cstate)) { 4477c8f13d97SJ. Bruce Fields struct nfsd4_slot *slot = resp->cstate.slot; 4478c8f13d97SJ. Bruce Fields 4479c8f13d97SJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) 4480c8f13d97SJ. Bruce Fields op->status = nfserr_rep_too_big_to_cache; 4481c8f13d97SJ. Bruce Fields else 4482c8f13d97SJ. Bruce Fields op->status = nfserr_rep_too_big; 4483c8f13d97SJ. Bruce Fields } 448407d1f802SJ. Bruce Fields if (op->status == nfserr_resource || 448507d1f802SJ. Bruce Fields op->status == nfserr_rep_too_big || 448607d1f802SJ. Bruce Fields op->status == nfserr_rep_too_big_to_cache) { 448707d1f802SJ. Bruce Fields /* 448807d1f802SJ. Bruce Fields * The operation may have already been encoded or 448907d1f802SJ. Bruce Fields * partially encoded. No op returns anything additional 449007d1f802SJ. Bruce Fields * in the case of one of these three errors, so we can 449107d1f802SJ. Bruce Fields * just truncate back to after the status. But it's a 449207d1f802SJ. Bruce Fields * bug if we had to do this on a non-idempotent op: 449307d1f802SJ. Bruce Fields */ 449407d1f802SJ. Bruce Fields warn_on_nonidempotent_op(op); 4495082d4bd7SJ. Bruce Fields xdr_truncate_encode(xdr, post_err_offset); 449607d1f802SJ. Bruce Fields } 44979411b1d4SJ. Bruce Fields if (so) { 4498082d4bd7SJ. Bruce Fields int len = xdr->buf->len - post_err_offset; 4499082d4bd7SJ. Bruce Fields 45009411b1d4SJ. Bruce Fields so->so_replay.rp_status = op->status; 4501082d4bd7SJ. Bruce Fields so->so_replay.rp_buflen = len; 4502082d4bd7SJ. Bruce Fields read_bytes_from_xdr_buf(xdr->buf, post_err_offset, 4503082d4bd7SJ. Bruce Fields so->so_replay.rp_buf, len); 45049411b1d4SJ. Bruce Fields } 4505695e12f8SBenny Halevy status: 4506082d4bd7SJ. Bruce Fields /* Note that op->status is already in network byte order: */ 4507082d4bd7SJ. Bruce Fields write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4); 45081da177e4SLinus Torvalds } 45091da177e4SLinus Torvalds 45101da177e4SLinus Torvalds /* 45111da177e4SLinus Torvalds * Encode the reply stored in the stateowner reply cache 45121da177e4SLinus Torvalds * 45131da177e4SLinus Torvalds * XDR note: do not encode rp->rp_buflen: the buffer contains the 45141da177e4SLinus Torvalds * previously sent already encoded operation. 45151da177e4SLinus Torvalds */ 45161da177e4SLinus Torvalds void 4517d0a381ddSJ. Bruce Fields nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op) 45181da177e4SLinus Torvalds { 4519bc749ca4SJ. Bruce Fields __be32 *p; 45201da177e4SLinus Torvalds struct nfs4_replay *rp = op->replay; 45211da177e4SLinus Torvalds 45221da177e4SLinus Torvalds BUG_ON(!rp); 45231da177e4SLinus Torvalds 4524d0a381ddSJ. Bruce Fields p = xdr_reserve_space(xdr, 8 + rp->rp_buflen); 4525d0a381ddSJ. Bruce Fields if (!p) { 4526d0a381ddSJ. Bruce Fields WARN_ON_ONCE(1); 4527d0a381ddSJ. Bruce Fields return; 4528d0a381ddSJ. Bruce Fields } 4529c373b0a4SJ. Bruce Fields *p++ = cpu_to_be32(op->opnum); 45301da177e4SLinus Torvalds *p++ = rp->rp_status; /* already xdr'ed */ 45311da177e4SLinus Torvalds 45320c0c267bSJ. Bruce Fields p = xdr_encode_opaque_fixed(p, rp->rp_buf, rp->rp_buflen); 45331da177e4SLinus Torvalds } 45341da177e4SLinus Torvalds 45351da177e4SLinus Torvalds int 45362ebbc012SAl Viro nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) 45371da177e4SLinus Torvalds { 45381da177e4SLinus Torvalds return xdr_ressize_check(rqstp, p); 45391da177e4SLinus Torvalds } 45401da177e4SLinus Torvalds 45413e98abffSJ. Bruce Fields int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp) 45421da177e4SLinus Torvalds { 45433e98abffSJ. Bruce Fields struct svc_rqst *rqstp = rq; 45443e98abffSJ. Bruce Fields struct nfsd4_compoundargs *args = rqstp->rq_argp; 45453e98abffSJ. Bruce Fields 45461da177e4SLinus Torvalds if (args->ops != args->iops) { 45471da177e4SLinus Torvalds kfree(args->ops); 45481da177e4SLinus Torvalds args->ops = args->iops; 45491da177e4SLinus Torvalds } 45501da177e4SLinus Torvalds kfree(args->tmpp); 45511da177e4SLinus Torvalds args->tmpp = NULL; 45521da177e4SLinus Torvalds while (args->to_free) { 4553d5e23383SJ. Bruce Fields struct svcxdr_tmpbuf *tb = args->to_free; 45541da177e4SLinus Torvalds args->to_free = tb->next; 45551da177e4SLinus Torvalds kfree(tb); 45561da177e4SLinus Torvalds } 45573e98abffSJ. Bruce Fields return 1; 45581da177e4SLinus Torvalds } 45591da177e4SLinus Torvalds 45601da177e4SLinus Torvalds int 45612ebbc012SAl Viro nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) 45621da177e4SLinus Torvalds { 4563e874f9f8SJeff Layton if (rqstp->rq_arg.head[0].iov_len % 4) { 4564e874f9f8SJeff Layton /* client is nuts */ 4565e874f9f8SJeff Layton dprintk("%s: compound not properly padded! (peeraddr=%pISc xid=0x%x)", 4566e874f9f8SJeff Layton __func__, svc_addr(rqstp), be32_to_cpu(rqstp->rq_xid)); 4567e874f9f8SJeff Layton return 0; 4568e874f9f8SJeff Layton } 45691da177e4SLinus Torvalds args->p = p; 45701da177e4SLinus Torvalds args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; 45711da177e4SLinus Torvalds args->pagelist = rqstp->rq_arg.pages; 45721da177e4SLinus Torvalds args->pagelen = rqstp->rq_arg.page_len; 45731da177e4SLinus Torvalds args->tmpp = NULL; 45741da177e4SLinus Torvalds args->to_free = NULL; 45751da177e4SLinus Torvalds args->ops = args->iops; 45761da177e4SLinus Torvalds args->rqstp = rqstp; 45771da177e4SLinus Torvalds 45783e98abffSJ. Bruce Fields return !nfsd4_decode_compound(args); 45791da177e4SLinus Torvalds } 45801da177e4SLinus Torvalds 45811da177e4SLinus Torvalds int 45822ebbc012SAl Viro nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp) 45831da177e4SLinus Torvalds { 45841da177e4SLinus Torvalds /* 45851da177e4SLinus Torvalds * All that remains is to write the tag and operation count... 45861da177e4SLinus Torvalds */ 45876ac90391SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 45886ac90391SJ. Bruce Fields 45896ac90391SJ. Bruce Fields WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + 45906ac90391SJ. Bruce Fields buf->tail[0].iov_len); 4591dd97fddeSJ. Bruce Fields 45922825a7f9SJ. Bruce Fields rqstp->rq_next_page = resp->xdr.page_ptr + 1; 45932825a7f9SJ. Bruce Fields 45941da177e4SLinus Torvalds p = resp->tagp; 45951da177e4SLinus Torvalds *p++ = htonl(resp->taglen); 45961da177e4SLinus Torvalds memcpy(p, resp->tag, resp->taglen); 45971da177e4SLinus Torvalds p += XDR_QUADLEN(resp->taglen); 45981da177e4SLinus Torvalds *p++ = htonl(resp->opcnt); 45991da177e4SLinus Torvalds 4600b607664eSTrond Myklebust nfsd4_sequence_done(resp); 46011da177e4SLinus Torvalds return 1; 46021da177e4SLinus Torvalds } 46031da177e4SLinus Torvalds 46041da177e4SLinus Torvalds /* 46051da177e4SLinus Torvalds * Local variables: 46061da177e4SLinus Torvalds * c-basic-offset: 8 46071da177e4SLinus Torvalds * End: 46081da177e4SLinus Torvalds */ 4609