aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c2
-rw-r--r--sys/fs/nfs/nfsport.h6
-rw-r--r--sys/fs/nfs/nfsproto.h4
-rw-r--r--sys/fs/nfsclient/nfs_clcomsubs.c4
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c991
5 files changed, 830 insertions, 177 deletions
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index b454b691d3e7..3b62ef18af11 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -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);
diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
index 96d85c9c9b40..f537372cd48f 100644
--- a/sys/fs/nfs/nfsport.h
+++ b/sys/fs/nfs/nfsport.h
@@ -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;
diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h
index 9c724357d132..13c7c3327837 100644
--- a/sys/fs/nfs/nfsproto.h
+++ b/sys/fs/nfs/nfsproto.h
@@ -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 */
diff --git a/sys/fs/nfsclient/nfs_clcomsubs.c b/sys/fs/nfsclient/nfs_clcomsubs.c
index c16a3402946d..cf3ab8e43b3b 100644
--- a/sys/fs/nfsclient/nfs_clcomsubs.c
+++ b/sys/fs/nfsclient/nfs_clcomsubs.c
@@ -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
};
/*
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 7efe72619c41..fe04aa770dbc 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -127,6 +127,29 @@ static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
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, struct vattr *vap,
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
@@ -4795,149 +4840,22 @@ nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
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);
}
@@ -5238,8 +5156,7 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
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;
@@ -5281,35 +5198,13 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
(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);
@@ -6032,3 +5927,755 @@ nfsmout:
}
#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;
+
+ /* Now, handle the RestoreFH and LayoutGet. */
+ if (nd->nd_repstat == 0) {
+ NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
+ *laystatp = fxdr_unsigned(int, *(tl + 3));
+ if (*laystatp == 0) {
+ error = nfsrv_parselayoutget(nd,
+ stateidp, retonclosep, flhp);
+ if (error != 0)
+ *laystatp = error;
+ }
+ NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n",
+ error);
+ } else
+ nd->nd_repstat = 0;
+ }
+ }
+ if (nd->nd_repstat != 0 && error == 0)
+ error = nd->nd_repstat;
+ if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION)
+ nfscl_initiate_recovery(owp->nfsow_clp);
+nfsmout:
+ NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error);
+ if (error == 0)
+ *dpp = dp;
+ else
+ free(dp, M_NFSCLDELEG);
+ mbuf_freem(nd->nd_mrep);
+ return (error);
+}
+
+/*
+ * Similar to nfsrpc_getopenlayout(), except that it used for the Create case.
+ */
+static int
+nfsrpc_getcreatelayout(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)
+{
+ struct nfscllayout *lyp;
+ struct nfsclflayouthead flh;
+ struct nfsfh *nfhp;
+ struct nfsclsession *tsep;
+ struct nfsmount *nmp;
+ nfsv4stateid_t stateid;
+ int error, layoutlen, retonclose, laystat;
+
+ error = 0;
+ nmp = VFSTONFS(dvp->v_mount);
+ LIST_INIT(&flh);
+ tsep = nfsmnt_mdssession(nmp);
+ layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED);
+ error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode,
+ owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
+ dstuff, unlockedp, &stateid, 1, layoutlen, &retonclose, &flh,
+ &laystat);
+ NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n",
+ laystat, error);
+ lyp = NULL;
+ nfhp = *nfhpp;
+ laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, nfhp->nfh_len,
+ &stateid, retonclose, NULL, &lyp, &flh, laystat, NULL, cred, p);
+ if (laystat == 0)
+ nfscl_rellayout(lyp, 0);
+ return (error);
+}
+
+/*
+ * Process the results of a layoutget() operation.
+ */
+static int
+nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp,
+ int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit,
+ struct nfscllayout **lypp, struct nfsclflayouthead *flhp,
+ int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p)
+{
+ struct nfsclflayout *tflp;
+ struct nfscldevinfo *dip;
+
+ if (laystat == NFSERR_UNKNLAYOUTTYPE) {
+ /* Disable PNFS. */
+ NFSCL_DEBUG(1, "disable PNFS\n");
+ NFSLOCKMNT(nmp);
+ nmp->nm_state &= ~NFSSTA_PNFS;
+ NFSUNLOCKMNT(nmp);
+ }
+ if (laystat == 0) {
+ NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n");
+ LIST_FOREACH(tflp, flhp, nfsfl_list) {
+ laystat = nfscl_adddevinfo(nmp, NULL, tflp);
+ NFSCL_DEBUG(4, "aft adddev=%d\n", laystat);
+ if (laystat != 0) {
+ laystat = nfsrpc_getdeviceinfo(nmp,
+ tflp->nfsfl_dev, NFSLAYOUT_NFSV4_1_FILES,
+ notifybit, &dip, cred, p);
+ NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n",
+ laystat);
+ if (laystat != 0)
+ break;
+ laystat = nfscl_adddevinfo(nmp, dip, tflp);
+ if (laystat != 0)
+ printf("getlayout: cannot add\n");
+ }
+ }
+ }
+ if (laystat == 0) {
+ /*
+ * nfscl_layout() always returns with the nfsly_lock
+ * set to a refcnt (shared lock).
+ * Passing in dvp is sufficient, since it is only used to
+ * get the fsid for the file system.
+ */
+ laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp,
+ retonclose, flhp, lypp, cred, p);
+ NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n",
+ laystat);
+ if (laystat == 0 && islockedp != NULL)
+ *islockedp = 1;
+ }
+ return (laystat);
+}
+