Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Mar 2018 22:17:14 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r330818 - in user/jeff/numa/sys: kern sys vm
Message-ID:  <201803122217.w2CMHEHw059214@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Mon Mar 12 22:17:14 2018
New Revision: 330818
URL: https://svnweb.freebsd.org/changeset/base/330818

Log:
  Provide convenience routines for manipulating domainsets in the kernel.
  
  domainset_create() will take a key, validate it, and return a valid
  domainset that can be placed on an object or other.
  
  sysctl_handle_domainset() allows manipulation of policy from sysctl.  Use
  this to make a default vnode domainset.
  
  Clean-up some header creep.  Define a generic bitset type.  Rewrite some
  string functions to be more generic.

Modified:
  user/jeff/numa/sys/kern/kern_cpuset.c
  user/jeff/numa/sys/sys/_bitset.h
  user/jeff/numa/sys/sys/domainset.h
  user/jeff/numa/sys/sys/proc.h
  user/jeff/numa/sys/vm/vnode_pager.c

Modified: user/jeff/numa/sys/kern/kern_cpuset.c
==============================================================================
--- user/jeff/numa/sys/kern/kern_cpuset.c	Mon Mar 12 22:10:06 2018	(r330817)
+++ user/jeff/numa/sys/kern/kern_cpuset.c	Mon Mar 12 22:17:14 2018	(r330818)
@@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/ctype.h>
 #include <sys/sysproto.h>
 #include <sys/jail.h>
 #include <sys/kernel.h>
@@ -112,6 +114,9 @@ __FBSDID("$FreeBSD$");
  * meaning 'curthread'.  It may query available cpus for that tid with a
  * getaffinity call using (CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, ...).
  */
+
+LIST_HEAD(domainlist, domainset);
+
 static uma_zone_t cpuset_zone;
 static uma_zone_t domainset_zone;
 static struct mtx cpuset_lock;
@@ -119,6 +124,7 @@ static struct setlist cpuset_ids;
 static struct domainlist cpuset_domains;
 static struct unrhdr *cpuset_unr;
 static struct cpuset *cpuset_zero, *cpuset_default, *cpuset_kernel;
+static struct domainset domainset0, domainset2;
 
 /* Return the size of cpuset_t at the kernel level */
 SYSCTL_INT(_kern_sched, OID_AUTO, cpusetsize, CTLFLAG_RD | CTLFLAG_CAPRD,
@@ -477,11 +483,24 @@ _domainset_create(struct domainset *domain, struct dom
 /*
  * Create or lookup a domainset based on the key held in 'domain'.
  */
-static struct domainset *
+struct domainset *
 domainset_create(const struct domainset *domain)
 {
 	struct domainset *ndomain;
 
+	/*
+	 * Validate the policy.  It must specify a useable policy number with
+	 * only valid domains.  Preferred must include the preferred domain
+	 * in the mask.
+	 */
+	if (domain->ds_policy <= DOMAINSET_POLICY_INVALID ||
+	    domain->ds_policy > DOMAINSET_POLICY_MAX)
+		return (NULL);
+	if (domain->ds_policy == DOMAINSET_POLICY_PREFER &&
+	    !DOMAINSET_ISSET(domain->ds_prefer, &domain->ds_mask))
+		return (NULL);
+	if (!DOMAINSET_SUBSET(&domainset0.ds_mask, &domain->ds_mask))
+		return (NULL);
 	ndomain = uma_zalloc(domainset_zone, M_WAITOK | M_ZERO);
 	domainset_copy(domain, ndomain);
 	return _domainset_create(ndomain, NULL);
@@ -1132,6 +1151,55 @@ out:
 	return (error);
 }
 
+static int
+bitset_strprint(char *buf, size_t bufsiz, const struct bitset *set, int setlen)
+{
+	size_t bytes;
+	int i, once;
+	char *p;
+
+	once = 0;
+	p = buf;
+	for (i = 0; i < __bitset_words(setlen); i++) {
+		if (once != 0) {
+			if (bufsiz < 1)
+				return (0);
+			*p = ',';
+			p++;
+			bufsiz--;
+		} else
+			once = 1;
+		if (bufsiz < sizeof(__STRING(ULONG_MAX)))
+			return (0);
+		bytes = snprintf(p, bufsiz, "%lx", set->__bits[i]);
+		p += bytes;
+		bufsiz -= bytes;
+	}
+	return (p - buf);
+}
+
+static int
+bitset_strscan(struct bitset *set, int setlen, const char *buf)
+{
+	int i, ret;
+	const char *p;
+
+	BIT_ZERO(setlen, set);
+	p = buf;
+	for (i = 0; i < __bitset_words(setlen); i++) {
+		if (*p == ',') {
+			p++;
+			continue;
+		}
+		ret = sscanf(p, "%lx", &set->__bits[i]);
+		if (ret == 0 || ret == -1)
+			break;
+		while (isxdigit(*p))
+			p++;
+	}
+	return (p - buf);
+}
+
 /*
  * Return a string representing a valid layout for a cpuset_t object.
  * It expects an incoming buffer at least sized as CPUSETBUFSIZ.
@@ -1139,19 +1207,9 @@ out:
 char *
 cpusetobj_strprint(char *buf, const cpuset_t *set)
 {
-	char *tbuf;
-	size_t i, bytesp, bufsiz;
 
-	tbuf = buf;
-	bytesp = 0;
-	bufsiz = CPUSETBUFSIZ;
-
-	for (i = 0; i < (_NCPUWORDS - 1); i++) {
-		bytesp = snprintf(tbuf, bufsiz, "%lx,", set->__bits[i]);
-		bufsiz -= bytesp;
-		tbuf += bytesp;
-	}
-	snprintf(tbuf, bufsiz, "%lx", set->__bits[_NCPUWORDS - 1]);
+	bitset_strprint(buf, CPUSETBUFSIZ, (const struct bitset *)set,
+	    CPU_SETSIZE);
 	return (buf);
 }
 
@@ -1162,37 +1220,71 @@ cpusetobj_strprint(char *buf, const cpuset_t *set)
 int
 cpusetobj_strscan(cpuset_t *set, const char *buf)
 {
-	u_int nwords;
-	int i, ret;
+	char p;
 
 	if (strlen(buf) > CPUSETBUFSIZ - 1)
 		return (-1);
 
-	/* Allow to pass a shorter version of the mask when necessary. */
-	nwords = 1;
-	for (i = 0; buf[i] != '\0'; i++)
-		if (buf[i] == ',')
-			nwords++;
-	if (nwords > _NCPUWORDS)
+	p = buf[bitset_strscan((struct bitset *)set, CPU_SETSIZE, buf)];
+	if (p != '\0')
 		return (-1);
 
-	CPU_ZERO(set);
-	for (i = 0; i < (nwords - 1); i++) {
-		ret = sscanf(buf, "%lx,", &set->__bits[i]);
-		if (ret == 0 || ret == -1)
-			return (-1);
-		buf = strstr(buf, ",");
-		if (buf == NULL)
-			return (-1);
-		buf++;
-	}
-	ret = sscanf(buf, "%lx", &set->__bits[nwords - 1]);
-	if (ret == 0 || ret == -1)
-		return (-1);
 	return (0);
 }
 
 /*
+ * Handle a domainset specifier in the sysctl tree.  A poiner to a pointer to
+ * a domainset is in arg1.  If the user specifies a valid domainset the
+ * pointer is updated.
+ *
+ * Format is:
+ * hex mask word 0,hex mask word 1,...:decimal policy:decimal preferred
+ */
+int
+sysctl_handle_domainset(SYSCTL_HANDLER_ARGS)
+{
+	char buf[DOMAINSETBUFSIZ];
+	struct domainset *dset;
+	struct domainset key;
+	char *p;
+	int error;
+
+	dset = *(struct domainset **)arg1;
+	error = 0;
+
+	if (dset != NULL) {
+		p = buf + bitset_strprint(buf, DOMAINSETBUFSIZ,
+		    (const struct bitset *)&dset->ds_mask, DOMAINSET_SETSIZE);
+		sprintf(p, ":%d:%d", dset->ds_policy, dset->ds_prefer);
+	} else
+		sprintf(buf, "<NULL>");
+	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+	if (error != 0 || req->newptr == NULL)
+		return (error);
+
+	/*
+	 * Read in and validate the string.
+	 */
+	memset(&key, 0, sizeof(key));
+	p = &buf[bitset_strscan((struct bitset *)&key.ds_mask,
+	    DOMAINSET_SETSIZE, buf)];
+	if (p == buf)
+		return (EINVAL);
+	if (sscanf(p, ":%hd:%hhd", &key.ds_policy, &key.ds_prefer) != 2)
+		return (EINVAL);
+
+	/* Domainset_create() validates the policy.*/
+	dset = domainset_create(&key);
+	if (dset == NULL)
+		return (EINVAL);
+	*(struct domainset **)arg1 = dset;
+
+	return (error);
+}
+
+#ifdef DDB
+
+/*
  * Apply an anonymous mask or a domain to a single thread.
  */
 static int
@@ -1256,8 +1348,6 @@ cpuset_setithread(lwpid_t id, int cpu)
 /*
  * Create the domainset for cpuset 0, 1 and cpuset 2.
  */
-static struct domainset domainset0, domainset2;
-
 void
 domainset_zero(void)
 {
@@ -2079,8 +2169,6 @@ out:
 	return (error);
 }
 
-#ifdef DDB
-BITSET_DEFINE(bitset, 1);
 static void
 ddb_display_bitset(const struct bitset *set, int size)
 {

Modified: user/jeff/numa/sys/sys/_bitset.h
==============================================================================
--- user/jeff/numa/sys/sys/_bitset.h	Mon Mar 12 22:10:06 2018	(r330817)
+++ user/jeff/numa/sys/sys/_bitset.h	Mon Mar 12 22:17:14 2018	(r330818)
@@ -57,4 +57,10 @@ struct t {								\
  */
 #define BITSET_DEFINE_VAR(t)	BITSET_DEFINE(t, 1)
 
+/*
+ * Define a default type that can be used while manually specifying size
+ * to every call.
+ */
+BITSET_DEFINE(bitset, 1);
+
 #endif /* !_SYS__BITSET_H_ */

Modified: user/jeff/numa/sys/sys/domainset.h
==============================================================================
--- user/jeff/numa/sys/sys/domainset.h	Mon Mar 12 22:10:06 2018	(r330817)
+++ user/jeff/numa/sys/sys/domainset.h	Mon Mar 12 22:17:14 2018	(r330818)
@@ -28,8 +28,8 @@
  * $FreeBSD$
  */
 
-#ifndef _SYS_DOMAINSETSET_H_
-#define	_SYS_DOMAINSETSET_H_
+#ifndef _SYS_DOMAINSET_H_
+#define	_SYS_DOMAINSET_H_
 
 #include <sys/_domainset.h>
 
@@ -38,8 +38,12 @@
 #define	_NDOMAINSETBITS			_BITSET_BITS
 #define	_NDOMAINSETWORDS		__bitset_words(DOMAINSET_SETSIZE)
 
-#define	DOMAINSETSETBUFSIZ	((2 + sizeof(long) * 2) * _NDOMAINSETWORDS)
+#define	DOMAINSETBUFSIZ							\
+	    (((2 + sizeof(long) * 2) * _NDOMAINSETWORDS) +		\
+	    sizeof("::") + sizeof(__XSTRING(DOMAINSET_POLICY_MAX)) +	\
+	    sizeof(__XSTRING(MAXMEMDOM)))
 
+
 #define	DOMAINSET_CLR(n, p)		BIT_CLR(DOMAINSET_SETSIZE, n, p)
 #define	DOMAINSET_COPY(f, t)		BIT_COPY(DOMAINSET_SETSIZE, f, t)
 #define	DOMAINSET_ISSET(n, p)		BIT_ISSET(DOMAINSET_SETSIZE, n, p)
@@ -77,9 +81,6 @@
 #define	DOMAINSET_POLICY_MAX		DOMAINSET_POLICY_INTERLEAVE
 
 #ifdef _KERNEL
-#include <sys/queue.h>
-LIST_HEAD(domainlist, domainset);
-
 #if MAXMEMDOM < 256
 typedef	uint8_t		domainid_t;
 #else
@@ -97,6 +98,16 @@ struct domainset {
 
 void domainset_zero(void);
 
+/*
+ * Add a domainset to the system based on a key initializing policy, prefer,
+ * and mask.  Do not create and directly use domainset structures.  The
+ * returned value will not match the key pointer.
+ */
+struct domainset *domainset_create(const struct domainset *);
+#ifdef _SYS_SYSCTL_H_
+int sysctl_handle_domainset(SYSCTL_HANDLER_ARGS);
+#endif
+
 #else
 __BEGIN_DECLS
 int	cpuset_getdomain(cpulevel_t, cpuwhich_t, id_t, size_t, domainset_t *,
@@ -106,4 +117,4 @@ int	cpuset_setdomain(cpulevel_t, cpuwhich_t, id_t, siz
 
 __END_DECLS
 #endif
-#endif /* !_SYS_DOMAINSETSET_H_ */
+#endif /* !_SYS_DOMAINSET_H_ */

Modified: user/jeff/numa/sys/sys/proc.h
==============================================================================
--- user/jeff/numa/sys/sys/proc.h	Mon Mar 12 22:10:06 2018	(r330817)
+++ user/jeff/numa/sys/sys/proc.h	Mon Mar 12 22:17:14 2018	(r330818)
@@ -67,7 +67,7 @@
 #include <sys/ucontext.h>
 #include <sys/ucred.h>
 #include <sys/types.h>
-#include <sys/domainset.h>
+#include <sys/_domainset.h>
 
 #include <machine/proc.h>		/* Machine-dependent proc substruct. */
 #ifdef _KERNEL

Modified: user/jeff/numa/sys/vm/vnode_pager.c
==============================================================================
--- user/jeff/numa/sys/vm/vnode_pager.c	Mon Mar 12 22:10:06 2018	(r330817)
+++ user/jeff/numa/sys/vm/vnode_pager.c	Mon Mar 12 22:17:14 2018	(r330818)
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/sysctl.h>
 #include <sys/proc.h>
 #include <sys/vnode.h>
 #include <sys/mount.h>
@@ -69,6 +70,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/conf.h>
 #include <sys/rwlock.h>
 #include <sys/sf_buf.h>
+#include <sys/domainset.h>
 
 #include <machine/atomic.h>
 
@@ -108,6 +110,12 @@ struct pagerops vnodepagerops = {
 int vnode_pbuf_freecnt;
 int vnode_async_pbuf_freecnt;
 
+static struct domainset *vnode_domainset = NULL;
+
+SYSCTL_PROC(_debug, OID_AUTO, vnode_domainset, CTLTYPE_STRING | CTLFLAG_RW,
+    &vnode_domainset, 0, sysctl_handle_domainset, "A",
+    "Default vnode NUMA policy");
+
 /* Create the VM system backing object for this vnode */
 int
 vnode_create_vobject(struct vnode *vp, off_t isize, struct thread *td)
@@ -242,6 +250,7 @@ retry:
 		object->un_pager.vnp.vnp_size = size;
 		object->un_pager.vnp.writemappings = 0;
 		object->iosize = vp->v_mount->mnt_stat.f_iosize;
+		object->domain.dr_policy = vnode_domainset;
 
 		object->handle = handle;
 		VI_LOCK(vp);



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