From owner-svn-src-user@freebsd.org Mon Mar 12 22:17:15 2018 Return-Path: Delivered-To: svn-src-user@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id A897DF4FE3A for ; Mon, 12 Mar 2018 22:17:15 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 58997776A2; Mon, 12 Mar 2018 22:17:15 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 537311187D; Mon, 12 Mar 2018 22:17:15 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w2CMHFen059219; Mon, 12 Mar 2018 22:17:15 GMT (envelope-from jeff@FreeBSD.org) Received: (from jeff@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w2CMHEHw059214; Mon, 12 Mar 2018 22:17:14 GMT (envelope-from jeff@FreeBSD.org) Message-Id: <201803122217.w2CMHEHw059214@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: jeff set sender to jeff@FreeBSD.org using -f From: Jeff Roberson Date: Mon, 12 Mar 2018 22:17:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r330818 - in user/jeff/numa/sys: kern sys vm X-SVN-Group: user X-SVN-Commit-Author: jeff X-SVN-Commit-Paths: in user/jeff/numa/sys: kern sys vm X-SVN-Commit-Revision: 330818 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Mar 2018 22:17:15 -0000 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 #include +#include +#include #include #include #include @@ -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, ""); + 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 @@ -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 -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 #include #include -#include +#include #include /* 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 #include +#include #include #include #include @@ -69,6 +70,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include @@ -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);