Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F163222044
D13403.id36330.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
78 KB
Referenced Files
None
Subscribers
None
D13403.id36330.diff
View Options
Index: compat/freebsd32/syscalls.master
===================================================================
--- compat/freebsd32/syscalls.master
+++ compat/freebsd32/syscalls.master
@@ -1119,4 +1119,13 @@
struct kevent32 *eventlist, \
int nevents, \
const struct timespec32 *timeout); }
+561 AUE_NULL STD { int cpuset_getdomain(cpulevel_t level, \
+ cpuwhich_t which, id_t id, \
+ size_t domainsetsize, domainset_t *mask, \
+ int *policy); }
+562 AUE_NULL STD { int cpuset_setdomain(cpulevel_t level, \
+ cpuwhich_t which, id_t id, \
+ size_t domainsetsize, domainset_t *mask, \
+ int policy); }
+
; vim: syntax=off
Index: conf/files
===================================================================
--- conf/files
+++ conf/files
@@ -4816,7 +4816,7 @@
vm/uma_core.c standard
vm/uma_dbg.c standard
vm/memguard.c optional DEBUG_MEMGUARD
-vm/vm_domain.c standard
+vm/vm_domainset.c standard
vm/vm_fault.c standard
vm/vm_glue.c standard
vm/vm_init.c standard
Index: kern/init_main.c
===================================================================
--- kern/init_main.c
+++ kern/init_main.c
@@ -493,10 +493,7 @@
td->td_flags = TDF_INMEM;
td->td_pflags = TDP_KTHREAD;
td->td_cpuset = cpuset_thread0();
- vm_domain_policy_init(&td->td_vm_dom_policy);
- vm_domain_policy_set(&td->td_vm_dom_policy, VM_POLICY_NONE, -1);
- vm_domain_policy_init(&p->p_vm_dom_policy);
- vm_domain_policy_set(&p->p_vm_dom_policy, VM_POLICY_NONE, -1);
+ td->td_domain.dr_policy = td->td_cpuset->cs_domain;
prison0_init();
p->p_peers = 0;
p->p_leader = p;
Index: kern/init_sysent.c
===================================================================
--- kern/init_sysent.c
+++ kern/init_sysent.c
@@ -612,4 +612,6 @@
{ AS(fhstatfs_args), (sy_call_t *)sys_fhstatfs, AUE_FHSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 558 = fhstatfs */
{ AS(mknodat_args), (sy_call_t *)sys_mknodat, AUE_MKNODAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 559 = mknodat */
{ AS(kevent_args), (sy_call_t *)sys_kevent, AUE_KEVENT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 560 = kevent */
+ { AS(cpuset_getdomain_args), (sy_call_t *)sys_cpuset_getdomain, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 561 = cpuset_getdomain */
+ { AS(cpuset_setdomain_args), (sy_call_t *)sys_cpuset_setdomain, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 562 = cpuset_setdomain */
};
Index: kern/kern_cpuset.c
===================================================================
--- kern/kern_cpuset.c
+++ kern/kern_cpuset.c
@@ -51,17 +51,20 @@
#include <sys/syscallsubr.h>
#include <sys/capsicum.h>
#include <sys/cpuset.h>
+#include <sys/domainset.h>
#include <sys/sx.h>
#include <sys/queue.h>
#include <sys/libkern.h>
#include <sys/limits.h>
#include <sys/bus.h>
#include <sys/interrupt.h>
+#include <sys/vmmeter.h>
#include <vm/uma.h>
#include <vm/vm.h>
#include <vm/vm_page.h>
#include <vm/vm_param.h>
+#include <vm/vm_phys.h>
#ifdef DDB
#include <ddb/ddb.h>
@@ -109,8 +112,10 @@
* getaffinity call using (CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, ...).
*/
static uma_zone_t cpuset_zone;
+static uma_zone_t domainset_zone;
static struct mtx cpuset_lock;
static struct setlist cpuset_ids;
+static struct domainlist cpuset_domains;
static struct unrhdr *cpuset_unr;
static struct cpuset *cpuset_zero, *cpuset_default;
@@ -122,6 +127,30 @@
cpuset_t cpuset_domain[MAXMEMDOM];
/*
+ * Find the first non-anonymous set starting from 'set'.
+ */
+static struct cpuset *
+cpuset_getbase(struct cpuset *set)
+{
+
+ if (set->cs_id == CPUSET_INVALID)
+ set = set->cs_parent;
+ return (set);
+}
+
+/*
+ * Walks up the tree from 'set' to find the root.
+ */
+static struct cpuset *
+cpuset_getroot(struct cpuset *set)
+{
+
+ while ((set->cs_flags & CPU_SET_ROOT) == 0 && set->cs_parent != NULL)
+ set = set->cs_parent;
+ return (set);
+}
+
+/*
* Acquire a reference to a cpuset, all pointers must be tracked with refs.
*/
struct cpuset *
@@ -140,12 +169,7 @@
cpuset_refroot(struct cpuset *set)
{
- for (; set->cs_parent != NULL; set = set->cs_parent)
- if (set->cs_flags & CPU_SET_ROOT)
- break;
- cpuset_ref(set);
-
- return (set);
+ return cpuset_ref(cpuset_getroot(set));
}
/*
@@ -157,11 +181,7 @@
cpuset_refbase(struct cpuset *set)
{
- if (set->cs_id == CPUSET_INVALID)
- set = set->cs_parent;
- cpuset_ref(set);
-
- return (set);
+ return cpuset_ref(cpuset_getbase(set));
}
/*
@@ -258,16 +278,24 @@
*/
static int
_cpuset_create(struct cpuset *set, struct cpuset *parent, const cpuset_t *mask,
- cpusetid_t id)
+ struct domainset *domain, cpusetid_t id)
{
+ if (domain == NULL)
+ domain = parent->cs_domain;
+ if (mask == NULL)
+ mask = &parent->cs_mask;
if (!CPU_OVERLAP(&parent->cs_mask, mask))
return (EDEADLK);
+ /* The domain must be prepared ahead of time. */
+ if (!DOMAINSET_SUBSET(&parent->cs_domain->ds_mask, &domain->ds_mask))
+ return (EDEADLK);
CPU_COPY(mask, &set->cs_mask);
LIST_INIT(&set->cs_children);
refcount_init(&set->cs_ref, 1);
set->cs_flags = 0;
mtx_lock_spin(&cpuset_lock);
+ set->cs_domain = domain;
CPU_AND(&set->cs_mask, &parent->cs_mask);
set->cs_id = id;
set->cs_parent = cpuset_ref(parent);
@@ -294,8 +322,8 @@
id = alloc_unr(cpuset_unr);
if (id == -1)
return (ENFILE);
- *setp = set = uma_zalloc(cpuset_zone, M_WAITOK);
- error = _cpuset_create(set, parent, mask, id);
+ *setp = set = uma_zalloc(cpuset_zone, M_WAITOK | M_ZERO);
+ error = _cpuset_create(set, parent, mask, NULL, id);
if (error == 0)
return (0);
free_unr(cpuset_unr, id);
@@ -304,7 +332,158 @@
return (error);
}
+static void
+cpuset_freelist_add(struct setlist *list, int count)
+{
+ struct cpuset *set;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ set = uma_zalloc(cpuset_zone, M_ZERO | M_WAITOK);
+ LIST_INSERT_HEAD(list, set, cs_link);
+ }
+}
+
+static void
+cpuset_freelist_init(struct setlist *list, int count)
+{
+
+ LIST_INIT(list);
+ cpuset_freelist_add(list, count);
+}
+
+static void
+cpuset_freelist_free(struct setlist *list)
+{
+ struct cpuset *set;
+
+ while ((set = LIST_FIRST(list)) != NULL) {
+ LIST_REMOVE(set, cs_link);
+ uma_zfree(cpuset_zone, set);
+ }
+}
+
+static void
+domainset_freelist_add(struct domainlist *list, int count)
+{
+ struct domainset *set;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ set = uma_zalloc(domainset_zone, M_ZERO | M_WAITOK);
+ LIST_INSERT_HEAD(list, set, ds_link);
+ }
+}
+
+static void
+domainset_freelist_init(struct domainlist *list, int count)
+{
+
+ LIST_INIT(list);
+ domainset_freelist_add(list, count);
+}
+
+static void
+domainset_freelist_free(struct domainlist *list)
+{
+ struct domainset *set;
+
+ while ((set = LIST_FIRST(list)) != NULL) {
+ LIST_REMOVE(set, ds_link);
+ uma_zfree(cpuset_zone, set);
+ }
+}
+
+/* Copy a domainset preserving mask and policy. */
+static void
+domainset_copy(struct domainset *from, struct domainset *to)
+{
+
+ DOMAINSET_COPY(&from->ds_mask, &to->ds_mask);
+ to->ds_policy = from->ds_policy;
+}
+
+/* Return 1 if mask and policy are equal, otherwise 0. */
+static int
+domainset_equal(struct domainset *one, struct domainset *two)
+{
+
+ return (DOMAINSET_CMP(&one->ds_mask, &two->ds_mask) == 0 &&
+ one->ds_policy == two->ds_policy);
+}
+
/*
+ * Lookup or create a domainset. The key is provided in ds_mask and
+ * ds_policy. If the domainset does not yet exist the storage in
+ * 'domain' is used to insert. Otherwise this storage is freed to the
+ * domainset_zone and the existing domainset is returned.
+ */
+static struct domainset *
+_domainset_create(struct domainset *domain, struct domainlist *freelist)
+{
+ struct domainset *ndomain;
+
+ mtx_lock_spin(&cpuset_lock);
+ LIST_FOREACH(ndomain, &cpuset_domains, ds_link)
+ if (domainset_equal(ndomain, domain))
+ break;
+ /*
+ * If the domain does not yet exist we insert it and initialize
+ * various iteration helpers which are not part of the key.
+ */
+ if (ndomain == NULL) {
+ LIST_INSERT_HEAD(&cpuset_domains, domain, ds_link);
+ domain->ds_cnt = DOMAINSET_COUNT(&domain->ds_mask);
+ domain->ds_max = DOMAINSET_FLS(&domain->ds_mask);
+ }
+ mtx_unlock_spin(&cpuset_lock);
+ if (ndomain == NULL)
+ return (domain);
+ if (freelist != NULL)
+ LIST_INSERT_HEAD(freelist, domain, ds_link);
+ else
+ uma_zfree(domainset_zone, domain);
+ return (ndomain);
+
+}
+
+/*
+ * Create or lookup a domainset based on the key held in 'domain'.
+ */
+static struct domainset *
+domainset_create(const struct domainset *domain)
+{
+ struct domainset *ndomain;
+
+ ndomain = uma_zalloc(domainset_zone, M_WAITOK | M_ZERO);
+ ndomain->ds_policy = domain->ds_policy;
+ DOMAINSET_COPY(&domain->ds_policy, &ndomain->ds_policy);
+ return _domainset_create(ndomain, NULL);
+}
+
+static struct domainset *
+domainset_shadow(struct domainset *pdomain,
+ struct domainset *domain, struct domainlist *freelist)
+{
+ struct domainset *ndomain;
+
+ ndomain = LIST_FIRST(freelist);
+ LIST_REMOVE(ndomain, ds_link);
+
+ /*
+ * Initialize the key from the request.
+ */
+ domainset_copy(domain, ndomain);
+
+ /*
+ * Restrict the key by the parent.
+ */
+ DOMAINSET_AND(&ndomain->ds_mask, &pdomain->ds_mask);
+
+ return _domainset_create(ndomain, freelist);
+}
+
+/*
* Recursively check for errors that would occur from applying mask to
* the tree of sets starting at 'set'. Checks for sets that would become
* empty as well as RDONLY flags.
@@ -376,10 +555,12 @@
* Verify that we have access to this set of
* cpus.
*/
- root = set->cs_parent;
- if (root && !CPU_SUBSET(&root->cs_mask, mask))
- return (EINVAL);
+ root = cpuset_getroot(set);
mtx_lock_spin(&cpuset_lock);
+ if (root && !CPU_SUBSET(&root->cs_mask, mask)) {
+ error = EINVAL;
+ goto out;
+ }
error = cpuset_testupdate(set, mask, 0);
if (error)
goto out;
@@ -392,6 +573,135 @@
}
/*
+ * Recursively check for errors that would occur from applying mask to
+ * the tree of sets starting at 'set'. Checks for sets that would become
+ * empty as well as RDONLY flags.
+ */
+static int
+cpuset_testupdate_domain(struct cpuset *set, struct domainset *dset,
+ struct domainset *orig, int *count, int check_mask)
+{
+ struct cpuset *nset;
+ struct domainset *domain;
+ struct domainset newset;
+ int error;
+
+ mtx_assert(&cpuset_lock, MA_OWNED);
+ if (set->cs_flags & CPU_SET_RDONLY)
+ return (EPERM);
+ domain = set->cs_domain;
+ domainset_copy(domain, &newset);
+ if (!domainset_equal(domain, orig)) {
+ if (!DOMAINSET_OVERLAP(&domain->ds_mask, &dset->ds_mask))
+ return (EDEADLK);
+ DOMAINSET_AND(&newset.ds_mask, &dset->ds_mask);
+ /* Count the number of domains that are changing. */
+ (*count)++;
+ }
+ error = 0;
+ LIST_FOREACH(nset, &set->cs_children, cs_siblings)
+ if ((error = cpuset_testupdate_domain(nset, &newset, domain,
+ count, 1)) != 0)
+ break;
+ return (error);
+}
+
+/*
+ * Applies the mask 'mask' without checking for empty sets or permissions.
+ */
+static void
+cpuset_update_domain(struct cpuset *set, struct domainset *domain,
+ struct domainset *orig, struct domainlist *domains)
+{
+ struct cpuset *nset;
+
+ mtx_assert(&cpuset_lock, MA_OWNED);
+ /*
+ * If this domainset has changed from the parent we must calculate
+ * a new set. Otherwise it simply inherits from the parent. When
+ * we inherit from the parent we get a new mask and policy. If the
+ * set is modified from the parent we keep the policy and only
+ * update the mask.
+ */
+ if (set->cs_domain != orig) {
+ orig = set->cs_domain;
+ set->cs_domain = domainset_shadow(domain, orig, domains);
+ } else
+ set->cs_domain = domain;
+ LIST_FOREACH(nset, &set->cs_children, cs_siblings)
+ cpuset_update_domain(nset, set->cs_domain, orig, domains);
+
+ return;
+}
+
+/*
+ * Modify the set 'set' to use a copy the domainset provided. Apply this new
+ * mask to restrict all children in the tree. Checks for validity before
+ * applying the changes.
+ */
+static int
+cpuset_modify_domain(struct cpuset *set, struct domainset *domain)
+{
+ struct domainlist domains;
+ struct domainset temp;
+ struct domainset *dset;
+ struct cpuset *root;
+ int ndomains, needed;
+ int error;
+
+ error = priv_check(curthread, PRIV_SCHED_CPUSET);
+ if (error)
+ return (error);
+ /*
+ * In case we are called from within the jail
+ * we do not allow modifying the dedicated root
+ * cpuset of the jail but may still allow to
+ * change child sets.
+ */
+ if (jailed(curthread->td_ucred) &&
+ set->cs_flags & CPU_SET_ROOT)
+ return (EPERM);
+ domainset_freelist_init(&domains, 0);
+ domain = domainset_create(domain);
+ ndomains = needed = 0;
+ do {
+ if (ndomains < needed) {
+ domainset_freelist_add(&domains, needed - ndomains);
+ ndomains = needed;
+ }
+ root = cpuset_getroot(set);
+ mtx_lock_spin(&cpuset_lock);
+ dset = root->cs_domain;
+ /*
+ * Verify that we have access to this set of domains.
+ */
+ if (root &&
+ !DOMAINSET_SUBSET(&dset->ds_mask, &domain->ds_mask)) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * Determine whether we can apply this set of domains and
+ * how many new domain structures it will require.
+ */
+ domainset_copy(domain, &temp);
+ needed = 0;
+ error = cpuset_testupdate_domain(set, &temp, set->cs_domain,
+ &needed, 0);
+ if (error)
+ goto out;
+ } while (ndomains < needed);
+ dset = set->cs_domain;
+ set->cs_domain = domain;
+ cpuset_update_domain(set, domain, dset, &domains);
+out:
+ mtx_unlock_spin(&cpuset_lock);
+ domainset_freelist_free(&domains);
+
+ return (error);
+}
+
+/*
* Resolve the 'which' parameter of several cpuset apis.
*
* For WHICH_PID and WHICH_TID return a locked proc and valid proc/tid. Also
@@ -481,44 +791,203 @@
return (0);
}
+static int
+cpuset_testshadow(struct cpuset *set, const cpuset_t *mask,
+ struct domainset *domain)
+{
+ struct cpuset *parent;
+ struct domainset *dset;
+
+ parent = cpuset_getbase(set);
+ /*
+ * If we are restricting a cpu mask it must be a subset of the
+ * parent or invalid CPUs have been specified.
+ */
+ if (mask != NULL && !CPU_SUBSET(&parent->cs_mask, mask))
+ return (EINVAL);
+
+ /*
+ * If we are restricting a domain mask it must be a subset of the
+ * parent or invalid domains have been specified.
+ */
+ dset = parent->cs_domain;
+ if (domain != NULL &&
+ !DOMAINSET_SUBSET(&dset->ds_mask, &domain->ds_mask))
+ return (EINVAL);
+
+ return (0);
+}
+
/*
* Create an anonymous set with the provided mask in the space provided by
- * 'fset'. If the passed in set is anonymous we use its parent otherwise
+ * 'nset'. If the passed in set is anonymous we use its parent otherwise
* the new set is a child of 'set'.
*/
static int
-cpuset_shadow(struct cpuset *set, struct cpuset *fset, const cpuset_t *mask)
+cpuset_shadow(struct cpuset *set, struct cpuset **nsetp, const cpuset_t *mask,
+ struct domainset *domain, struct setlist *cpusets,
+ struct domainlist *domains)
{
struct cpuset *parent;
+ struct cpuset *nset;
+ struct domainset *dset;
+ int error;
- if (set->cs_id == CPUSET_INVALID)
- parent = set->cs_parent;
+ error = cpuset_testshadow(set, mask, domain);
+ if (error)
+ return (error);
+
+ parent = cpuset_getbase(set);
+ dset = parent->cs_domain;
+ if (mask == NULL)
+ mask = &set->cs_mask;
+ if (domain != NULL)
+ domain = domainset_shadow(dset, domain, domains);
else
- parent = set;
- if (!CPU_SUBSET(&parent->cs_mask, mask))
+ domain = set->cs_domain;
+ nset = LIST_FIRST(cpusets);
+ error = _cpuset_create(nset, parent, mask, domain, CPUSET_INVALID);
+ if (error == 0) {
+ LIST_REMOVE(nset, cs_link);
+ *nsetp = nset;
+ }
+ return (error);
+}
+
+static struct cpuset *
+cpuset_update_thread(struct thread *td, struct cpuset *nset)
+{
+ struct cpuset *tdset;
+
+ tdset = td->td_cpuset;
+ td->td_cpuset = nset;
+ td->td_domain.dr_policy = nset->cs_domain;
+ sched_affinity(td);
+
+ return (tdset);
+}
+
+static int
+cpuset_setproc_test_maskthread(struct cpuset *tdset, cpuset_t *mask,
+ struct domainset *domain)
+{
+ struct cpuset *parent;
+
+ parent = cpuset_getbase(tdset);
+ if (mask == NULL)
+ mask = &tdset->cs_mask;
+ if (domain == NULL)
+ domain = tdset->cs_domain;
+ return cpuset_testshadow(parent, mask, domain);
+}
+
+static int
+cpuset_setproc_maskthread(struct cpuset *tdset, cpuset_t *mask,
+ struct domainset *domain, struct cpuset **nsetp,
+ struct setlist *freelist, struct domainlist *domainlist)
+{
+ struct cpuset *parent;
+
+ parent = cpuset_getbase(tdset);
+ if (mask == NULL)
+ mask = &tdset->cs_mask;
+ if (domain == NULL)
+ domain = tdset->cs_domain;
+ return cpuset_shadow(parent, nsetp, mask, domain, freelist,
+ domainlist);
+}
+
+static int
+cpuset_setproc_setthread_mask(struct cpuset *tdset, struct cpuset *set,
+ cpuset_t *mask, struct domainset *domain)
+{
+ struct cpuset *parent;
+
+ parent = cpuset_getbase(tdset);
+
+ /*
+ * If the thread restricted its mask then apply that same
+ * restriction to the new set, otherwise take it wholesale.
+ */
+ if (CPU_CMP(&tdset->cs_mask, &parent->cs_mask) != 0) {
+ CPU_COPY(&tdset->cs_mask, mask);
+ CPU_AND(mask, &set->cs_mask);
+ } else
+ CPU_COPY(&set->cs_mask, mask);
+
+ /*
+ * If the thread restricted the domain then we apply the
+ * restriction to the new set but retain the policy.
+ */
+ if (tdset->cs_domain != parent->cs_domain) {
+ domainset_copy(tdset->cs_domain, domain);
+ DOMAINSET_AND(&domain->ds_mask, &set->cs_domain->ds_mask);
+ } else
+ domainset_copy(set->cs_domain, domain);
+
+ if (CPU_EMPTY(mask) || DOMAINSET_EMPTY(&domain->ds_mask))
return (EDEADLK);
- return (_cpuset_create(fset, parent, mask, CPUSET_INVALID));
+
+ return (0);
}
+static int
+cpuset_setproc_test_setthread(struct cpuset *tdset, struct cpuset *set)
+{
+ struct domainset domain;
+ cpuset_t mask;
+
+ if (tdset->cs_id != CPUSET_INVALID)
+ return (0);
+ return cpuset_setproc_setthread_mask(tdset, set, &mask, &domain);
+}
+
+static int
+cpuset_setproc_setthread(struct cpuset *tdset, struct cpuset *set,
+ struct cpuset **nsetp, struct setlist *freelist,
+ struct domainlist *domainlist)
+{
+ struct domainset domain;
+ cpuset_t mask;
+ int error;
+
+ /*
+ * If we're replacing on a thread that has not constrained the
+ * original set we can simply accept the new set.
+ */
+ if (tdset->cs_id != CPUSET_INVALID) {
+ *nsetp = cpuset_ref(set);
+ return (0);
+ }
+ error = cpuset_setproc_setthread_mask(tdset, set, &mask, &domain);
+ if (error)
+ return (error);
+
+ return cpuset_shadow(tdset, nsetp, &mask, &domain, freelist,
+ domainlist);
+}
+
/*
- * Handle two cases for replacing the base set or mask of an entire process.
+ * Handle three cases for updating an entire process.
*
- * 1) Set is non-null and mask is null. This reparents all anonymous sets
- * to the provided set and replaces all non-anonymous td_cpusets with the
- * provided set.
- * 2) Mask is non-null and set is null. This replaces or creates anonymous
- * sets for every thread with the existing base as a parent.
+ * 1) Set is non-null. This reparents all anonymous sets to the provided
+ * set and replaces all non-anonymous td_cpusets with the provided set.
+ * 2) Mask is non-null. This replaces or creates anonymous sets for every
+ * thread with the existing base as a parent.
+ * 3) domain is non-null. This creates anonymous sets for every thread
+ * and replaces the domain set.
*
* This is overly complicated because we can't allocate while holding a
* spinlock and spinlocks must be held while changing and examining thread
* state.
*/
static int
-cpuset_setproc(pid_t pid, struct cpuset *set, cpuset_t *mask)
+cpuset_setproc(pid_t pid, struct cpuset *set, cpuset_t *mask,
+ struct domainset *domain)
{
struct setlist freelist;
struct setlist droplist;
- struct cpuset *tdset;
+ struct domainlist domainlist;
struct cpuset *nset;
struct thread *td;
struct proc *p;
@@ -533,7 +1002,9 @@
* 2) If enough cpusets have not been allocated release the locks and
* allocate them. Loop.
*/
- LIST_INIT(&freelist);
+ cpuset_freelist_init(&freelist, 1);
+ domainset_freelist_init(&domainlist, 1);
+ nfree = 1;
LIST_INIT(&droplist);
nfree = 0;
for (;;) {
@@ -544,39 +1015,27 @@
break;
threads = p->p_numthreads;
PROC_UNLOCK(p);
- for (; nfree < threads; nfree++) {
- nset = uma_zalloc(cpuset_zone, M_WAITOK);
- LIST_INSERT_HEAD(&freelist, nset, cs_link);
+ if (nfree < threads) {
+ cpuset_freelist_add(&freelist, threads - nfree);
+ domainset_freelist_add(&domainlist, threads - nfree);
+ nfree = threads;
}
}
PROC_LOCK_ASSERT(p, MA_OWNED);
/*
* Now that the appropriate locks are held and we have enough cpusets,
- * make sure the operation will succeed before applying changes. The
+ * make sure the operation will succeed before applying changes. The
* proc lock prevents td_cpuset from changing between calls.
*/
error = 0;
FOREACH_THREAD_IN_PROC(p, td) {
thread_lock(td);
- tdset = td->td_cpuset;
- /*
- * Verify that a new mask doesn't specify cpus outside of
- * the set the thread is a member of.
- */
- if (mask) {
- if (tdset->cs_id == CPUSET_INVALID)
- tdset = tdset->cs_parent;
- if (!CPU_SUBSET(&tdset->cs_mask, mask))
- error = EDEADLK;
- /*
- * Verify that a new set won't leave an existing thread
- * mask without a cpu to run on. It can, however, restrict
- * the set.
- */
- } else if (tdset->cs_id == CPUSET_INVALID) {
- if (!CPU_OVERLAP(&set->cs_mask, &tdset->cs_mask))
- error = EDEADLK;
- }
+ if (set != NULL)
+ error = cpuset_setproc_test_setthread(td->td_cpuset,
+ set);
+ else
+ error = cpuset_setproc_test_maskthread(td->td_cpuset,
+ mask, domain);
thread_unlock(td);
if (error)
goto unlock_out;
@@ -588,33 +1047,17 @@
*/
FOREACH_THREAD_IN_PROC(p, td) {
thread_lock(td);
- /*
- * If we presently have an anonymous set or are applying a
- * mask we must create an anonymous shadow set. That is
- * either parented to our existing base or the supplied set.
- *
- * If we have a base set with no anonymous shadow we simply
- * replace it outright.
- */
- tdset = td->td_cpuset;
- if (tdset->cs_id == CPUSET_INVALID || mask) {
- nset = LIST_FIRST(&freelist);
- LIST_REMOVE(nset, cs_link);
- if (mask)
- error = cpuset_shadow(tdset, nset, mask);
- else
- error = _cpuset_create(nset, set,
- &tdset->cs_mask, CPUSET_INVALID);
- if (error) {
- LIST_INSERT_HEAD(&freelist, nset, cs_link);
- thread_unlock(td);
- break;
- }
- } else
- nset = cpuset_ref(set);
- cpuset_rel_defer(&droplist, tdset);
- td->td_cpuset = nset;
- sched_affinity(td);
+ if (set != NULL)
+ error = cpuset_setproc_setthread(td->td_cpuset, set,
+ &nset, &freelist, &domainlist);
+ else
+ error = cpuset_setproc_maskthread(td->td_cpuset, mask,
+ domain, &nset, &freelist, &domainlist);
+ if (error) {
+ thread_unlock(td);
+ break;
+ }
+ cpuset_rel_defer(&droplist, cpuset_update_thread(td, nset));
thread_unlock(td);
}
unlock_out:
@@ -622,10 +1065,8 @@
out:
while ((nset = LIST_FIRST(&droplist)) != NULL)
cpuset_rel_complete(nset);
- while ((nset = LIST_FIRST(&freelist)) != NULL) {
- LIST_REMOVE(nset, cs_link);
- uma_zfree(cpuset_zone, nset);
- }
+ cpuset_freelist_free(&freelist);
+ domainset_freelist_free(&domainlist);
return (error);
}
@@ -690,46 +1131,57 @@
}
/*
- * Apply an anonymous mask to a single thread.
+ * Apply an anonymous mask or a domain to a single thread.
*/
-int
-cpuset_setthread(lwpid_t id, cpuset_t *mask)
+static int
+_cpuset_setthread(lwpid_t id, cpuset_t *mask, struct domainset *domain)
{
+ struct setlist cpusets;
+ struct domainlist domainlist;
struct cpuset *nset;
struct cpuset *set;
struct thread *td;
struct proc *p;
int error;
- nset = uma_zalloc(cpuset_zone, M_WAITOK);
+ cpuset_freelist_init(&cpusets, 1);
+ domainset_freelist_init(&domainlist, domain != NULL);
error = cpuset_which(CPU_WHICH_TID, id, &p, &td, &set);
if (error)
goto out;
set = NULL;
thread_lock(td);
- error = cpuset_shadow(td->td_cpuset, nset, mask);
- if (error == 0) {
- set = td->td_cpuset;
- td->td_cpuset = nset;
- sched_affinity(td);
- nset = NULL;
- }
+ error = cpuset_shadow(td->td_cpuset, &nset, mask, domain,
+ &cpusets, &domainlist);
+ if (error == 0)
+ set = cpuset_update_thread(td, nset);
thread_unlock(td);
PROC_UNLOCK(p);
if (set)
cpuset_rel(set);
out:
- if (nset)
- uma_zfree(cpuset_zone, nset);
+ cpuset_freelist_free(&cpusets);
+ domainset_freelist_free(&domainlist);
return (error);
}
/*
+ * Apply an anonymous mask to a single thread.
+ */
+int
+cpuset_setthread(lwpid_t id, cpuset_t *mask)
+{
+
+ return _cpuset_setthread(id, mask, NULL);
+}
+
+/*
* Apply new cpumask to the ithread.
*/
int
cpuset_setithread(lwpid_t id, int cpu)
{
+ struct setlist cpusets;
struct cpuset *nset, *rset;
struct cpuset *parent, *old_set;
struct thread *td;
@@ -738,8 +1190,8 @@
cpuset_t mask;
int error;
- nset = uma_zalloc(cpuset_zone, M_WAITOK);
- rset = uma_zalloc(cpuset_zone, M_WAITOK);
+ cpuset_freelist_init(&cpusets, 1);
+ rset = uma_zalloc(cpuset_zone, M_WAITOK | M_ZERO);
cs_id = CPUSET_INVALID;
CPU_ZERO(&mask);
@@ -756,13 +1208,15 @@
old_set = td->td_cpuset;
if (cpu == NOCPU) {
+ nset = LIST_FIRST(&cpusets);
+ LIST_REMOVE(nset, cs_link);
/*
* roll back to default set. We're not using cpuset_shadow()
* here because we can fail CPU_SUBSET() check. This can happen
* if default set does not contain all CPUs.
*/
- error = _cpuset_create(nset, cpuset_default, &mask,
+ error = _cpuset_create(nset, cpuset_default, &mask, NULL,
CPUSET_INVALID);
goto applyset;
@@ -779,7 +1233,7 @@
* with any mask.
*/
error = _cpuset_create(rset, cpuset_zero,
- &cpuset_zero->cs_mask, cs_id);
+ &cpuset_zero->cs_mask, NULL, cs_id);
if (error != 0) {
PROC_UNLOCK(p);
goto out;
@@ -794,22 +1248,19 @@
old_set = NULL;
}
- error = cpuset_shadow(parent, nset, &mask);
+ error = cpuset_shadow(parent, &nset, &mask, NULL, &cpusets, NULL);
applyset:
if (error == 0) {
thread_lock(td);
- td->td_cpuset = nset;
- sched_affinity(td);
+ old_set = cpuset_update_thread(td, nset);
thread_unlock(td);
- nset = NULL;
} else
old_set = NULL;
PROC_UNLOCK(p);
if (old_set != NULL)
cpuset_rel(old_set);
out:
- if (nset != NULL)
- uma_zfree(cpuset_zone, nset);
+ cpuset_freelist_free(&cpusets);
if (rset != NULL)
uma_zfree(cpuset_zone, rset);
if (cs_id != CPUSET_INVALID)
@@ -817,7 +1268,24 @@
return (error);
}
+struct domainset domainset0;
+void
+domainset_zero(void)
+{
+ struct domainset *dset;
+ int i;
+
+ mtx_init(&cpuset_lock, "cpuset", NULL, MTX_SPIN | MTX_RECURSE);
+
+ dset = &domainset0;
+ DOMAINSET_ZERO(&dset->ds_mask);
+ for (i = 0; i < vm_ndomains; i++)
+ DOMAINSET_SET(i, &dset->ds_mask);
+ dset->ds_policy = DOMAINSET_POLICY_ROUNDROBIN;
+ curthread->td_domain.dr_policy = _domainset_create(dset, NULL);
+}
+
/*
* Creates system-wide cpusets and the cpuset for thread0 including two
* sets:
@@ -834,11 +1302,12 @@
cpuset_thread0(void)
{
struct cpuset *set;
- int error, i;
+ int error;
cpuset_zone = uma_zcreate("cpuset", sizeof(struct cpuset), NULL, NULL,
NULL, NULL, UMA_ALIGN_PTR, 0);
- mtx_init(&cpuset_lock, "cpuset", NULL, MTX_SPIN | MTX_RECURSE);
+ domainset_zone = uma_zcreate("domainset", sizeof(struct domainset),
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
/*
* Create the root system set for the whole machine. Doesn't use
@@ -850,14 +1319,15 @@
LIST_INSERT_HEAD(&cpuset_ids, set, cs_link);
set->cs_ref = 1;
set->cs_flags = CPU_SET_ROOT;
+ set->cs_domain = &domainset0;
cpuset_zero = set;
cpuset_root = &set->cs_mask;
/*
* Now derive a default, modifiable set from that to give out.
*/
- set = uma_zalloc(cpuset_zone, M_WAITOK);
- error = _cpuset_create(set, cpuset_zero, &cpuset_zero->cs_mask, 1);
+ set = uma_zalloc(cpuset_zone, M_WAITOK | M_ZERO);
+ error = _cpuset_create(set, cpuset_zero, NULL, NULL, 1);
KASSERT(error == 0, ("Error creating default set: %d\n", error));
cpuset_default = set;
@@ -866,16 +1336,6 @@
*/
cpuset_unr = new_unrhdr(2, INT_MAX, NULL);
- /*
- * If MD code has not initialized per-domain cpusets, place all
- * CPUs in domain 0.
- */
- for (i = 0; i < MAXMEMDOM; i++)
- if (!CPU_EMPTY(&cpuset_domain[i]))
- goto domains_set;
- CPU_COPY(&all_cpus, &cpuset_domain[0]);
-domains_set:
-
return (set);
}
@@ -920,7 +1380,7 @@
KASSERT(set != NULL, ("[%s:%d] invalid set", __func__, __LINE__));
cpuset_ref(set);
- error = cpuset_setproc(p->p_pid, set, NULL);
+ error = cpuset_setproc(p->p_pid, set, NULL, NULL);
if (error)
return (error);
cpuset_rel(set);
@@ -935,11 +1395,23 @@
cpuset_init(void *arg)
{
cpuset_t mask;
+ int i;
mask = all_cpus;
if (cpuset_modify(cpuset_zero, &mask))
panic("Can't set initial cpuset mask.\n");
cpuset_zero->cs_flags |= CPU_SET_RDONLY;
+
+ /*
+ * If MD code has not initialized per-domain cpusets, place all
+ * CPUs in domain 0.
+ */
+ for (i = 0; i < MAXMEMDOM; i++)
+ if (!CPU_EMPTY(&cpuset_domain[i]))
+ goto domains_set;
+ CPU_COPY(&all_cpus, &cpuset_domain[0]);
+domains_set:
+ return;
}
SYSINIT(cpuset, SI_SUB_SMP, SI_ORDER_ANY, cpuset_init, NULL);
@@ -964,7 +1436,7 @@
return (error);
error = copyout(&set->cs_id, uap->setid, sizeof(set->cs_id));
if (error == 0)
- error = cpuset_setproc(-1, set, NULL);
+ error = cpuset_setproc(-1, set, NULL, NULL);
cpuset_rel(set);
return (error);
}
@@ -998,7 +1470,7 @@
set = cpuset_lookup(setid, td);
if (set == NULL)
return (ESRCH);
- error = cpuset_setproc(id, set, NULL);
+ error = cpuset_setproc(id, set, NULL, NULL);
cpuset_rel(set);
return (error);
}
@@ -1285,7 +1757,7 @@
error = cpuset_setthread(id, mask);
break;
case CPU_WHICH_PID:
- error = cpuset_setproc(id, NULL, mask);
+ error = cpuset_setproc(id, NULL, mask, NULL);
break;
case CPU_WHICH_CPUSET:
case CPU_WHICH_JAIL:
@@ -1314,25 +1786,303 @@
return (error);
}
+#ifndef _SYS_SYSPROTO_H_
+struct cpuset_getdomain_args {
+ cpulevel_t level;
+ cpuwhich_t which;
+ id_t id;
+ size_t domainsetsize;
+ domainset_t *mask;
+ int *policy;
+};
+#endif
+int
+sys_cpuset_getdomain(struct thread *td, struct cpuset_getdomain_args *uap)
+{
+
+ return (kern_cpuset_getdomain(td, uap->level, uap->which,
+ uap->id, uap->domainsetsize, uap->mask, uap->policy));
+}
+
+int
+kern_cpuset_getdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
+ id_t id, size_t domainsetsize, domainset_t *maskp, int *policyp)
+{
+ struct thread *ttd;
+ struct cpuset *nset;
+ struct cpuset *set;
+ struct domainset *dset;
+ struct proc *p;
+ domainset_t *mask;
+ int policy;
+ int error;
+ size_t size;
+
+ if (domainsetsize < sizeof(domainset_t) ||
+ domainsetsize > DOMAINSET_MAXSIZE / NBBY)
+ return (ERANGE);
+ /* In Capability mode, you can only get your own domain set. */
+ if (IN_CAPABILITY_MODE(td)) {
+ if (level != CPU_LEVEL_WHICH)
+ return (ECAPMODE);
+ if (which != CPU_WHICH_TID && which != CPU_WHICH_PID)
+ return (ECAPMODE);
+ if (id != -1)
+ return (ECAPMODE);
+ }
+ policy = 0;
+ size = domainsetsize;
+ mask = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
+ error = cpuset_which(which, id, &p, &ttd, &set);
+ if (error)
+ goto out;
+ switch (level) {
+ case CPU_LEVEL_ROOT:
+ case CPU_LEVEL_CPUSET:
+ switch (which) {
+ case CPU_WHICH_TID:
+ case CPU_WHICH_PID:
+ thread_lock(ttd);
+ set = cpuset_ref(ttd->td_cpuset);
+ thread_unlock(ttd);
+ break;
+ case CPU_WHICH_CPUSET:
+ case CPU_WHICH_JAIL:
+ break;
+ case CPU_WHICH_IRQ:
+ case CPU_WHICH_INTRHANDLER:
+ case CPU_WHICH_ITHREAD:
+ case CPU_WHICH_DOMAIN:
+ error = EINVAL;
+ goto out;
+ }
+ if (level == CPU_LEVEL_ROOT)
+ nset = cpuset_refroot(set);
+ else
+ nset = cpuset_refbase(set);
+ /* Fetch once for a coherent result. */
+ dset = nset->cs_domain;
+ DOMAINSET_COPY(&dset->ds_mask, mask);
+ policy = dset->ds_policy;
+ cpuset_rel(nset);
+ break;
+ case CPU_LEVEL_WHICH:
+ switch (which) {
+ case CPU_WHICH_TID:
+ thread_lock(ttd);
+ /* Fetch once for a coherent result. */
+ dset = ttd->td_cpuset->cs_domain;
+ DOMAINSET_COPY(&dset->ds_mask, mask);
+ policy = dset->ds_policy;
+ thread_unlock(ttd);
+ break;
+ case CPU_WHICH_PID:
+ FOREACH_THREAD_IN_PROC(p, ttd) {
+ thread_lock(ttd);
+ dset = ttd->td_cpuset->cs_domain;
+ /* Show all domains in the proc. */
+ DOMAINSET_OR(mask, &dset->ds_mask);
+ /* Last policy wins. */
+ policy = dset->ds_policy;
+ thread_unlock(ttd);
+ }
+ break;
+ case CPU_WHICH_CPUSET:
+ case CPU_WHICH_JAIL:
+ dset = set->cs_domain;
+ policy = dset->ds_policy;
+ DOMAINSET_OR(mask, &dset->ds_mask);
+ break;
+ case CPU_WHICH_IRQ:
+ case CPU_WHICH_INTRHANDLER:
+ case CPU_WHICH_ITHREAD:
+ case CPU_WHICH_DOMAIN:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (set)
+ cpuset_rel(set);
+ if (p)
+ PROC_UNLOCK(p);
+ if (error == 0)
+ error = copyout(mask, maskp, size);
+ if (error == 0)
+ error = copyout(&policy, policyp, sizeof(*policyp));
+out:
+ free(mask, M_TEMP);
+ return (error);
+ return 0;
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct cpuset_setdomain_args {
+ cpulevel_t level;
+ cpuwhich_t which;
+ id_t id;
+ size_t domainsetsize;
+ domainset_t *mask;
+ int policy;
+};
+#endif
+int
+sys_cpuset_setdomain(struct thread *td, struct cpuset_setdomain_args *uap)
+{
+
+ return (kern_cpuset_setdomain(td, uap->level, uap->which,
+ uap->id, uap->domainsetsize, uap->mask, uap->policy));
+}
+
+int
+kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
+ id_t id, size_t domainsetsize, const domainset_t *maskp, int policy)
+{
+ struct cpuset *nset;
+ struct cpuset *set;
+ struct thread *ttd;
+ struct proc *p;
+ struct domainset domain;
+ domainset_t *mask;
+ int error;
+
+ if (domainsetsize < sizeof(domainset_t) ||
+ domainsetsize > DOMAINSET_MAXSIZE / NBBY)
+ return (ERANGE);
+ /* In Capability mode, you can only set your own CPU set. */
+ if (IN_CAPABILITY_MODE(td)) {
+ if (level != CPU_LEVEL_WHICH)
+ return (ECAPMODE);
+ if (which != CPU_WHICH_TID && which != CPU_WHICH_PID)
+ return (ECAPMODE);
+ if (id != -1)
+ return (ECAPMODE);
+ }
+ memset(&domain, 0, sizeof(domain));
+ mask = malloc(domainsetsize, M_TEMP, M_WAITOK | M_ZERO);
+ error = copyin(maskp, mask, domainsetsize);
+ if (error)
+ goto out;
+ /*
+ * Verify that no high bits are set.
+ */
+ if (domainsetsize > sizeof(domainset_t)) {
+ char *end;
+ char *cp;
+
+ end = cp = (char *)&mask->__bits;
+ end += domainsetsize;
+ cp += sizeof(domainset_t);
+ while (cp != end)
+ if (*cp++ != 0) {
+ error = EINVAL;
+ goto out;
+ }
+
+ }
+ DOMAINSET_COPY(mask, &domain.ds_mask);
+ domain.ds_policy = policy;
+
+ switch (level) {
+ case CPU_LEVEL_ROOT:
+ case CPU_LEVEL_CPUSET:
+ error = cpuset_which(which, id, &p, &ttd, &set);
+ if (error)
+ break;
+ switch (which) {
+ case CPU_WHICH_TID:
+ case CPU_WHICH_PID:
+ thread_lock(ttd);
+ set = cpuset_ref(ttd->td_cpuset);
+ thread_unlock(ttd);
+ PROC_UNLOCK(p);
+ break;
+ case CPU_WHICH_CPUSET:
+ case CPU_WHICH_JAIL:
+ break;
+ case CPU_WHICH_IRQ:
+ case CPU_WHICH_INTRHANDLER:
+ case CPU_WHICH_ITHREAD:
+ case CPU_WHICH_DOMAIN:
+ error = EINVAL;
+ goto out;
+ }
+ if (level == CPU_LEVEL_ROOT)
+ nset = cpuset_refroot(set);
+ else
+ nset = cpuset_refbase(set);
+ error = cpuset_modify_domain(nset, &domain);
+ cpuset_rel(nset);
+ cpuset_rel(set);
+ break;
+ case CPU_LEVEL_WHICH:
+ switch (which) {
+ case CPU_WHICH_TID:
+ error = _cpuset_setthread(id, NULL, &domain);
+ break;
+ case CPU_WHICH_PID:
+ error = cpuset_setproc(id, NULL, NULL, &domain);
+ break;
+ case CPU_WHICH_CPUSET:
+ case CPU_WHICH_JAIL:
+ error = cpuset_which(which, id, &p, &ttd, &set);
+ if (error == 0) {
+ error = cpuset_modify_domain(set, &domain);
+ cpuset_rel(set);
+ }
+ break;
+ case CPU_WHICH_IRQ:
+ case CPU_WHICH_INTRHANDLER:
+ case CPU_WHICH_ITHREAD:
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+out:
+ free(mask, M_TEMP);
+ return (error);
+}
+
#ifdef DDB
-void
-ddb_display_cpuset(const cpuset_t *set)
+BITSET_DEFINE(bitset, 1);
+static void
+ddb_display_bitset(const struct bitset *set, int size)
{
- int cpu, once;
+ int bit, once;
- for (once = 0, cpu = 0; cpu < CPU_SETSIZE; cpu++) {
- if (CPU_ISSET(cpu, set)) {
+ for (once = 0, bit = 0; bit < size; bit++) {
+ if (CPU_ISSET(bit, set)) {
if (once == 0) {
- db_printf("%d", cpu);
+ db_printf("%d", bit);
once = 1;
} else
- db_printf(",%d", cpu);
+ db_printf(",%d", bit);
}
}
if (once == 0)
db_printf("<none>");
}
+void
+ddb_display_cpuset(const cpuset_t *set)
+{
+ ddb_display_bitset((const struct bitset *)set, CPU_SETSIZE);
+}
+
+static void
+ddb_display_domainset(const domainset_t *set)
+{
+ ddb_display_bitset((const struct bitset *)set, DOMAINSET_SETSIZE);
+}
+
DB_SHOW_COMMAND(cpusets, db_show_cpusets)
{
struct cpuset *set;
@@ -1341,8 +2091,11 @@
db_printf("set=%p id=%-6u ref=%-6d flags=0x%04x parent id=%d\n",
set, set->cs_id, set->cs_ref, set->cs_flags,
(set->cs_parent != NULL) ? set->cs_parent->cs_id : 0);
- db_printf(" mask=");
+ db_printf(" cpu mask=");
ddb_display_cpuset(&set->cs_mask);
+ db_printf("\n");
+ db_printf(" domain mask=");
+ ddb_display_domainset(&set->cs_domain->ds_mask);
db_printf("\n");
if (db_pager_quit)
break;
Index: kern/kern_exit.c
===================================================================
--- kern/kern_exit.c
+++ kern/kern_exit.c
@@ -931,10 +931,6 @@
#ifdef MAC
mac_proc_destroy(p);
#endif
- /*
- * Free any domain policy that's still hiding around.
- */
- vm_domain_policy_cleanup(&p->p_vm_dom_policy);
KASSERT(FIRST_THREAD_IN_PROC(p),
("proc_reap: no residual thread!"));
Index: kern/kern_fork.c
===================================================================
--- kern/kern_fork.c
+++ kern/kern_fork.c
@@ -512,14 +512,6 @@
if (p1->p_flag & P_PROFIL)
startprofclock(p2);
- /*
- * Whilst the proc lock is held, copy the VM domain data out
- * using the VM domain method.
- */
- vm_domain_policy_init(&p2->p_vm_dom_policy);
- vm_domain_policy_localcopy(&p2->p_vm_dom_policy,
- &p1->p_vm_dom_policy);
-
if (fr->fr_flags & RFSIGSHARE) {
p2->p_sigacts = sigacts_hold(p1->p_sigacts);
} else {
Index: kern/kern_numa.c
===================================================================
--- kern/kern_numa.c
+++ kern/kern_numa.c
@@ -31,139 +31,16 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
-#include <sys/jail.h>
#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mutex.h>
-#include <sys/priv.h>
-#include <sys/proc.h>
-#include <sys/refcount.h>
-#include <sys/sched.h>
-#include <sys/smp.h>
-#include <sys/syscallsubr.h>
-#include <sys/cpuset.h>
-#include <sys/sx.h>
-#include <sys/queue.h>
-#include <sys/libkern.h>
-#include <sys/limits.h>
-#include <sys/bus.h>
-#include <sys/interrupt.h>
-#include <vm/uma.h>
-#include <vm/vm.h>
-#include <vm/vm_page.h>
-#include <vm/vm_param.h>
-#include <vm/vm_domain.h>
-
int
sys_numa_setaffinity(struct thread *td, struct numa_setaffinity_args *uap)
{
- int error;
- struct vm_domain_policy vp;
- struct thread *ttd;
- struct proc *p;
- struct cpuset *set;
-
- set = NULL;
- p = NULL;
-
- /*
- * Copy in just the policy information into the policy
- * struct. Userland only supplies vm_domain_policy_entry.
- */
- error = copyin(uap->policy, &vp.p, sizeof(vp.p));
- if (error)
- goto out;
-
- /*
- * Ensure the seq number is zero - otherwise seq.h
- * may get very confused.
- */
- vp.seq = 0;
-
- /*
- * Validate policy.
- */
- if (vm_domain_policy_validate(&vp) != 0) {
- error = EINVAL;
- goto out;
- }
-
- /*
- * Go find the desired proc/tid for this operation.
- */
- error = cpuset_which(uap->which, uap->id, &p,
- &ttd, &set);
- if (error)
- goto out;
-
- /* Only handle CPU_WHICH_TID and CPU_WHICH_PID */
- /*
- * XXX if cpuset_which is called with WHICH_CPUSET and NULL cpuset,
- * it'll return ESRCH. We should just return EINVAL.
- */
- switch (uap->which) {
- case CPU_WHICH_TID:
- vm_domain_policy_copy(&ttd->td_vm_dom_policy, &vp);
- break;
- case CPU_WHICH_PID:
- vm_domain_policy_copy(&p->p_vm_dom_policy, &vp);
- break;
- default:
- error = EINVAL;
- break;
- }
-
- PROC_UNLOCK(p);
-out:
- if (set)
- cpuset_rel(set);
- return (error);
+ return (ENOSYS);
}
int
sys_numa_getaffinity(struct thread *td, struct numa_getaffinity_args *uap)
{
- int error;
- struct vm_domain_policy vp;
- struct thread *ttd;
- struct proc *p;
- struct cpuset *set;
-
- set = NULL;
- p = NULL;
-
- error = cpuset_which(uap->which, uap->id, &p,
- &ttd, &set);
- if (error)
- goto out;
-
- /* Only handle CPU_WHICH_TID and CPU_WHICH_PID */
- /*
- * XXX if cpuset_which is called with WHICH_CPUSET and NULL cpuset,
- * it'll return ESRCH. We should just return EINVAL.
- */
- switch (uap->which) {
- case CPU_WHICH_TID:
- vm_domain_policy_localcopy(&vp, &ttd->td_vm_dom_policy);
- break;
- case CPU_WHICH_PID:
- vm_domain_policy_localcopy(&vp, &p->p_vm_dom_policy);
- break;
- default:
- error = EINVAL;
- break;
- }
- if (p)
- PROC_UNLOCK(p);
- /*
- * Copy out only the vm_domain_policy_entry part.
- */
- if (error == 0)
- error = copyout(&vp.p, uap->policy, sizeof(vp.p));
-out:
- if (set)
- cpuset_rel(set);
- return (error);
+ return (ENOSYS);
}
Index: kern/kern_thr.c
===================================================================
--- kern/kern_thr.c
+++ kern/kern_thr.c
@@ -260,12 +260,6 @@
if (p->p_ptevents & PTRACE_LWP)
newtd->td_dbgflags |= TDB_BORN;
- /*
- * Copy the existing thread VM policy into the new thread.
- */
- vm_domain_policy_localcopy(&newtd->td_vm_dom_policy,
- &td->td_vm_dom_policy);
-
PROC_UNLOCK(p);
tidhash_add(newtd);
Index: kern/kern_thread.c
===================================================================
--- kern/kern_thread.c
+++ kern/kern_thread.c
@@ -78,13 +78,13 @@
* structures.
*/
#ifdef __amd64__
-_Static_assert(offsetof(struct thread, td_flags) == 0xf4,
+_Static_assert(offsetof(struct thread, td_flags) == 0xfc,
"struct thread KBI td_flags");
-_Static_assert(offsetof(struct thread, td_pflags) == 0xfc,
+_Static_assert(offsetof(struct thread, td_pflags) == 0x104,
"struct thread KBI td_pflags");
-_Static_assert(offsetof(struct thread, td_frame) == 0x460,
+_Static_assert(offsetof(struct thread, td_frame) == 0x468,
"struct thread KBI td_frame");
-_Static_assert(offsetof(struct thread, td_emuldata) == 0x508,
+_Static_assert(offsetof(struct thread, td_emuldata) == 0x510,
"struct thread KBI td_emuldata");
_Static_assert(offsetof(struct proc, p_flag) == 0xb0,
"struct proc KBI p_flag");
@@ -98,13 +98,13 @@
"struct proc KBI p_emuldata");
#endif
#ifdef __i386__
-_Static_assert(offsetof(struct thread, td_flags) == 0x9c,
+_Static_assert(offsetof(struct thread, td_flags) == 0x100,
"struct thread KBI td_flags");
-_Static_assert(offsetof(struct thread, td_pflags) == 0xa4,
+_Static_assert(offsetof(struct thread, td_pflags) == 0xa8,
"struct thread KBI td_pflags");
-_Static_assert(offsetof(struct thread, td_frame) == 0x2ec,
+_Static_assert(offsetof(struct thread, td_frame) == 0x2f0,
"struct thread KBI td_frame");
-_Static_assert(offsetof(struct thread, td_emuldata) == 0x338,
+_Static_assert(offsetof(struct thread, td_emuldata) == 0x33c,
"struct thread KBI td_emuldata");
_Static_assert(offsetof(struct proc, p_flag) == 0x68,
"struct proc KBI p_flag");
@@ -413,7 +413,6 @@
return (NULL);
}
cpu_thread_alloc(td);
- vm_domain_policy_init(&td->td_vm_dom_policy);
return (td);
}
@@ -443,7 +442,6 @@
cpu_thread_free(td);
if (td->td_kstack != 0)
vm_thread_dispose(td);
- vm_domain_policy_cleanup(&td->td_vm_dom_policy);
callout_drain(&td->td_slpcallout);
uma_zfree(thread_zone, td);
}
Index: kern/makesyscalls.sh
===================================================================
--- kern/makesyscalls.sh
+++ kern/makesyscalls.sh
@@ -139,6 +139,7 @@
printf "#include <sys/signal.h>\n" > sysarg
printf "#include <sys/acl.h>\n" > sysarg
printf "#include <sys/cpuset.h>\n" > sysarg
+ printf "#include <sys/domainset.h>\n" > sysarg
printf "#include <sys/_ffcounter.h>\n" > sysarg
printf "#include <sys/_semaphore.h>\n" > sysarg
printf "#include <sys/ucontext.h>\n" > sysarg
Index: kern/sched_4bsd.c
===================================================================
--- kern/sched_4bsd.c
+++ kern/sched_4bsd.c
@@ -781,6 +781,7 @@
childtd->td_lastcpu = NOCPU;
childtd->td_lock = &sched_lock;
childtd->td_cpuset = cpuset_ref(td->td_cpuset);
+ child->td_domain.dr_policy = td->td_cpuset->cs_domain;
childtd->td_priority = childtd->td_base_pri;
ts = td_get_sched(childtd);
bzero(ts, sizeof(*ts));
Index: kern/sched_ule.c
===================================================================
--- kern/sched_ule.c
+++ kern/sched_ule.c
@@ -2131,6 +2131,7 @@
child->td_lastcpu = NOCPU;
child->td_lock = TDQ_LOCKPTR(tdq);
child->td_cpuset = cpuset_ref(td->td_cpuset);
+ child->td_domain.dr_policy = td->td_cpuset->cs_domain;
ts2->ts_cpu = ts->ts_cpu;
ts2->ts_flags = 0;
/*
Index: kern/syscalls.c
===================================================================
--- kern/syscalls.c
+++ kern/syscalls.c
@@ -567,4 +567,6 @@
"fhstatfs", /* 558 = fhstatfs */
"mknodat", /* 559 = mknodat */
"kevent", /* 560 = kevent */
+ "cpuset_getdomain", /* 561 = cpuset_getdomain */
+ "cpuset_setdomain", /* 562 = cpuset_setdomain */
};
Index: kern/syscalls.master
===================================================================
--- kern/syscalls.master
+++ kern/syscalls.master
@@ -1023,6 +1023,14 @@
struct kevent *changelist, int nchanges, \
struct kevent *eventlist, int nevents, \
const struct timespec *timeout); }
+561 AUE_NULL STD { int cpuset_getdomain(cpulevel_t level, \
+ cpuwhich_t which, id_t id, \
+ size_t domainsetsize, domainset_t *mask, \
+ int *policy); }
+562 AUE_NULL STD { int cpuset_setdomain(cpulevel_t level, \
+ cpuwhich_t which, id_t id, \
+ size_t domainsetsize, domainset_t *mask, \
+ int policy); }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
Index: kern/systrace_args.c
===================================================================
--- kern/systrace_args.c
+++ kern/systrace_args.c
@@ -3276,6 +3276,30 @@
*n_args = 6;
break;
}
+ /* cpuset_getdomain */
+ case 561: {
+ struct cpuset_getdomain_args *p = params;
+ iarg[0] = p->level; /* cpulevel_t */
+ iarg[1] = p->which; /* cpuwhich_t */
+ iarg[2] = p->id; /* id_t */
+ uarg[3] = p->domainsetsize; /* size_t */
+ uarg[4] = (intptr_t) p->mask; /* domainset_t * */
+ uarg[5] = (intptr_t) p->policy; /* int * */
+ *n_args = 6;
+ break;
+ }
+ /* cpuset_setdomain */
+ case 562: {
+ struct cpuset_setdomain_args *p = params;
+ iarg[0] = p->level; /* cpulevel_t */
+ iarg[1] = p->which; /* cpuwhich_t */
+ iarg[2] = p->id; /* id_t */
+ uarg[3] = p->domainsetsize; /* size_t */
+ uarg[4] = (intptr_t) p->mask; /* domainset_t * */
+ iarg[5] = p->policy; /* int */
+ *n_args = 6;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -8728,6 +8752,56 @@
break;
};
break;
+ /* cpuset_getdomain */
+ case 561:
+ switch(ndx) {
+ case 0:
+ p = "cpulevel_t";
+ break;
+ case 1:
+ p = "cpuwhich_t";
+ break;
+ case 2:
+ p = "id_t";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ case 4:
+ p = "userland domainset_t *";
+ break;
+ case 5:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cpuset_setdomain */
+ case 562:
+ switch(ndx) {
+ case 0:
+ p = "cpulevel_t";
+ break;
+ case 1:
+ p = "cpuwhich_t";
+ break;
+ case 2:
+ p = "id_t";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ case 4:
+ p = "userland domainset_t *";
+ break;
+ case 5:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -10611,6 +10685,16 @@
break;
/* kevent */
case 560:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* cpuset_getdomain */
+ case 561:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* cpuset_setdomain */
+ case 562:
if (ndx == 0 || ndx == 1)
p = "int";
break;
Index: sys/_domainset.h
===================================================================
--- sys/_domainset.h
+++ sys/_domainset.h
@@ -0,0 +1,62 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2017, Jeffrey Roberson <jeff@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS__DOMAINSET_H_
+#define _SYS__DOMAINSET_H_
+
+#include <sys/_bitset.h>
+
+#ifdef _KERNEL
+#define DOMAINSET_SETSIZE MAXMEMDOM
+#endif
+
+#define DOMAINSET_MAXSIZE 256
+
+#ifndef DOMAINSET_SETSIZE
+#define DOMAINSET_SETSIZE DOMAINSET_MAXSIZE
+#endif
+
+BITSET_DEFINE(_domainset, DOMAINSET_SETSIZE);
+typedef struct _domainset domainset_t;
+
+#ifdef _KERNEL
+/*
+ * This structure is intended to be embedded in objects which have policy
+ * attributes. Each object keeps its own iterator so round-robin is
+ * synchronized and accurate.
+ */
+struct domainset;
+struct domainset_ref {
+ struct domainset * volatile dr_policy;
+ int dr_iterator;
+};
+#endif
+
+#endif /* !_SYS__DOMAINSET_H_ */
Index: sys/cpuset.h
===================================================================
--- sys/cpuset.h
+++ sys/cpuset.h
@@ -112,6 +112,7 @@
*/
struct cpuset {
cpuset_t cs_mask; /* bitmask of valid cpus. */
+ struct domainset *cs_domain; /* (c) NUMA policy. */
volatile u_int cs_ref; /* (a) Reference count. */
int cs_flags; /* (s) Flags from below. */
cpusetid_t cs_id; /* (s) Id or INVALID. */
Index: sys/domainset.h
===================================================================
--- sys/domainset.h
+++ sys/domainset.h
@@ -0,0 +1,95 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2017, Jeffrey Roberson <jeff@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_DOMAINSETSET_H_
+#define _SYS_DOMAINSETSET_H_
+
+#include <sys/_domainset.h>
+
+#include <sys/bitset.h>
+
+#define _NDOMAINSETBITS _BITSET_BITS
+#define _NDOMAINSETWORDS __bitset_words(DOMAINSET_SETSIZE)
+
+#define DOMAINSETSETBUFSIZ ((2 + sizeof(long) * 2) * _NDOMAINSETWORDS)
+
+#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)
+#define DOMAINSET_SET(n, p) BIT_SET(DOMAINSET_SETSIZE, n, p)
+#define DOMAINSET_ZERO(p) BIT_ZERO(DOMAINSET_SETSIZE, p)
+#define DOMAINSET_FILL(p) BIT_FILL(DOMAINSET_SETSIZE, p)
+#define DOMAINSET_SETOF(n, p) BIT_SETOF(DOMAINSET_SETSIZE, n, p)
+#define DOMAINSET_EMPTY(p) BIT_EMPTY(DOMAINSET_SETSIZE, p)
+#define DOMAINSET_ISFULLSET(p) BIT_ISFULLSET(DOMAINSET_SETSIZE, p)
+#define DOMAINSET_SUBSET(p, c) BIT_SUBSET(DOMAINSET_SETSIZE, p, c)
+#define DOMAINSET_OVERLAP(p, c) BIT_OVERLAP(DOMAINSET_SETSIZE, p, c)
+#define DOMAINSET_CMP(p, c) BIT_CMP(DOMAINSET_SETSIZE, p, c)
+#define DOMAINSET_OR(d, s) BIT_OR(DOMAINSET_SETSIZE, d, s)
+#define DOMAINSET_AND(d, s) BIT_AND(DOMAINSET_SETSIZE, d, s)
+#define DOMAINSET_NAND(d, s) BIT_NAND(DOMAINSET_SETSIZE, d, s)
+#define DOMAINSET_CLR_ATOMIC(n, p) BIT_CLR_ATOMIC(DOMAINSET_SETSIZE, n, p)
+#define DOMAINSET_SET_ATOMIC(n, p) BIT_SET_ATOMIC(DOMAINSET_SETSIZE, n, p)
+#define DOMAINSET_SET_ATOMIC_ACQ(n, p) \
+ BIT_SET_ATOMIC_ACQ(DOMAINSET_SETSIZE, n, p)
+#define DOMAINSET_AND_ATOMIC(n, p) BIT_AND_ATOMIC(DOMAINSET_SETSIZE, n, p)
+#define DOMAINSET_OR_ATOMIC(d, s) BIT_OR_ATOMIC(DOMAINSET_SETSIZE, d, s)
+#define DOMAINSET_COPY_STORE_REL(f, t) \
+ BIT_COPY_STORE_REL(DOMAINSET_SETSIZE, f, t)
+#define DOMAINSET_FFS(p) BIT_FFS(DOMAINSET_SETSIZE, p)
+#define DOMAINSET_FLS(p) BIT_FLS(DOMAINSET_SETSIZE, p)
+#define DOMAINSET_COUNT(p) BIT_COUNT(DOMAINSET_SETSIZE, p)
+#define DOMAINSET_FSET BITSET_FSET(_NDOMAINSETWORDS)
+#define DOMAINSET_T_INITIALIZER BITSET_T_INITIALIZER
+
+#define DOMAINSET_POLICY_INVALID 0
+#define DOMAINSET_POLICY_ROUNDROBIN 1
+#define DOMAINSET_POLICY_FIRSTTOUCH 2
+#define DOMAINSET_POLICY_MAX DOMAINSET_POLICY_FIRSTTOUCH
+
+#ifdef _KERNEL
+#include <sys/queue.h>
+LIST_HEAD(domainlist, domainset);
+
+struct domainset {
+ LIST_ENTRY(domainset) ds_link;
+ domainset_t ds_mask; /* allowed domains. */
+ uint16_t ds_cnt; /* popcnt from above. */
+ uint16_t ds_max; /* Maximum domain in set. */
+ uint16_t ds_policy; /* Policy type. */
+};
+
+void domainset_zero(void);
+
+#else
+__BEGIN_DECLS
+__END_DECLS
+#endif
+#endif /* !_SYS_DOMAINSETSET_H_ */
Index: sys/param.h
===================================================================
--- sys/param.h
+++ sys/param.h
@@ -60,7 +60,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1200054 /* Master, propagated to newvers */
+#define __FreeBSD_version 1200055 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
Index: sys/proc.h
===================================================================
--- sys/proc.h
+++ sys/proc.h
@@ -40,6 +40,7 @@
#ifndef _SYS_PROC_H_
#define _SYS_PROC_H_
+#include <sys/systm.h>
#include <sys/callout.h> /* For struct callout. */
#include <sys/event.h> /* For struct klist. */
#include <sys/condvar.h>
@@ -63,9 +64,11 @@
#else
#include <sys/pcpu.h>
#endif
+#include <sys/types.h>
#include <sys/ucontext.h>
#include <sys/ucred.h>
-#include <sys/_vm_domain.h>
+#include <sys/_domainset.h>
+#include <machine/cpu.h>
#include <machine/proc.h> /* Machine-dependent proc substruct. */
/*
@@ -220,12 +223,12 @@
TAILQ_ENTRY(thread) td_lockq; /* (t) Lock queue. */
LIST_ENTRY(thread) td_hash; /* (d) Hash chain. */
struct cpuset *td_cpuset; /* (t) CPU affinity mask. */
+ struct domainset_ref td_domain; /* (a) NUMA policy */
struct seltd *td_sel; /* Select queue/channel. */
struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */
struct turnstile *td_turnstile; /* (k) Associated turnstile. */
struct rl_q_entry *td_rlqe; /* (k) Associated range lock entry. */
struct umtx_q *td_umtxq; /* (c?) Link for when we're blocked. */
- struct vm_domain_policy td_vm_dom_policy; /* (c) current numa domain policy */
lwpid_t td_tid; /* (b) Thread ID. */
sigqueue_t td_sigqueue; /* (c) Sigs arrived, not delivered. */
#define td_siglist td_sigqueue.sq_signals
@@ -284,7 +287,6 @@
pid_t td_dbg_forked; /* (c) Child pid for debugger. */
u_int td_vp_reserv; /* (k) Count of reserved vnodes. */
int td_no_sleeping; /* (k) Sleeping disabled count. */
- int td_dom_rr_idx; /* (k) RR Numa domain selection. */
void *td_su; /* (k) FFS SU private */
sbintime_t td_sleeptimo; /* (t) Sleep timeout. */
int td_rtcgen; /* (s) rtc_generation of abs. sleep */
@@ -653,7 +655,6 @@
uint64_t p_prev_runtime; /* (c) Resource usage accounting. */
struct racct *p_racct; /* (b) Resource accounting. */
int p_throttled; /* (c) Flag for racct pcpu throttling */
- struct vm_domain_policy p_vm_dom_policy; /* (c) process default VM domain, or -1 */
/*
* An orphan is the child that has beed re-parented to the
* debugger as a result of attaching to it. Need to keep
Index: sys/syscall.h
===================================================================
--- sys/syscall.h
+++ sys/syscall.h
@@ -478,4 +478,6 @@
#define SYS_fhstatfs 558
#define SYS_mknodat 559
#define SYS_kevent 560
-#define SYS_MAXSYSCALL 561
+#define SYS_cpuset_getdomain 561
+#define SYS_cpuset_setdomain 562
+#define SYS_MAXSYSCALL 563
Index: sys/syscall.mk
===================================================================
--- sys/syscall.mk
+++ sys/syscall.mk
@@ -405,4 +405,6 @@
getfsstat.o \
fhstatfs.o \
mknodat.o \
- kevent.o
+ kevent.o \
+ cpuset_getdomain.o \
+ cpuset_setdomain.o
Index: sys/syscallsubr.h
===================================================================
--- sys/syscallsubr.h
+++ sys/syscallsubr.h
@@ -36,6 +36,7 @@
#include <sys/mac.h>
#include <sys/mount.h>
#include <sys/_cpuset.h>
+#include <sys/_domainset.h>
struct file;
struct filecaps;
@@ -96,6 +97,12 @@
int kern_cpuset_setaffinity(struct thread *td, cpulevel_t level,
cpuwhich_t which, id_t id, size_t cpusetsize,
const cpuset_t *maskp);
+int kern_cpuset_getdomain(struct thread *td, cpulevel_t level,
+ cpuwhich_t which, id_t id, size_t domainsetsize,
+ domainset_t *maskp, int *policyp);
+int kern_cpuset_setdomain(struct thread *td, cpulevel_t level,
+ cpuwhich_t which, id_t id, size_t domainsetsize,
+ const domainset_t *maskp, int policy);
int kern_cpuset_getid(struct thread *td, cpulevel_t level,
cpuwhich_t which, id_t id, cpusetid_t *setid);
int kern_cpuset_setid(struct thread *td, cpuwhich_t which,
Index: sys/sysproto.h
===================================================================
--- sys/sysproto.h
+++ sys/sysproto.h
@@ -11,6 +11,7 @@
#include <sys/signal.h>
#include <sys/acl.h>
#include <sys/cpuset.h>
+#include <sys/domainset.h>
#include <sys/_ffcounter.h>
#include <sys/_semaphore.h>
#include <sys/ucontext.h>
@@ -1761,6 +1762,22 @@
char nevents_l_[PADL_(int)]; int nevents; char nevents_r_[PADR_(int)];
char timeout_l_[PADL_(const struct timespec *)]; const struct timespec * timeout; char timeout_r_[PADR_(const struct timespec *)];
};
+struct cpuset_getdomain_args {
+ char level_l_[PADL_(cpulevel_t)]; cpulevel_t level; char level_r_[PADR_(cpulevel_t)];
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id_l_[PADL_(id_t)]; id_t id; char id_r_[PADR_(id_t)];
+ char domainsetsize_l_[PADL_(size_t)]; size_t domainsetsize; char domainsetsize_r_[PADR_(size_t)];
+ char mask_l_[PADL_(domainset_t *)]; domainset_t * mask; char mask_r_[PADR_(domainset_t *)];
+ char policy_l_[PADL_(int *)]; int * policy; char policy_r_[PADR_(int *)];
+};
+struct cpuset_setdomain_args {
+ char level_l_[PADL_(cpulevel_t)]; cpulevel_t level; char level_r_[PADR_(cpulevel_t)];
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id_l_[PADL_(id_t)]; id_t id; char id_r_[PADR_(id_t)];
+ char domainsetsize_l_[PADL_(size_t)]; size_t domainsetsize; char domainsetsize_r_[PADR_(size_t)];
+ char mask_l_[PADL_(domainset_t *)]; domainset_t * mask; char mask_r_[PADR_(domainset_t *)];
+ char policy_l_[PADL_(int)]; int policy; char policy_r_[PADR_(int)];
+};
int nosys(struct thread *, struct nosys_args *);
void sys_sys_exit(struct thread *, struct sys_exit_args *);
int sys_fork(struct thread *, struct fork_args *);
@@ -2141,6 +2158,8 @@
int sys_fhstatfs(struct thread *, struct fhstatfs_args *);
int sys_mknodat(struct thread *, struct mknodat_args *);
int sys_kevent(struct thread *, struct kevent_args *);
+int sys_cpuset_getdomain(struct thread *, struct cpuset_getdomain_args *);
+int sys_cpuset_setdomain(struct thread *, struct cpuset_setdomain_args *);
#ifdef COMPAT_43
@@ -3033,6 +3052,8 @@
#define SYS_AUE_fhstatfs AUE_FHSTATFS
#define SYS_AUE_mknodat AUE_MKNODAT
#define SYS_AUE_kevent AUE_KEVENT
+#define SYS_AUE_cpuset_getdomain AUE_NULL
+#define SYS_AUE_cpuset_setdomain AUE_NULL
#undef PAD_
#undef PADL_
Index: vm/uma_core.c
===================================================================
--- vm/uma_core.c
+++ vm/uma_core.c
@@ -78,7 +78,6 @@
#include <sys/vmmeter.h>
#include <vm/vm.h>
-#include <vm/vm_domain.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_pageout.h>
Index: vm/vm_domainset.h
===================================================================
--- vm/vm_domainset.h
+++ vm/vm_domainset.h
@@ -0,0 +1,47 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2017, Jeffrey Roberson <jeff@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef __VM_DOMAINSET_H__
+#define __VM_DOMAINSET_H__
+
+struct vm_domainset_iter {
+ struct domainset *di_domain;
+ int *di_iter;
+ int di_flags;
+ int di_n;
+};
+
+int vm_domainset_iter_page(struct vm_domainset_iter *, int *, int *);
+void vm_domainset_iter_page_init(struct vm_domainset_iter *,
+ struct vm_object *, int *, int *);
+int vm_domainset_iter_malloc(struct vm_domainset_iter *, int *, int *);
+void vm_domainset_iter_malloc_init(struct vm_domainset_iter *,
+ struct vm_object *, int *, int *);
+
+#endif /* __VM_DOMAINSET_H__ */
Index: vm/vm_domainset.c
===================================================================
--- vm/vm_domainset.c
+++ vm/vm_domainset.c
@@ -0,0 +1,214 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2017, Jeffrey Roberson <jeff@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_vm.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bitset.h>
+#include <sys/domainset.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/malloc.h>
+#include <sys/vmmeter.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_domainset.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_phys.h>
+
+/*
+ * Iterators are written such that the first nowait pass has as short a
+ * codepath as possible to eliminate bloat from the allocator. It is
+ * assumed that most allocations are successful.
+ */
+
+/*
+ * Determine which policy is to be used for this allocation.
+ */
+static void
+vm_domainset_iter_domain(struct vm_domainset_iter *di, struct vm_object *obj)
+{
+ struct domainset *domain;
+
+ /*
+ * object policy takes precedence over thread policy. The policies
+ * are immutable and unsychronized. Updates can race but pointer
+ * loads are assumed to be atomic.
+ */
+ if (obj != NULL && (domain = obj->domain.dr_policy) != NULL) {
+ di->di_domain = domain;
+ di->di_iter = &obj->domain.dr_iterator;
+ } else {
+ di->di_domain = curthread->td_domain.dr_policy;
+ di->di_iter = &curthread->td_domain.dr_iterator;
+ }
+}
+
+static void
+vm_domainset_iter_rr(struct vm_domainset_iter *di, int *domain)
+{
+ int d;
+
+ d = *di->di_iter;
+ do {
+ d = (d + 1) % di->di_domain->ds_max;
+ } while (!DOMAINSET_ISSET(d, &di->di_domain->ds_mask));
+ *di->di_iter = *domain = d;
+}
+
+static void
+vm_domainset_iter_next(struct vm_domainset_iter *di, int *domain)
+{
+
+ switch (di->di_domain->ds_policy) {
+ case DOMAINSET_POLICY_FIRSTTOUCH:
+ /* FALLTHROUGH */
+ case DOMAINSET_POLICY_ROUNDROBIN:
+ vm_domainset_iter_rr(di, domain);
+ break;
+ default:
+ panic("vm_domainset_iter_first: Unknown policy %d",
+ di->di_domain->ds_policy);
+ }
+ di->di_n++;
+ KASSERT(*domain < vm_ndomains,
+ ("vm_domainset_iter_next: Invalid domain %d", *domain));
+}
+
+static void
+vm_domainset_iter_first(struct vm_domainset_iter *di, int *domain)
+{
+
+ di->di_n = 0;
+ switch (di->di_domain->ds_policy) {
+ case DOMAINSET_POLICY_FIRSTTOUCH:
+ *domain = PCPU_GET(domain);
+ /*
+ * To prevent impossible allocations we convert an invalid
+ * first-touch to round-robin.
+ */
+ if (DOMAINSET_ISSET(*domain, &di->di_domain->ds_mask))
+ break;
+ /* FALLTHROUGH */
+ case DOMAINSET_POLICY_ROUNDROBIN:
+ vm_domainset_iter_rr(di, domain);
+ break;
+ default:
+ panic("vm_domainset_iter_first: Unknown policy %d",
+ di->di_domain->ds_policy);
+ }
+ KASSERT(*domain < vm_ndomains,
+ ("vm_domainset_iter_first: Invalid domain %d", *domain));
+}
+
+void
+vm_domainset_iter_page_init(struct vm_domainset_iter *di, struct vm_object *obj,
+ int *domain, int *req)
+{
+
+ vm_domainset_iter_domain(di, obj);
+ di->di_flags = *req;
+ *req = (di->di_flags & ~(VM_ALLOC_WAITOK | VM_ALLOC_WAITFAIL)) |
+ VM_ALLOC_NOWAIT;
+ vm_domainset_iter_first(di, domain);
+}
+
+int
+vm_domainset_iter_page(struct vm_domainset_iter *di, int *domain, int *req)
+{
+
+ /*
+ * If we exhausted all options with NOWAIT and did a WAITFAIL it
+ * is time to return an error to the caller.
+ */
+ if ((*req & VM_ALLOC_WAITFAIL) != 0)
+ return (ENOMEM);
+
+ /* If there are more domains to visit we run the iterator. */
+ if (++di->di_n != di->di_domain->ds_cnt) {
+ vm_domainset_iter_next(di, domain);
+ return (0);
+ }
+
+ /* If we visited all domains and this was a NOWAIT we return error. */
+ if ((di->di_flags & (VM_ALLOC_WAITOK | VM_ALLOC_WAITFAIL)) == 0)
+ return (ENOMEM);
+
+ /*
+ * We have visited all domains with non-blocking allocations, try
+ * from the beginning with a blocking allocation.
+ */
+ vm_domainset_iter_first(di, domain);
+ *req = di->di_flags;
+
+ return (0);
+}
+
+
+void
+vm_domainset_iter_malloc_init(struct vm_domainset_iter *di,
+ struct vm_object *obj, int *domain, int *flags)
+{
+
+ vm_domainset_iter_domain(di, obj);
+ di->di_flags = *flags;
+ *flags = (di->di_flags & ~M_WAITOK) | M_NOWAIT;
+ vm_domainset_iter_first(di, domain);
+}
+
+int
+vm_domainset_iter_malloc(struct vm_domainset_iter *di, int *domain, int *flags)
+{
+
+ /* If there are more domains to visit we run the iterator. */
+ if (++di->di_n != di->di_domain->ds_cnt) {
+ vm_domainset_iter_next(di, domain);
+ return (0);
+ }
+
+ /* If we visited all domains and this was a NOWAIT we return error. */
+ if ((di->di_flags & M_WAITOK) == 0)
+ return (ENOMEM);
+
+ /*
+ * We have visited all domains with non-blocking allocations, try
+ * from the beginning with a blocking allocation.
+ */
+ vm_domainset_iter_first(di, domain);
+ *flags = di->di_flags;
+
+ return (0);
+}
Index: vm/vm_kern.c
===================================================================
--- vm/vm_kern.c
+++ vm/vm_kern.c
@@ -72,6 +72,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h> /* for ticks and hz */
+#include <sys/domainset.h>
#include <sys/eventhandler.h>
#include <sys/lock.h>
#include <sys/proc.h>
@@ -82,8 +83,8 @@
#include <sys/vmmeter.h>
#include <vm/vm.h>
-#include <vm/vm_domain.h>
#include <vm/vm_param.h>
+#include <vm/vm_domainset.h>
#include <vm/vm_kern.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
@@ -221,28 +222,20 @@
kmem_alloc_attr(vmem_t *vmem, vm_size_t size, int flags, vm_paddr_t low,
vm_paddr_t high, vm_memattr_t memattr)
{
- struct vm_domain_iterator vi;
+ struct vm_domainset_iter di;
vm_offset_t addr;
- int domain, wait;
+ int domain;
KASSERT(vmem == kernel_arena,
("kmem_alloc_attr: Only kernel_arena is supported."));
- addr = 0;
- vm_policy_iterator_init(&vi);
- wait = flags & M_WAITOK;
- flags &= ~M_WAITOK;
- flags |= M_NOWAIT;
- while (vm_domain_iterator_run(&vi, &domain) == 0) {
- if (vm_domain_iterator_isdone(&vi) && wait) {
- flags |= wait;
- flags &= ~M_NOWAIT;
- }
+
+ vm_domainset_iter_malloc_init(&di, kernel_object, &domain, &flags);
+ do {
addr = kmem_alloc_attr_domain(domain, size, flags, low, high,
memattr);
if (addr != 0)
break;
- }
- vm_policy_iterator_finish(&vi);
+ } while (vm_domainset_iter_malloc(&di, &domain, &flags) == 0);
return (addr);
}
@@ -317,28 +310,20 @@
vm_paddr_t high, u_long alignment, vm_paddr_t boundary,
vm_memattr_t memattr)
{
- struct vm_domain_iterator vi;
+ struct vm_domainset_iter di;
vm_offset_t addr;
- int domain, wait;
+ int domain;
KASSERT(vmem == kernel_arena,
("kmem_alloc_contig: Only kernel_arena is supported."));
- addr = 0;
- vm_policy_iterator_init(&vi);
- wait = flags & M_WAITOK;
- flags &= ~M_WAITOK;
- flags |= M_NOWAIT;
- while (vm_domain_iterator_run(&vi, &domain) == 0) {
- if (vm_domain_iterator_isdone(&vi) && wait) {
- flags |= wait;
- flags &= ~M_NOWAIT;
- }
+
+ vm_domainset_iter_malloc_init(&di, kernel_object, &domain, &flags);
+ do {
addr = kmem_alloc_contig_domain(domain, size, flags, low, high,
alignment, boundary, memattr);
if (addr != 0)
break;
- }
- vm_policy_iterator_finish(&vi);
+ } while (vm_domainset_iter_malloc(&di, &domain, &flags) == 0);
return (addr);
}
@@ -408,27 +393,19 @@
vm_offset_t
kmem_malloc(struct vmem *vmem, vm_size_t size, int flags)
{
- struct vm_domain_iterator vi;
+ struct vm_domainset_iter di;
vm_offset_t addr;
- int domain, wait;
+ int domain;
KASSERT(vmem == kernel_arena,
("kmem_malloc: Only kernel_arena is supported."));
- addr = 0;
- vm_policy_iterator_init(&vi);
- wait = flags & M_WAITOK;
- flags &= ~M_WAITOK;
- flags |= M_NOWAIT;
- while (vm_domain_iterator_run(&vi, &domain) == 0) {
- if (vm_domain_iterator_isdone(&vi) && wait) {
- flags |= wait;
- flags &= ~M_NOWAIT;
- }
+
+ vm_domainset_iter_malloc_init(&di, kernel_object, &domain, &flags);
+ do {
addr = kmem_malloc_domain(domain, size, flags);
if (addr != 0)
break;
- }
- vm_policy_iterator_finish(&vi);
+ } while (vm_domainset_iter_malloc(&di, &domain, &flags) == 0);
return (addr);
}
@@ -494,26 +471,19 @@
int
kmem_back(vm_object_t object, vm_offset_t addr, vm_size_t size, int flags)
{
- struct vm_domain_iterator vi;
- int domain, wait, ret;
+ struct vm_domainset_iter di;
+ int domain;
+ int ret;
KASSERT(object == kernel_object,
("kmem_back: only supports kernel object."));
- ret = 0;
- vm_policy_iterator_init(&vi);
- wait = flags & M_WAITOK;
- flags &= ~M_WAITOK;
- flags |= M_NOWAIT;
- while (vm_domain_iterator_run(&vi, &domain) == 0) {
- if (vm_domain_iterator_isdone(&vi) && wait) {
- flags |= wait;
- flags &= ~M_NOWAIT;
- }
+
+ vm_domainset_iter_malloc_init(&di, kernel_object, &domain, &flags);
+ do {
ret = kmem_back_domain(domain, object, addr, size, flags);
if (ret == KERN_SUCCESS)
break;
- }
- vm_policy_iterator_finish(&vi);
+ } while (vm_domainset_iter_malloc(&di, &domain, &flags) == 0);
return (ret);
}
Index: vm/vm_object.h
===================================================================
--- vm/vm_object.h
+++ vm/vm_object.h
@@ -74,6 +74,7 @@
#include <sys/_mutex.h>
#include <sys/_pctrie.h>
#include <sys/_rwlock.h>
+#include <sys/_domainset.h>
#include <vm/_vm_radix.h>
@@ -102,6 +103,7 @@
struct pglist memq; /* list of resident pages */
struct vm_radix rtree; /* root of the resident page radix trie*/
vm_pindex_t size; /* Object size */
+ struct domainset_ref domain; /* NUMA policy. */
int generation; /* generation ID */
int ref_count; /* How many refs?? */
int shadow_count; /* how many objects that this is a shadow for */
Index: vm/vm_page.c
===================================================================
--- vm/vm_page.c
+++ vm/vm_page.c
@@ -91,6 +91,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
+#include <sys/domainset.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/linker.h>
@@ -109,7 +110,7 @@
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_param.h>
-#include <vm/vm_domain.h>
+#include <vm/vm_domainset.h>
#include <vm/vm_kern.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
@@ -742,6 +743,12 @@
*/
vm_reserv_init();
#endif
+ /*
+ * Set an initial domain policy for thread0 so that allocations
+ * can work.
+ */
+ domainset_zero();
+
return (vaddr);
}
@@ -1624,23 +1631,17 @@
vm_page_alloc_after(vm_object_t object, vm_pindex_t pindex,
int req, vm_page_t mpred)
{
- struct vm_domain_iterator vi;
+ struct vm_domainset_iter di;
vm_page_t m;
- int domain, wait;
+ int domain;
- m = NULL;
- vm_policy_iterator_init(&vi);
- wait = req & (VM_ALLOC_WAITFAIL | VM_ALLOC_WAITOK);
- req &= ~wait;
- while (vm_domain_iterator_run(&vi, &domain) == 0) {
- if (vm_domain_iterator_isdone(&vi))
- req |= wait;
+ vm_domainset_iter_page_init(&di, object, &domain, &req);
+ do {
m = vm_page_alloc_domain_after(object, pindex, domain, req,
mpred);
if (m != NULL)
break;
- }
- vm_policy_iterator_finish(&vi);
+ } while (vm_domainset_iter_page(&di, &domain, &req) == 0);
return (m);
}
@@ -1839,23 +1840,17 @@
u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment,
vm_paddr_t boundary, vm_memattr_t memattr)
{
- struct vm_domain_iterator vi;
+ struct vm_domainset_iter di;
vm_page_t m;
- int domain, wait;
+ int domain;
- m = NULL;
- vm_policy_iterator_init(&vi);
- wait = req & (VM_ALLOC_WAITFAIL | VM_ALLOC_WAITOK);
- req &= ~wait;
- while (vm_domain_iterator_run(&vi, &domain) == 0) {
- if (vm_domain_iterator_isdone(&vi))
- req |= wait;
+ vm_domainset_iter_page_init(&di, object, &domain, &req);
+ do {
m = vm_page_alloc_contig_domain(object, pindex, domain, req,
npages, low, high, alignment, boundary, memattr);
if (m != NULL)
break;
- }
- vm_policy_iterator_finish(&vi);
+ } while (vm_domainset_iter_page(&di, &domain, &req) == 0);
return (m);
}
@@ -2051,22 +2046,16 @@
vm_page_t
vm_page_alloc_freelist(int flind, int req)
{
- struct vm_domain_iterator vi;
+ struct vm_domainset_iter di;
vm_page_t m;
- int domain, wait;
+ int domain;
- m = NULL;
- vm_policy_iterator_init(&vi);
- wait = req & (VM_ALLOC_WAITFAIL | VM_ALLOC_WAITOK);
- req &= ~wait;
- while (vm_domain_iterator_run(&vi, &domain) == 0) {
- if (vm_domain_iterator_isdone(&vi))
- req |= wait;
+ vm_domainset_iter_page_init(&di, NULL, &domain, &req);
+ do {
m = vm_page_alloc_freelist_domain(domain, flind, req);
if (m != NULL)
break;
- }
- vm_policy_iterator_finish(&vi);
+ } while (vm_domainset_iter_page(&di, &domain, &req) == 0);
return (m);
}
@@ -2655,19 +2644,17 @@
vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, vm_paddr_t high,
u_long alignment, vm_paddr_t boundary)
{
- struct vm_domain_iterator vi;
+ struct vm_domainset_iter di;
int domain;
bool ret;
- ret = false;
- vm_policy_iterator_init(&vi);
- while ((vm_domain_iterator_run(&vi, &domain)) == 0) {
+ vm_domainset_iter_page_init(&di, NULL, &domain, &req);
+ do {
ret = vm_page_reclaim_contig_domain(domain, req, npages, low,
high, alignment, boundary);
if (ret)
break;
- }
- vm_policy_iterator_finish(&vi);
+ } while (vm_domainset_iter_page(&di, &domain, &req) == 0);
return (ret);
}
Index: vm/vm_phys.c
===================================================================
--- vm/vm_phys.c
+++ vm/vm_phys.c
@@ -68,8 +68,6 @@
#include <vm/vm_page.h>
#include <vm/vm_phys.h>
-#include <vm/vm_domain.h>
-
_Static_assert(sizeof(long) * NBBY >= VM_PHYSSEG_MAX,
"Too many physsegs.");
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jul 22, 4:54 AM (3 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35348001
Default Alt Text
D13403.id36330.diff (78 KB)
Attached To
Mode
D13403: Implement thread domain policy via cpuset
Attached
Detach File
Event Timeline
Log In to Comment