svn commit: r317528 - projects/pnfs-planb-server/sys/fs/nfsserver
Rick Macklem
rmacklem at FreeBSD.org
Thu Apr 27 22:03:09 UTC 2017
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);
+}
+
More information about the svn-src-projects
mailing list