Inserting a new priority allocates a replacement per-CPU reader array even when earlier ring removal left enough storage. An unnecessary allocation can add swapon work or fail despite sufficient capacity. Track the installed reader capacity and retain its high-water mark until the queue becomes empty. Reuse existing storage when the new ring fits, initializing every valid ring index for the new topology. Prepare larger storage outside the writer only when growth is required and recheck capacity under the writer before publishing. Preserve the existing prepare/install ownership and failure rollback protocol. Device removal continues to avoid per-CPU shrinking allocation under the writer. Signed-off-by: Lian Wang --- mm/swapfile.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index 7b3520ce1e41..5b6492b1bdc6 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -201,6 +201,8 @@ struct swap_queue_cursor { }; static __percpu struct swap_queue_reader *swap_queue_readers; +/* Keep the high-water capacity until the last priority ring is removed. */ +static unsigned int swap_queue_readers_capacity; static inline bool swap_device_masked(struct swap_info_struct *si) { @@ -240,7 +242,7 @@ static bool swap_queue_needs_readers(int prio) return false; } - return true; + return swap_queue_len >= swap_queue_readers_capacity; } /* @@ -288,13 +290,15 @@ static void swap_queue_reset_readers(void) } } -static void swap_queue_install_readers(struct swap_queue_reader __percpu *readers) +static void swap_queue_install_readers(struct swap_queue_reader __percpu *readers, + unsigned int capacity) { int cpu; lockdep_assert_held_write(&swapon_rwsem); free_percpu(swap_queue_readers); swap_queue_readers = readers; + swap_queue_readers_capacity = capacity; if (!readers) return; @@ -431,7 +435,8 @@ static int swap_queue_add(struct swap_info_struct *si, } /* No ring at this priority: insert a new one at pos. */ - if (!*readers || nr_readers <= swap_queue_len) + if (swap_queue_len >= swap_queue_readers_capacity && + (!*readers || nr_readers <= swap_queue_len)) goto failed; new_queue = kmalloc_array(swap_queue_len + 1, sizeof(*swap_queue), gfp); if (!new_queue) @@ -459,8 +464,12 @@ static int swap_queue_add(struct swap_info_struct *si, memalloc_noreclaim_restore(noreclaim_flag); kfree(old_queue); - swap_queue_install_readers(*readers); - *readers = NULL; + if (swap_queue_len > swap_queue_readers_capacity) { + swap_queue_install_readers(*readers, nr_readers); + *readers = NULL; + } else { + swap_queue_reset_readers(); + } return 0; add_to_ring: @@ -503,10 +512,9 @@ static void swap_queue_del(struct swap_info_struct *si) } /* - * Shrinking the small topology arrays is optional. Keep reader storage - * until a new priority is inserted or the queue is empty: per-CPU - * allocation must not run under this writer's noreclaim scope, which - * can grant backing pages reserve access. + * Shrinking the small topology arrays is optional. Keep reader capacity + * until the queue is empty: per-CPU allocation must not run under this + * writer's noreclaim scope, which can grant backing pages reserve access. */ gfp = GFP_NOIO | __GFP_HIGH | __GFP_NOMEMALLOC; noreclaim_flag = memalloc_noreclaim_save(); @@ -549,7 +557,7 @@ static void swap_queue_del(struct swap_info_struct *si) swap_queue = NULL; } if (!swap_queue_len) - swap_queue_install_readers(NULL); + swap_queue_install_readers(NULL, 0); } spin_unlock(&swap_queue_update_lock);