Group short-lived and reclaimable kernel allocations
[sfrench/cifs-2.6.git] / kernel / cpuset.c
index f57854b0892275d901e9e1b7b8f2e4784adcc37a..e196510aa40f6975310655450030c9d28a4b1e12 100644 (file)
@@ -516,7 +516,7 @@ static void cpuset_release_agent(const char *pathbuf)
        envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
        envp[i] = NULL;
 
-       call_usermodehelper(argv[0], argv, envp, 0);
+       call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
        kfree(pathbuf);
 }
 
@@ -581,26 +581,28 @@ static void guarantee_online_cpus(const struct cpuset *cs, cpumask_t *pmask)
 
 /*
  * Return in *pmask the portion of a cpusets's mems_allowed that
- * are online.  If none are online, walk up the cpuset hierarchy
- * until we find one that does have some online mems.  If we get
- * all the way to the top and still haven't found any online mems,
- * return node_online_map.
+ * are online, with memory.  If none are online with memory, walk
+ * up the cpuset hierarchy until we find one that does have some
+ * online mems.  If we get all the way to the top and still haven't
+ * found any online mems, return node_states[N_HIGH_MEMORY].
  *
  * One way or another, we guarantee to return some non-empty subset
- * of node_online_map.
+ * of node_states[N_HIGH_MEMORY].
  *
  * Call with callback_mutex held.
  */
 
 static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
 {
-       while (cs && !nodes_intersects(cs->mems_allowed, node_online_map))
+       while (cs && !nodes_intersects(cs->mems_allowed,
+                                       node_states[N_HIGH_MEMORY]))
                cs = cs->parent;
        if (cs)
-               nodes_and(*pmask, cs->mems_allowed, node_online_map);
+               nodes_and(*pmask, cs->mems_allowed,
+                                       node_states[N_HIGH_MEMORY]);
        else
-               *pmask = node_online_map;
-       BUG_ON(!nodes_intersects(*pmask, node_online_map));
+               *pmask = node_states[N_HIGH_MEMORY];
+       BUG_ON(!nodes_intersects(*pmask, node_states[N_HIGH_MEMORY]));
 }
 
 /**
@@ -924,7 +926,10 @@ static int update_nodemask(struct cpuset *cs, char *buf)
        int fudge;
        int retval;
 
-       /* top_cpuset.mems_allowed tracks node_online_map; it's read-only */
+       /*
+        * top_cpuset.mems_allowed tracks node_stats[N_HIGH_MEMORY];
+        * it's read-only
+        */
        if (cs == &top_cpuset)
                return -EACCES;
 
@@ -941,8 +946,21 @@ static int update_nodemask(struct cpuset *cs, char *buf)
                retval = nodelist_parse(buf, trialcs.mems_allowed);
                if (retval < 0)
                        goto done;
+               if (!nodes_intersects(trialcs.mems_allowed,
+                                               node_states[N_HIGH_MEMORY])) {
+                       /*
+                        * error if only memoryless nodes specified.
+                        */
+                       retval = -ENOSPC;
+                       goto done;
+               }
        }
-       nodes_and(trialcs.mems_allowed, trialcs.mems_allowed, node_online_map);
+       /*
+        * Exclude memoryless nodes.  We know that trialcs.mems_allowed
+        * contains at least one node with memory.
+        */
+       nodes_and(trialcs.mems_allowed, trialcs.mems_allowed,
+                                               node_states[N_HIGH_MEMORY]);
        oldmem = cs->mems_allowed;
        if (nodes_equal(oldmem, trialcs.mems_allowed)) {
                retval = 0;             /* Too easy - nothing to do */
@@ -981,10 +999,10 @@ static int update_nodemask(struct cpuset *cs, char *buf)
                mmarray = kmalloc(ntasks * sizeof(*mmarray), GFP_KERNEL);
                if (!mmarray)
                        goto done;
-               write_lock_irq(&tasklist_lock);         /* block fork */
+               read_lock(&tasklist_lock);              /* block fork */
                if (atomic_read(&cs->count) <= ntasks)
                        break;                          /* got enough */
-               write_unlock_irq(&tasklist_lock);       /* try again */
+               read_unlock(&tasklist_lock);            /* try again */
                kfree(mmarray);
        }
 
@@ -1006,7 +1024,7 @@ static int update_nodemask(struct cpuset *cs, char *buf)
                        continue;
                mmarray[n++] = mm;
        } while_each_thread(g, p);
-       write_unlock_irq(&tasklist_lock);
+       read_unlock(&tasklist_lock);
 
        /*
         * Now that we've dropped the tasklist spinlock, we can
@@ -1445,7 +1463,7 @@ static ssize_t cpuset_common_file_read(struct file *file, char __user *buf,
        ssize_t retval = 0;
        char *s;
 
-       if (!(page = (char *)__get_free_page(GFP_KERNEL)))
+       if (!(page = (char *)__get_free_page(GFP_TEMPORARY)))
                return -ENOMEM;
 
        s = page;
@@ -1682,9 +1700,9 @@ static int pid_array_load(pid_t *pidarray, int npids, struct cpuset *cs)
 
        do_each_thread(g, p) {
                if (p->cpuset == cs) {
-                       pidarray[n++] = p->pid;
                        if (unlikely(n == npids))
                                goto array_full;
+                       pidarray[n++] = p->pid;
                }
        } while_each_thread(g, p);
 
@@ -2098,8 +2116,9 @@ static void guarantee_online_cpus_mems_in_subtree(const struct cpuset *cur)
 
 /*
  * The cpus_allowed and mems_allowed nodemasks in the top_cpuset track
- * cpu_online_map and node_online_map.  Force the top cpuset to track
- * whats online after any CPU or memory node hotplug or unplug event.
+ * cpu_online_map and node_states[N_HIGH_MEMORY].  Force the top cpuset to
+ * track what's online after any CPU or memory node hotplug or unplug
+ * event.
  *
  * To ensure that we don't remove a CPU or node from the top cpuset
  * that is currently in use by a child cpuset (which would violate
@@ -2119,7 +2138,7 @@ static void common_cpu_mem_hotplug_unplug(void)
 
        guarantee_online_cpus_mems_in_subtree(&top_cpuset);
        top_cpuset.cpus_allowed = cpu_online_map;
-       top_cpuset.mems_allowed = node_online_map;
+       top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
 
        mutex_unlock(&callback_mutex);
        mutex_unlock(&manage_mutex);
@@ -2138,14 +2157,18 @@ static void common_cpu_mem_hotplug_unplug(void)
 static int cpuset_handle_cpuhp(struct notifier_block *nb,
                                unsigned long phase, void *cpu)
 {
+       if (phase == CPU_DYING || phase == CPU_DYING_FROZEN)
+               return NOTIFY_DONE;
+
        common_cpu_mem_hotplug_unplug();
        return 0;
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 /*
- * Keep top_cpuset.mems_allowed tracking node_online_map.
- * Call this routine anytime after you change node_online_map.
+ * Keep top_cpuset.mems_allowed tracking node_states[N_HIGH_MEMORY].
+ * Call this routine anytime after you change
+ * node_states[N_HIGH_MEMORY].
  * See also the previous routine cpuset_handle_cpuhp().
  */
 
@@ -2164,7 +2187,7 @@ void cpuset_track_online_nodes(void)
 void __init cpuset_init_smp(void)
 {
        top_cpuset.cpus_allowed = cpu_online_map;
-       top_cpuset.mems_allowed = node_online_map;
+       top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
 
        hotcpu_notifier(cpuset_handle_cpuhp, 0);
 }
@@ -2306,7 +2329,7 @@ void cpuset_init_current_mems_allowed(void)
  *
  * Description: Returns the nodemask_t mems_allowed of the cpuset
  * attached to the specified @tsk.  Guaranteed to return some non-empty
- * subset of node_online_map, even if this means going outside the
+ * subset of node_states[N_HIGH_MEMORY], even if this means going outside the
  * tasks cpuset.
  **/