@@ -673,6 +673,7 @@ struct vm_operations_struct {
static inline void vma_numab_state_init(struct vm_area_struct *vma)
{
vma->numab_state = NULL;
+ mutex_init(&vma->numab_state_lock);
}
static inline void vma_numab_state_free(struct vm_area_struct *vma)
{
@@ -768,6 +768,7 @@ struct vm_area_struct {
#endif
#ifdef CONFIG_NUMA_BALANCING
struct vma_numab_state *numab_state; /* NUMA Balancing state */
+ struct mutex numab_state_lock; /* NUMA Balancing state lock */
#endif
struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;
@@ -3397,12 +3397,24 @@ static void task_numa_work(struct callback_head *work)
continue;
}
+ /*
+ * In case of the shared vma, the vma->numab_state will be
+ * overwritten if two or more cores observe vma->numab_state
+ * is NULL at the same time. Make sure that only one core
+ * allocates memory for vma->numab_state. This can prevent
+ * the memory leak.
+ */
+ if (!mutex_trylock(&vma->numab_state_lock))
+ continue;
+
/* Initialise new per-VMA NUMAB state. */
if (!vma->numab_state) {
vma->numab_state = kzalloc(sizeof(struct vma_numab_state),
GFP_KERNEL);
- if (!vma->numab_state)
+ if (!vma->numab_state) {
+ mutex_unlock(&vma->numab_state_lock);
continue;
+ }
vma->numab_state->start_scan_seq = mm->numa_scan_seq;
@@ -3428,6 +3440,7 @@ static void task_numa_work(struct callback_head *work)
if (mm->numa_scan_seq && time_before(jiffies,
vma->numab_state->next_scan)) {
trace_sched_skip_vma_numa(mm, vma, NUMAB_SKIP_SCAN_DELAY);
+ mutex_unlock(&vma->numab_state_lock);
continue;
}
@@ -3440,6 +3453,8 @@ static void task_numa_work(struct callback_head *work)
vma->numab_state->pids_active[1] = 0;
}
+ mutex_unlock(&vma->numab_state_lock);
+
/* Do not rescan VMAs twice within the same sequence. */
if (vma->numab_state->prev_scan_seq == mm->numa_scan_seq) {
mm->numa_scan_offset = vma->vm_end;