diff options
-rw-r--r-- | include/linux/cpuset.h | 6 | ||||
-rw-r--r-- | kernel/cpuset.c | 33 | ||||
-rw-r--r-- | mm/oom_kill.c | 3 |
3 files changed, 37 insertions, 5 deletions
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index c472f972bd6d..3bc606927116 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h | |||
@@ -48,6 +48,9 @@ extern void __cpuset_memory_pressure_bump(void); | |||
48 | extern struct file_operations proc_cpuset_operations; | 48 | extern struct file_operations proc_cpuset_operations; |
49 | extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer); | 49 | extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer); |
50 | 50 | ||
51 | extern void cpuset_lock(void); | ||
52 | extern void cpuset_unlock(void); | ||
53 | |||
51 | #else /* !CONFIG_CPUSETS */ | 54 | #else /* !CONFIG_CPUSETS */ |
52 | 55 | ||
53 | static inline int cpuset_init_early(void) { return 0; } | 56 | static inline int cpuset_init_early(void) { return 0; } |
@@ -93,6 +96,9 @@ static inline char *cpuset_task_status_allowed(struct task_struct *task, | |||
93 | return buffer; | 96 | return buffer; |
94 | } | 97 | } |
95 | 98 | ||
99 | static inline void cpuset_lock(void) {} | ||
100 | static inline void cpuset_unlock(void) {} | ||
101 | |||
96 | #endif /* !CONFIG_CPUSETS */ | 102 | #endif /* !CONFIG_CPUSETS */ |
97 | 103 | ||
98 | #endif /* _LINUX_CPUSET_H */ | 104 | #endif /* _LINUX_CPUSET_H */ |
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index d4b6bd7d74e5..fe2f71f92ae0 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -2150,6 +2150,33 @@ int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) | |||
2150 | } | 2150 | } |
2151 | 2151 | ||
2152 | /** | 2152 | /** |
2153 | * cpuset_lock - lock out any changes to cpuset structures | ||
2154 | * | ||
2155 | * The out of memory (oom) code needs to lock down cpusets | ||
2156 | * from being changed while it scans the tasklist looking for a | ||
2157 | * task in an overlapping cpuset. Expose callback_sem via this | ||
2158 | * cpuset_lock() routine, so the oom code can lock it, before | ||
2159 | * locking the task list. The tasklist_lock is a spinlock, so | ||
2160 | * must be taken inside callback_sem. | ||
2161 | */ | ||
2162 | |||
2163 | void cpuset_lock(void) | ||
2164 | { | ||
2165 | down(&callback_sem); | ||
2166 | } | ||
2167 | |||
2168 | /** | ||
2169 | * cpuset_unlock - release lock on cpuset changes | ||
2170 | * | ||
2171 | * Undo the lock taken in a previous cpuset_lock() call. | ||
2172 | */ | ||
2173 | |||
2174 | void cpuset_unlock(void) | ||
2175 | { | ||
2176 | up(&callback_sem); | ||
2177 | } | ||
2178 | |||
2179 | /** | ||
2153 | * cpuset_excl_nodes_overlap - Do we overlap @p's mem_exclusive ancestors? | 2180 | * cpuset_excl_nodes_overlap - Do we overlap @p's mem_exclusive ancestors? |
2154 | * @p: pointer to task_struct of some other task. | 2181 | * @p: pointer to task_struct of some other task. |
2155 | * | 2182 | * |
@@ -2158,7 +2185,7 @@ int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) | |||
2158 | * determine if task @p's memory usage might impact the memory | 2185 | * determine if task @p's memory usage might impact the memory |
2159 | * available to the current task. | 2186 | * available to the current task. |
2160 | * | 2187 | * |
2161 | * Acquires callback_sem - not suitable for calling from a fast path. | 2188 | * Call while holding callback_sem. |
2162 | **/ | 2189 | **/ |
2163 | 2190 | ||
2164 | int cpuset_excl_nodes_overlap(const struct task_struct *p) | 2191 | int cpuset_excl_nodes_overlap(const struct task_struct *p) |
@@ -2166,8 +2193,6 @@ int cpuset_excl_nodes_overlap(const struct task_struct *p) | |||
2166 | const struct cpuset *cs1, *cs2; /* my and p's cpuset ancestors */ | 2193 | const struct cpuset *cs1, *cs2; /* my and p's cpuset ancestors */ |
2167 | int overlap = 0; /* do cpusets overlap? */ | 2194 | int overlap = 0; /* do cpusets overlap? */ |
2168 | 2195 | ||
2169 | down(&callback_sem); | ||
2170 | |||
2171 | task_lock(current); | 2196 | task_lock(current); |
2172 | if (current->flags & PF_EXITING) { | 2197 | if (current->flags & PF_EXITING) { |
2173 | task_unlock(current); | 2198 | task_unlock(current); |
@@ -2186,8 +2211,6 @@ int cpuset_excl_nodes_overlap(const struct task_struct *p) | |||
2186 | 2211 | ||
2187 | overlap = nodes_intersects(cs1->mems_allowed, cs2->mems_allowed); | 2212 | overlap = nodes_intersects(cs1->mems_allowed, cs2->mems_allowed); |
2188 | done: | 2213 | done: |
2189 | up(&callback_sem); | ||
2190 | |||
2191 | return overlap; | 2214 | return overlap; |
2192 | } | 2215 | } |
2193 | 2216 | ||
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 4748b906aff2..14bd4ec79597 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -274,6 +274,7 @@ void out_of_memory(gfp_t gfp_mask, int order) | |||
274 | show_mem(); | 274 | show_mem(); |
275 | } | 275 | } |
276 | 276 | ||
277 | cpuset_lock(); | ||
277 | read_lock(&tasklist_lock); | 278 | read_lock(&tasklist_lock); |
278 | retry: | 279 | retry: |
279 | p = select_bad_process(); | 280 | p = select_bad_process(); |
@@ -284,6 +285,7 @@ retry: | |||
284 | /* Found nothing?!?! Either we hang forever, or we panic. */ | 285 | /* Found nothing?!?! Either we hang forever, or we panic. */ |
285 | if (!p) { | 286 | if (!p) { |
286 | read_unlock(&tasklist_lock); | 287 | read_unlock(&tasklist_lock); |
288 | cpuset_unlock(); | ||
287 | panic("Out of memory and no killable processes...\n"); | 289 | panic("Out of memory and no killable processes...\n"); |
288 | } | 290 | } |
289 | 291 | ||
@@ -293,6 +295,7 @@ retry: | |||
293 | 295 | ||
294 | out: | 296 | out: |
295 | read_unlock(&tasklist_lock); | 297 | read_unlock(&tasklist_lock); |
298 | cpuset_unlock(); | ||
296 | if (mm) | 299 | if (mm) |
297 | mmput(mm); | 300 | mmput(mm); |
298 | 301 | ||