Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm, swap: consolidate bad slots setup and make it more robust

In preparation for using the swap table to track bad slots directly, move
the bad slot setup to one place, set up the swap_map mark, and cluster
counter update together.

While at it, provide more informative logs and a more robust fallback if
any bad slot info looks incorrect.

Fixes a potential issue that a malformed swap file may cause the cluster
to be unusable upon swapon, and provides a more verbose warning on a
malformed swap file

Link: https://lkml.kernel.org/r/20260218-swap-table-p3-v3-4-f4e34be021a7@tencent.com
Signed-off-by: Kairui Song <kasong@tencent.com>
Acked-by: Chris Li <chrisl@kernel.org>
Cc: Baoquan He <bhe@redhat.com>
Cc: Barry Song <baohua@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Kairui Song <ryncsn@gmail.com>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: kernel test robot <lkp@intel.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Kairui Song and committed by
Andrew Morton
0c7e6014 50f8c419

+38 -30
+38 -30
mm/swapfile.c
··· 743 743 * slot. The cluster will not be added to the free cluster list, and its 744 744 * usage counter will be increased by 1. Only used for initialization. 745 745 */ 746 - static int swap_cluster_setup_bad_slot(struct swap_cluster_info *cluster_info, 747 - unsigned long offset) 746 + static int swap_cluster_setup_bad_slot(struct swap_info_struct *si, 747 + struct swap_cluster_info *cluster_info, 748 + unsigned int offset, bool mask) 748 749 { 749 750 unsigned long idx = offset / SWAPFILE_CLUSTER; 750 751 struct swap_table *table; 751 752 struct swap_cluster_info *ci; 752 753 754 + /* si->max may got shrunk by swap swap_activate() */ 755 + if (offset >= si->max && !mask) { 756 + pr_debug("Ignoring bad slot %u (max: %u)\n", offset, si->max); 757 + return 0; 758 + } 759 + /* 760 + * Account it, skip header slot: si->pages is initiated as 761 + * si->max - 1. Also skip the masking of last cluster, 762 + * si->pages doesn't include that part. 763 + */ 764 + if (offset && !mask) 765 + si->pages -= 1; 766 + if (!si->pages) { 767 + pr_warn("Empty swap-file\n"); 768 + return -EINVAL; 769 + } 770 + /* Check for duplicated bad swap slots. */ 771 + if (si->swap_map[offset]) { 772 + pr_warn("Duplicated bad slot offset %d\n", offset); 773 + return -EINVAL; 774 + } 775 + 776 + si->swap_map[offset] = SWAP_MAP_BAD; 753 777 ci = cluster_info + idx; 754 778 if (!ci->table) { 755 779 table = swap_table_alloc(GFP_KERNEL); ··· 3244 3220 union swap_header *swap_header, 3245 3221 unsigned long maxpages) 3246 3222 { 3247 - unsigned long i; 3248 3223 unsigned char *swap_map; 3249 3224 3250 3225 swap_map = vzalloc(maxpages); 3251 3226 si->swap_map = swap_map; 3252 3227 if (!swap_map) 3253 3228 return -ENOMEM; 3254 - 3255 - swap_map[0] = SWAP_MAP_BAD; /* omit header page */ 3256 - for (i = 0; i < swap_header->info.nr_badpages; i++) { 3257 - unsigned int page_nr = swap_header->info.badpages[i]; 3258 - if (page_nr == 0 || page_nr > swap_header->info.last_page) 3259 - return -EINVAL; 3260 - if (page_nr < maxpages) { 3261 - swap_map[page_nr] = SWAP_MAP_BAD; 3262 - si->pages--; 3263 - } 3264 - } 3265 - 3266 - if (!si->pages) { 3267 - pr_warn("Empty swap-file\n"); 3268 - return -EINVAL; 3269 - } 3270 - 3271 3229 return 0; 3272 3230 } 3273 3231 ··· 3279 3273 } 3280 3274 3281 3275 /* 3282 - * Mark unusable pages as unavailable. The clusters aren't 3283 - * marked free yet, so no list operations are involved yet. 3284 - * 3285 - * See setup_swap_map(): header page, bad pages, 3286 - * and the EOF part of the last cluster. 3276 + * Mark unusable pages (header page, bad pages, and the EOF part of 3277 + * the last cluster) as unavailable. The clusters aren't marked free 3278 + * yet, so no list operations are involved yet. 3287 3279 */ 3288 - err = swap_cluster_setup_bad_slot(cluster_info, 0); 3280 + err = swap_cluster_setup_bad_slot(si, cluster_info, 0, false); 3289 3281 if (err) 3290 3282 goto err; 3291 3283 for (i = 0; i < swap_header->info.nr_badpages; i++) { 3292 3284 unsigned int page_nr = swap_header->info.badpages[i]; 3293 3285 3294 - if (page_nr >= maxpages) 3295 - continue; 3296 - err = swap_cluster_setup_bad_slot(cluster_info, page_nr); 3286 + if (!page_nr || page_nr > swap_header->info.last_page) { 3287 + pr_warn("Bad slot offset is out of border: %d (last_page: %d)\n", 3288 + page_nr, swap_header->info.last_page); 3289 + err = -EINVAL; 3290 + goto err; 3291 + } 3292 + err = swap_cluster_setup_bad_slot(si, cluster_info, page_nr, false); 3297 3293 if (err) 3298 3294 goto err; 3299 3295 } 3300 3296 for (i = maxpages; i < round_up(maxpages, SWAPFILE_CLUSTER); i++) { 3301 - err = swap_cluster_setup_bad_slot(cluster_info, i); 3297 + err = swap_cluster_setup_bad_slot(si, cluster_info, i, true); 3302 3298 if (err) 3303 3299 goto err; 3304 3300 }