aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/fs/nfs/nfs_var.h2
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c1114
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c55
3 files changed, 947 insertions, 224 deletions
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index c6cc3c619602..86db40ec1521 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -555,7 +555,7 @@ int nfscl_tryclose(struct nfsclopen *, struct ucred *,
struct nfsmount *, NFSPROC_T *);
void nfscl_cleanup(NFSPROC_T *);
int nfscl_layout(struct nfsmount *, vnode_t, u_int8_t *, int, nfsv4stateid_t *,
- int, struct nfsclflayouthead *, struct nfscllayout **, struct ucred *,
+ int, int, struct nfsclflayouthead *, struct nfscllayout **, struct ucred *,
NFSPROC_T *);
struct nfscllayout *nfscl_getlayout(struct nfsclclient *, uint8_t *, int,
uint64_t, struct nfsclflayout **, int *);
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 926d8e617c59..4c9e47740423 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -116,18 +116,28 @@ static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *,
NFSPROC_T *);
+static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *,
+ nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
+ struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *,
+ struct ucred *, NFSPROC_T *);
+static struct mbuf *nfsm_copym(struct mbuf *, int, int);
static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
- struct nfsclds *, uint64_t, int, struct nfsfh *, struct ucred *,
- NFSPROC_T *);
+ struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int,
+ struct ucred *, NFSPROC_T *);
static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
- struct nfsfh *, int, struct ucred *, NFSPROC_T *);
+ struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *);
+static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
+ struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
+ struct ucred *, NFSPROC_T *);
static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
struct nfsclds *, struct nfsclds **);
static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
- struct nfsfh *, struct ucred *, NFSPROC_T *);
+ struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t,
- uint64_t, uint64_t, nfsv4stateid_t *, int, int);
+ uint64_t, uint64_t, nfsv4stateid_t *, int, int, int);
+static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *,
+ NFSPROC_T *);
static int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *,
int *, struct nfsclflayouthead *);
static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *,
@@ -139,19 +149,19 @@ static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *,
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 nfscldeleg **, nfsv4stateid_t *, int, 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 *);
+ int, int, int, int *, struct nfsclflayouthead *, int *);
static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t,
- uint64_t, uint64_t, int, nfsv4stateid_t *, int *, struct nfsclflayouthead *,
- struct ucred *, NFSPROC_T *, void *);
+ uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *,
+ struct nfsclflayouthead *, struct ucred *, NFSPROC_T *, void *);
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 *);
+ struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *);
/*
* nfs null call from vfs.
@@ -4849,9 +4859,10 @@ nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
*/
static int
nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
- uint64_t offset, uint64_t len, uint64_t minlen, int layoutlen,
- nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp,
- struct ucred *cred, NFSPROC_T *p, void *stuff)
+ uint64_t offset, uint64_t len, uint64_t minlen, int layouttype,
+ int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep,
+ struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p,
+ void *stuff)
{
struct nfsrv_descript nfsd, *nd = &nfsd;
int error;
@@ -4859,7 +4870,7 @@ nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0,
0);
nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp,
- layoutlen, 0);
+ layouttype, 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);
@@ -4882,7 +4893,7 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
NFSPROC_T *p)
{
- uint32_t cnt, *tl;
+ uint32_t cnt, *tl, vers, minorvers;
struct nfsrv_descript nfsd;
struct nfsrv_descript *nd = &nfsd;
struct sockaddr_in sin, ssin;
@@ -4915,51 +4926,68 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
if (error != 0)
return (error);
if (nd->nd_repstat == 0) {
- NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
- if (layouttype != fxdr_unsigned(int, *tl++))
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ if (layouttype != fxdr_unsigned(int, *tl))
printf("EEK! devinfo layout type not same!\n");
- stripecnt = fxdr_unsigned(int, *++tl);
- NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
- if (stripecnt < 1 || stripecnt > 4096) {
- printf("NFS devinfo stripecnt %d: out of range\n",
- stripecnt);
- error = NFSERR_BADXDR;
- goto nfsmout;
- }
- NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED);
- addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
- NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
- if (addrcnt < 1 || addrcnt > 128) {
- printf("NFS devinfo addrcnt %d: out of range\n",
- addrcnt);
- error = NFSERR_BADXDR;
- goto nfsmout;
- }
-
- /*
- * Now we know how many stripe indices and addresses, so
- * we can allocate the structure the correct size.
- */
- i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *)
- + 1;
- NFSCL_DEBUG(4, "stripeindices=%d\n", i);
- ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
- sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO);
- NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID);
- ndi->nfsdi_refcnt = 0;
- ndi->nfsdi_stripecnt = stripecnt;
- ndi->nfsdi_addrcnt = addrcnt;
- /* Fill in the stripe indices. */
- for (i = 0; i < stripecnt; i++) {
- stripeindex = fxdr_unsigned(uint8_t, *tl++);
- NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
- if (stripeindex >= addrcnt) {
- printf("NFS devinfo stripeindex %d: too big\n",
- (int)stripeindex);
+ if (layouttype == NFSLAYOUT_NFSV4_1_FILES) {
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ stripecnt = fxdr_unsigned(int, *tl);
+ NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
+ if (stripecnt < 1 || stripecnt > 4096) {
+ printf("pNFS File layout devinfo stripecnt %d:"
+ " out of range\n", stripecnt);
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) *
+ NFSX_UNSIGNED);
+ addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
+ NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
+ if (addrcnt < 1 || addrcnt > 128) {
+ printf("NFS devinfo addrcnt %d: out of range\n",
+ addrcnt);
error = NFSERR_BADXDR;
goto nfsmout;
}
- nfsfldi_setstripeindex(ndi, i, stripeindex);
+
+ /*
+ * Now we know how many stripe indices and addresses, so
+ * we can allocate the structure the correct size.
+ */
+ i = (stripecnt * sizeof(uint8_t)) /
+ sizeof(struct nfsclds *) + 1;
+ NFSCL_DEBUG(4, "stripeindices=%d\n", i);
+ ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
+ sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK |
+ M_ZERO);
+ NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
+ NFSX_V4DEVICEID);
+ ndi->nfsdi_refcnt = 0;
+ ndi->nfsdi_flags = NFSDI_FILELAYOUT;
+ ndi->nfsdi_stripecnt = stripecnt;
+ ndi->nfsdi_addrcnt = addrcnt;
+ /* Fill in the stripe indices. */
+ for (i = 0; i < stripecnt; i++) {
+ stripeindex = fxdr_unsigned(uint8_t, *tl++);
+ NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
+ if (stripeindex >= addrcnt) {
+ printf("pNFS File Layout devinfo"
+ " stripeindex %d: too big\n",
+ (int)stripeindex);
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ nfsfldi_setstripeindex(ndi, i, stripeindex);
+ }
+ } else if (layouttype == NFSLAYOUT_FLEXFILE) {
+ /* For Flex File, we only get one address list. */
+ ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *),
+ M_NFSDEVINFO, M_WAITOK | M_ZERO);
+ NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
+ NFSX_V4DEVICEID);
+ ndi->nfsdi_refcnt = 0;
+ ndi->nfsdi_flags = NFSDI_FLEXFILE;
+ addrcnt = ndi->nfsdi_addrcnt = 1;
}
/* Now, dissect the server address(es). */
@@ -5005,6 +5033,46 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
}
gotvers = NFS_VER4; /* Always NFSv4 for File Layout. */
+ /* For Flex File, we will take one of the versions to use. */
+ if (layouttype == NFSLAYOUT_FLEXFILE) {
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ j = fxdr_unsigned(int, *tl);
+ if (j < 1 || j > NFSDEV_MAXVERS) {
+ printf("pNFS: too many versions\n");
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ gotvers = 0;
+ for (i = 0; i < j; i++) {
+ NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED);
+ vers = fxdr_unsigned(uint32_t, *tl++);
+ minorvers = fxdr_unsigned(uint32_t, *tl++);
+ if ((vers == NFS_VER4 && minorvers ==
+ NFSV41_MINORVERSION) || (vers == NFS_VER3 &&
+ gotvers == 0)) {
+ gotvers = vers;
+ /* We'll take this one. */
+ ndi->nfsdi_versindex = i;
+ ndi->nfsdi_vers = vers;
+ ndi->nfsdi_minorvers = minorvers;
+ ndi->nfsdi_rsize = fxdr_unsigned(
+ uint32_t, *tl++);
+ ndi->nfsdi_wsize = fxdr_unsigned(
+ uint32_t, *tl++);
+ if (*tl == newnfs_true)
+ ndi->nfsdi_flags |=
+ NFSDI_TIGHTCOUPLED;
+ else
+ ndi->nfsdi_flags &=
+ ~NFSDI_TIGHTCOUPLED;
+ }
+ }
+ if (gotvers == 0) {
+ printf("pNFS: no NFSv3 or NFSv4.1\n");
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ }
/* And the notify bits. */
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
@@ -5033,7 +5101,7 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
*gotdspp = dsp;
}
}
- if (nd->nd_repstat != 0)
+ if (nd->nd_repstat != 0 && error == 0)
error = nd->nd_repstat;
nfsmout:
if (error != 0 && ndi != NULL)
@@ -5126,7 +5194,15 @@ nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
*tl++ = stateidp->other[0];
*tl++ = stateidp->other[1];
*tl++ = stateidp->other[2];
- *tl = txdr_unsigned(0);
+ if (layouttype == NFSLAYOUT_NFSV4_1_FILES)
+ *tl = txdr_unsigned(0);
+ else if (layouttype == NFSLAYOUT_FLEXFILE) {
+ *tl = txdr_unsigned(2 * NFSX_UNSIGNED);
+ NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ /* No ioerrs or stats yet. */
+ *tl++ = 0;
+ *tl = 0;
+ }
}
nd->nd_flag |= ND_USEGSSNAME;
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
@@ -5162,11 +5238,15 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
struct nfscllayout *lyp;
struct nfsclflayout *flp;
struct nfsclflayouthead flh;
- int error = 0, islocked, layoutlen, recalled, retonclose;
+ int error = 0, islocked, layoutlen, layouttype, recalled, retonclose;
nfsv4stateid_t stateid;
struct nfsclsession *tsep;
*lypp = NULL;
+ if (NFSHASFLEXFILE(nmp))
+ layouttype = NFSLAYOUT_FLEXFILE;
+ else
+ layouttype = NFSLAYOUT_NFSV4_1_FILES;
/*
* 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
@@ -5189,8 +5269,8 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
stateid.other[2] = stateidp->other[2];
error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX,
- (uint64_t)0, layoutlen, &stateid, &retonclose,
- &flh, cred, p, NULL);
+ (uint64_t)0, layouttype, layoutlen, &stateid,
+ &retonclose, &flh, cred, p, NULL);
} else {
islocked = 1;
stateid.seqid = lyp->nfsly_stateid.seqid;
@@ -5199,12 +5279,12 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
stateid.other[2] = lyp->nfsly_stateid.other[2];
error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
nfhp->nfh_len, iomode, off, UINT64_MAX,
- (uint64_t)0, layoutlen, &stateid, &retonclose,
- &flh, cred, p, NULL);
+ (uint64_t)0, layouttype, 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);
+ &flh, layouttype, error, NULL, cred, p);
if (error == 0)
*lypp = lyp;
else if (islocked != 0)
@@ -5336,38 +5416,53 @@ nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin,
error = newnfs_connect(nmp, nrp, NULL, p, 0);
NFSCL_DEBUG(3, "DS connect=%d\n", error);
+ dsp = NULL;
/* Now, do the exchangeid and create session. */
if (error == 0) {
- error = nfsrpc_exchangeid(nmp, clp, nrp, NFSV4EXCH_USEPNFSDS,
- &dsp, nrp->nr_cred, p);
- NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
- if (error != 0)
- newnfs_disconnect(nrp);
+ if (vers == NFS_VER4) {
+ error = nfsrpc_exchangeid(nmp, clp, nrp,
+ NFSV4EXCH_USEPNFSDS, &dsp, nrp->nr_cred, p);
+ NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
+ if (error != 0)
+ newnfs_disconnect(nrp);
+ } else {
+ dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS,
+ M_WAITOK | M_ZERO);
+ dsp->nfsclds_flags |= NFSCLDS_DS;
+ dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */
+ mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
+ mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
+ NULL, MTX_DEF);
+ }
}
if (error == 0) {
dsp->nfsclds_sockp = nrp;
- NFSLOCKMNT(nmp);
- retv = nfscl_getsameserver(nmp, dsp, &tdsp);
- NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
- if (retv == NFSDSP_USETHISSESSION) {
+ if (vers == NFS_VER4) {
+ NFSLOCKMNT(nmp);
+ retv = nfscl_getsameserver(nmp, dsp, &tdsp);
+ NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
+ if (retv == NFSDSP_USETHISSESSION) {
+ NFSUNLOCKMNT(nmp);
+ /*
+ * If there is already a session for this
+ * server, use it.
+ */
+ (void)newnfs_disconnect(nrp);
+ nfscl_freenfsclds(dsp);
+ *dspp = tdsp;
+ return (0);
+ }
+ if (retv == NFSDSP_SEQTHISSESSION)
+ sequenceid =
+ tdsp->nfsclds_sess.nfsess_sequenceid;
+ else
+ sequenceid =
+ dsp->nfsclds_sess.nfsess_sequenceid;
NFSUNLOCKMNT(nmp);
- /*
- * If there is already a session for this server,
- * use it.
- */
- (void)newnfs_disconnect(nrp);
- nfscl_freenfsclds(dsp);
- *dspp = tdsp;
- return (0);
+ error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
+ nrp, sequenceid, 0, nrp->nr_cred, p);
+ NFSCL_DEBUG(3, "DS createsess=%d\n", error);
}
- if (retv == NFSDSP_SEQTHISSESSION)
- sequenceid = tdsp->nfsclds_sess.nfsess_sequenceid;
- else
- sequenceid = dsp->nfsclds_sess.nfsess_sequenceid;
- NFSUNLOCKMNT(nmp);
- error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
- nrp, sequenceid, 0, nrp->nr_cred, p);
- NFSCL_DEBUG(3, "DS createsess=%d\n", error);
} else {
NFSFREECRED(nrp->nr_cred);
NFSFREEMUTEX(&nrp->nr_mtx);
@@ -5448,11 +5543,17 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
struct nfscllayout *layp;
struct nfscldevinfo *dip;
struct nfsclflayout *rflp;
+ struct mbuf *m;
nfsv4stateid_t stateid;
struct ucred *newcred;
uint64_t lastbyte, len, off, oresid, xfer;
- int eof, error, iolaymode, recalled;
+ int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled;
void *lckp;
+ uint8_t *dev;
+ void *iovbase;
+ size_t iovlen;
+ off_t offs;
+ ssize_t resid;
if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
(np->n_flag & NNOLAYOUT) != 0)
@@ -5520,30 +5621,93 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
oresid = xfer = (uint64_t)uiop->uio_resid;
if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
xfer = rflp->nfsfl_end - rflp->nfsfl_off;
- dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev,
- rflp->nfsfl_devp);
- if (dip != NULL) {
- error = nfscl_doflayoutio(vp, uiop, iomode,
- must_commit, &eof, &stateid, rwaccess, dip,
- layp, rflp, off, xfer, docommit, newcred,
- p);
- nfscl_reldevinfo(dip);
- lastbyte = off + xfer - 1;
- if (error == 0) {
+ /*
+ * For Flex File layout with mirrored DSs, select one
+ * of them at random for reads. For writes and commits,
+ * do all mirrors.
+ */
+ m = NULL;
+ firstmirror = 0;
+ mirrorcnt = 1;
+ if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 &&
+ (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) {
+ if (rwaccess == NFSV4OPEN_ACCESSREAD) {
+ firstmirror = arc4random() % mirrorcnt;
+ mirrorcnt = firstmirror + 1;
+ } else if (docommit == 0) {
+ /*
+ * Save values, so uiop can be rolled
+ * back upon a write error.
+ */
+ offs = uiop->uio_offset;
+ resid = uiop->uio_resid;
+ iovbase = uiop->uio_iov->iov_base;
+ iovlen = uiop->uio_iov->iov_len;
+ m = nfsm_uiombuflist(uiop, len, NULL,
+ NULL);
+ }
+ }
+ for (i = firstmirror; i < mirrorcnt && error == 0; i++){
+ if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0)
+ dev = rflp->nfsfl_ffm[i].dev;
+ else
+ dev = rflp->nfsfl_dev;
+ dip = nfscl_getdevinfo(nmp->nm_clp, dev,
+ rflp->nfsfl_devp);
+ if (dip != NULL) {
+ if ((rflp->nfsfl_flags & NFSFL_FLEXFILE)
+ != 0)
+ error = nfscl_dofflayoutio(vp,
+ uiop, iomode, must_commit,
+ &eof, &stateid, rwaccess,
+ dip, layp, rflp, off, xfer,
+ i, docommit, m, newcred,
+ p);
+ else
+ error = nfscl_doflayoutio(vp,
+ uiop, iomode, must_commit,
+ &eof, &stateid, rwaccess,
+ dip, layp, rflp, off, xfer,
+ docommit, newcred, p);
+ nfscl_reldevinfo(dip);
+ } else
+ error = EIO;
+ }
+ if (m != NULL)
+ m_freem(m);
+ if (error == 0) {
+ if (mirrorcnt > 1 && rwaccess ==
+ NFSV4OPEN_ACCESSWRITE && docommit == 0) {
NFSLOCKCLSTATE();
- if (lastbyte > layp->nfsly_lastbyte)
- layp->nfsly_lastbyte = lastbyte;
+ layp->nfsly_flags |= NFSLY_WRITTEN;
NFSUNLOCKCLSTATE();
- } else if (error == NFSERR_OPENMODE &&
- rwaccess == NFSV4OPEN_ACCESSREAD) {
- NFSLOCKMNT(nmp);
- nmp->nm_state |= NFSSTA_OPENMODE;
- NFSUNLOCKMNT(nmp);
}
+ lastbyte = off + xfer - 1;
+ NFSLOCKCLSTATE();
+ if (lastbyte > layp->nfsly_lastbyte)
+ layp->nfsly_lastbyte = lastbyte;
+ NFSUNLOCKCLSTATE();
+ } else if (error == NFSERR_OPENMODE &&
+ rwaccess == NFSV4OPEN_ACCESSREAD) {
+ NFSLOCKMNT(nmp);
+ nmp->nm_state |= NFSSTA_OPENMODE;
+ NFSUNLOCKMNT(nmp);
} else
error = EIO;
if (error == 0)
len -= (oresid - (uint64_t)uiop->uio_resid);
+ else if (mirrorcnt > 1 && rwaccess ==
+ NFSV4OPEN_ACCESSWRITE && docommit == 0) {
+ /*
+ * In case the rpc gets retried, roll the
+ * uio fields changed by nfsm_uiombuflist()
+ * back.
+ */
+ uiop->uio_offset = offs;
+ uiop->uio_resid = resid;
+ uiop->uio_iov->iov_base = iovbase;
+ uiop->uio_iov->iov_len = iovlen;
+ }
}
}
if (lckp != NULL)
@@ -5555,6 +5719,38 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
}
/*
+ * Make a copy of the mbuf chain and add an mbuf for null padding, as required.
+ */
+static struct mbuf *
+nfsm_copym(struct mbuf *m, int off, int xfer)
+{
+ struct mbuf *m2, *m3, *m4;
+ uint32_t *tl;
+ int rem;
+
+ m2 = m_copym(m, off, xfer, M_WAITOK);
+ rem = NFSM_RNDUP(xfer) - xfer;
+ if (rem > 0) {
+ /*
+ * The zero padding to a multiple of 4 bytes is required by
+ * the XDR. So that the mbufs copied by reference aren't
+ * modified, add an mbuf with the zero'd bytes to the list.
+ * rem will be a maximum of 3, so one zero'd uint32_t is
+ * sufficient.
+ */
+ m3 = m2;
+ while (m3->m_next != NULL)
+ m3 = m3->m_next;
+ NFSMGET(m4);
+ tl = NFSMTOD(m4, uint32_t *);
+ *tl = 0;
+ mbuf_setlen(m4, rem);
+ mbuf_setnext(m3, m4);
+ }
+ return (m2);
+}
+
+/*
* Find a file layout that will handle the first bytes of the requested
* range and return the information from it needed to to the I/O operation.
*/
@@ -5659,7 +5855,7 @@ nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
if (docommit != 0) {
if (error == 0)
error = nfsrpc_commitds(vp, io_off, xfer,
- *dspp, fhp, cred, p);
+ *dspp, fhp, 0, 0, cred, p);
if (error == 0) {
/*
* Set both eof and uio_resid = 0 to end any
@@ -5674,11 +5870,11 @@ nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
}
} else if (rwflag == NFSV4OPEN_ACCESSREAD)
error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
- io_off, xfer, fhp, cred, p);
+ io_off, xfer, fhp, 0, 0, 0, cred, p);
else {
error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
- cred, p);
+ 0, 0, 0, cred, p);
if (error == 0) {
NFSLOCKCLSTATE();
lyp->nfsly_flags |= NFSLY_WRITTEN;
@@ -5696,42 +5892,174 @@ nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
}
/*
+ * Do I/O using an NFSv4.1 flex file layout.
+ */
+static int
+nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
+ int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
+ struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
+ uint64_t len, int mirror, int docommit, struct mbuf *mp, struct ucred *cred,
+ NFSPROC_T *p)
+{
+ uint64_t transfer, xfer;
+ int error, rel_off;
+ struct nfsnode *np;
+ struct nfsfh *fhp;
+ struct nfsclds **dspp;
+ struct ucred *tcred;
+ struct mbuf *m;
+
+ np = VTONFS(vp);
+ error = 0;
+ rel_off = 0;
+ NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off,
+ (uintmax_t)len);
+ /* Loop around, doing I/O for each stripe unit. */
+ while (len > 0 && error == 0) {
+ dspp = nfsfldi_addr(dp, 0);
+ fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex];
+ stateidp = &flp->nfsfl_ffm[mirror].st;
+ NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n",
+ mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid);
+ if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) {
+ tcred = NFSNEWCRED(cred);
+ tcred->cr_uid = flp->nfsfl_ffm[mirror].user;
+ tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group;
+ tcred->cr_ngroups = 1;
+ } else
+ tcred = cred;
+ if (rwflag == NFSV4OPEN_ACCESSREAD)
+ transfer = dp->nfsdi_rsize;
+ else
+ transfer = dp->nfsdi_wsize;
+ mtx_lock(&np->n_mtx);
+ np->n_flag |= NDSCOMMIT;
+ mtx_unlock(&np->n_mtx);
+ if (len > transfer && docommit == 0)
+ xfer = transfer;
+ else
+ xfer = len;
+ if (docommit != 0) {
+ if (error == 0)
+ error = nfsrpc_commitds(vp, off, xfer, *dspp,
+ fhp, dp->nfsdi_vers, dp->nfsdi_minorvers,
+ tcred, p);
+ NFSCL_DEBUG(4, "aft nfsrpc_commitds=%d\n", error);
+ if (error == 0) {
+ /*
+ * Set both eof and uio_resid = 0 to end any
+ * loops.
+ */
+ *eofp = 1;
+ uiop->uio_resid = 0;
+ } else {
+ mtx_lock(&np->n_mtx);
+ np->n_flag &= ~NDSCOMMIT;
+ mtx_unlock(&np->n_mtx);
+ }
+ } else if (rwflag == NFSV4OPEN_ACCESSREAD)
+ error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
+ off, xfer, fhp, 1, dp->nfsdi_vers,
+ dp->nfsdi_minorvers, tcred, p);
+ else {
+ if (flp->nfsfl_mirrorcnt == 1) {
+ error = nfsrpc_writeds(vp, uiop, iomode,
+ must_commit, stateidp, *dspp, off, xfer,
+ fhp, 0, 1, dp->nfsdi_vers,
+ dp->nfsdi_minorvers, tcred, p);
+ if (error == 0) {
+ NFSLOCKCLSTATE();
+ lyp->nfsly_flags |= NFSLY_WRITTEN;
+ NFSUNLOCKCLSTATE();
+ }
+ } else {
+ m = nfsm_copym(mp, rel_off, xfer);
+ NFSCL_DEBUG(4, "mcopy reloff=%d xfer=%jd\n",
+ rel_off, (uintmax_t)xfer);
+ error = nfsrpc_writedsmir(vp, iomode,
+ must_commit, stateidp, *dspp, off, xfer,
+ fhp, m, dp->nfsdi_vers, dp->nfsdi_minorvers,
+ tcred, p);
+ NFSCL_DEBUG(4, "nfsrpc_writedsmir=%d\n", error);
+ }
+ }
+ NFSCL_DEBUG(4, "aft read/writeds=%d\n", error);
+ if (error == 0) {
+ len -= xfer;
+ off += xfer;
+ rel_off += xfer;
+ }
+ if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0)
+ NFSFREECRED(tcred);
+ }
+ NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error);
+ return (error);
+}
+
+/*
* The actual read RPC done to a DS.
*/
static int
nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
- struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp,
- struct ucred *cred, NFSPROC_T *p)
+ struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex,
+ int vers, int minorvers, struct ucred *cred, NFSPROC_T *p)
{
uint32_t *tl;
- int error, retlen;
+ int attrflag, error, retlen;
struct nfsrv_descript nfsd;
struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
struct nfsrv_descript *nd = &nfsd;
struct nfssockreq *nrp;
+ struct nfsvattr na;
nd->nd_mrep = NULL;
- nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len,
- NULL, &dsp->nfsclds_sess, 0, 0);
- nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
+ if (vers == 0 || vers == NFS_VER4) {
+ nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh,
+ fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
+ vers = NFS_VER4;
+ NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers);
+ if (flex != 0)
+ nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
+ else
+ nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
+ } else {
+ nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh,
+ fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
+ NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n");
+ }
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
txdr_hyper(io_off, tl);
*(tl + 2) = txdr_unsigned(len);
nrp = dsp->nfsclds_sockp;
+ NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp);
if (nrp == NULL)
/* If NULL, use the MDS socket. */
nrp = &nmp->nm_sockreq;
error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
- NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
+ NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
+ NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat,
+ error);
if (error != 0)
return (error);
+ if (vers == NFS_VER3) {
+ error = nfscl_postop_attr(nd, &na, &attrflag, NULL);
+ NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error);
+ if (error != 0)
+ goto nfsmout;
+ }
if (nd->nd_repstat != 0) {
error = nd->nd_repstat;
goto nfsmout;
}
- NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
- *eofp = fxdr_unsigned(int, *tl);
+ if (vers == NFS_VER3) {
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ *eofp = fxdr_unsigned(int, *(tl + 1));
+ } else {
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ *eofp = fxdr_unsigned(int, *tl);
+ }
NFSM_STRSIZ(retlen, len);
+ NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp);
error = nfsm_mbufuio(nd, uiop, retlen);
nfsmout:
if (nd->nd_mrep != NULL)
@@ -5745,24 +6073,40 @@ nfsmout:
static int
nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
- struct nfsfh *fhp, int commit_thru_mds, struct ucred *cred, NFSPROC_T *p)
+ struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers,
+ struct ucred *cred, NFSPROC_T *p)
{
uint32_t *tl;
struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
- int error, rlen, commit, committed = NFSWRITE_FILESYNC;
+ int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC;
int32_t backup;
struct nfsrv_descript nfsd;
struct nfsrv_descript *nd = &nfsd;
struct nfssockreq *nrp;
+ struct nfsvattr na;
KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
nd->nd_mrep = NULL;
- nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len,
- NULL, &dsp->nfsclds_sess, 0, 0);
- nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
- NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
+ if (vers == 0 || vers == NFS_VER4) {
+ nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
+ fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
+ NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers);
+ vers = NFS_VER4;
+ if (flex != 0)
+ nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
+ else
+ nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
+ NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
+ } else {
+ nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
+ fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
+ NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n");
+ NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
+ }
txdr_hyper(io_off, tl);
tl += 2;
+ if (vers == NFS_VER3)
+ *tl++ = txdr_unsigned(len);
*tl++ = txdr_unsigned(*iomode);
*tl = txdr_unsigned(len);
nfsm_uiombuf(nd, uiop, len);
@@ -5771,7 +6115,9 @@ nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
/* If NULL, use the MDS socket. */
nrp = &nmp->nm_sockreq;
error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
- NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
+ NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
+ NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error,
+ nd->nd_repstat);
if (error != 0)
return (error);
if (nd->nd_repstat != 0) {
@@ -5786,8 +6132,16 @@ nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
uio_iov_len_add(uiop, len);
error = nd->nd_repstat;
} else {
+ if (vers == NFS_VER3) {
+ error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
+ NULL);
+ NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error);
+ if (error != 0)
+ goto nfsmout;
+ }
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
rlen = fxdr_unsigned(int, *tl++);
+ NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen);
if (rlen == 0) {
error = NFSERR_IO;
goto nfsmout;
@@ -5842,6 +6196,117 @@ nfsmout:
}
/*
+ * The actual write RPC done to a DS.
+ * This variant is called from a separate kernel process for mirrors.
+ * Any short write is considered an IO error.
+ */
+static int
+nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit,
+ nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
+ struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers,
+ struct ucred *cred, NFSPROC_T *p)
+{
+ uint32_t *tl;
+ struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
+ int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen;
+ struct nfsrv_descript nfsd;
+ struct nfsrv_descript *nd = &nfsd;
+ struct nfssockreq *nrp;
+ struct nfsvattr na;
+
+ nd->nd_mrep = NULL;
+ if (vers == 0 || vers == NFS_VER4) {
+ nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
+ fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
+ vers = NFS_VER4;
+ NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n",
+ minorvers);
+ nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
+ NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
+ } else {
+ nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
+ fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
+ NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n");
+ NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
+ }
+ txdr_hyper(io_off, tl);
+ tl += 2;
+ if (vers == NFS_VER3)
+ *tl++ = txdr_unsigned(len);
+ *tl++ = txdr_unsigned(*iomode);
+ *tl = txdr_unsigned(len);
+ if (len > 0) {
+ /* Put data in mbuf chain. */
+ nd->nd_mb->m_next = m;
+ /* Set nd_mb and nd_bpos to end of data. */
+ while (m->m_next != NULL)
+ m = m->m_next;
+ nd->nd_mb = m;
+ nd->nd_bpos = mtod(m, char *) + m->m_len;
+ NFSCL_DEBUG(4, "nfsrpc_writedsmir: lastmb len=%d\n", m->m_len);
+ }
+ nrp = dsp->nfsclds_sockp;
+ if (nrp == NULL)
+ /* If NULL, use the MDS socket. */
+ nrp = &nmp->nm_sockreq;
+ error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
+ NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
+ NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error,
+ nd->nd_repstat);
+ if (error != 0)
+ return (error);
+ if (nd->nd_repstat != 0)
+ error = nd->nd_repstat;
+ else {
+ if (vers == NFS_VER3) {
+ error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
+ NULL);
+ NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n",
+ error);
+ if (error != 0)
+ goto nfsmout;
+ }
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
+ rlen = fxdr_unsigned(int, *tl++);
+ NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len,
+ rlen);
+ if (rlen != len) {
+ error = NFSERR_IO;
+ NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n",
+ len, rlen);
+ goto nfsmout;
+ }
+ commit = fxdr_unsigned(int, *tl++);
+
+ /*
+ * Return the lowest commitment level
+ * obtained by any of the RPCs.
+ */
+ if (committed == NFSWRITE_FILESYNC)
+ committed = commit;
+ else if (committed == NFSWRITE_DATASYNC &&
+ commit == NFSWRITE_UNSTABLE)
+ committed = commit;
+ NFSLOCKDS(dsp);
+ if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
+ NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
+ dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
+ } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
+ *must_commit = 1;
+ NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
+ }
+ NFSUNLOCKDS(dsp);
+ }
+nfsmout:
+ if (nd->nd_mrep != NULL)
+ mbuf_freem(nd->nd_mrep);
+ *iomode = committed;
+ if (nd->nd_repstat != 0 && error == 0)
+ error = nd->nd_repstat;
+ return (error);
+}
+
+/*
* Free up the nfsclds structure.
*/
void
@@ -5913,17 +6378,26 @@ nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
*/
static int
nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
- struct nfsfh *fhp, struct ucred *cred, NFSPROC_T *p)
+ struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred,
+ NFSPROC_T *p)
{
uint32_t *tl;
struct nfsrv_descript nfsd, *nd = &nfsd;
struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
struct nfssockreq *nrp;
- int error;
+ struct nfsvattr na;
+ int attrflag, error;
nd->nd_mrep = NULL;
- nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len,
- NULL, &dsp->nfsclds_sess, 0, 0);
+ if (vers == 0 || vers == NFS_VER4) {
+ nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh,
+ fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
+ vers = NFS_VER4;
+ } else
+ nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh,
+ fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
+ NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers,
+ minorvers);
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
txdr_hyper(offset, tl);
tl += 2;
@@ -5933,10 +6407,19 @@ nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
/* If NULL, use the MDS socket. */
nrp = &nmp->nm_sockreq;
error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
- NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
+ NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
+ NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error,
+ nd->nd_repstat);
if (error != 0)
return (error);
if (nd->nd_repstat == 0) {
+ if (vers == NFS_VER3) {
+ error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
+ NULL);
+ NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error);
+ if (error != 0)
+ goto nfsmout;
+ }
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
NFSLOCKDS(dsp);
if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
@@ -5957,15 +6440,15 @@ nfsmout:
*/
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)
+ uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype,
+ 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(layouttype);
*tl++ = txdr_unsigned(iomode);
txdr_hyper(offset, tl);
tl += 2;
@@ -5998,11 +6481,15 @@ nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp,
{
uint32_t *tl;
struct nfsclflayout *flp, *prevflp, *tflp;
- int cnt, error, gotiomode, fhcnt, nfhlen, i, j;
- uint64_t retlen;
+ int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen;
+ int m, mirrorcnt;
+ uint64_t retlen, off;
struct nfsfh *nfhp;
uint8_t *cp;
+ uid_t user;
+ gid_t grp;
+ NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n");
error = 0;
flp = NULL;
gotiomode = -1;
@@ -6025,64 +6512,204 @@ nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp,
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;
+ /* Dissect to the layout type. */
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER +
+ 3 * NFSX_UNSIGNED);
+ 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) {
+ iomode = fxdr_unsigned(int, *tl++);
+ laytype = fxdr_unsigned(int, *tl);
+ NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype,
+ (uintmax_t)off, (uintmax_t)retlen, iomode);
+ /* Ignore length of layout body for now. */
+ if (laytype == NFSLAYOUT_NFSV4_1_FILES) {
+ /* Parse the File layout up to fhcnt. */
+ NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED +
+ NFSX_HYPER + NFSX_V4DEVICEID);
+ fhcnt = fxdr_unsigned(int, *(tl + 4 +
+ 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 > 0)
+ flp = malloc(sizeof(*flp) + fhcnt *
+ sizeof(struct nfsfh *), M_NFSFLAYOUT,
+ M_WAITOK);
+ else
+ flp = malloc(sizeof(*flp), M_NFSFLAYOUT,
+ M_WAITOK);
+ flp->nfsfl_flags = NFSFL_FILE;
+ flp->nfsfl_fhcnt = 0;
+ flp->nfsfl_devp = NULL;
+ flp->nfsfl_off = off;
+ 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 = iomode;
+ if (gotiomode == -1)
+ gotiomode = flp->nfsfl_iomode;
+ /* Ignore layout body length for now. */
+ 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;
+ NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n",
+ flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff);
+ 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);
+ }
+ } else if (laytype == NFSLAYOUT_FLEXFILE) {
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED +
+ NFSX_HYPER);
+ mirrorcnt = fxdr_unsigned(int, *(tl + 2));
+ NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt);
+ if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) {
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);
+ flp = malloc(sizeof(*flp) + mirrorcnt *
+ sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK);
+ flp->nfsfl_flags = NFSFL_FLEXFILE;
+ flp->nfsfl_mirrorcnt = mirrorcnt;
+ flp->nfsfl_devp = NULL;
+ flp->nfsfl_off = off;
+ 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 = iomode;
+ if (gotiomode == -1)
+ gotiomode = flp->nfsfl_iomode;
+ flp->nfsfl_stripeunit = fxdr_hyper(tl);
+ NFSCL_DEBUG(4, "stripeunit=%ju\n",
+ (uintmax_t)flp->nfsfl_stripeunit);
+ for (j = 0; j < mirrorcnt; j++) {
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ k = fxdr_unsigned(int, *tl);
+ if (k < 1 || k > 128) {
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ NFSCL_DEBUG(4, "servercnt=%d\n", k);
+ for (l = 0; l < k; l++) {
+ NFSM_DISSECT(tl, uint32_t *,
+ NFSX_V4DEVICEID + NFSX_STATEID +
+ 2 * NFSX_UNSIGNED);
+ if (l == 0) {
+ /* Just use the first server. */
+ NFSBCOPY(tl,
+ flp->nfsfl_ffm[j].dev,
+ NFSX_V4DEVICEID);
+ tl += (NFSX_V4DEVICEID /
+ NFSX_UNSIGNED);
+ tl++;
+ flp->nfsfl_ffm[j].st.seqid =
+ *tl++;
+ flp->nfsfl_ffm[j].st.other[0] =
+ *tl++;
+ flp->nfsfl_ffm[j].st.other[1] =
+ *tl++;
+ flp->nfsfl_ffm[j].st.other[2] =
+ *tl++;
+ NFSCL_DEBUG(4, "st.seqid=%u "
+ "st.o0=0x%x st.o1=0x%x "
+ "st.o2=0x%x\n",
+ flp->nfsfl_ffm[j].st.seqid,
+ flp->nfsfl_ffm[j].st.other[0],
+ flp->nfsfl_ffm[j].st.other[1],
+ flp->nfsfl_ffm[j].st.other[2]);
+ } else
+ tl += ((NFSX_V4DEVICEID +
+ NFSX_STATEID +
+ NFSX_UNSIGNED) /
+ NFSX_UNSIGNED);
+ fhcnt = fxdr_unsigned(int, *tl);
+ NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
+ if (fhcnt < 1 ||
+ fhcnt > NFSDEV_MAXVERS) {
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ for (m = 0; m < fhcnt; m++) {
+ NFSM_DISSECT(tl, uint32_t *,
+ NFSX_UNSIGNED);
+ nfhlen = fxdr_unsigned(int,
+ *tl);
+ NFSCL_DEBUG(4, "nfhlen=%d\n",
+ nfhlen);
+ if (nfhlen <= 0 || nfhlen >
+ NFSX_V4FHMAX) {
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ NFSM_DISSECT(cp, uint8_t *,
+ NFSM_RNDUP(nfhlen));
+ if (l == 0) {
+ flp->nfsfl_ffm[j].fhcnt
+ = fhcnt;
+ nfhp = malloc(
+ sizeof(*nfhp) +
+ nfhlen - 1, M_NFSFH,
+ M_WAITOK);
+ flp->nfsfl_ffm[j].fh[m]
+ = nfhp;
+ nfhp->nfh_len = nfhlen;
+ NFSBCOPY(cp,
+ nfhp->nfh_fh,
+ nfhlen);
+ NFSCL_DEBUG(4,
+ "got fh\n");
+ }
+ }
+ /* Now, get the ffsd_user/ffds_group. */
+ error = nfsrv_parseug(nd, 0, &user,
+ &grp, curthread);
+ NFSCL_DEBUG(4, "after parseu=%d\n",
+ error);
+ if (error == 0)
+ error = nfsrv_parseug(nd, 1,
+ &user, &grp, curthread);
+ NFSCL_DEBUG(4, "aft parseg=%d\n",
+ grp);
+ if (error != 0)
+ goto nfsmout;
+ NFSCL_DEBUG(4, "user=%d group=%d\n",
+ user, grp);
+ if (l == 0) {
+ flp->nfsfl_ffm[j].user = user;
+ flp->nfsfl_ffm[j].group = grp;
+ NFSCL_DEBUG(4,
+ "usr=%d grp=%d\n", user,
+ grp);
+ }
+ }
+ }
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++);
+ flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl);
+ NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n",
+ flp->nfsfl_fflags, flp->nfsfl_statshint);
+ } else {
+ error = NFSERR_BADXDR;
+ goto nfsmout;
}
if (flp->nfsfl_iomode == gotiomode) {
/* Keep the list in increasing offset order. */
@@ -6098,6 +6725,7 @@ nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp,
else
LIST_INSERT_AFTER(prevflp, flp,
nfsfl_list);
+ NFSCL_DEBUG(4, "flp inserted\n");
} else {
printf("nfscl_layoutget(): got wrong iomode\n");
nfscl_freeflayout(flp);
@@ -6105,12 +6733,58 @@ nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp,
flp = NULL;
}
nfsmout:
+ NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error);
if (error != 0 && flp != NULL)
nfscl_freeflayout(flp);
return (error);
}
/*
+ * Parse a user/group digit string.
+ */
+static int
+nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp,
+ NFSPROC_T *p)
+{
+ uint32_t *tl;
+ char *cp, *str, str0[NFSV4_SMALLSTR + 1];
+ uint32_t len = 0;
+ int error = 0;
+
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ len = fxdr_unsigned(uint32_t, *tl);
+ if (len > NFSV4_OPAQUELIMIT) {
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len);
+ if (len == 0) {
+ if (dogrp != 0)
+ *gidp = GID_NOGROUP;
+ else
+ *uidp = UID_NOBODY;
+ return (0);
+ }
+ if (len > NFSV4_SMALLSTR)
+ str = malloc(len + 1, M_TEMP, M_WAITOK);
+ else
+ str = str0;
+ NFSM_DISSECT(cp, char *, NFSM_RNDUP(len));
+ NFSBCOPY(cp, str, len);
+ str[len] = '\0';
+ NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str);
+ if (dogrp != 0)
+ error = nfsv4_strtogid(nd, str, len, gidp, p);
+ else
+ error = nfsv4_strtouid(nd, str, len, uidp, p);
+nfsmout:
+ if (len > NFSV4_SMALLSTR)
+ free(str, M_TEMP);
+ NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error);
+ return (error);
+}
+
+/*
* Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(),
* so that it does both an Open and a Layoutget.
*/
@@ -6124,11 +6798,15 @@ nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
struct nfsclflayout *flp;
struct nfsclflayouthead flh;
int error, islocked, layoutlen, recalled, retonclose, usecurstateid;
- int laystat;
+ int layouttype, laystat;
nfsv4stateid_t stateid;
struct nfsclsession *tsep;
error = 0;
+ if (NFSHASFLEXFILE(nmp))
+ layouttype = NFSLAYOUT_FLEXFILE;
+ else
+ layouttype = NFSLAYOUT_NFSV4_1_FILES;
/*
* 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
@@ -6159,13 +6837,13 @@ nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
}
error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen,
newfhp, newfhlen, mode, op, name, namelen,
- dpp, &stateid, usecurstateid, layoutlen,
+ dpp, &stateid, usecurstateid, layouttype, 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);
+ &stateid, retonclose, NULL, &lyp, &flh, layouttype, 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);
@@ -6187,7 +6865,7 @@ 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,
+ nfsv4stateid_t *stateidp, int usecurstateid, int layouttype,
int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp,
int *laystatp, struct ucred *cred, NFSPROC_T *p)
{
@@ -6229,7 +6907,7 @@ nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
else
iomode = NFSLAYOUTIOMODE_READ;
nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp,
- layoutlen, usecurstateid);
+ layouttype, 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)
@@ -6363,7 +7041,7 @@ nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
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,
+ int usecurstateid, int layouttype, int layoutlen, int *retonclosep,
struct nfsclflayouthead *flhp, int *laystatp)
{
uint32_t *tl;
@@ -6442,7 +7120,7 @@ nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
*tl++ = txdr_unsigned(NFSV4OP_RESTOREFH);
*tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp,
- layoutlen, usecurstateid);
+ layouttype, layoutlen, usecurstateid);
error = nfscl_request(nd, dvp, p, cred, dstuff);
if (error != 0)
return (error);
@@ -6628,17 +7306,21 @@ nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
struct nfsclsession *tsep;
struct nfsmount *nmp;
nfsv4stateid_t stateid;
- int error, layoutlen, retonclose, laystat;
+ int error, layoutlen, layouttype, retonclose, laystat;
error = 0;
nmp = VFSTONFS(dvp->v_mount);
+ if (NFSHASFLEXFILE(nmp))
+ layouttype = NFSLAYOUT_FLEXFILE;
+ else
+ layouttype = NFSLAYOUT_NFSV4_1_FILES;
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);
+ dstuff, unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose,
+ &flh, &laystat);
NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n",
laystat, error);
lyp = NULL;
@@ -6646,10 +7328,11 @@ nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
nfhp = *nfhpp;
laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh,
nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh,
- laystat, NULL, cred, p);
+ layouttype, laystat, NULL, cred, p);
} else
laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid,
- retonclose, NULL, &lyp, &flh, laystat, NULL, cred, p);
+ retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL,
+ cred, p);
if (laystat == 0)
nfscl_rellayout(lyp, 0);
return (error);
@@ -6661,17 +7344,23 @@ nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
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,
+ struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype,
int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p)
{
struct nfsclflayout *tflp;
struct nfscldevinfo *dip;
+ uint8_t *dev;
if (laystat == NFSERR_UNKNLAYOUTTYPE) {
- /* Disable PNFS. */
- NFSCL_DEBUG(1, "disable PNFS\n");
NFSLOCKMNT(nmp);
- nmp->nm_state &= ~NFSSTA_PNFS;
+ if (!NFSHASFLEXFILE(nmp)) {
+ /* Switch to using Flex File Layout. */
+ nmp->nm_state |= NFSSTA_FLEXFILE;
+ } else if (layouttype == NFSLAYOUT_FLEXFILE) {
+ /* Disable pNFS. */
+ NFSCL_DEBUG(1, "disable PNFS\n");
+ nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE);
+ }
NFSUNLOCKMNT(nmp);
}
if (laystat == 0) {
@@ -6680,9 +7369,12 @@ nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp,
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);
+ if (layouttype == NFSLAYOUT_FLEXFILE)
+ dev = tflp->nfsfl_ffm[0].dev;
+ else
+ dev = tflp->nfsfl_dev;
+ laystat = nfsrpc_getdeviceinfo(nmp, dev,
+ layouttype, notifybit, &dip, cred, p);
NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n",
laystat);
if (laystat != 0)
@@ -6701,7 +7393,7 @@ nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp,
* get the fsid for the file system.
*/
laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp,
- retonclose, flhp, lypp, cred, p);
+ layouttype, retonclose, flhp, lypp, cred, p);
NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n",
laystat);
if (laystat == 0 && islockedp != NULL)
diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index e0687eeaf8bf..cedc157b0dac 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -4783,7 +4783,7 @@ nfscl_errmap(struct nfsrv_descript *nd, u_int32_t minorvers)
*/
APPLESTATIC int
nfscl_layout(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen,
- nfsv4stateid_t *stateidp, int retonclose,
+ nfsv4stateid_t *stateidp, int layouttype, int retonclose,
struct nfsclflayouthead *fhlp, struct nfscllayout **lypp,
struct ucred *cred, NFSPROC_T *p)
{
@@ -4835,8 +4835,12 @@ nfscl_layout(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen,
lyp->nfsly_filesid[0] = np->n_vattr.na_filesid[0];
lyp->nfsly_filesid[1] = np->n_vattr.na_filesid[1];
lyp->nfsly_clp = clp;
- lyp->nfsly_flags = (retonclose != 0) ?
- (NFSLY_FILES | NFSLY_RETONCLOSE) : NFSLY_FILES;
+ if (layouttype == NFSLAYOUT_FLEXFILE)
+ lyp->nfsly_flags = NFSLY_FLEXFILE;
+ else
+ lyp->nfsly_flags = NFSLY_FILES;
+ if (retonclose != 0)
+ lyp->nfsly_flags |= NFSLY_RETONCLOSE;
lyp->nfsly_fhlen = fhlen;
NFSBCOPY(fhp, lyp->nfsly_fh, fhlen);
TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list);
@@ -5079,6 +5083,7 @@ nfscl_adddevinfo(struct nfsmount *nmp, struct nfscldevinfo *dip,
{
struct nfsclclient *clp;
struct nfscldevinfo *tdip;
+ uint8_t *dev;
NFSLOCKCLSTATE();
clp = nmp->nm_clp;
@@ -5088,7 +5093,11 @@ nfscl_adddevinfo(struct nfsmount *nmp, struct nfscldevinfo *dip,
free(dip, M_NFSDEVINFO);
return (ENODEV);
}
- tdip = nfscl_finddevinfo(clp, flp->nfsfl_dev);
+ if ((flp->nfsfl_flags & NFSFL_FILE) != 0)
+ dev = flp->nfsfl_dev;
+ else
+ dev = flp->nfsfl_ffm[0].dev;
+ tdip = nfscl_finddevinfo(clp, dev);
if (tdip != NULL) {
tdip->nfsdi_layoutrefs++;
flp->nfsfl_devp = tdip;
@@ -5140,10 +5149,15 @@ nfscl_freelayout(struct nfscllayout *layp)
APPLESTATIC void
nfscl_freeflayout(struct nfsclflayout *flp)
{
- int i;
-
- for (i = 0; i < flp->nfsfl_fhcnt; i++)
- free(flp->nfsfl_fh[i], M_NFSFH);
+ int i, j;
+
+ if ((flp->nfsfl_flags & NFSFL_FILE) != 0)
+ for (i = 0; i < flp->nfsfl_fhcnt; i++)
+ free(flp->nfsfl_fh[i], M_NFSFH);
+ if ((flp->nfsfl_flags & NFSFL_FLEXFILE) != 0)
+ for (i = 0; i < flp->nfsfl_mirrorcnt; i++)
+ for (j = 0; j < flp->nfsfl_ffm[i].fhcnt; j++)
+ free(flp->nfsfl_ffm[i].fh[j], M_NFSFH);
if (flp->nfsfl_devp != NULL)
flp->nfsfl_devp->nfsdi_layoutrefs--;
free(flp, M_NFSFLAYOUT);
@@ -5235,12 +5249,17 @@ nfscl_layoutreturn(struct nfsmount *nmp, struct nfscllayout *lyp,
{
struct nfsclrecalllayout *rp;
nfsv4stateid_t stateid;
+ int layouttype;
NFSBCOPY(lyp->nfsly_stateid.other, stateid.other, NFSX_STATEIDOTHER);
stateid.seqid = lyp->nfsly_stateid.seqid;
+ if ((lyp->nfsly_flags & NFSLY_FILES) != 0)
+ layouttype = NFSLAYOUT_NFSV4_1_FILES;
+ else
+ layouttype = NFSLAYOUT_FLEXFILE;
LIST_FOREACH(rp, &lyp->nfsly_recall, nfsrecly_list) {
(void)nfsrpc_layoutreturn(nmp, lyp->nfsly_fh,
- lyp->nfsly_fhlen, 0, NFSLAYOUT_NFSV4_1_FILES,
+ lyp->nfsly_fhlen, 0, layouttype,
rp->nfsrecly_iomode, rp->nfsrecly_recalltype,
rp->nfsrecly_off, rp->nfsrecly_len,
&stateid, cred, p, NULL);
@@ -5256,15 +5275,27 @@ nfscl_dolayoutcommit(struct nfsmount *nmp, struct nfscllayout *lyp,
{
struct nfsclflayout *flp;
uint64_t len;
- int error;
+ int error, layouttype;
+ if ((lyp->nfsly_flags & NFSLY_FILES) != 0)
+ layouttype = NFSLAYOUT_NFSV4_1_FILES;
+ else
+ layouttype = NFSLAYOUT_FLEXFILE;
LIST_FOREACH(flp, &lyp->nfsly_flayrw, nfsfl_list) {
- if (flp->nfsfl_off <= lyp->nfsly_lastbyte) {
+ if (layouttype == NFSLAYOUT_FLEXFILE &&
+ (flp->nfsfl_fflags & NFSFLEXFLAG_NO_LAYOUTCOMMIT) != 0) {
+ NFSCL_DEBUG(4, "Flex file: no layoutcommit\n");
+ /* If not supported, don't bother doing it. */
+ NFSLOCKMNT(nmp);
+ nmp->nm_state |= NFSSTA_NOLAYOUTCOMMIT;
+ NFSUNLOCKMNT(nmp);
+ break;
+ } else if (flp->nfsfl_off <= lyp->nfsly_lastbyte) {
len = flp->nfsfl_end - flp->nfsfl_off;
error = nfsrpc_layoutcommit(nmp, lyp->nfsly_fh,
lyp->nfsly_fhlen, 0, flp->nfsfl_off, len,
lyp->nfsly_lastbyte, &lyp->nfsly_stateid,
- NFSLAYOUT_NFSV4_1_FILES, cred, p, NULL);
+ layouttype, cred, p, NULL);
NFSCL_DEBUG(4, "layoutcommit err=%d\n", error);
if (error == NFSERR_NOTSUPP) {
/* If not supported, don't bother doing it. */