Patch "percpu: fix synchronization between synchronous map extension and chunk destruction" has been added to the 4.6-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
percpu: fix synchronization between synchronous map extension and chunk destruction
to the 4.6-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
percpu-fix-synchronization-between-synchronous-map-extension-and-chunk-destruction.patch
and it can be found in the queue-4.6 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
6710e594f71ccaad8101bc64321152af7cd9ea28Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Wed, 25 May 2016 11:48:25 -0400
Subject: percpu: fix synchronization between synchronous map extension and chunk destruction
From: Tejun Heo <[email protected]>
commit 6710e594f71ccaad8101bc64321152af7cd9ea28 upstream.
For non-atomic allocations, pcpu_alloc() can try to extend the area map synchronously after dropping pcpu_lock; however, the extension wasn't synchronized against chunk destruction and the chunk might get freed while extension is in progress.
This patch fixes the bug by putting most of non-atomic allocations under pcpu_alloc_mutex to synchronize against pcpu_balance_work which is responsible for async chunk management including destruction.
--- mm/percpu.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
mm/percpu.c +8 -8
@@ -162,7 +162,7 @@ static struct pcpu_chunk *pcpu_reserved_static int pcpu_reserved_chunk_limit;static DEFINE_SPINLOCK (pcpu_lock);/* all internal data structures */ -static DEFINE_MUTEX (pcpu_alloc_mutex);/* chunk create/destroy, [de]pop */ +static DEFINE_MUTEX (pcpu_alloc_mutex);/* chunk create/destroy, [de]pop, map ext */ static struct list_head *pcpu_slot__read_mostly ;/* chunk list slots */
@@ -444,6 +444,8 @@ static int pcpu_extend_area_map(struct psize_t old_size =0 , new_size = new_alloc *sizeof (new[0 ]);unsigned long flags; +lockdep_assert_held (&pcpu_alloc_mutex); + new =pcpu_mem_zalloc (new_size);if (!new)return -ENOMEM ;
@@ -890,6 +892,9 @@ static void __percpu *pcpu_alloc(size_treturn NULL ; } +if (!is_atomic) +mutex_lock (&pcpu_alloc_mutex); +spin_lock_irqsave (&pcpu_lock, flags);/* serve reserved allocations from the reserved chunk if available */
@@ -962,12 +967,9 @@ restart:if (is_atomic) goto fail; -mutex_lock (&pcpu_alloc_mutex); -if (list_empty (&pcpu_slot[pcpu_nr_slots -1 ])) { chunk =pcpu_create_chunk ();if (!chunk) { -mutex_unlock (&pcpu_alloc_mutex); err ="failed to allocate new chunk" ; goto fail; }
@@ -978,7 +980,6 @@ restart:spin_lock_irqsave (&pcpu_lock, flags); } -mutex_unlock (&pcpu_alloc_mutex); goto restart; area_found:
@@ -988,8 +989,6 @@ area_found:if (!is_atomic) {int page_start, page_end, rs, re; -mutex_lock (&pcpu_alloc_mutex); - page_start =PFN_DOWN (off); page_end =PFN_UP (off + size);
@@ -1000,7 +999,6 @@ area_found:spin_lock_irqsave (&pcpu_lock, flags);if (ret) { -mutex_unlock (&pcpu_alloc_mutex);pcpu_free_area (chunk, off, &occ_pages); err ="failed to populate" ; goto fail_unlock;
@@ -1040,6 +1038,8 @@ fail:/* see the flag handling in pcpu_blance_workfn() */ pcpu_atomic_alloc_failed = true;pcpu_schedule_balance_work (); + }else { +mutex_unlock (&pcpu_alloc_mutex); }return NULL ; }
Patches currently in stable-queue which might be from [email protected] are
queue-4.6/writeback-use-higher-precision-calculation-in-domain_dirty_limits.patch queue-4.6/percpu-fix-synchronization-between-synchronous-map-extension-and-chunk-destruction.patch queue-4.6/percpu-fix-synchronization-between-chunk-map_extend_work-and-chunk-destruction.patch