svn commit: r359910 - in head/sys: conf fs/nfsserver modules/nfsd nfs

Rick Macklem rmacklem at FreeBSD.org
Tue Apr 14 00:01:28 UTC 2020


Author: rmacklem
Date: Tue Apr 14 00:01:26 2020
New Revision: 359910
URL: https://svnweb.freebsd.org/changeset/base/359910

Log:
  Re-organize the NFS file handle affinity code for the NFS server.
  
  The file handle affinity code was configured to be used by both the
  old and new NFS servers. This no longer makes sense, since there is
  only one NFS server.
  This patch copies a majority of the code in sys/nfs/nfs_fha.c and
  sys/nfs/nfs_fha.h into sys/fs/nfsserver/nfs_fha_new.c and
  sys/fs/nfsserver/nfs_fha_new.h, so that the files in sys/nfs can be
  deleted. The code is simplified by deleting the function callback pointers
  used to call functions in either the old or new NFS server and they were
  replaced by calls to the functions.
  
  As well as a cleanup, this re-organization simplifies the changes
  required for handling of external page mbufs, which is required for KERN_TLS.
  
  This patch should not result in a semantic change to file handle affinity.

Deleted:
  head/sys/nfs/nfs_fha.c
  head/sys/nfs/nfs_fha.h
Modified:
  head/sys/conf/files
  head/sys/fs/nfsserver/nfs_fha_new.c
  head/sys/fs/nfsserver/nfs_fha_new.h
  head/sys/fs/nfsserver/nfs_nfsdkrpc.c
  head/sys/modules/nfsd/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Mon Apr 13 23:16:32 2020	(r359909)
+++ head/sys/conf/files	Tue Apr 14 00:01:26 2020	(r359910)
@@ -4435,7 +4435,6 @@ netsmb/smb_usr.c		optional netsmb
 nfs/bootp_subr.c		optional bootp nfscl
 nfs/krpc_subr.c			optional bootp nfscl
 nfs/nfs_diskless.c		optional nfscl nfs_root
-nfs/nfs_fha.c			optional nfsd
 nfs/nfs_nfssvc.c		optional nfscl | nfslockd | nfsd
 nlm/nlm_advlock.c		optional nfslockd | nfsd
 nlm/nlm_prot_clnt.c		optional nfslockd | nfsd

Modified: head/sys/fs/nfsserver/nfs_fha_new.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_fha_new.c	Mon Apr 13 23:16:32 2020	(r359909)
+++ head/sys/fs/nfsserver/nfs_fha_new.c	Tue Apr 14 00:01:26 2020	(r359910)
@@ -29,29 +29,33 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/types.h>
+#include <sys/mbuf.h>
+#include <sys/sbuf.h>
+
 #include <fs/nfs/nfsport.h>
+#include <fs/nfsserver/nfs_fha_new.h>
 
 #include <rpc/rpc.h>
-#include <nfs/nfs_fha.h>
-#include <fs/nfs/xdr_subs.h>
-#include <fs/nfs/nfs.h>
-#include <fs/nfs/nfsproto.h>
-#include <fs/nfs/nfsm_subs.h>
-#include <fs/nfsserver/nfs_fha_new.h>
 
-static void fhanew_init(void *foo);
-static void fhanew_uninit(void *foo);
-rpcproc_t fhanew_get_procnum(rpcproc_t procnum);
-int fhanew_realign(struct mbuf **mb, int malloc_flags);
-int fhanew_get_fh(uint64_t *fh, int v3, struct mbuf **md, caddr_t *dpos);
-int fhanew_is_read(rpcproc_t procnum);
-int fhanew_is_write(rpcproc_t procnum);
-int fhanew_get_offset(struct mbuf **md, caddr_t *dpos, int v3,
-		      struct fha_info *info);
-int fhanew_no_offset(rpcproc_t procnum);
-void fhanew_set_locktype(rpcproc_t procnum, struct fha_info *info);
-static int fhenew_stats_sysctl(SYSCTL_HANDLER_ARGS);
+static MALLOC_DEFINE(M_NFS_FHA, "NFS FHA", "NFS FHA");
 
+static void		fhanew_init(void *foo);
+static void		fhanew_uninit(void *foo);
+static rpcproc_t	fhanew_get_procnum(rpcproc_t procnum);
+static int		fhanew_get_fh(uint64_t *fh, int v3, struct mbuf **md,
+			    caddr_t *dpos);
+static int		fhanew_is_read(rpcproc_t procnum);
+static int		fhanew_is_write(rpcproc_t procnum);
+static int		fhanew_get_offset(struct mbuf **md, caddr_t *dpos,
+			    int v3, struct fha_info *info);
+static int		fhanew_no_offset(rpcproc_t procnum);
+static void		fhanew_set_locktype(rpcproc_t procnum,
+			    struct fha_info *info);
+static int		fhenew_stats_sysctl(SYSCTL_HANDLER_ARGS);
+static void		fha_extract_info(struct svc_req *req,
+			    struct fha_info *i);
+
 static struct fha_params fhanew_softc;
 
 SYSCTL_DECL(_vfs_nfsd);
@@ -66,24 +70,12 @@ static void
 fhanew_init(void *foo)
 {
 	struct fha_params *softc;
+	int i;
 
 	softc = &fhanew_softc;
 
 	bzero(softc, sizeof(*softc));
 
-	/*
-	 * Setup the callbacks for this FHA personality.
-	 */
-	softc->callbacks.get_procnum = fhanew_get_procnum;
-	softc->callbacks.realign = fhanew_realign;
-	softc->callbacks.get_fh = fhanew_get_fh;
-	softc->callbacks.is_read = fhanew_is_read;
-	softc->callbacks.is_write = fhanew_is_write;
-	softc->callbacks.get_offset = fhanew_get_offset;
-	softc->callbacks.no_offset = fhanew_no_offset;
-	softc->callbacks.set_locktype = fhanew_set_locktype;
-	softc->callbacks.fhe_stats_sysctl = fhenew_stats_sysctl;
-
 	snprintf(softc->server_name, sizeof(softc->server_name),
 	    FHANEW_SERVER_NAME);
 
@@ -101,20 +93,68 @@ fhanew_init(void *foo)
 		return;
 	}
 
-	fha_init(softc);
+	for (i = 0; i < FHA_HASH_SIZE; i++)
+		mtx_init(&softc->fha_hash[i].mtx, "fhalock", NULL, MTX_DEF);
+
+	/*
+	 * Set the default tuning parameters.
+	 */
+	softc->ctls.enable = FHA_DEF_ENABLE;
+	softc->ctls.read = FHA_DEF_READ;
+	softc->ctls.write = FHA_DEF_WRITE;
+	softc->ctls.bin_shift = FHA_DEF_BIN_SHIFT;
+	softc->ctls.max_nfsds_per_fh = FHA_DEF_MAX_NFSDS_PER_FH;
+	softc->ctls.max_reqs_per_nfsd = FHA_DEF_MAX_REQS_PER_NFSD;
+
+	/*
+	 * Add sysctls so the user can change the tuning parameters.
+	 */
+	SYSCTL_ADD_UINT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
+	    OID_AUTO, "enable", CTLFLAG_RWTUN,
+	    &softc->ctls.enable, 0, "Enable NFS File Handle Affinity (FHA)");
+
+	SYSCTL_ADD_UINT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
+	    OID_AUTO, "read", CTLFLAG_RWTUN,
+	    &softc->ctls.read, 0, "Enable NFS FHA read locality");
+
+	SYSCTL_ADD_UINT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
+	    OID_AUTO, "write", CTLFLAG_RWTUN,
+	    &softc->ctls.write, 0, "Enable NFS FHA write locality");
+
+	SYSCTL_ADD_UINT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
+	    OID_AUTO, "bin_shift", CTLFLAG_RWTUN,
+	    &softc->ctls.bin_shift, 0,
+	    "Maximum locality distance 2^(bin_shift) bytes");
+
+	SYSCTL_ADD_UINT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
+	    OID_AUTO, "max_nfsds_per_fh", CTLFLAG_RWTUN,
+	    &softc->ctls.max_nfsds_per_fh, 0, "Maximum nfsd threads that "
+	    "should be working on requests for the same file handle");
+
+	SYSCTL_ADD_UINT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
+	    OID_AUTO, "max_reqs_per_nfsd", CTLFLAG_RWTUN,
+	    &softc->ctls.max_reqs_per_nfsd, 0, "Maximum requests that "
+	    "single nfsd thread should be working on at any time");
+
+	SYSCTL_ADD_OID(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
+	    OID_AUTO, "fhe_stats", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+	    0, 0, fhenew_stats_sysctl, "A", "");
 }
 
 static void
 fhanew_uninit(void *foo)
 {
 	struct fha_params *softc;
+	int i;
 
 	softc = &fhanew_softc;
 
-	fha_uninit(softc);
+	sysctl_ctx_free(&softc->sysctl_ctx);
+	for (i = 0; i < FHA_HASH_SIZE; i++)
+		mtx_destroy(&softc->fha_hash[i].mtx);
 }
 
-rpcproc_t
+static rpcproc_t
 fhanew_get_procnum(rpcproc_t procnum)
 {
 	if (procnum > NFSV2PROC_STATFS)
@@ -123,13 +163,7 @@ fhanew_get_procnum(rpcproc_t procnum)
 	return (newnfs_nfsv3_procid[procnum]);
 }
 
-int
-fhanew_realign(struct mbuf **mb, int malloc_flags)
-{
-	return (newnfs_realign(mb, malloc_flags));
-}
-
-int
+static int
 fhanew_get_fh(uint64_t *fh, int v3, struct mbuf **md, caddr_t *dpos)
 {
 	struct nfsrv_descript lnd, *nd;
@@ -170,7 +204,7 @@ nfsmout:
 	return (error);
 }
 
-int
+static int
 fhanew_is_read(rpcproc_t procnum)
 {
 	if (procnum == NFSPROC_READ)
@@ -179,7 +213,7 @@ fhanew_is_read(rpcproc_t procnum)
 		return (0);
 }
 
-int
+static int
 fhanew_is_write(rpcproc_t procnum)
 {
 	if (procnum == NFSPROC_WRITE)
@@ -188,9 +222,9 @@ fhanew_is_write(rpcproc_t procnum)
 		return (0);
 }
 
-int
+static int
 fhanew_get_offset(struct mbuf **md, caddr_t *dpos, int v3,
-		  struct fha_info *info)
+    struct fha_info *info)
 {
 	struct nfsrv_descript lnd, *nd;
 	uint32_t *tl;
@@ -217,7 +251,7 @@ nfsmout:
 	return (error);
 }
 
-int
+static int
 fhanew_no_offset(rpcproc_t procnum)
 {
 	if (procnum == NFSPROC_FSSTAT ||
@@ -230,7 +264,7 @@ fhanew_no_offset(rpcproc_t procnum)
 		return (0);
 }
 
-void
+static void
 fhanew_set_locktype(rpcproc_t procnum, struct fha_info *info)
 {
 	switch (procnum) {
@@ -264,15 +298,414 @@ fhanew_set_locktype(rpcproc_t procnum, struct fha_info
 	}
 }
 
-static int
-fhenew_stats_sysctl(SYSCTL_HANDLER_ARGS)
+
+/*
+ * This just specifies that offsets should obey affinity when within
+ * the same 1Mbyte (1<<20) chunk for the file (reads only for now).
+ */
+static void
+fha_extract_info(struct svc_req *req, struct fha_info *i)
 {
-	return (fhe_stats_sysctl(oidp, arg1, arg2, req, &fhanew_softc));
+	struct mbuf *md;
+	caddr_t dpos;
+	static u_int64_t random_fh = 0;
+	int error;
+	int v3 = (req->rq_vers == 3);
+	rpcproc_t procnum;
+
+	/*
+	 * We start off with a random fh.  If we get a reasonable
+	 * procnum, we set the fh.  If there's a concept of offset
+	 * that we're interested in, we set that.
+	 */
+	i->fh = ++random_fh;
+	i->offset = 0;
+	i->locktype = LK_EXCLUSIVE;
+	i->read = i->write = 0;
+
+	/*
+	 * Extract the procnum and convert to v3 form if necessary,
+	 * taking care to deal with out-of-range procnums.  Caller will
+	 * ensure that rq_vers is either 2 or 3.
+	 */
+	procnum = req->rq_proc;
+	if (!v3) {
+		rpcproc_t tmp_procnum;
+
+		tmp_procnum = fhanew_get_procnum(procnum);
+		if (tmp_procnum == -1)
+			goto out;
+		procnum = tmp_procnum;
+	}
+
+	/*
+	 * We do affinity for most.  However, we divide a realm of affinity
+	 * by file offset so as to allow for concurrent random access.  We
+	 * only do this for reads today, but this may change when IFS supports
+	 * efficient concurrent writes.
+	 */
+	if (fhanew_no_offset(procnum))
+		goto out;
+
+	i->read = fhanew_is_read(procnum);
+	i->write = fhanew_is_write(procnum);
+
+	error = newnfs_realign(&req->rq_args, M_NOWAIT);
+	if (error)
+		goto out;
+	md = req->rq_args;
+	dpos = mtod(md, caddr_t);
+
+	/* Grab the filehandle. */
+	error = fhanew_get_fh(&i->fh, v3, &md, &dpos);
+	if (error)
+		goto out;
+
+	/* Content ourselves with zero offset for all but reads. */
+	if (i->read || i->write)
+		fhanew_get_offset(&md, &dpos, v3, i);
+
+out:
+	fhanew_set_locktype(procnum, i);
 }
 
+static struct fha_hash_entry *
+fha_hash_entry_new(u_int64_t fh)
+{
+	struct fha_hash_entry *e;
 
+	e = malloc(sizeof(*e), M_NFS_FHA, M_WAITOK);
+	e->fh = fh;
+	e->num_rw = 0;
+	e->num_exclusive = 0;
+	e->num_threads = 0;
+	LIST_INIT(&e->threads);
+
+	return (e);
+}
+
+static void
+fha_hash_entry_destroy(struct fha_hash_entry *e)
+{
+
+	mtx_assert(e->mtx, MA_OWNED);
+	KASSERT(e->num_rw == 0,
+	    ("%d reqs on destroyed fhe %p", e->num_rw, e));
+	KASSERT(e->num_exclusive == 0,
+	    ("%d exclusive reqs on destroyed fhe %p", e->num_exclusive, e));
+	KASSERT(e->num_threads == 0,
+	    ("%d threads on destroyed fhe %p", e->num_threads, e));
+	free(e, M_NFS_FHA);
+}
+
+static void
+fha_hash_entry_remove(struct fha_hash_entry *e)
+{
+
+	mtx_assert(e->mtx, MA_OWNED);
+	LIST_REMOVE(e, link);
+	fha_hash_entry_destroy(e);
+}
+
+static struct fha_hash_entry *
+fha_hash_entry_lookup(struct fha_params *softc, u_int64_t fh)
+{
+	struct fha_hash_slot *fhs;
+	struct fha_hash_entry *fhe, *new_fhe;
+
+	fhs = &softc->fha_hash[fh % FHA_HASH_SIZE];
+	new_fhe = fha_hash_entry_new(fh);
+	new_fhe->mtx = &fhs->mtx;
+	mtx_lock(&fhs->mtx);
+	LIST_FOREACH(fhe, &fhs->list, link)
+		if (fhe->fh == fh)
+			break;
+	if (!fhe) {
+		fhe = new_fhe;
+		LIST_INSERT_HEAD(&fhs->list, fhe, link);
+	} else
+		fha_hash_entry_destroy(new_fhe);
+	return (fhe);
+}
+
+static void
+fha_hash_entry_add_thread(struct fha_hash_entry *fhe, SVCTHREAD *thread)
+{
+
+	mtx_assert(fhe->mtx, MA_OWNED);
+	thread->st_p2 = 0;
+	LIST_INSERT_HEAD(&fhe->threads, thread, st_alink);
+	fhe->num_threads++;
+}
+
+static void
+fha_hash_entry_remove_thread(struct fha_hash_entry *fhe, SVCTHREAD *thread)
+{
+
+	mtx_assert(fhe->mtx, MA_OWNED);
+	KASSERT(thread->st_p2 == 0,
+	    ("%d reqs on removed thread %p", thread->st_p2, thread));
+	LIST_REMOVE(thread, st_alink);
+	fhe->num_threads--;
+}
+
+/*
+ * Account for an ongoing operation associated with this file.
+ */
+static void
+fha_hash_entry_add_op(struct fha_hash_entry *fhe, int locktype, int count)
+{
+
+	mtx_assert(fhe->mtx, MA_OWNED);
+	if (LK_EXCLUSIVE == locktype)
+		fhe->num_exclusive += count;
+	else
+		fhe->num_rw += count;
+}
+
+/*
+ * Get the service thread currently associated with the fhe that is
+ * appropriate to handle this operation.
+ */
+static SVCTHREAD *
+fha_hash_entry_choose_thread(struct fha_params *softc,
+    struct fha_hash_entry *fhe, struct fha_info *i, SVCTHREAD *this_thread)
+{
+	SVCTHREAD *thread, *min_thread = NULL;
+	int req_count, min_count = 0;
+	off_t offset1, offset2;
+
+	LIST_FOREACH(thread, &fhe->threads, st_alink) {
+		req_count = thread->st_p2;
+
+		/* If there are any writes in progress, use the first thread. */
+		if (fhe->num_exclusive) {
+#if 0
+			ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO,
+			    "fha: %p(%d)w", thread, req_count);
+#endif
+			return (thread);
+		}
+
+		/* Check whether we should consider locality. */
+		if ((i->read && !softc->ctls.read) ||
+		    (i->write && !softc->ctls.write))
+			goto noloc;
+
+		/*
+		 * Check for locality, making sure that we won't
+		 * exceed our per-thread load limit in the process.
+		 */
+		offset1 = i->offset;
+		offset2 = thread->st_p3;
+
+		if (((offset1 >= offset2)
+		  && ((offset1 - offset2) < (1 << softc->ctls.bin_shift)))
+		 || ((offset2 > offset1)
+		  && ((offset2 - offset1) < (1 << softc->ctls.bin_shift)))) {
+			if ((softc->ctls.max_reqs_per_nfsd == 0) ||
+			    (req_count < softc->ctls.max_reqs_per_nfsd)) {
+#if 0
+				ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO,
+				    "fha: %p(%d)r", thread, req_count);
+#endif
+				return (thread);
+			}
+		}
+
+noloc:
+		/*
+		 * We don't have a locality match, so skip this thread,
+		 * but keep track of the most attractive thread in case
+		 * we need to come back to it later.
+		 */
+#if 0
+		ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO,
+		    "fha: %p(%d)s off1 %llu off2 %llu", thread,
+		    req_count, offset1, offset2);
+#endif
+		if ((min_thread == NULL) || (req_count < min_count)) {
+			min_count = req_count;
+			min_thread = thread;
+		}
+	}
+
+	/*
+	 * We didn't find a good match yet.  See if we can add
+	 * a new thread to this file handle entry's thread list.
+	 */
+	if ((softc->ctls.max_nfsds_per_fh == 0) ||
+	    (fhe->num_threads < softc->ctls.max_nfsds_per_fh)) {
+		thread = this_thread;
+#if 0
+		ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO,
+		    "fha: %p(%d)t", thread, thread->st_p2);
+#endif
+		fha_hash_entry_add_thread(fhe, thread);
+	} else {
+		/*
+		 * We don't want to use any more threads for this file, so
+		 * go back to the most attractive nfsd we're already using.
+		 */
+		thread = min_thread;
+	}
+
+	return (thread);
+}
+
+/*
+ * After getting a request, try to assign it to some thread.  Usually we
+ * handle it ourselves.
+ */
 SVCTHREAD *
 fhanew_assign(SVCTHREAD *this_thread, struct svc_req *req)
 {
-	return (fha_assign(this_thread, req, &fhanew_softc));
+	struct fha_params *softc = &fhanew_softc;
+	SVCTHREAD *thread;
+	struct fha_info i;
+	struct fha_hash_entry *fhe;
+
+	/* Check to see whether we're enabled. */
+	if (softc->ctls.enable == 0)
+		goto thist;
+
+	/*
+	 * Only do placement if this is an NFS request.
+	 */
+	if (req->rq_prog != NFS_PROG)
+		goto thist;
+
+	if (req->rq_vers != 2 && req->rq_vers != 3)
+		goto thist;
+
+	fha_extract_info(req, &i);
+
+	/*
+	 * We save the offset associated with this request for later
+	 * nfsd matching.
+	 */
+	fhe = fha_hash_entry_lookup(softc, i.fh);
+	req->rq_p1 = fhe;
+	req->rq_p2 = i.locktype;
+	req->rq_p3 = i.offset;
+
+	/*
+	 * Choose a thread, taking into consideration locality, thread load,
+	 * and the number of threads already working on this file.
+	 */
+	thread = fha_hash_entry_choose_thread(softc, fhe, &i, this_thread);
+	KASSERT(thread, ("fha_assign: NULL thread!"));
+	fha_hash_entry_add_op(fhe, i.locktype, 1);
+	thread->st_p2++;
+	thread->st_p3 = i.offset;
+
+	/*
+	 * Grab the pool lock here to not let chosen thread go away before
+	 * the new request inserted to its queue while we drop fhe lock.
+	 */
+	mtx_lock(&thread->st_lock);
+	mtx_unlock(fhe->mtx);
+
+	return (thread);
+thist:
+	req->rq_p1 = NULL;
+	mtx_lock(&this_thread->st_lock);
+	return (this_thread);
+}
+
+/*
+ * Called when we're done with an operation.  The request has already
+ * been de-queued.
+ */
+void
+fhanew_nd_complete(SVCTHREAD *thread, struct svc_req *req)
+{
+	struct fha_hash_entry *fhe = req->rq_p1;
+	struct mtx *mtx;
+
+	/*
+	 * This may be called for reqs that didn't go through
+	 * fha_assign (e.g. extra NULL ops used for RPCSEC_GSS.
+	 */
+	if (!fhe)
+		return;
+
+	mtx = fhe->mtx;
+	mtx_lock(mtx);
+	fha_hash_entry_add_op(fhe, req->rq_p2, -1);
+	thread->st_p2--;
+	KASSERT(thread->st_p2 >= 0, ("Negative request count %d on %p",
+	    thread->st_p2, thread));
+	if (thread->st_p2 == 0) {
+		fha_hash_entry_remove_thread(fhe, thread);
+		if (0 == fhe->num_rw + fhe->num_exclusive)
+			fha_hash_entry_remove(fhe);
+	}
+	mtx_unlock(mtx);
+}
+
+static int
+fhenew_stats_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct fha_params *softc = &fhanew_softc;
+	int error, i;
+	struct sbuf sb;
+	struct fha_hash_entry *fhe;
+	bool_t first, hfirst;
+	SVCTHREAD *thread;
+
+	sbuf_new(&sb, NULL, 65536, SBUF_FIXEDLEN);
+
+	if (!*softc->pool) {
+		sbuf_printf(&sb, "NFSD not running\n");
+		goto out;
+	}
+
+	for (i = 0; i < FHA_HASH_SIZE; i++)
+		if (!LIST_EMPTY(&softc->fha_hash[i].list))
+			break;
+
+	if (i == FHA_HASH_SIZE) {
+		sbuf_printf(&sb, "No file handle entries.\n");
+		goto out;
+	}
+
+	hfirst = TRUE;
+	for (; i < FHA_HASH_SIZE; i++) {
+		mtx_lock(&softc->fha_hash[i].mtx);
+		if (LIST_EMPTY(&softc->fha_hash[i].list)) {
+			mtx_unlock(&softc->fha_hash[i].mtx);
+			continue;
+		}
+		sbuf_printf(&sb, "%shash %d: {\n", hfirst ? "" : ", ", i);
+		first = TRUE;
+		LIST_FOREACH(fhe, &softc->fha_hash[i].list, link) {
+			sbuf_printf(&sb, "%sfhe %p: {\n", first ? "  " : ", ",
+			    fhe);
+			sbuf_printf(&sb, "    fh: %ju\n", (uintmax_t) fhe->fh);
+			sbuf_printf(&sb, "    num_rw/exclusive: %d/%d\n",
+			    fhe->num_rw, fhe->num_exclusive);
+			sbuf_printf(&sb, "    num_threads: %d\n",
+			    fhe->num_threads);
+
+			LIST_FOREACH(thread, &fhe->threads, st_alink) {
+				sbuf_printf(&sb, "      thread %p offset %ju "
+				    "reqs %d\n", thread,
+				    thread->st_p3, thread->st_p2);
+			}
+
+			sbuf_printf(&sb, "  }");
+			first = FALSE;
+		}
+		sbuf_printf(&sb, "\n}");
+		mtx_unlock(&softc->fha_hash[i].mtx);
+		hfirst = FALSE;
+	}
+
+ out:
+	sbuf_trim(&sb);
+	sbuf_finish(&sb);
+	error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
+	sbuf_delete(&sb);
+	return (error);
 }

Modified: head/sys/fs/nfsserver/nfs_fha_new.h
==============================================================================
--- head/sys/fs/nfsserver/nfs_fha_new.h	Mon Apr 13 23:16:32 2020	(r359909)
+++ head/sys/fs/nfsserver/nfs_fha_new.h	Tue Apr 14 00:01:26 2020	(r359910)
@@ -35,7 +35,75 @@
 
 #define	FHANEW_SERVER_NAME	"nfsd"
 
+/* Sysctl defaults. */
+#define FHA_DEF_ENABLE			1
+#define FHA_DEF_READ			1
+#define FHA_DEF_WRITE			1
+#define FHA_DEF_BIN_SHIFT		22 /* 4MB */
+#define FHA_DEF_MAX_NFSDS_PER_FH	8
+#define FHA_DEF_MAX_REQS_PER_NFSD	0  /* Unlimited */
+
+#define FHA_HASH_SIZE	251
+
+struct fha_ctls {
+	int	 enable;
+	int	 read;
+	int	 write;
+	uint32_t bin_shift;
+	uint32_t max_nfsds_per_fh;
+	uint32_t max_reqs_per_nfsd;
+};
+
+/*
+ * These are the entries in the filehandle hash.  They talk about a specific
+ * file, requests against which are being handled by one or more nfsds.  We
+ * keep a chain of nfsds against the file. We only have more than one if reads
+ * are ongoing, and then only if the reads affect disparate regions of the
+ * file.
+ *
+ * In general, we want to assign a new request to an existing nfsd if it is
+ * going to contend with work happening already on that nfsd, or if the
+ * operation is a read and the nfsd is already handling a proximate read.  We
+ * do this to avoid jumping around in the read stream unnecessarily, and to
+ * avoid contention between threads over single files.
+ */
+struct fha_hash_entry {
+	struct mtx *mtx;
+	LIST_ENTRY(fha_hash_entry) link;
+	u_int64_t fh;
+	u_int32_t num_rw;
+	u_int32_t num_exclusive;
+	u_int8_t num_threads;
+	struct svcthread_list threads;
+};
+
+LIST_HEAD(fha_hash_entry_list, fha_hash_entry);
+
+struct fha_hash_slot {
+	struct fha_hash_entry_list list;
+	struct mtx mtx;
+};
+
+/* A structure used for passing around data internally. */
+struct fha_info {
+	u_int64_t fh;
+	off_t offset;
+	int locktype;
+	int read;
+	int write;
+};
+
+struct fha_params {
+	struct fha_hash_slot fha_hash[FHA_HASH_SIZE];
+	struct sysctl_ctx_list sysctl_ctx;
+	struct sysctl_oid *sysctl_tree;
+	struct fha_ctls ctls;
+	char server_name[32];
+	SVCPOOL **pool;
+};
+
 SVCTHREAD *fhanew_assign(SVCTHREAD *this_thread, struct svc_req *req);
+void fhanew_nd_complete(SVCTHREAD *, struct svc_req *);
 #endif /* _KERNEL */
 
 #endif /* _NFS_FHA_NEW_H */

Modified: head/sys/fs/nfsserver/nfs_nfsdkrpc.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdkrpc.c	Mon Apr 13 23:16:32 2020	(r359909)
+++ head/sys/fs/nfsserver/nfs_nfsdkrpc.c	Tue Apr 14 00:01:26 2020	(r359910)
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
 #include <rpc/rpc.h>
 #include <rpc/rpcsec_gss.h>
 
-#include <nfs/nfs_fha.h>
 #include <fs/nfsserver/nfs_fha_new.h>
 
 #include <security/mac/mac_framework.h>
@@ -589,7 +588,7 @@ nfsrvd_init(int terminating)
 		    SYSCTL_STATIC_CHILDREN(_vfs_nfsd));
 		nfsrvd_pool->sp_rcache = NULL;
 		nfsrvd_pool->sp_assign = fhanew_assign;
-		nfsrvd_pool->sp_done = fha_nd_complete;
+		nfsrvd_pool->sp_done = fhanew_nd_complete;
 		NFSD_LOCK();
 	}
 }

Modified: head/sys/modules/nfsd/Makefile
==============================================================================
--- head/sys/modules/nfsd/Makefile	Mon Apr 13 23:16:32 2020	(r359909)
+++ head/sys/modules/nfsd/Makefile	Tue Apr 14 00:01:26 2020	(r359910)
@@ -1,9 +1,8 @@
 # $FreeBSD$
 
-.PATH: ${SRCTOP}/sys/fs/nfsserver ${SRCTOP}/sys/nfs
+.PATH: ${SRCTOP}/sys/fs/nfsserver
 KMOD=	nfsd
 SRCS=	vnode_if.h \
-	nfs_fha.c \
 	nfs_fha_new.c \
 	nfs_nfsdserv.c \
 	nfs_nfsdcache.c \


More information about the svn-src-all mailing list