![Paul Jackson](/assets/img/avatar_default.png)
The problem, reported in: http://bugzilla.kernel.org/show_bug.cgi?id=5859 and by various other email messages and lkml posts is that the cpuset hook in the oom (out of memory) code can try to take a cpuset semaphore while holding the tasklist_lock (a spinlock). One must not sleep while holding a spinlock. The fix seems easy enough - move the cpuset semaphore region outside the tasklist_lock region. This required a few lines of mechanism to implement. The oom code where the locking needs to be changed does not have access to the cpuset locks, which are internal to kernel/cpuset.c only. So I provided a couple more cpuset interface routines, available to the rest of the kernel, which simple take and drop the lock needed here (cpusets callback_sem). Signed-off-by: Paul Jackson <pj@sgi.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
105 lines
2.8 KiB
C
105 lines
2.8 KiB
C
#ifndef _LINUX_CPUSET_H
|
|
#define _LINUX_CPUSET_H
|
|
/*
|
|
* cpuset interface
|
|
*
|
|
* Copyright (C) 2003 BULL SA
|
|
* Copyright (C) 2004 Silicon Graphics, Inc.
|
|
*
|
|
*/
|
|
|
|
#include <linux/sched.h>
|
|
#include <linux/cpumask.h>
|
|
#include <linux/nodemask.h>
|
|
|
|
#ifdef CONFIG_CPUSETS
|
|
|
|
extern int number_of_cpusets; /* How many cpusets are defined in system? */
|
|
|
|
extern int cpuset_init_early(void);
|
|
extern int cpuset_init(void);
|
|
extern void cpuset_init_smp(void);
|
|
extern void cpuset_fork(struct task_struct *p);
|
|
extern void cpuset_exit(struct task_struct *p);
|
|
extern cpumask_t cpuset_cpus_allowed(struct task_struct *p);
|
|
extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
|
|
void cpuset_init_current_mems_allowed(void);
|
|
void cpuset_update_task_memory_state(void);
|
|
#define cpuset_nodes_subset_current_mems_allowed(nodes) \
|
|
nodes_subset((nodes), current->mems_allowed)
|
|
int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl);
|
|
|
|
extern int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask);
|
|
static int inline cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
|
|
{
|
|
return number_of_cpusets <= 1 || __cpuset_zone_allowed(z, gfp_mask);
|
|
}
|
|
|
|
extern int cpuset_excl_nodes_overlap(const struct task_struct *p);
|
|
|
|
#define cpuset_memory_pressure_bump() \
|
|
do { \
|
|
if (cpuset_memory_pressure_enabled) \
|
|
__cpuset_memory_pressure_bump(); \
|
|
} while (0)
|
|
extern int cpuset_memory_pressure_enabled;
|
|
extern void __cpuset_memory_pressure_bump(void);
|
|
|
|
extern struct file_operations proc_cpuset_operations;
|
|
extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer);
|
|
|
|
extern void cpuset_lock(void);
|
|
extern void cpuset_unlock(void);
|
|
|
|
#else /* !CONFIG_CPUSETS */
|
|
|
|
static inline int cpuset_init_early(void) { return 0; }
|
|
static inline int cpuset_init(void) { return 0; }
|
|
static inline void cpuset_init_smp(void) {}
|
|
static inline void cpuset_fork(struct task_struct *p) {}
|
|
static inline void cpuset_exit(struct task_struct *p) {}
|
|
|
|
static inline cpumask_t cpuset_cpus_allowed(struct task_struct *p)
|
|
{
|
|
return cpu_possible_map;
|
|
}
|
|
|
|
static inline nodemask_t cpuset_mems_allowed(struct task_struct *p)
|
|
{
|
|
return node_possible_map;
|
|
}
|
|
|
|
static inline void cpuset_init_current_mems_allowed(void) {}
|
|
static inline void cpuset_update_task_memory_state(void) {}
|
|
#define cpuset_nodes_subset_current_mems_allowed(nodes) (1)
|
|
|
|
static inline int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static inline int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static inline int cpuset_excl_nodes_overlap(const struct task_struct *p)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static inline void cpuset_memory_pressure_bump(void) {}
|
|
|
|
static inline char *cpuset_task_status_allowed(struct task_struct *task,
|
|
char *buffer)
|
|
{
|
|
return buffer;
|
|
}
|
|
|
|
static inline void cpuset_lock(void) {}
|
|
static inline void cpuset_unlock(void) {}
|
|
|
|
#endif /* !CONFIG_CPUSETS */
|
|
|
|
#endif /* _LINUX_CPUSET_H */
|