Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Apr 2017 22:03:08 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r317528 - projects/pnfs-planb-server/sys/fs/nfsserver
Message-ID:  <201704272203.v3RM38RA092559@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Thu Apr 27 22:03:08 2017
New Revision: 317528
URL: https://svnweb.freebsd.org/changeset/base/317528

Log:
  Update nfs_nfsdstate.c with the pNFS server code.

Modified:
  projects/pnfs-planb-server/sys/fs/nfsserver/nfs_nfsdstate.c

Modified: projects/pnfs-planb-server/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- projects/pnfs-planb-server/sys/fs/nfsserver/nfs_nfsdstate.c	Thu Apr 27 22:00:03 2017	(r317527)
+++ projects/pnfs-planb-server/sys/fs/nfsserver/nfs_nfsdstate.c	Thu Apr 27 22:03:08 2017	(r317528)
@@ -41,6 +41,9 @@ extern struct nfsstatsv1 nfsstatsv1;
 extern int nfsrv_lease;
 extern struct timeval nfsboottime;
 extern u_int32_t newnfs_true, newnfs_false;
+extern struct mtx nfsrv_dslock_mtx;
+extern int nfsd_debuglevel;
+extern u_int nfsrv_dsdirsize;
 NFSV4ROOTLOCKMUTEX;
 NFSSTATESPINLOCK;
 
@@ -65,6 +68,11 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, sessionh
     &nfsrv_sessionhashsize, 0,
     "Size of session hash table set via loader.conf");
 
+int	nfsrv_layouthashsize = NFSLAYOUTHASHSIZE;
+SYSCTL_INT(_vfs_nfsd, OID_AUTO, layouthashsize, CTLFLAG_RDTUN,
+    &nfsrv_layouthashsize, 0,
+    "Size of layout hash table set via loader.conf");
+
 static int	nfsrv_v4statelimit = NFSRV_V4STATELIMIT;
 SYSCTL_INT(_vfs_nfsd, OID_AUTO, v4statelimit, CTLFLAG_RWTUN,
     &nfsrv_v4statelimit, 0,
@@ -86,6 +94,7 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, allowrea
 struct nfsclienthashhead	*nfsclienthash;
 struct nfslockhashhead		*nfslockhash;
 struct nfssessionhash		*nfssessionhash;
+struct nfslayouthash		*nfslayouthash;
 #endif	/* !APPLEKEXT */
 
 static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0;
@@ -165,6 +174,16 @@ static int nfsrv_freesession(struct nfsd
 static int nfsv4_setcbsequence(struct nfsrv_descript *nd, struct nfsclient *clp,
     int dont_replycache, struct nfsdsession **sepp);
 static int nfsv4_getcbsession(struct nfsclient *clp, struct nfsdsession **sepp);
+static int nfsrv_addlayout(struct nfsrv_descript *nd, struct nfslayout **lypp,
+    nfsv4stateid_t *stateidp, char *layp, int *layoutlenp, NFSPROC_T *p);
+static void nfsrv_freelayout(struct nfslayout *lyp);
+static void nfsrv_freelayoutlist(nfsquad_t clientid);
+static void nfsrv_freealllayouts(int *fndp);
+static void nfsrv_freedevid(struct nfsdevice *ds);
+static int nfsrv_setdsserver(char *dspathp, NFSPROC_T *p,
+    struct nfsdevice **dsp);
+static void nfsrv_allocdevid(struct nfsdevice *ds, char *addr, char *dnshost);
+static void nfsrv_freealldevids(void);
 
 /*
  * Scan the client list for a match and either return the current one,
@@ -723,6 +742,12 @@ nfsrv_destroyclient(nfsquad_t clientid, 
 		goto out;
 	}
 
+	/*
+	 * Free up all layouts on the clientid.  Should the client return the
+	 * layouts?
+	 */
+	nfsrv_freelayoutlist(clientid);
+
 	/* Scan for state on the clientid. */
 	for (i = 0; i < nfsrv_statehashsize; i++)
 		if (!LIST_EMPTY(&clp->lc_stateid[i])) {
@@ -5281,8 +5306,7 @@ out:
  */
 APPLESTATIC int
 nfsrv_checkgetattr(struct nfsrv_descript *nd, vnode_t vp,
-    struct nfsvattr *nvap, nfsattrbit_t *attrbitp, struct ucred *cred,
-    NFSPROC_T *p)
+    struct nfsvattr *nvap, nfsattrbit_t *attrbitp, NFSPROC_T *p)
 {
 	struct nfsstate *stp;
 	struct nfslockfile *lfp;
@@ -5364,7 +5388,7 @@ nfsrv_checkgetattr(struct nfsrv_descript
 			    nva.na_filerev > delegfilerev) ||
 			    (NFSVNO_ISSETSIZE(&nva) &&
 			     nva.na_size != nvap->na_size)) {
-				error = nfsvno_updfilerev(vp, nvap, cred, p);
+				error = nfsvno_updfilerev(vp, nvap, nd, p);
 				if (NFSVNO_ISSETSIZE(&nva))
 					nvap->na_size = nva.na_size;
 			}
@@ -5792,6 +5816,9 @@ nfsrv_throwawayallstate(NFSPROC_T *p)
 			nfsrv_freenfslockfile(lfp);
 		}
 	}
+
+	/* And get rid of the deviceid structures and layouts. */
+	nfsrv_freealllayoutsanddevids();
 }
 
 /*
@@ -6126,3 +6153,631 @@ nfsrv_freeallbackchannel_xprts(void)
 	}
 }
 
+/*
+ * Do a layout commit.  Actually just call nfsrv_updatemdsattr().
+ * I have no idea if the rest of these arguments will ever be useful?
+ */
+int
+nfsrv_layoutcommit(struct nfsrv_descript *nd, vnode_t vp, int layouttype,
+    int hasnewoff, uint64_t newoff, uint64_t offset, uint64_t len,
+    int hasnewmtime, struct timespec *newmtimep, int reclaim,
+    nfsv4stateid_t *stateidp, int maxcnt, char *layp, int *hasnewsizep,
+    uint64_t *newsizep, struct ucred *cred, NFSPROC_T *p)
+{
+	struct nfsvattr na;
+	int error;
+
+	error = nfsrv_updatemdsattr(vp, &na, p);
+	if (error == 0) {
+		*hasnewsizep = 1;
+		*newsizep = na.na_size;
+	}
+	return (error);
+}
+
+/*
+ * Try and get a layout.
+ */
+int
+nfsrv_layoutget(struct nfsrv_descript *nd, vnode_t vp, struct nfsexstuff *exp,
+    int layouttype, int *iomode, uint64_t *offset, uint64_t *len,
+    uint64_t minlen, nfsv4stateid_t *stateidp, int maxcnt, int *retonclose,
+    int *layoutlenp, char *layp, struct ucred *cred, NFSPROC_T *p)
+{
+	uint32_t *tl;
+	struct nfslayouthash *lhyp;
+	struct nfslayout *lyp;
+	char devid[NFSX_V4DEVICEID];
+	fhandle_t fh, dsfh;
+	uint64_t pattern_offset;
+	int error;
+
+	if (layouttype != NFSLAYOUT_NFSV4_1_FILES)
+		return (NFSERR_UNKNLAYOUTTYPE);
+	if (maxcnt < NFSX_V4FILELAYOUT)
+		return (NFSERR_TOOSMALL);
+	NFSDDSLOCK();
+	if (TAILQ_EMPTY(&nfsrv_devidhead)) {
+		NFSDDSUNLOCK();
+		return (NFSERR_LAYOUTTRYLATER);
+	}
+	NFSDDSUNLOCK();
+
+	if (*offset != 0 || *len != UINT64_MAX)
+		printf("nfsrv_layoutget: off=%ju len=%ju\n", (uintmax_t)*offset,
+		    (uintmax_t)*len);
+	error = nfsvno_getfh(vp, &fh, p);
+	NFSD_DEBUG(4, "layoutget getfh=%d\n", error);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * For now, all layouts are for entire files.
+	 * Only issue Read/Write layouts if requested for a non-readonly fs.
+	 */
+	if (NFSVNO_EXRDONLY(exp)) {
+		if (*iomode == NFSLAYOUTIOMODE_RW)
+			return (NFSERR_LAYOUTTRYLATER);
+		*iomode = NFSLAYOUTIOMODE_READ;
+	}
+	if (*iomode != NFSLAYOUTIOMODE_RW)
+		*iomode = NFSLAYOUTIOMODE_READ;
+
+	*retonclose = 0;
+	*offset = 0;
+	*len = UINT64_MAX;
+
+	/* First, see if a layout already exists and return if found. */
+	lhyp = NFSLAYOUTHASH(&fh);
+	NFSLOCKLAYOUT(lhyp);
+	error = nfsrv_findlayout(nd, &fh, p, &lyp);
+	NFSD_DEBUG(4, "layoutget findlay=%d\n", error);
+	if (error == 0) {
+		if (*iomode == NFSLAYOUTIOMODE_RW)
+			lyp->lay_rw = 1;
+		else
+			lyp->lay_read = 1;
+		NFSBCOPY(lyp->lay_xdr, layp, lyp->lay_layoutlen);
+		*layoutlenp = lyp->lay_layoutlen;
+		if (++lyp->lay_stateid.seqid == 0)
+			lyp->lay_stateid.seqid = 1;
+		stateidp->seqid = lyp->lay_stateid.seqid;
+		stateidp->other[0] = lyp->lay_stateid.other[0];
+		stateidp->other[1] = lyp->lay_stateid.other[1];
+		stateidp->other[2] = lyp->lay_stateid.other[2];
+		NFSUNLOCKLAYOUT(lhyp);
+		NFSD_DEBUG(4, "ret fnd layout\n");
+		return (0);
+	}
+	NFSUNLOCKLAYOUT(lhyp);
+
+	/* Find the device id and file handle. */
+	error = nfsrv_dsgetdevandfh(vp, p, &dsfh, devid);
+	NFSD_DEBUG(4, "layoutget devandfh=%d\n", error);
+	if (error != 0)
+		return (error);
+
+	lyp = malloc(sizeof(struct nfslayout) + NFSX_V4FILELAYOUT, M_NFSDSTATE,
+	    M_WAITOK | M_ZERO);
+	if (*iomode == NFSLAYOUTIOMODE_RW)
+		lyp->lay_rw = 1;
+	else
+		lyp->lay_read = 1;
+	NFSBCOPY(&fh, &lyp->lay_fh, sizeof(fh));
+	lyp->lay_clientid.qval = nd->nd_clientid.qval;
+
+	/* Fill in the xdr for the files layout. */
+	tl = (uint32_t *)lyp->lay_xdr;
+	NFSBCOPY(devid, tl, NFSX_V4DEVICEID);		/* Device ID. */
+	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
+	*tl++ = txdr_unsigned(NFSFLAYUTIL_STRIPE_MASK);	/* Max stripe size. */
+	*tl++ = 0;					/* 1st stripe index. */
+	pattern_offset = 0;
+	txdr_hyper(pattern_offset, tl); tl += 2;	/* Pattern offset. */
+	*tl++ = txdr_unsigned(1);			/* 1 file handle. */
+	*tl++ = txdr_unsigned(NFSX_V4PNFSFH);
+	NFSBCOPY(&dsfh, tl, sizeof(dsfh));
+	lyp->lay_layoutlen = NFSX_V4FILELAYOUT;
+
+	/*
+	 * Now, add this layout to the list.
+	 */
+	error = nfsrv_addlayout(nd, &lyp, stateidp, layp, layoutlenp, p);
+	NFSD_DEBUG(4, "layoutget addl=%d\n", error);
+	/*
+	 * The lyp will be set to NULL by nfsrv_addlayout() if it
+	 * linked the new structure into the lists.
+	 */
+	free(lyp, M_NFSDSTATE);
+	return (error);
+}
+
+/*
+ * Try and return layout(s).
+ */
+int
+nfsrv_layoutreturn(struct nfsrv_descript *nd, vnode_t vp,
+    int layouttype, int iomode, uint64_t offset, uint64_t len, int reclaim,
+    int kind, nfsv4stateid_t *stateidp, int maxcnt, char *layp, int *fndp,
+    struct ucred *cred, NFSPROC_T *p)
+{
+	struct nfsvattr na;
+	struct nfslayouthash *lhyp;
+	struct nfslayout *lyp;
+	fhandle_t fh;
+	int error = 0;
+
+	if (kind == NFSV4LAYOUTRET_FILE) {
+		*fndp = 0;
+		error = nfsvno_getfh(vp, &fh, p);
+		if (error == 0 && (iomode & NFSLAYOUTIOMODE_RW) != 0) {
+			error = nfsrv_updatemdsattr(vp, &na, p);
+			if (error != 0)
+				printf("nfsrv_layoutreturn: updatemdsattr"
+				    " failed=%d\n", error);
+		}
+		if (error == 0) {
+			lhyp = NFSLAYOUTHASH(&fh);
+			NFSLOCKLAYOUT(lhyp);
+			error = nfsrv_findlayout(nd, &fh, p, &lyp);
+			NFSD_DEBUG(4, "layoutret findlay=%d\n", error);
+			if (error == 0) {
+				NFSD_DEBUG(4, "nfsrv_layoutreturn: stateid %d"
+				    " %x %x %x laystateid %d %x %x %x"
+				    " off=%ju len=%ju rd=%d rw=%d\n",
+				    stateidp->seqid, stateidp->other[0],
+				    stateidp->other[1], stateidp->other[2],
+				    lyp->lay_stateid.seqid,
+				    lyp->lay_stateid.other[0],
+				    lyp->lay_stateid.other[1],
+				    lyp->lay_stateid.other[2],
+				    (uintmax_t)offset, (uintmax_t)len,
+				    lyp->lay_read, lyp->lay_rw);
+				if (stateidp->other[0] !=
+				    lyp->lay_stateid.other[0] ||
+				    stateidp->other[1] !=
+				    lyp->lay_stateid.other[1] ||
+				    stateidp->other[2] !=
+				    lyp->lay_stateid.other[2])
+					error = NFSERR_BADSTATEID;
+			}
+			if (error == 0) {
+				if (++lyp->lay_stateid.seqid == 0)
+					lyp->lay_stateid.seqid = 1;
+				stateidp->seqid = lyp->lay_stateid.seqid;
+				*fndp = 1;
+				if (offset == 0 && len == UINT64_MAX) {
+					if ((iomode & NFSLAYOUTIOMODE_READ) !=
+					    0)
+						lyp->lay_read = 0;
+					if ((iomode & NFSLAYOUTIOMODE_RW) != 0)
+						lyp->lay_rw = 0;
+					if (lyp->lay_read == 0 &&
+					    lyp->lay_rw == 0)
+						nfsrv_freelayout(lyp);
+				}
+			}
+			NFSUNLOCKLAYOUT(lhyp);
+		}
+	} else
+		nfsrv_freealllayouts(fndp);
+	if (error == -1)
+		error = 0;
+	return (error);
+}
+
+/*
+ * Look for an existing layout.
+ */
+int
+nfsrv_findlayout(struct nfsrv_descript *nd, fhandle_t *fhp, NFSPROC_T *p,
+    struct nfslayout **lypp)
+{
+	struct nfslayouthash *lhyp;
+	struct nfslayout *lyp;
+	int ret;
+
+	KASSERT((nd->nd_flag & ND_IMPLIEDCLID) != 0,
+	    ("nfsrv_layoutget: no nd_clientid\n"));
+	*lypp = NULL;
+	ret = 0;
+	lhyp = NFSLAYOUTHASH(fhp);
+	LIST_FOREACH(lyp, &lhyp->list, lay_list) {
+		if (NFSBCMP(&lyp->lay_fh, fhp, sizeof(*fhp)) == 0 &&
+		    lyp->lay_clientid.qval == nd->nd_clientid.qval)
+			break;
+	}
+	if (lyp != NULL)
+		*lypp = lyp;
+	else
+		ret = -1;
+	return (ret);
+}
+
+/*
+ * Add the new layout, as required.
+ */
+static int
+nfsrv_addlayout(struct nfsrv_descript *nd, struct nfslayout **lypp,
+    nfsv4stateid_t *stateidp, char *layp, int *layoutlenp, NFSPROC_T *p)
+{
+	struct nfsclient *clp;
+	struct nfslayouthash *lhyp;
+	struct nfslayout *lyp, *nlyp;
+	fhandle_t *fhp;
+	int error;
+
+	KASSERT((nd->nd_flag & ND_IMPLIEDCLID) != 0,
+	    ("nfsrv_layoutget: no nd_clientid\n"));
+	lyp = *lypp;
+	fhp = &lyp->lay_fh;
+	NFSLOCKSTATE();
+	error = nfsrv_getclient((nfsquad_t)((u_quad_t)0), CLOPS_RENEW, &clp,
+	    NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
+	if (error != 0) {
+		NFSUNLOCKSTATE();
+		return (error);
+	}
+	lyp->lay_stateid.seqid = stateidp->seqid = 1;
+	lyp->lay_stateid.other[0] = stateidp->other[0] =
+	    clp->lc_clientid.lval[0];
+	lyp->lay_stateid.other[1] = stateidp->other[1] =
+	    clp->lc_clientid.lval[1];
+	lyp->lay_stateid.other[2] = stateidp->other[2] =
+	    nfsrv_nextstateindex(clp);
+	NFSUNLOCKSTATE();
+
+	lhyp = NFSLAYOUTHASH(fhp);
+	NFSLOCKLAYOUT(lhyp);
+	LIST_FOREACH(nlyp, &lhyp->list, lay_list) {
+		if (NFSBCMP(&nlyp->lay_fh, fhp, sizeof(*fhp)) == 0 &&
+		    nlyp->lay_clientid.qval == nd->nd_clientid.qval)
+			break;
+	}
+	if (nlyp != NULL) {
+		/* A layout already exists, so use it. */
+		if (lyp->lay_read != 0)
+			nlyp->lay_read = lyp->lay_read;
+		if (lyp->lay_rw != 0)
+			nlyp->lay_rw = lyp->lay_rw;
+		NFSBCOPY(nlyp->lay_xdr, layp, nlyp->lay_layoutlen);
+		*layoutlenp = nlyp->lay_layoutlen;
+		if (++nlyp->lay_stateid.seqid == 0)
+			nlyp->lay_stateid.seqid = 1;
+		stateidp->seqid = nlyp->lay_stateid.seqid;
+		stateidp->other[0] = nlyp->lay_stateid.other[0];
+		stateidp->other[1] = nlyp->lay_stateid.other[1];
+		stateidp->other[2] = nlyp->lay_stateid.other[2];
+		NFSUNLOCKLAYOUT(lhyp);
+		return (0);
+	}
+
+	/* Insert the new layout in the lists. */
+	*lypp = NULL;
+	NFSBCOPY(lyp->lay_xdr, layp, lyp->lay_layoutlen);
+	*layoutlenp = lyp->lay_layoutlen;
+	LIST_INSERT_HEAD(&lhyp->list, lyp, lay_list);
+	NFSUNLOCKLAYOUT(lhyp);
+	return (0);
+}
+
+/*
+ * Get the devinfo for a deviceid.
+ */
+int
+nfsrv_getdevinfo(char *devid, int layouttype, uint32_t *maxcnt,
+    uint32_t *notify, int *devaddrlen, char **devaddr)
+{
+	struct nfsdevice *ds;
+	int i;
+
+	if (layouttype != NFSLAYOUT_NFSV4_1_FILES)
+		return (NFSERR_UNKNLAYOUTTYPE);
+
+	/*
+	 * Now, search for the device id.  Note that the structures won't go
+	 * away, but the order changes in the list.  As such, the lock only
+	 * needs to be held during the search through the list.
+	 */
+	NFSDDSLOCK();
+	TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
+		if (NFSBCMP(devid, ds->nfsdev_deviceid, NFSX_V4DEVICEID) == 0)
+			break;
+	}
+	NFSDDSUNLOCK();
+	if (ds == NULL)
+		return (NFSERR_NOENT);
+
+	/* If the correct nfsdev_XXXXaddrlen is > 0, we have the device info. */
+	if (layouttype == NFSLAYOUT_NFSV4_1_FILES &&
+	    ds->nfsdev_fileaddrlen > 0) {
+		/*
+		 * The XDR overhead is 3 unsigned values: layout_type,
+		 * length_of_address and notify bitmap.
+		 * If the notify array is changed to not all zeros, the
+		 * count of unsigned values must be increased.
+		 */
+		if (*maxcnt > 0 && *maxcnt <
+		    NFSM_RNDUP(ds->nfsdev_fileaddrlen) + 3 * NFSX_UNSIGNED) {
+			*maxcnt = NFSM_RNDUP(ds->nfsdev_fileaddrlen) +
+			    3 * NFSX_UNSIGNED;
+			return (NFSERR_TOOSMALL);
+		}
+		*devaddrlen = ds->nfsdev_fileaddrlen;
+		*devaddr = ds->nfsdev_fileaddr;
+	} else
+		return (NFSERR_UNKNLAYOUTTYPE);
+
+	/* No notifies for now. */
+	for (i = 0; i < NFSV4_NOTIFYBITMAP; i++)
+		*notify++ = 0;
+	return (0);
+}
+
+/*
+ * Free a list of layout state structures.
+ * (This function will also free all nfslockfile structures that no
+ *  longer have associated state.)
+ */
+static void
+nfsrv_freelayoutlist(nfsquad_t clientid)
+{
+	struct nfslayouthash *lhyp;
+	struct nfslayout *lyp, *nlyp;
+	int i;
+
+	for (i = 0; i < nfsrv_layouthashsize; i++) {
+		lhyp = &nfslayouthash[i];
+		NFSLOCKLAYOUT(lhyp);
+		LIST_FOREACH_SAFE(lyp, &lhyp->list, lay_list, nlyp) {
+			if (lyp->lay_clientid.qval == clientid.qval)
+				nfsrv_freelayout(lyp);
+		}
+		NFSUNLOCKLAYOUT(lhyp);
+	}
+}
+
+/*
+ * Free up a layout.
+ */
+static void
+nfsrv_freelayout(struct nfslayout *lyp)
+{
+
+	NFSD_DEBUG(4, "Freelayout=%p\n", lyp);
+	LIST_REMOVE(lyp, lay_list);
+	free(lyp, M_NFSDSTATE);
+}
+
+/*
+ * Free up a device id.
+ */
+static void
+nfsrv_freedevid(struct nfsdevice *ds)
+{
+	int i;
+
+	TAILQ_REMOVE(&nfsrv_devidhead, ds, nfsdev_list);
+	vrele(ds->nfsdev_dvp);
+	for (i = 0; i < nfsrv_dsdirsize; i++)
+		vrele(ds->nfsdev_dsdir[i]);
+	free(ds->nfsdev_fileaddr, M_NFSDSTATE);
+	free(ds->nfsdev_host, M_NFSDSTATE);
+	free(ds, M_NFSDSTATE);
+}
+
+/*
+ * Free all layouts and device ids.
+ * Done when the nfsd threads are shut down since there may be a new
+ * modified device id list created when the nfsd is restarted.
+ */
+void
+nfsrv_freealllayoutsanddevids(void)
+{
+	int fnd;
+
+	/* Get rid of the deviceid structures. */
+	nfsrv_freealldevids();
+	TAILQ_INIT(&nfsrv_devidhead);
+
+	/* Get rid of all layouts. */
+	nfsrv_freealllayouts(&fnd);
+}
+
+/*
+ * Free all layouts.
+ */
+static void
+nfsrv_freealllayouts(int *fndp)
+{
+	struct nfslayouthash *lhyp;
+	struct nfslayout *lyp, *nlyp;
+	int i;
+
+	*fndp = 0;
+	for (i = 0; i < nfsrv_layouthashsize; i++) {
+		lhyp = &nfslayouthash[i];
+		NFSLOCKLAYOUT(lhyp);
+		if (!LIST_EMPTY(&lhyp->list))
+			*fndp = 1;
+		LIST_FOREACH_SAFE(lyp, &lhyp->list, lay_list, nlyp)
+			nfsrv_freelayout(lyp);
+		NFSUNLOCKLAYOUT(lhyp);
+	}
+}
+
+/*
+ * Look up the mount path for the DS server.
+ */
+static int
+nfsrv_setdsserver(char *dspathp, NFSPROC_T *p, struct nfsdevice **dsp)
+{
+	struct nameidata nd;
+	struct nfsdevice *ds;
+	int error, i;
+	char *dsdirpath;
+	size_t dsdirsize;
+
+	NFSD_DEBUG(4, "setdssrv path=%s\n", dspathp);
+	*dsp = NULL;
+	NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF, UIO_SYSSPACE,
+	    dspathp, p);
+	error = namei(&nd);
+	NFSD_DEBUG(4, "lookup=%d\n", error);
+	if (error != 0)
+		return (error);
+	if (nd.ni_vp->v_type != VDIR) {
+		vput(nd.ni_vp);
+		NFSD_DEBUG(4, "dspath not dir\n");
+		return (ENOTDIR);
+	}
+	if (strcmp(nd.ni_vp->v_mount->mnt_vfc->vfc_name, "nfs") != 0) {
+		vput(nd.ni_vp);
+		NFSD_DEBUG(4, "dspath not an NFS mount\n");
+		return (ENXIO);
+	}
+
+	/*
+	 * Allocate a DS server structure with the NFS mounted directory
+	 * vnode reference counted, so that a non-forced dismount will
+	 * fail with EBUSY.
+	 */
+	*dsp = ds = malloc(sizeof(*ds) + nfsrv_dsdirsize * sizeof(vnode_t),
+	    M_NFSDSTATE, M_WAITOK | M_ZERO);
+	ds->nfsdev_dvp = nd.ni_vp;
+	NFSVOPUNLOCK(nd.ni_vp, 0);
+
+	dsdirsize = strlen(dspathp) + 16;
+	dsdirpath = malloc(dsdirsize, M_TEMP, M_WAITOK);
+	/* Now, create the DS directory structures. */
+	for (i = 0; i < nfsrv_dsdirsize; i++) {
+		snprintf(dsdirpath, dsdirsize, "%s/ds%d", dspathp, i);
+		NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF,
+		    UIO_SYSSPACE, dsdirpath, p);
+		error = namei(&nd);
+		NFSD_DEBUG(4, "dsdirpath=%s lookup=%d\n", dsdirpath, error);
+		if (error != 0)
+			break;
+		if (nd.ni_vp->v_type != VDIR) {
+			vput(nd.ni_vp);
+			error = ENOTDIR;
+			NFSD_DEBUG(4, "dsdirpath not a VDIR\n");
+			break;
+		}
+		if (strcmp(nd.ni_vp->v_mount->mnt_vfc->vfc_name, "nfs") != 0) {
+			vput(nd.ni_vp);
+			error = ENXIO;
+			NFSD_DEBUG(4, "dsdirpath not an NFS mount\n");
+			break;
+		}
+		ds->nfsdev_dsdir[i] = nd.ni_vp;
+		NFSVOPUNLOCK(nd.ni_vp, 0);
+	}
+	free(dsdirpath, M_TEMP);
+
+	/*
+	 * Since this is done before the nfsd threads are running, locking
+	 * isn't required.
+	 */
+	TAILQ_INSERT_TAIL(&nfsrv_devidhead, ds, nfsdev_list);
+	return (error);
+}
+
+/*
+ * Fill in the addr structures for the File and Flex File layouts.
+ */
+static void
+nfsrv_allocdevid(struct nfsdevice *ds, char *addr, char *dnshost)
+{
+	uint32_t *tl;
+	char *netprot;
+	int addrlen;
+	static uint64_t new_devid = 0;
+
+	if (strchr(addr, ':') != NULL)
+		netprot = "tcp6";
+	else
+		netprot = "tcp";
+
+	/* Fill in the device id. */
+	NFSBCOPY(&nfsdev_time, ds->nfsdev_deviceid, sizeof(nfsdev_time));
+	new_devid++;
+	NFSBCOPY(&new_devid, &ds->nfsdev_deviceid[sizeof(nfsdev_time)],
+	    sizeof(new_devid));
+
+	/*
+	 * Fill in the file addr (actually the nfsv4_file_layout_ds_addr4
+	 * as defined in RFC5661) in XDR.
+	 */
+	addrlen = NFSM_RNDUP(strlen(addr)) + NFSM_RNDUP(strlen(netprot)) +
+	    6 * NFSX_UNSIGNED;
+	NFSD_DEBUG(4, "hn=%s addr=%s netprot=%s\n", dnshost, addr, netprot);
+	ds->nfsdev_fileaddrlen = addrlen;
+	tl = malloc(addrlen, M_NFSDSTATE, M_WAITOK | M_ZERO);
+	ds->nfsdev_fileaddr = (char *)tl;
+	*tl++ = txdr_unsigned(1);		/* One stripe with index 0. */
+	*tl++ = 0;
+	*tl++ = txdr_unsigned(1);		/* One multipath list */
+	*tl++ = txdr_unsigned(1);		/* with one entry in it. */
+	/* The netaddr for this one entry. */
+	*tl++ = txdr_unsigned(strlen(netprot));
+	NFSBCOPY(netprot, tl, strlen(netprot));
+	tl += (NFSM_RNDUP(strlen(netprot)) / NFSX_UNSIGNED);
+	*tl++ = txdr_unsigned(strlen(addr));
+	NFSBCOPY(addr, tl, strlen(addr));
+
+	ds->nfsdev_hostnamelen = strlen(dnshost);
+	ds->nfsdev_host = malloc(ds->nfsdev_hostnamelen, M_NFSDSTATE,
+	    M_WAITOK | M_ZERO);
+	NFSBCOPY(dnshost, ds->nfsdev_host, ds->nfsdev_hostnamelen);
+}
+
+
+/*
+ * Create the device id list.
+ */
+void
+nfsrv_createdevids(struct nfsd_nfsd_args *args, NFSPROC_T *p)
+{
+	struct nfsdevice *ds;
+	char *addrp, *dnshostp, *dspathp;
+	int error;
+
+	addrp = args->addr;
+	dnshostp = args->dnshost;
+	dspathp = args->dspath;
+	if (addrp == NULL || dnshostp == NULL || dspathp == NULL)
+		return;
+
+	/*
+	 * Loop around for each nul-terminated string in args->addr and
+	 * args->dnshost.
+	 */
+	while (addrp < (args->addr + args->addrlen) &&
+	    dnshostp < (args->dnshost + args->dnshostlen) &&
+	    dspathp < (args->dspath + args->dspathlen)) {
+		error = nfsrv_setdsserver(dspathp, p, &ds);
+		if (error != 0) {
+			/* Free all DS servers. */
+			nfsrv_freealldevids();
+			return;
+		}
+		nfsrv_allocdevid(ds, addrp, dnshostp);
+		addrp += (strlen(addrp) + 1);
+		dnshostp += (strlen(dnshostp) + 1);
+		dspathp += (strlen(dspathp) + 1);
+	}
+}
+
+/*
+ * Free all device ids.
+ */
+static void
+nfsrv_freealldevids(void)
+{
+	struct nfsdevice *ds, *nds;
+
+	TAILQ_FOREACH_SAFE(ds, &nfsrv_devidhead, nfsdev_list, nds)
+		nfsrv_freedevid(ds);
+}
+



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201704272203.v3RM38RA092559>