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: free each cluster individually in swap_entries_put_map_nr()

1. Factor out general swap_entries_put_map() helper to drop entries
belonging to one cluster. If entries are last map, free entries in
batch, otherwise put entries with cluster lock acquired and released
only once.

2. Iterate and call swap_entries_put_map() for each cluster in
swap_entries_put_nr() to leverage batch-remove for last map belonging
to one cluster and reduce lock acquire/release in fallback case.

3. As swap_entries_put_nr() won't handle SWAP_HSA_CACHE drop, rename
it to swap_entries_put_map_nr().

4. As we won't drop each entry invidually with swap_entry_put() now,
do reclaim in free_swap_and_cache_nr() because
swap_entries_put_map_nr() is general routine to drop reference and the
relcaim work should only be done in free_swap_and_cache_nr(). Remove
stale comment accordingly.

Link: https://lkml.kernel.org/r/20250325162528.68385-7-shikemeng@huaweicloud.com
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
Reviewed-by: Tim Chen <tim.c.chen@linux.intel.com>
Reviewed-by: Baoquan He <bhe@redhat.com>
Cc: Kairui Song <kasong@tencent.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Kemeng Shi and committed by
Andrew Morton
4d71d906 f2252acf

+32 -38
+32 -38
mm/swapfile.c
··· 1463 1463 return NULL; 1464 1464 } 1465 1465 1466 - static unsigned char swap_entry_put(struct swap_info_struct *si, 1467 - swp_entry_t entry) 1468 - { 1469 - struct swap_cluster_info *ci; 1470 - unsigned long offset = swp_offset(entry); 1471 - unsigned char usage; 1472 - 1473 - ci = lock_cluster(si, offset); 1474 - usage = swap_entry_put_locked(si, ci, entry, 1); 1475 - unlock_cluster(ci); 1476 - 1477 - return usage; 1478 - } 1479 - 1480 - static bool swap_entries_put_nr(struct swap_info_struct *si, 1481 - swp_entry_t entry, int nr) 1466 + static bool swap_entries_put_map(struct swap_info_struct *si, 1467 + swp_entry_t entry, int nr) 1482 1468 { 1483 1469 unsigned long offset = swp_offset(entry); 1484 - unsigned int type = swp_type(entry); 1485 1470 struct swap_cluster_info *ci; 1486 1471 bool has_cache = false; 1487 1472 unsigned char count; ··· 1477 1492 count = swap_count(data_race(si->swap_map[offset])); 1478 1493 if (count != 1 && count != SWAP_MAP_SHMEM) 1479 1494 goto fallback; 1480 - /* cross into another cluster */ 1481 - if (nr > SWAPFILE_CLUSTER - offset % SWAPFILE_CLUSTER) 1482 - goto fallback; 1483 1495 1484 1496 ci = lock_cluster(si, offset); 1485 1497 if (!swap_is_last_map(si, offset, nr, &has_cache)) { 1486 - unlock_cluster(ci); 1487 - goto fallback; 1498 + goto locked_fallback; 1488 1499 } 1489 1500 if (!has_cache) 1490 1501 swap_entries_free(si, ci, entry, nr); ··· 1492 1511 return has_cache; 1493 1512 1494 1513 fallback: 1495 - for (i = 0; i < nr; i++) { 1496 - if (data_race(si->swap_map[offset + i])) { 1497 - count = swap_entry_put(si, swp_entry(type, offset + i)); 1498 - if (count == SWAP_HAS_CACHE) 1499 - has_cache = true; 1500 - } else { 1501 - WARN_ON_ONCE(1); 1502 - } 1514 + ci = lock_cluster(si, offset); 1515 + locked_fallback: 1516 + for (i = 0; i < nr; i++, entry.val++) { 1517 + count = swap_entry_put_locked(si, ci, entry, 1); 1518 + if (count == SWAP_HAS_CACHE) 1519 + has_cache = true; 1503 1520 } 1521 + unlock_cluster(ci); 1522 + return has_cache; 1523 + 1524 + } 1525 + 1526 + static bool swap_entries_put_map_nr(struct swap_info_struct *si, 1527 + swp_entry_t entry, int nr) 1528 + { 1529 + int cluster_nr, cluster_rest; 1530 + unsigned long offset = swp_offset(entry); 1531 + bool has_cache = false; 1532 + 1533 + cluster_rest = SWAPFILE_CLUSTER - offset % SWAPFILE_CLUSTER; 1534 + while (nr) { 1535 + cluster_nr = min(nr, cluster_rest); 1536 + has_cache |= swap_entries_put_map(si, entry, cluster_nr); 1537 + cluster_rest = SWAPFILE_CLUSTER; 1538 + nr -= cluster_nr; 1539 + entry.val += cluster_nr; 1540 + } 1541 + 1504 1542 return has_cache; 1505 1543 } 1506 1544 ··· 1818 1818 /* 1819 1819 * First free all entries in the range. 1820 1820 */ 1821 - any_only_cache = swap_entries_put_nr(si, entry, nr); 1821 + any_only_cache = swap_entries_put_map_nr(si, entry, nr); 1822 1822 1823 1823 /* 1824 1824 * Short-circuit the below loop if none of the entries had their ··· 1828 1828 goto out; 1829 1829 1830 1830 /* 1831 - * Now go back over the range trying to reclaim the swap cache. This is 1832 - * more efficient for large folios because we will only try to reclaim 1833 - * the swap once per folio in the common case. If we do 1834 - * swap_entry_put() and __try_to_reclaim_swap() in the same loop, the 1835 - * latter will get a reference and lock the folio for every individual 1836 - * page but will only succeed once the swap slot for every subpage is 1837 - * zero. 1831 + * Now go back over the range trying to reclaim the swap cache. 1838 1832 */ 1839 1833 for (offset = start_offset; offset < end_offset; offset += nr) { 1840 1834 nr = 1;