Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102705107
D27298.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D27298.diff
View Options
Index: head/sys/kern/kern_cpuset.c
===================================================================
--- head/sys/kern/kern_cpuset.c
+++ head/sys/kern/kern_cpuset.c
@@ -1104,14 +1104,63 @@
domainlist);
}
+static int
+cpuset_setproc_newbase(struct thread *td, struct cpuset *set,
+ struct cpuset *nroot, struct cpuset **nsetp,
+ struct setlist *cpusets, struct domainlist *domainlist)
+{
+ struct domainset ndomain;
+ cpuset_t nmask;
+ struct cpuset *pbase;
+ int error;
+
+ pbase = cpuset_getbase(td->td_cpuset);
+
+ /* Copy process mask, then further apply the new root mask. */
+ CPU_COPY(&pbase->cs_mask, &nmask);
+ CPU_AND(&nmask, &nroot->cs_mask);
+
+ domainset_copy(pbase->cs_domain, &ndomain);
+ DOMAINSET_AND(&ndomain.ds_mask, &set->cs_domain->ds_mask);
+
+ /* Policy is too restrictive, will not work. */
+ if (CPU_EMPTY(&nmask) || DOMAINSET_EMPTY(&ndomain.ds_mask))
+ return (EDEADLK);
+
+ /*
+ * Remove pbase from the freelist in advance, it'll be pushed to
+ * cpuset_ids on success. We assume here that cpuset_create() will not
+ * touch pbase on failure, and we just enqueue it back to the freelist
+ * to remain in a consistent state.
+ */
+ pbase = LIST_FIRST(cpusets);
+ LIST_REMOVE(pbase, cs_link);
+ error = cpuset_create(&pbase, set, &nmask);
+ if (error != 0) {
+ LIST_INSERT_HEAD(cpusets, pbase, cs_link);
+ return (error);
+ }
+
+ /* Duplicates some work from above... oh well. */
+ pbase->cs_domain = domainset_shadow(set->cs_domain, &ndomain,
+ domainlist);
+ *nsetp = pbase;
+ return (0);
+}
+
/*
- * Handle three cases for updating an entire process.
+ * Handle four cases for updating an entire process.
*
- * 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
+ * 1) Set is non-null and the process is not rebasing onto a new root. This
+ * reparents all anonymous sets to the provided set and replaces all
+ * non-anonymous td_cpusets with the provided set.
+ * 2) Set is non-null and the process is rebasing onto a new root. This
+ * creates a new base set if the process previously had its own base set,
+ * then reparents all anonymous sets either to that set or the provided set
+ * if one was not created. Non-anonymous sets are similarly replaced.
+ * 3) 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
+ * 4) 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
@@ -1120,15 +1169,15 @@
*/
static int
cpuset_setproc(pid_t pid, struct cpuset *set, cpuset_t *mask,
- struct domainset *domain)
+ struct domainset *domain, bool rebase)
{
struct setlist freelist;
struct setlist droplist;
struct domainlist domainlist;
- struct cpuset *nset;
+ struct cpuset *base, *nset, *nroot, *tdroot;
struct thread *td;
struct proc *p;
- int threads;
+ int needed;
int nfree;
int error;
@@ -1144,22 +1193,50 @@
nfree = 1;
LIST_INIT(&droplist);
nfree = 0;
+ base = set;
+ nroot = NULL;
+ if (set != NULL)
+ nroot = cpuset_getroot(set);
for (;;) {
error = cpuset_which(CPU_WHICH_PID, pid, &p, &td, &nset);
if (error)
goto out;
- if (nfree >= p->p_numthreads)
+ tdroot = cpuset_getroot(td->td_cpuset);
+ needed = p->p_numthreads;
+ if (set != NULL && rebase && tdroot != nroot)
+ needed++;
+ if (nfree >= needed)
break;
- threads = p->p_numthreads;
PROC_UNLOCK(p);
- if (nfree < threads) {
- cpuset_freelist_add(&freelist, threads - nfree);
- domainset_freelist_add(&domainlist, threads - nfree);
- nfree = threads;
+ if (nfree < needed) {
+ cpuset_freelist_add(&freelist, needed - nfree);
+ domainset_freelist_add(&domainlist, needed - nfree);
+ nfree = needed;
}
}
PROC_LOCK_ASSERT(p, MA_OWNED);
+
/*
+ * If we're changing roots and the root set is what has been specified
+ * as the parent, then we'll check if the process was previously using
+ * the root set and, if it wasn't, create a new base with the process's
+ * mask applied to it.
+ */
+ if (set != NULL && rebase && nroot != tdroot) {
+ cpusetid_t base_id, root_id;
+
+ root_id = td->td_ucred->cr_prison->pr_cpuset->cs_id;
+ base_id = cpuset_getbase(td->td_cpuset)->cs_id;
+
+ if (base_id != root_id) {
+ error = cpuset_setproc_newbase(td, set, nroot, &base,
+ &freelist, &domainlist);
+ if (error != 0)
+ goto unlock_out;
+ }
+ }
+
+ /*
* Now that the appropriate locks are held and we have enough cpusets,
* make sure the operation will succeed before applying changes. The
* proc lock prevents td_cpuset from changing between calls.
@@ -1169,7 +1246,7 @@
thread_lock(td);
if (set != NULL)
error = cpuset_setproc_test_setthread(td->td_cpuset,
- set);
+ base);
else
error = cpuset_setproc_test_maskthread(td->td_cpuset,
mask, domain);
@@ -1185,7 +1262,7 @@
FOREACH_THREAD_IN_PROC(p, td) {
thread_lock(td);
if (set != NULL)
- error = cpuset_setproc_setthread(td->td_cpuset, set,
+ error = cpuset_setproc_setthread(td->td_cpuset, base,
&nset, &freelist, &domainlist);
else
error = cpuset_setproc_maskthread(td->td_cpuset, mask,
@@ -1200,6 +1277,8 @@
unlock_out:
PROC_UNLOCK(p);
out:
+ if (base != NULL && base != set)
+ cpuset_rel(base);
while ((nset = LIST_FIRST(&droplist)) != NULL)
cpuset_rel_complete(nset);
cpuset_freelist_free(&freelist);
@@ -1584,7 +1663,7 @@
KASSERT(set != NULL, ("[%s:%d] invalid set", __func__, __LINE__));
cpuset_ref(set);
- error = cpuset_setproc(p->p_pid, set, NULL, NULL);
+ error = cpuset_setproc(p->p_pid, set, NULL, NULL, true);
if (error)
return (error);
cpuset_rel(set);
@@ -1634,7 +1713,7 @@
return (error);
error = copyout(&set->cs_id, uap->setid, sizeof(set->cs_id));
if (error == 0)
- error = cpuset_setproc(-1, set, NULL, NULL);
+ error = cpuset_setproc(-1, set, NULL, NULL, false);
cpuset_rel(set);
return (error);
}
@@ -1668,7 +1747,7 @@
set = cpuset_lookup(setid, td);
if (set == NULL)
return (ESRCH);
- error = cpuset_setproc(id, set, NULL, NULL);
+ error = cpuset_setproc(id, set, NULL, NULL, false);
cpuset_rel(set);
return (error);
}
@@ -1942,7 +2021,7 @@
error = cpuset_setthread(id, mask);
break;
case CPU_WHICH_PID:
- error = cpuset_setproc(id, NULL, mask, NULL);
+ error = cpuset_setproc(id, NULL, mask, NULL, false);
break;
case CPU_WHICH_CPUSET:
case CPU_WHICH_JAIL:
@@ -2226,7 +2305,7 @@
error = _cpuset_setthread(id, NULL, &domain);
break;
case CPU_WHICH_PID:
- error = cpuset_setproc(id, NULL, NULL, &domain);
+ error = cpuset_setproc(id, NULL, NULL, &domain, false);
break;
case CPU_WHICH_CPUSET:
case CPU_WHICH_JAIL:
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 17, 2:57 AM (20 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14669397
Default Alt Text
D27298.diff (6 KB)
Attached To
Mode
D27298: [2/2] kern: cpuset: properly rebase when attaching to a jail
Attached
Detach File
Event Timeline
Log In to Comment