diff options
Diffstat (limited to 'mm/swap_state.c')
-rw-r--r-- | mm/swap_state.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/mm/swap_state.c b/mm/swap_state.c index f3a32a06a950..d1f5b8fa52fc 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -235,6 +235,39 @@ void swap_cache_del_folio(struct folio *folio) } /** + * __swap_cache_replace_folio - Replace a folio in the swap cache. + * @old: The old folio to be replaced. + * @new: The new folio. + * + * Replace an existing folio in the swap cache with a new folio. The + * caller is responsible for setting up the new folio's flag and swap + * entries. Replacement will take the new folio's swap entry value as + * the starting offset to override all slots covered by the new folio. + * + * Context: Caller must ensure both folios are locked, also lock the + * swap address_space that holds the old folio to avoid races. + */ +void __swap_cache_replace_folio(struct folio *old, struct folio *new) +{ + swp_entry_t entry = new->swap; + unsigned long nr_pages = folio_nr_pages(new); + unsigned long offset = swap_cache_index(entry); + unsigned long end = offset + nr_pages; + + XA_STATE(xas, &swap_address_space(entry)->i_pages, offset); + + VM_WARN_ON_ONCE(!folio_test_swapcache(old) || !folio_test_swapcache(new)); + VM_WARN_ON_ONCE(!folio_test_locked(old) || !folio_test_locked(new)); + VM_WARN_ON_ONCE(!entry.val); + + /* Swap cache still stores N entries instead of a high-order entry */ + do { + WARN_ON_ONCE(xas_store(&xas, new) != old); + xas_next(&xas); + } while (++offset < end); +} + +/** * swap_cache_clear_shadow - Clears a set of shadows in the swap cache. * @type: Indicates the swap device. * @begin: Beginning offset of the range. |