From owner-svn-src-stable@freebsd.org Fri Jul 14 20:47:43 2017 Return-Path: Delivered-To: svn-src-stable@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id A7FDBDAC08E; Fri, 14 Jul 2017 20:47:43 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6D010762B1; Fri, 14 Jul 2017 20:47:43 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v6EKlgwv070976; Fri, 14 Jul 2017 20:47:42 GMT (envelope-from rmacklem@FreeBSD.org) Received: (from rmacklem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v6EKlgWq070971; Fri, 14 Jul 2017 20:47:42 GMT (envelope-from rmacklem@FreeBSD.org) Message-Id: <201707142047.v6EKlgWq070971@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: rmacklem set sender to rmacklem@FreeBSD.org using -f From: Rick Macklem Date: Fri, 14 Jul 2017 20:47:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r320998 - in stable/11/sys/fs: nfs nfsclient X-SVN-Group: stable-11 X-SVN-Commit-Author: rmacklem X-SVN-Commit-Paths: in stable/11/sys/fs: nfs nfsclient X-SVN-Commit-Revision: 320998 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 14 Jul 2017 20:47:43 -0000 Author: rmacklem Date: Fri Jul 14 20:47:41 2017 New Revision: 320998 URL: https://svnweb.freebsd.org/changeset/base/320998 Log: MFC: r320322 Add two new compound RPCs to the NFSv4.1/pNFS client. When the NFSv4.1 client is doing pNFS, it needs to get an Open and a Layout for every file it will be doing I/O on. The current code does two separate RPCs to get these. This patch adds two new compounds that do the both the Open and LayoutGet in the same RPC, reducing the RPC count. It also factors out the code that sets up and parses the LayoutGet operation into separate functions, so that the code doesn't get duplicated for these new RPCs. This patch is fairly large, but should only affect the NFSv4.1 client when the "pnfs" option is specified. Modified: stable/11/sys/fs/nfs/nfs_commonsubs.c stable/11/sys/fs/nfs/nfsport.h stable/11/sys/fs/nfs/nfsproto.h stable/11/sys/fs/nfsclient/nfs_clcomsubs.c stable/11/sys/fs/nfsclient/nfs_clrpcops.c Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/fs/nfs/nfs_commonsubs.c ============================================================================== --- stable/11/sys/fs/nfs/nfs_commonsubs.c Fri Jul 14 18:36:15 2017 (r320997) +++ stable/11/sys/fs/nfs/nfs_commonsubs.c Fri Jul 14 20:47:41 2017 (r320998) @@ -175,7 +175,7 @@ static struct nfsrv_lughash *nfsgroupnamehash; */ int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; /* local functions */ static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); Modified: stable/11/sys/fs/nfs/nfsport.h ============================================================================== --- stable/11/sys/fs/nfs/nfsport.h Fri Jul 14 18:36:15 2017 (r320997) +++ stable/11/sys/fs/nfs/nfsport.h Fri Jul 14 20:47:41 2017 (r320998) @@ -357,11 +357,13 @@ #define NFSPROC_WRITEDS 51 #define NFSPROC_READDS 52 #define NFSPROC_COMMITDS 53 +#define NFSPROC_OPENLAYGET 54 +#define NFSPROC_CREATELAYGET 55 /* * Must be defined as one higher than the last NFSv4.1 Proc# above. */ -#define NFSV41_NPROCS 54 +#define NFSV41_NPROCS 56 #endif /* NFS_V3NPROCS */ @@ -390,7 +392,7 @@ struct nfsstatsv1 { uint64_t readlink_bios; uint64_t biocache_readdirs; uint64_t readdir_bios; - uint64_t rpccnt[NFSV41_NPROCS + 15]; + uint64_t rpccnt[NFSV41_NPROCS + 13]; uint64_t rpcretries; uint64_t srvrpccnt[NFSV42_NOPS + NFSV4OP_FAKENOPS]; uint64_t srvrpc_errs; Modified: stable/11/sys/fs/nfs/nfsproto.h ============================================================================== --- stable/11/sys/fs/nfs/nfsproto.h Fri Jul 14 18:36:15 2017 (r320997) +++ stable/11/sys/fs/nfs/nfsproto.h Fri Jul 14 20:47:41 2017 (r320998) @@ -342,11 +342,13 @@ #define NFSPROC_WRITEDS 51 #define NFSPROC_READDS 52 #define NFSPROC_COMMITDS 53 +#define NFSPROC_OPENLAYGET 54 +#define NFSPROC_CREATELAYGET 55 /* * Must be defined as one higher than the last NFSv4.1 Proc# above. */ -#define NFSV41_NPROCS 54 +#define NFSV41_NPROCS 56 #endif /* NFS_V3NPROCS */ Modified: stable/11/sys/fs/nfsclient/nfs_clcomsubs.c ============================================================================== --- stable/11/sys/fs/nfsclient/nfs_clcomsubs.c Fri Jul 14 18:36:15 2017 (r320997) +++ stable/11/sys/fs/nfsclient/nfs_clcomsubs.c Fri Jul 14 20:47:41 2017 (r320998) @@ -112,6 +112,8 @@ static struct { { NFSV4OP_WRITE, 1, "WriteDS", 7, }, { NFSV4OP_READ, 1, "ReadDS", 6, }, { NFSV4OP_COMMIT, 1, "CommitDS", 8, }, + { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, }, + { NFSV4OP_OPEN, 8, "CreateLayGet", 12, }, }; /* @@ -120,7 +122,7 @@ static struct { static int nfs_bigrequest[NFSV41_NPROCS] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0 + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; /* Modified: stable/11/sys/fs/nfsclient/nfs_clrpcops.c ============================================================================== --- stable/11/sys/fs/nfsclient/nfs_clrpcops.c Fri Jul 14 18:36:15 2017 (r320997) +++ stable/11/sys/fs/nfsclient/nfs_clrpcops.c Fri Jul 14 20:47:41 2017 (r320998) @@ -127,6 +127,29 @@ static enum nfsclds_state nfscl_getsameserver(struct n static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *, struct nfsfh *, struct ucred *, NFSPROC_T *, void *); #endif +static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t, + uint64_t, uint64_t, nfsv4stateid_t *, int, int); +static int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *, + int *, struct nfsclflayouthead *); +static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *, + int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, + struct nfscldeleg **, struct ucred *, NFSPROC_T *); +static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *, + nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, + struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, + struct nfsfh **, int *, int *, void *, int *); +static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *, + int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, + struct nfscldeleg **, nfsv4stateid_t *, int, int, int *, + struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *); +static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *, + nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, + struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, + struct nfsfh **, int *, int *, void *, int *, nfsv4stateid_t *, + int, int, int *, struct nfsclflayouthead *, int *); +static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *, + int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **, + struct nfsclflayouthead *, int, int *, struct ucred *, NFSPROC_T *); /* * nfs null call from vfs. @@ -301,11 +324,27 @@ else printf(" fhl=0\n"); clidrev = 0; if (ret == NFSCLOPEN_DOOPEN) { if (np->n_v4 != NULL) { - error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data, - np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, - np->n_fhp->nfh_len, mode, op, - NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp, - 0, 0x0, cred, p, 0, 0); + /* + * For the first attempt, try and get a layout, if + * pNFS is enabled for the mount. + */ + if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || + nfs_numnfscbd == 0 || + (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0) + error = nfsrpc_openrpc(nmp, vp, + np->n_v4->n4_data, + np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, + np->n_fhp->nfh_len, mode, op, + NFS4NODENAME(np->n_v4), + np->n_v4->n4_namelen, + &dp, 0, 0x0, cred, p, 0, 0); + else + error = nfsrpc_getopenlayout(nmp, vp, + np->n_v4->n4_data, + np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, + np->n_fhp->nfh_len, mode, op, + NFS4NODENAME(np->n_v4), + np->n_v4->n4_namelen, &dp, cred, p); if (dp != NULL) { #ifdef APPLE OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); @@ -1894,9 +1933,15 @@ nfsrpc_create(vnode_t dvp, char *name, int namelen, st clidrev = nmp->nm_clp->nfsc_clientidrev; else clidrev = 0; - error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode, - owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, - dstuff, &unlocked); + if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || + nfs_numnfscbd == 0 || retrycnt > 0) + error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, + fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, + attrflagp, dattrflagp, dstuff, &unlocked); + else + error = nfsrpc_getcreatelayout(dvp, name, namelen, vap, + cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, + attrflagp, dattrflagp, dstuff, &unlocked); /* * There is no need to invalidate cached attributes here, * since new post-delegation issue attributes are always @@ -4785,149 +4830,22 @@ nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, i nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p, void *stuff) { - uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; - struct nfsfh *nfhp; - struct nfsclflayout *flp, *prevflp, *tflp; - int cnt, error, gotiomode, fhcnt, nfhlen, i, j; - uint8_t *cp; - uint64_t retlen; + int error; - flp = NULL; - gotiomode = -1; nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL); - NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + - NFSX_STATEID); - *tl++ = newnfs_false; /* Don't signal availability. */ - *tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES); - *tl++ = txdr_unsigned(iomode); - txdr_hyper(offset, tl); - tl += 2; - txdr_hyper(len, tl); - tl += 2; - txdr_hyper(minlen, tl); - tl += 2; - *tl++ = txdr_unsigned(stateidp->seqid); - NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); - *tl++ = stateidp->other[0]; - *tl++ = stateidp->other[1]; - *tl++ = stateidp->other[2]; - *tl = txdr_unsigned(layoutlen); + nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, + layoutlen, 0); nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); + NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); if (error != 0) return (error); - if (nd->nd_repstat == 0) { - NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); - if (*tl++ != 0) - *retonclosep = 1; - else - *retonclosep = 0; - stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); - NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, - (int)stateidp->seqid); - stateidp->other[0] = *tl++; - stateidp->other[1] = *tl++; - stateidp->other[2] = *tl++; - cnt = fxdr_unsigned(int, *tl); - NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); - if (cnt <= 0 || cnt > 10000) { - /* Don't accept more than 10000 layouts in reply. */ - error = NFSERR_BADXDR; - goto nfsmout; - } - for (i = 0; i < cnt; i++) { - /* Dissect all the way to the file handle cnt. */ - NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER + - 6 * NFSX_UNSIGNED + NFSX_V4DEVICEID); - fhcnt = fxdr_unsigned(int, *(tl + 11 + - NFSX_V4DEVICEID / NFSX_UNSIGNED)); - NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); - if (fhcnt < 0 || fhcnt > 100) { - /* Don't accept more than 100 file handles. */ - error = NFSERR_BADXDR; - goto nfsmout; - } - if (fhcnt > 1) - flp = malloc(sizeof(*flp) + (fhcnt - 1) * - sizeof(struct nfsfh *), - M_NFSFLAYOUT, M_WAITOK); - else - flp = malloc(sizeof(*flp), - M_NFSFLAYOUT, M_WAITOK); - flp->nfsfl_flags = 0; - flp->nfsfl_fhcnt = 0; - flp->nfsfl_devp = NULL; - flp->nfsfl_off = fxdr_hyper(tl); tl += 2; - retlen = fxdr_hyper(tl); tl += 2; - if (flp->nfsfl_off + retlen < flp->nfsfl_off) - flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; - else - flp->nfsfl_end = flp->nfsfl_off + retlen; - flp->nfsfl_iomode = fxdr_unsigned(int, *tl++); - if (gotiomode == -1) - gotiomode = flp->nfsfl_iomode; - NFSCL_DEBUG(4, "layg reqiom=%d retiom=%d\n", iomode, - (int)flp->nfsfl_iomode); - if (fxdr_unsigned(int, *tl++) != - NFSLAYOUT_NFSV4_1_FILES) { - printf("NFSv4.1: got non-files layout\n"); - error = NFSERR_BADXDR; - goto nfsmout; - } - NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID); - tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); - flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); - NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); - flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); - flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; - if (fxdr_unsigned(int, *tl) != fhcnt) { - printf("EEK! bad fhcnt\n"); - error = NFSERR_BADXDR; - goto nfsmout; - } - for (j = 0; j < fhcnt; j++) { - NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); - nfhlen = fxdr_unsigned(int, *tl); - if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { - error = NFSERR_BADXDR; - goto nfsmout; - } - nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, - M_NFSFH, M_WAITOK); - flp->nfsfl_fh[j] = nfhp; - flp->nfsfl_fhcnt++; - nfhp->nfh_len = nfhlen; - NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); - NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); - } - if (flp->nfsfl_iomode == gotiomode) { - /* Keep the list in increasing offset order. */ - tflp = LIST_FIRST(flhp); - prevflp = NULL; - while (tflp != NULL && - tflp->nfsfl_off < flp->nfsfl_off) { - prevflp = tflp; - tflp = LIST_NEXT(tflp, nfsfl_list); - } - if (prevflp == NULL) - LIST_INSERT_HEAD(flhp, flp, nfsfl_list); - else - LIST_INSERT_AFTER(prevflp, flp, - nfsfl_list); - } else { - printf("nfscl_layoutget(): got wrong iomode\n"); - nfscl_freeflayout(flp); - } - flp = NULL; - } - } - if (nd->nd_repstat != 0 && error == 0) + if (nd->nd_repstat == 0) + error = nfsrv_parselayoutget(nd, stateidp, retonclosep, flhp); + if (error == 0 && nd->nd_repstat != 0) error = nd->nd_repstat; -nfsmout: - if (error != 0 && flp != NULL) - nfscl_freeflayout(flp); mbuf_freem(nd->nd_mrep); return (error); } @@ -5228,8 +5146,7 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, str struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) { struct nfscllayout *lyp; - struct nfsclflayout *flp, *tflp; - struct nfscldevinfo *dip; + struct nfsclflayout *flp; struct nfsclflayouthead flh; int error = 0, islocked, layoutlen, recalled, retonclose; nfsv4stateid_t stateid; @@ -5271,35 +5188,13 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, str (uint64_t)0, layoutlen, &stateid, &retonclose, &flh, cred, p, NULL); } + error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, + nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, + &flh, error, NULL, cred, p); if (error == 0) - LIST_FOREACH(tflp, &flh, nfsfl_list) { - error = nfscl_adddevinfo(nmp, NULL, tflp); - if (error != 0) { - error = nfsrpc_getdeviceinfo(nmp, - tflp->nfsfl_dev, - NFSLAYOUT_NFSV4_1_FILES, - notifybitsp, &dip, cred, p); - if (error != 0) - break; - error = nfscl_adddevinfo(nmp, dip, - tflp); - if (error != 0) - printf( - "getlayout: cannot add\n"); - } - } - if (error == 0) { - /* - * nfscl_layout() always returns with the nfsly_lock - * set to a refcnt (shared lock). - */ - error = nfscl_layout(nmp, vp, nfhp->nfh_fh, - nfhp->nfh_len, &stateid, retonclose, &flh, &lyp, - cred, p); - if (error == 0) - *lypp = lyp; - } else if (islocked != 0) - nfsv4_unlock(&lyp->nfsly_lock, 0); + *lypp = lyp; + else if (islocked != 0) + nfscl_rellayout(lyp, 1); } else *lypp = lyp; return (error); @@ -6021,4 +5916,756 @@ nfsmout: return (error); } #endif + +/* + * Set up the XDR arguments for the LayoutGet operation. + */ +static void +nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, + uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layoutlen, + int usecurstateid) +{ + uint32_t *tl; + + NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + + NFSX_STATEID); + *tl++ = newnfs_false; /* Don't signal availability. */ + *tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES); + *tl++ = txdr_unsigned(iomode); + txdr_hyper(offset, tl); + tl += 2; + txdr_hyper(len, tl); + tl += 2; + txdr_hyper(minlen, tl); + tl += 2; + if (usecurstateid != 0) { + /* Special stateid for Current stateid. */ + *tl++ = txdr_unsigned(1); + *tl++ = 0; + *tl++ = 0; + *tl++ = 0; + } else { + *tl++ = txdr_unsigned(stateidp->seqid); + NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); + *tl++ = stateidp->other[0]; + *tl++ = stateidp->other[1]; + *tl++ = stateidp->other[2]; + } + *tl = txdr_unsigned(layoutlen); +} + +/* + * Parse the reply for a successful LayoutGet operation. + */ +static int +nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, + int *retonclosep, struct nfsclflayouthead *flhp) +{ + uint32_t *tl; + struct nfsclflayout *flp, *prevflp, *tflp; + int cnt, error, gotiomode, fhcnt, nfhlen, i, j; + uint64_t retlen; + struct nfsfh *nfhp; + uint8_t *cp; + + error = 0; + flp = NULL; + gotiomode = -1; + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); + if (*tl++ != 0) + *retonclosep = 1; + else + *retonclosep = 0; + stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); + NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, + (int)stateidp->seqid); + stateidp->other[0] = *tl++; + stateidp->other[1] = *tl++; + stateidp->other[2] = *tl++; + cnt = fxdr_unsigned(int, *tl); + NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); + if (cnt <= 0 || cnt > 10000) { + /* Don't accept more than 10000 layouts in reply. */ + error = NFSERR_BADXDR; + goto nfsmout; + } + for (i = 0; i < cnt; i++) { + /* Dissect all the way to the file handle cnt. */ + NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER + + 6 * NFSX_UNSIGNED + NFSX_V4DEVICEID); + fhcnt = fxdr_unsigned(int, *(tl + 11 + + NFSX_V4DEVICEID / NFSX_UNSIGNED)); + NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); + if (fhcnt < 0 || fhcnt > 100) { + /* Don't accept more than 100 file handles. */ + error = NFSERR_BADXDR; + goto nfsmout; + } + if (fhcnt > 1) + flp = malloc(sizeof(*flp) + (fhcnt - 1) * + sizeof(struct nfsfh *), M_NFSFLAYOUT, M_WAITOK); + else + flp = malloc(sizeof(*flp), M_NFSFLAYOUT, M_WAITOK); + flp->nfsfl_flags = 0; + flp->nfsfl_fhcnt = 0; + flp->nfsfl_devp = NULL; + flp->nfsfl_off = fxdr_hyper(tl); tl += 2; + retlen = fxdr_hyper(tl); tl += 2; + if (flp->nfsfl_off + retlen < flp->nfsfl_off) + flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; + else + flp->nfsfl_end = flp->nfsfl_off + retlen; + flp->nfsfl_iomode = fxdr_unsigned(int, *tl++); + if (gotiomode == -1) + gotiomode = flp->nfsfl_iomode; + if (fxdr_unsigned(int, *tl++) != NFSLAYOUT_NFSV4_1_FILES) { + printf("NFSv4.1: got non-files layout\n"); + error = NFSERR_BADXDR; + goto nfsmout; + } + NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID); + tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); + flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); + NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); + flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); + flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; + if (fxdr_unsigned(int, *tl) != fhcnt) { + printf("EEK! bad fhcnt\n"); + error = NFSERR_BADXDR; + goto nfsmout; + } + for (j = 0; j < fhcnt; j++) { + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + nfhlen = fxdr_unsigned(int, *tl); + if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { + error = NFSERR_BADXDR; + goto nfsmout; + } + nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, M_NFSFH, + M_WAITOK); + flp->nfsfl_fh[j] = nfhp; + flp->nfsfl_fhcnt++; + nfhp->nfh_len = nfhlen; + NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); + NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); + } + if (flp->nfsfl_iomode == gotiomode) { + /* Keep the list in increasing offset order. */ + tflp = LIST_FIRST(flhp); + prevflp = NULL; + while (tflp != NULL && + tflp->nfsfl_off < flp->nfsfl_off) { + prevflp = tflp; + tflp = LIST_NEXT(tflp, nfsfl_list); + } + if (prevflp == NULL) + LIST_INSERT_HEAD(flhp, flp, nfsfl_list); + else + LIST_INSERT_AFTER(prevflp, flp, + nfsfl_list); + } else { + printf("nfscl_layoutget(): got wrong iomode\n"); + nfscl_freeflayout(flp); + } + flp = NULL; + } +nfsmout: + if (error != 0 && flp != NULL) + nfscl_freeflayout(flp); + return (error); +} + +/* + * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), + * so that it does both an Open and a Layoutget. + */ +static int +nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, + int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, + struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, + struct ucred *cred, NFSPROC_T *p) +{ + struct nfscllayout *lyp; + struct nfsclflayout *flp; + struct nfsclflayouthead flh; + int error, islocked, layoutlen, recalled, retonclose, usecurstateid; + int laystat; + nfsv4stateid_t stateid; + struct nfsclsession *tsep; + + error = 0; + /* + * If lyp is returned non-NULL, there will be a refcnt (shared lock) + * on it, iff flp != NULL or a lock (exclusive lock) on it iff + * flp == NULL. + */ + lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, &flp, + &recalled); + NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); + if (lyp == NULL) + islocked = 0; + else if (flp != NULL) + islocked = 1; + else + islocked = 2; + if ((lyp == NULL || flp == NULL) && recalled == 0) { + LIST_INIT(&flh); + tsep = nfsmnt_mdssession(nmp); + layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + + 3 * NFSX_UNSIGNED); + if (lyp == NULL) + usecurstateid = 1; + else { + usecurstateid = 0; + stateid.seqid = lyp->nfsly_stateid.seqid; + stateid.other[0] = lyp->nfsly_stateid.other[0]; + stateid.other[1] = lyp->nfsly_stateid.other[1]; + stateid.other[2] = lyp->nfsly_stateid.other[2]; + } + error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, + newfhp, newfhlen, mode, op, name, namelen, + dpp, &stateid, usecurstateid, layoutlen, + &retonclose, &flh, &laystat, cred, p); + NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", + laystat, error); + laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, + &stateid, retonclose, NULL, &lyp, &flh, laystat, &islocked, + cred, p); + } else + error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, + mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); + if (islocked == 2) + nfscl_rellayout(lyp, 1); + else if (islocked == 1) + nfscl_rellayout(lyp, 0); + return (error); +} + +/* + * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS + * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are + * handled by nfsrpc_openrpc(). + * For the case where op == NULL, dvp is the directory. When op != NULL, it + * can be NULL. + */ +static int +nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, + int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, + struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, + nfsv4stateid_t *stateidp, int usecurstateid, + int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, + int *laystatp, struct ucred *cred, NFSPROC_T *p) +{ + uint32_t *tl; + struct nfsrv_descript nfsd, *nd = &nfsd; + struct nfscldeleg *ndp = NULL; + struct nfsvattr nfsva; + struct nfsclsession *tsep; + uint32_t rflags, deleg; + nfsattrbit_t attrbits; + int error, ret, acesize, limitby, iomode; + + *dpp = NULL; + *laystatp = ENXIO; + nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL); + NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); + *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); + *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); + tsep = nfsmnt_mdssession(nmp); + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl = tsep->nfsess_clientid.lval[1]; + nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); + NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); + *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); + nfsm_strtom(nd, name, namelen); + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + NFSZERO_ATTRBIT(&attrbits); + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); + nfsrv_putattrbit(nd, &attrbits); + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); + if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) + iomode = NFSLAYOUTIOMODE_RW; + else + iomode = NFSLAYOUTIOMODE_READ; + nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, + layoutlen, usecurstateid); + error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, + NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); + if (error != 0) + return (error); + NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); + if (nd->nd_repstat != 0) + *laystatp = nd->nd_repstat; + if ((nd->nd_flag & ND_NOMOREDATA) == 0) { + /* ND_NOMOREDATA will be set if the Open operation failed. */ + NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + + 6 * NFSX_UNSIGNED); + op->nfso_stateid.seqid = *tl++; + op->nfso_stateid.other[0] = *tl++; + op->nfso_stateid.other[1] = *tl++; + op->nfso_stateid.other[2] = *tl; + rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); + error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); + if (error != 0) + goto nfsmout; + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + deleg = fxdr_unsigned(u_int32_t, *tl); + if (deleg == NFSV4OPEN_DELEGATEREAD || + deleg == NFSV4OPEN_DELEGATEWRITE) { + if (!(op->nfso_own->nfsow_clp->nfsc_flags & + NFSCLFLAGS_FIRSTDELEG)) + op->nfso_own->nfsow_clp->nfsc_flags |= + (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); + ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, + M_NFSCLDELEG, M_WAITOK); + LIST_INIT(&ndp->nfsdl_owner); + LIST_INIT(&ndp->nfsdl_lock); + ndp->nfsdl_clp = op->nfso_own->nfsow_clp; + ndp->nfsdl_fhlen = newfhlen; + NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); + newnfs_copyincred(cred, &ndp->nfsdl_cred); + nfscl_lockinit(&ndp->nfsdl_rwlock); + NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + + NFSX_UNSIGNED); + ndp->nfsdl_stateid.seqid = *tl++; + ndp->nfsdl_stateid.other[0] = *tl++; + ndp->nfsdl_stateid.other[1] = *tl++; + ndp->nfsdl_stateid.other[2] = *tl++; + ret = fxdr_unsigned(int, *tl); + if (deleg == NFSV4OPEN_DELEGATEWRITE) { + ndp->nfsdl_flags = NFSCLDL_WRITE; + /* + * Indicates how much the file can grow. + */ + NFSM_DISSECT(tl, u_int32_t *, + 3 * NFSX_UNSIGNED); + limitby = fxdr_unsigned(int, *tl++); + switch (limitby) { + case NFSV4OPEN_LIMITSIZE: + ndp->nfsdl_sizelimit = fxdr_hyper(tl); + break; + case NFSV4OPEN_LIMITBLOCKS: + ndp->nfsdl_sizelimit = + fxdr_unsigned(u_int64_t, *tl++); + ndp->nfsdl_sizelimit *= + fxdr_unsigned(u_int64_t, *tl); + break; + default: + error = NFSERR_BADXDR; + goto nfsmout; + }; + } else + ndp->nfsdl_flags = NFSCLDL_READ; + if (ret != 0) + ndp->nfsdl_flags |= NFSCLDL_RECALL; + error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, + &acesize, p); + if (error != 0) + goto nfsmout; + } else if (deleg != NFSV4OPEN_DELEGATENONE) { + error = NFSERR_BADXDR; + goto nfsmout; + } + if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || + nfscl_assumeposixlocks) + op->nfso_posixlock = 1; + else + op->nfso_posixlock = 0; + NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + /* If the 2nd element == NFS_OK, the Getattr succeeded. */ + if (*++tl == 0) { + error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, + NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, + NULL, NULL, NULL, p, cred); + if (error != 0) + goto nfsmout; + if (ndp != NULL) { + ndp->nfsdl_change = nfsva.na_filerev; + ndp->nfsdl_modtime = nfsva.na_mtime; + ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; + *dpp = ndp; + ndp = NULL; + } + /* + * At this point, the Open has succeeded, so set + * nd_repstat = NFS_OK. If the Layoutget failed, + * this function just won't return a layout. + */ + if (nd->nd_repstat == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + *laystatp = fxdr_unsigned(int, *++tl); + if (*laystatp == 0) { + error = nfsrv_parselayoutget(nd, + stateidp, retonclosep, flhp); + if (error != 0) + *laystatp = error; + } + } else + nd->nd_repstat = 0; /* Return 0 for Open. */ + } + } + if (nd->nd_repstat != 0 && error == 0) + error = nd->nd_repstat; +nfsmout: + free(ndp, M_NFSCLDELEG); + mbuf_freem(nd->nd_mrep); + return (error); +} + +/* + * Similar nfsrpc_createv4(), but also does the LayoutGet operation. + * Used only for mounts with pNFS enabled. + */ +static int +nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, + nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, + struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, + struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, + int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp, + int usecurstateid, int layoutlen, int *retonclosep, + struct nfsclflayouthead *flhp, int *laystatp) +{ + uint32_t *tl; + int error = 0, deleg, newone, ret, acesize, limitby; + struct nfsrv_descript nfsd, *nd = &nfsd; + struct nfsclopen *op; + struct nfscldeleg *dp = NULL; + struct nfsnode *np; + struct nfsfh *nfhp; + struct nfsclsession *tsep; + nfsattrbit_t attrbits; + nfsv4stateid_t stateid; + uint32_t rflags; + struct nfsmount *nmp; + + nmp = VFSTONFS(dvp->v_mount); + np = VTONFS(dvp); + *laystatp = ENXIO; + *unlockedp = 0; + *nfhpp = NULL; + *dpp = NULL; + *attrflagp = 0; + *dattrflagp = 0; + if (namelen > NFS_MAXNAMLEN) + return (ENAMETOOLONG); + NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp); + /* + * For V4, this is actually an Open op. + */ + NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(owp->nfsow_seqid); + *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | + NFSV4OPEN_ACCESSREAD); + *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); + tsep = nfsmnt_mdssession(nmp); + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl = tsep->nfsess_clientid.lval[1]; + nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); + NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); + if ((fmode & O_EXCL) != 0) { + if (NFSHASSESSPERSIST(nmp)) { + /* Use GUARDED for persistent sessions. */ + *tl = txdr_unsigned(NFSCREATE_GUARDED); + nfscl_fillsattr(nd, vap, dvp, 0, 0); + } else { + /* Otherwise, use EXCLUSIVE4_1. */ + *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); + NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); + *tl++ = cverf.lval[0]; + *tl = cverf.lval[1]; + nfscl_fillsattr(nd, vap, dvp, 0, 0); + } + } else { + *tl = txdr_unsigned(NFSCREATE_UNCHECKED); + nfscl_fillsattr(nd, vap, dvp, 0, 0); + } + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); + nfsm_strtom(nd, name, namelen); + /* Get the new file's handle and attributes, plus save the FH. */ + NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV4OP_SAVEFH); + *tl++ = txdr_unsigned(NFSV4OP_GETFH); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + NFSGETATTR_ATTRBIT(&attrbits); + nfsrv_putattrbit(nd, &attrbits); + /* Get the directory's post-op attributes. */ + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_PUTFH); + nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + nfsrv_putattrbit(nd, &attrbits); + NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); + *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); + nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, + layoutlen, usecurstateid); + error = nfscl_request(nd, dvp, p, cred, dstuff); + if (error != 0) + return (error); + NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, + error); + if (nd->nd_repstat != 0) + *laystatp = nd->nd_repstat; + NFSCL_INCRSEQID(owp->nfsow_seqid, nd); + if ((nd->nd_flag & ND_NOMOREDATA) == 0) { + NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); + NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + + 6 * NFSX_UNSIGNED); + stateid.seqid = *tl++; + stateid.other[0] = *tl++; + stateid.other[1] = *tl++; + stateid.other[2] = *tl; + rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); + nfsrv_getattrbits(nd, &attrbits, NULL, NULL); + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + deleg = fxdr_unsigned(int, *tl); + if (deleg == NFSV4OPEN_DELEGATEREAD || + deleg == NFSV4OPEN_DELEGATEWRITE) { + if (!(owp->nfsow_clp->nfsc_flags & + NFSCLFLAGS_FIRSTDELEG)) + owp->nfsow_clp->nfsc_flags |= + (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); + dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, + M_NFSCLDELEG, M_WAITOK); + LIST_INIT(&dp->nfsdl_owner); + LIST_INIT(&dp->nfsdl_lock); + dp->nfsdl_clp = owp->nfsow_clp; + newnfs_copyincred(cred, &dp->nfsdl_cred); + nfscl_lockinit(&dp->nfsdl_rwlock); + NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + + NFSX_UNSIGNED); + dp->nfsdl_stateid.seqid = *tl++; + dp->nfsdl_stateid.other[0] = *tl++; + dp->nfsdl_stateid.other[1] = *tl++; + dp->nfsdl_stateid.other[2] = *tl++; + ret = fxdr_unsigned(int, *tl); + if (deleg == NFSV4OPEN_DELEGATEWRITE) { + dp->nfsdl_flags = NFSCLDL_WRITE; + /* + * Indicates how much the file can grow. + */ + NFSM_DISSECT(tl, u_int32_t *, + 3 * NFSX_UNSIGNED); + limitby = fxdr_unsigned(int, *tl++); + switch (limitby) { + case NFSV4OPEN_LIMITSIZE: + dp->nfsdl_sizelimit = fxdr_hyper(tl); + break; + case NFSV4OPEN_LIMITBLOCKS: + dp->nfsdl_sizelimit = + fxdr_unsigned(u_int64_t, *tl++); + dp->nfsdl_sizelimit *= + fxdr_unsigned(u_int64_t, *tl); + break; + default: + error = NFSERR_BADXDR; + goto nfsmout; + }; + } else { + dp->nfsdl_flags = NFSCLDL_READ; + } + if (ret != 0) + dp->nfsdl_flags |= NFSCLDL_RECALL; + error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, + &acesize, p); + if (error != 0) + goto nfsmout; + } else if (deleg != NFSV4OPEN_DELEGATENONE) { + error = NFSERR_BADXDR; + goto nfsmout; + } + + /* Now, we should have the status for the SaveFH. */ + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*++tl == 0) { + NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); + /* + * Now, process the GetFH and Getattr for the newly + * created file. nfscl_mtofh() will set + * ND_NOMOREDATA if these weren't successful. + */ + error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); + NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); + if (error != 0) + goto nfsmout; + } else + nd->nd_flag |= ND_NOMOREDATA; + /* Now we have the PutFH and Getattr for the directory. */ + if ((nd->nd_flag & ND_NOMOREDATA) == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*++tl != 0) + nd->nd_flag |= ND_NOMOREDATA; + else { + NFSM_DISSECT(tl, uint32_t *, 2 * + NFSX_UNSIGNED); + if (*++tl != 0) + nd->nd_flag |= ND_NOMOREDATA; + } + } + if ((nd->nd_flag & ND_NOMOREDATA) == 0) { + /* Load the directory attributes. */ + error = nfsm_loadattr(nd, dnap); + NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); + if (error != 0) + goto nfsmout; + *dattrflagp = 1; + if (dp != NULL && *attrflagp != 0) { + dp->nfsdl_change = nnap->na_filerev; + dp->nfsdl_modtime = nnap->na_mtime; + dp->nfsdl_flags |= NFSCLDL_MODTIMESET; + } + /* + * We can now complete the Open state. + */ + nfhp = *nfhpp; + if (dp != NULL) { + dp->nfsdl_fhlen = nfhp->nfh_len; + NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, + nfhp->nfh_len); + } + /* + * Get an Open structure that will be + * attached to the OpenOwner, acquired already. + */ + error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, + (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, + cred, p, NULL, &op, &newone, NULL, 0); + if (error != 0) + goto nfsmout; + op->nfso_stateid = stateid; + newnfs_copyincred(cred, &op->nfso_cred); + + nfscl_openrelease(nmp, op, error, newone); + *unlockedp = 1; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***