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 | ||
