if (is_cpuset_online(((des_cs) = css_cs((pos_css)))))
 
 /*
- * There are two global locks guarding cpuset structures - cpuset_rwsem and
+ * There are two global locks guarding cpuset structures - cpuset_mutex and
  * callback_lock. We also require taking task_lock() when dereferencing a
  * task's cpuset pointer. See "The task_lock() exception", at the end of this
- * comment.  The cpuset code uses only cpuset_rwsem write lock.  Other
- * kernel subsystems can use cpuset_read_lock()/cpuset_read_unlock() to
- * prevent change to cpuset structures.
+ * comment.  The cpuset code uses only cpuset_mutex. Other kernel subsystems
+ * can use cpuset_lock()/cpuset_unlock() to prevent change to cpuset
+ * structures. Note that cpuset_mutex needs to be a mutex as it is used in
+ * paths that rely on priority inheritance (e.g. scheduler - on RT) for
+ * correctness.
  *
  * A task must hold both locks to modify cpusets.  If a task holds
- * cpuset_rwsem, it blocks others wanting that rwsem, ensuring that it
- * is the only task able to also acquire callback_lock and be able to
- * modify cpusets.  It can perform various checks on the cpuset structure
- * first, knowing nothing will change.  It can also allocate memory while
- * just holding cpuset_rwsem.  While it is performing these checks, various
- * callback routines can briefly acquire callback_lock to query cpusets.
- * Once it is ready to make the changes, it takes callback_lock, blocking
- * everyone else.
+ * cpuset_mutex, it blocks others, ensuring that it is the only task able to
+ * also acquire callback_lock and be able to modify cpusets.  It can perform
+ * various checks on the cpuset structure first, knowing nothing will change.
+ * It can also allocate memory while just holding cpuset_mutex.  While it is
+ * performing these checks, various callback routines can briefly acquire
+ * callback_lock to query cpusets.  Once it is ready to make the changes, it
+ * takes callback_lock, blocking everyone else.
  *
  * Calls to the kernel memory allocator can not be made while holding
  * callback_lock, as that would risk double tripping on callback_lock
  * guidelines for accessing subsystem state in kernel/cgroup.c
  */
 
-DEFINE_STATIC_PERCPU_RWSEM(cpuset_rwsem);
+static DEFINE_MUTEX(cpuset_mutex);
 
-void cpuset_read_lock(void)
+void cpuset_lock(void)
 {
-       percpu_down_read(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
 }
 
-void cpuset_read_unlock(void)
+void cpuset_unlock(void)
 {
-       percpu_up_read(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
 }
 
 static DEFINE_SPINLOCK(callback_lock);
  * One way or another, we guarantee to return some non-empty subset
  * of cpu_online_mask.
  *
- * Call with callback_lock or cpuset_rwsem held.
+ * Call with callback_lock or cpuset_mutex held.
  */
 static void guarantee_online_cpus(struct task_struct *tsk,
                                  struct cpumask *pmask)
  * One way or another, we guarantee to return some non-empty subset
  * of node_states[N_MEMORY].
  *
- * Call with callback_lock or cpuset_rwsem held.
+ * Call with callback_lock or cpuset_mutex held.
  */
 static void guarantee_online_mems(struct cpuset *cs, nodemask_t *pmask)
 {
 /*
  * update task's spread flag if cpuset's page/slab spread flag is set
  *
- * Call with callback_lock or cpuset_rwsem held. The check can be skipped
+ * Call with callback_lock or cpuset_mutex held. The check can be skipped
  * if on default hierarchy.
  */
 static void cpuset_update_task_spread_flags(struct cpuset *cs,
  *
  * One cpuset is a subset of another if all its allowed CPUs and
  * Memory Nodes are a subset of the other, and its exclusive flags
- * are only set if the other's are set.  Call holding cpuset_rwsem.
+ * are only set if the other's are set.  Call holding cpuset_mutex.
  */
 
 static int is_cpuset_subset(const struct cpuset *p, const struct cpuset *q)
  * If we replaced the flag and mask values of the current cpuset
  * (cur) with those values in the trial cpuset (trial), would
  * our various subset and exclusive rules still be valid?  Presumes
- * cpuset_rwsem held.
+ * cpuset_mutex held.
  *
  * 'cur' is the address of an actual, in-use cpuset.  Operations
  * such as list traversal that depend on the actual address of the
        rcu_read_unlock();
 }
 
-/* Must be called with cpuset_rwsem held.  */
+/* Must be called with cpuset_mutex held.  */
 static inline int nr_cpusets(void)
 {
        /* jump label reference count + the top-level cpuset */
  * domains when operating in the severe memory shortage situations
  * that could cause allocation failures below.
  *
- * Must be called with cpuset_rwsem held.
+ * Must be called with cpuset_mutex held.
  *
  * The three key local variables below are:
  *    cp - cpuset pointer, used (together with pos_css) to perform a
        struct cpuset *cs = NULL;
        struct cgroup_subsys_state *pos_css;
 
-       percpu_rwsem_assert_held(&cpuset_rwsem);
+       lockdep_assert_held(&cpuset_mutex);
        lockdep_assert_cpus_held();
        lockdep_assert_held(&sched_domains_mutex);
 
  * 'cpus' is removed, then call this routine to rebuild the
  * scheduler's dynamic sched domains.
  *
- * Call with cpuset_rwsem held.  Takes cpus_read_lock().
+ * Call with cpuset_mutex held.  Takes cpus_read_lock().
  */
 static void rebuild_sched_domains_locked(void)
 {
        int ndoms;
 
        lockdep_assert_cpus_held();
-       percpu_rwsem_assert_held(&cpuset_rwsem);
+       lockdep_assert_held(&cpuset_mutex);
 
        /*
         * If we have raced with CPU hotplug, return early to avoid
 void rebuild_sched_domains(void)
 {
        cpus_read_lock();
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        rebuild_sched_domains_locked();
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
        cpus_read_unlock();
 }
 
  * @new_cpus: the temp variable for the new effective_cpus mask
  *
  * Iterate through each task of @cs updating its cpus_allowed to the
- * effective cpuset's.  As this function is called with cpuset_rwsem held,
+ * effective cpuset's.  As this function is called with cpuset_mutex held,
  * cpuset membership stays stable. For top_cpuset, task_cpu_possible_mask()
  * is used instead of effective_cpus to make sure all offline CPUs are also
  * included as hotplug code won't update cpumasks for tasks in top_cpuset.
        int old_prs, new_prs;
        int part_error = PERR_NONE;     /* Partition error? */
 
-       percpu_rwsem_assert_held(&cpuset_rwsem);
+       lockdep_assert_held(&cpuset_mutex);
 
        /*
         * The parent must be a partition root.
  *
  * On legacy hierarchy, effective_cpus will be the same with cpu_allowed.
  *
- * Called with cpuset_rwsem held
+ * Called with cpuset_mutex held
  */
 static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
                                 bool force)
        struct cpuset *sibling;
        struct cgroup_subsys_state *pos_css;
 
-       percpu_rwsem_assert_held(&cpuset_rwsem);
+       lockdep_assert_held(&cpuset_mutex);
 
        /*
         * Check all its siblings and call update_cpumasks_hier()
  * @cs: the cpuset in which each task's mems_allowed mask needs to be changed
  *
  * Iterate through each task of @cs updating its mems_allowed to the
- * effective cpuset's.  As this function is called with cpuset_rwsem held,
+ * effective cpuset's.  As this function is called with cpuset_mutex held,
  * cpuset membership stays stable.
  */
 static void update_tasks_nodemask(struct cpuset *cs)
 {
-       static nodemask_t newmems;      /* protected by cpuset_rwsem */
+       static nodemask_t newmems;      /* protected by cpuset_mutex */
        struct css_task_iter it;
        struct task_struct *task;
 
         * take while holding tasklist_lock.  Forks can happen - the
         * mpol_dup() cpuset_being_rebound check will catch such forks,
         * and rebind their vma mempolicies too.  Because we still hold
-        * the global cpuset_rwsem, we know that no other rebind effort
+        * the global cpuset_mutex, we know that no other rebind effort
         * will be contending for the global variable cpuset_being_rebound.
         * It's ok if we rebind the same mm twice; mpol_rebind_mm()
         * is idempotent.  Also migrate pages in each mm to new nodes.
  *
  * On legacy hierarchy, effective_mems will be the same with mems_allowed.
  *
- * Called with cpuset_rwsem held
+ * Called with cpuset_mutex held
  */
 static void update_nodemasks_hier(struct cpuset *cs, nodemask_t *new_mems)
 {
  * mempolicies and if the cpuset is marked 'memory_migrate',
  * migrate the tasks pages to the new memory.
  *
- * Call with cpuset_rwsem held. May take callback_lock during call.
+ * Call with cpuset_mutex held. May take callback_lock during call.
  * Will take tasklist_lock, scan tasklist for tasks in cpuset cs,
  * lock each such tasks mm->mmap_lock, scan its vma's and rebind
  * their mempolicies to the cpusets new mems_allowed.
  * @cs: the cpuset in which each task's spread flags needs to be changed
  *
  * Iterate through each task of @cs updating its spread flags.  As this
- * function is called with cpuset_rwsem held, cpuset membership stays
+ * function is called with cpuset_mutex held, cpuset membership stays
  * stable.
  */
 static void update_tasks_flags(struct cpuset *cs)
  * cs:         the cpuset to update
  * turning_on:         whether the flag is being set or cleared
  *
- * Call with cpuset_rwsem held.
+ * Call with cpuset_mutex held.
  */
 
 static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
  * @new_prs: new partition root state
  * Return: 0 if successful, != 0 if error
  *
- * Call with cpuset_rwsem held.
+ * Call with cpuset_mutex held.
  */
 static int update_prstate(struct cpuset *cs, int new_prs)
 {
        return 0;
 }
 
-/* Called by cgroups to determine if a cpuset is usable; cpuset_rwsem held */
+/* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */
 static int cpuset_can_attach(struct cgroup_taskset *tset)
 {
        struct cgroup_subsys_state *css;
        cpuset_attach_old_cs = task_cs(cgroup_taskset_first(tset, &css));
        cs = css_cs(css);
 
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
 
        /* Check to see if task is allowed in the cpuset */
        ret = cpuset_can_attach_check(cs);
         */
        cs->attach_in_progress++;
 out_unlock:
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
        return ret;
 }
 
        cgroup_taskset_first(tset, &css);
        cs = css_cs(css);
 
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        cs->attach_in_progress--;
        if (!cs->attach_in_progress)
                wake_up(&cpuset_attach_wq);
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
 }
 
 /*
- * Protected by cpuset_rwsem. cpus_attach is used only by cpuset_attach_task()
+ * Protected by cpuset_mutex. cpus_attach is used only by cpuset_attach_task()
  * but we can't allocate it dynamically there.  Define it global and
  * allocate from cpuset_init().
  */
 
 static void cpuset_attach_task(struct cpuset *cs, struct task_struct *task)
 {
-       percpu_rwsem_assert_held(&cpuset_rwsem);
+       lockdep_assert_held(&cpuset_mutex);
 
        if (cs != &top_cpuset)
                guarantee_online_cpus(task, cpus_attach);
        cs = css_cs(css);
 
        lockdep_assert_cpus_held();     /* see cgroup_attach_lock() */
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        cpus_updated = !cpumask_equal(cs->effective_cpus,
                                      oldcs->effective_cpus);
        mems_updated = !nodes_equal(cs->effective_mems, oldcs->effective_mems);
        if (!cs->attach_in_progress)
                wake_up(&cpuset_attach_wq);
 
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
 }
 
 /* The various types of files and directories in a cpuset file system */
        int retval = 0;
 
        cpus_read_lock();
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        if (!is_cpuset_online(cs)) {
                retval = -ENODEV;
                goto out_unlock;
                break;
        }
 out_unlock:
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
        cpus_read_unlock();
        return retval;
 }
        int retval = -ENODEV;
 
        cpus_read_lock();
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        if (!is_cpuset_online(cs))
                goto out_unlock;
 
                break;
        }
 out_unlock:
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
        cpus_read_unlock();
        return retval;
 }
         * operation like this one can lead to a deadlock through kernfs
         * active_ref protection.  Let's break the protection.  Losing the
         * protection is okay as we check whether @cs is online after
-        * grabbing cpuset_rwsem anyway.  This only happens on the legacy
+        * grabbing cpuset_mutex anyway.  This only happens on the legacy
         * hierarchies.
         */
        css_get(&cs->css);
        flush_work(&cpuset_hotplug_work);
 
        cpus_read_lock();
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        if (!is_cpuset_online(cs))
                goto out_unlock;
 
 
        free_cpuset(trialcs);
 out_unlock:
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
        cpus_read_unlock();
        kernfs_unbreak_active_protection(of->kn);
        css_put(&cs->css);
 
        css_get(&cs->css);
        cpus_read_lock();
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        if (!is_cpuset_online(cs))
                goto out_unlock;
 
        retval = update_prstate(cs, val);
 out_unlock:
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
        cpus_read_unlock();
        css_put(&cs->css);
        return retval ?: nbytes;
                return 0;
 
        cpus_read_lock();
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
 
        set_bit(CS_ONLINE, &cs->flags);
        if (is_spread_page(parent))
        cpumask_copy(cs->effective_cpus, parent->cpus_allowed);
        spin_unlock_irq(&callback_lock);
 out_unlock:
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
        cpus_read_unlock();
        return 0;
 }
        struct cpuset *cs = css_cs(css);
 
        cpus_read_lock();
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
 
        if (is_partition_valid(cs))
                update_prstate(cs, 0);
        cpuset_dec();
        clear_bit(CS_ONLINE, &cs->flags);
 
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
        cpus_read_unlock();
 }
 
 
 static void cpuset_bind(struct cgroup_subsys_state *root_css)
 {
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        spin_lock_irq(&callback_lock);
 
        if (is_in_v2_mode()) {
        }
 
        spin_unlock_irq(&callback_lock);
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
 }
 
 /*
                return 0;
 
        lockdep_assert_held(&cgroup_mutex);
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
 
        /* Check to see if task is allowed in the cpuset */
        ret = cpuset_can_attach_check(cs);
         */
        cs->attach_in_progress++;
 out_unlock:
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
        return ret;
 }
 
        if (same_cs)
                return;
 
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        cs->attach_in_progress--;
        if (!cs->attach_in_progress)
                wake_up(&cpuset_attach_wq);
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
 }
 
 /*
        }
 
        /* CLONE_INTO_CGROUP */
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
        guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
        cpuset_attach_task(cs, task);
 
        if (!cs->attach_in_progress)
                wake_up(&cpuset_attach_wq);
 
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
 }
 
 struct cgroup_subsys cpuset_cgrp_subsys = {
        is_empty = cpumask_empty(cs->cpus_allowed) ||
                   nodes_empty(cs->mems_allowed);
 
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
 
        /*
         * Move tasks to the nearest ancestor with execution resources,
        if (is_empty)
                remove_tasks_in_empty_cpuset(cs);
 
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
 }
 
 static void
 retry:
        wait_event(cpuset_attach_wq, cs->attach_in_progress == 0);
 
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
 
        /*
         * We have raced with task attaching. We wait until attaching
         * is finished, so we won't attach a task to an empty cpuset.
         */
        if (cs->attach_in_progress) {
-               percpu_up_write(&cpuset_rwsem);
+               mutex_unlock(&cpuset_mutex);
                goto retry;
        }
 
                                            cpus_updated, mems_updated);
 
 unlock:
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
 }
 
 /**
        if (on_dfl && !alloc_cpumasks(NULL, &tmp))
                ptmp = &tmp;
 
-       percpu_down_write(&cpuset_rwsem);
+       mutex_lock(&cpuset_mutex);
 
        /* fetch the available cpus/mems and find out which changed how */
        cpumask_copy(&new_cpus, cpu_active_mask);
                update_tasks_nodemask(&top_cpuset);
        }
 
-       percpu_up_write(&cpuset_rwsem);
+       mutex_unlock(&cpuset_mutex);
 
        /* if cpus or mems changed, we need to propagate to descendants */
        if (cpus_updated || mems_updated) {
  *  - Used for /proc/<pid>/cpuset.
  *  - No need to task_lock(tsk) on this tsk->cpuset reference, as it
  *    doesn't really matter if tsk->cpuset changes after we read it,
- *    and we take cpuset_rwsem, keeping cpuset_attach() from changing it
+ *    and we take cpuset_mutex, keeping cpuset_attach() from changing it
  *    anyway.
  */
 int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns,