Commit e2e3fdc7 authored by Matthew Wilcox (Oracle)'s avatar Matthew Wilcox (Oracle) Committed by Andrew Morton

swap: turn get_swap_page() into folio_alloc_swap()

This removes an assumption that a large folio is HPAGE_PMD_NR pages
in size.

Link: https://lkml.kernel.org/r/20220504182857.4013401-8-willy@infradead.orgSigned-off-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent d33e4e14
...@@ -470,7 +470,7 @@ static inline long get_nr_swap_pages(void) ...@@ -470,7 +470,7 @@ static inline long get_nr_swap_pages(void)
} }
extern void si_swapinfo(struct sysinfo *); extern void si_swapinfo(struct sysinfo *);
extern swp_entry_t get_swap_page(struct page *page); swp_entry_t folio_alloc_swap(struct folio *folio);
extern void put_swap_page(struct page *page, swp_entry_t entry); extern void put_swap_page(struct page *page, swp_entry_t entry);
extern swp_entry_t get_swap_page_of_type(int); extern swp_entry_t get_swap_page_of_type(int);
extern int get_swap_pages(int n, swp_entry_t swp_entries[], int entry_size); extern int get_swap_pages(int n, swp_entry_t swp_entries[], int entry_size);
...@@ -583,7 +583,7 @@ static inline int try_to_free_swap(struct page *page) ...@@ -583,7 +583,7 @@ static inline int try_to_free_swap(struct page *page)
return 0; return 0;
} }
static inline swp_entry_t get_swap_page(struct page *page) static inline swp_entry_t folio_alloc_swap(struct folio *folio)
{ {
swp_entry_t entry; swp_entry_t entry;
entry.val = 0; entry.val = 0;
...@@ -643,12 +643,13 @@ static inline void cgroup_throttle_swaprate(struct page *page, gfp_t gfp_mask) ...@@ -643,12 +643,13 @@ static inline void cgroup_throttle_swaprate(struct page *page, gfp_t gfp_mask)
#ifdef CONFIG_MEMCG_SWAP #ifdef CONFIG_MEMCG_SWAP
void mem_cgroup_swapout(struct folio *folio, swp_entry_t entry); void mem_cgroup_swapout(struct folio *folio, swp_entry_t entry);
extern int __mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry); int __mem_cgroup_try_charge_swap(struct folio *folio, swp_entry_t entry);
static inline int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry) static inline int mem_cgroup_try_charge_swap(struct folio *folio,
swp_entry_t entry)
{ {
if (mem_cgroup_disabled()) if (mem_cgroup_disabled())
return 0; return 0;
return __mem_cgroup_try_charge_swap(page, entry); return __mem_cgroup_try_charge_swap(folio, entry);
} }
extern void __mem_cgroup_uncharge_swap(swp_entry_t entry, unsigned int nr_pages); extern void __mem_cgroup_uncharge_swap(swp_entry_t entry, unsigned int nr_pages);
...@@ -666,7 +667,7 @@ static inline void mem_cgroup_swapout(struct folio *folio, swp_entry_t entry) ...@@ -666,7 +667,7 @@ static inline void mem_cgroup_swapout(struct folio *folio, swp_entry_t entry)
{ {
} }
static inline int mem_cgroup_try_charge_swap(struct page *page, static inline int mem_cgroup_try_charge_swap(struct folio *folio,
swp_entry_t entry) swp_entry_t entry)
{ {
return 0; return 0;
......
...@@ -7162,17 +7162,17 @@ void mem_cgroup_swapout(struct folio *folio, swp_entry_t entry) ...@@ -7162,17 +7162,17 @@ void mem_cgroup_swapout(struct folio *folio, swp_entry_t entry)
} }
/** /**
* __mem_cgroup_try_charge_swap - try charging swap space for a page * __mem_cgroup_try_charge_swap - try charging swap space for a folio
* @page: page being added to swap * @folio: folio being added to swap
* @entry: swap entry to charge * @entry: swap entry to charge
* *
* Try to charge @page's memcg for the swap space at @entry. * Try to charge @folio's memcg for the swap space at @entry.
* *
* Returns 0 on success, -ENOMEM on failure. * Returns 0 on success, -ENOMEM on failure.
*/ */
int __mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry) int __mem_cgroup_try_charge_swap(struct folio *folio, swp_entry_t entry)
{ {
unsigned int nr_pages = thp_nr_pages(page); unsigned int nr_pages = folio_nr_pages(folio);
struct page_counter *counter; struct page_counter *counter;
struct mem_cgroup *memcg; struct mem_cgroup *memcg;
unsigned short oldid; unsigned short oldid;
...@@ -7180,9 +7180,9 @@ int __mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry) ...@@ -7180,9 +7180,9 @@ int __mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
return 0; return 0;
memcg = page_memcg(page); memcg = folio_memcg(folio);
VM_WARN_ON_ONCE_PAGE(!memcg, page); VM_WARN_ON_ONCE_FOLIO(!memcg, folio);
if (!memcg) if (!memcg)
return 0; return 0;
...@@ -7205,7 +7205,7 @@ int __mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry) ...@@ -7205,7 +7205,7 @@ int __mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
if (nr_pages > 1) if (nr_pages > 1)
mem_cgroup_id_get_many(memcg, nr_pages - 1); mem_cgroup_id_get_many(memcg, nr_pages - 1);
oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg), nr_pages); oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg), nr_pages);
VM_BUG_ON_PAGE(oldid, page); VM_BUG_ON_FOLIO(oldid, folio);
mod_memcg_state(memcg, MEMCG_SWAP, nr_pages); mod_memcg_state(memcg, MEMCG_SWAP, nr_pages);
return 0; return 0;
......
...@@ -1313,6 +1313,7 @@ int shmem_unuse(unsigned int type) ...@@ -1313,6 +1313,7 @@ int shmem_unuse(unsigned int type)
*/ */
static int shmem_writepage(struct page *page, struct writeback_control *wbc) static int shmem_writepage(struct page *page, struct writeback_control *wbc)
{ {
struct folio *folio = page_folio(page);
struct shmem_inode_info *info; struct shmem_inode_info *info;
struct address_space *mapping; struct address_space *mapping;
struct inode *inode; struct inode *inode;
...@@ -1386,7 +1387,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) ...@@ -1386,7 +1387,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
SetPageUptodate(page); SetPageUptodate(page);
} }
swap = get_swap_page(page); swap = folio_alloc_swap(folio);
if (!swap.val) if (!swap.val)
goto redirty; goto redirty;
......
...@@ -117,7 +117,7 @@ static int alloc_swap_slot_cache(unsigned int cpu) ...@@ -117,7 +117,7 @@ static int alloc_swap_slot_cache(unsigned int cpu)
/* /*
* Do allocation outside swap_slots_cache_mutex * Do allocation outside swap_slots_cache_mutex
* as kvzalloc could trigger reclaim and get_swap_page, * as kvzalloc could trigger reclaim and folio_alloc_swap,
* which can lock swap_slots_cache_mutex. * which can lock swap_slots_cache_mutex.
*/ */
slots = kvcalloc(SWAP_SLOTS_CACHE_SIZE, sizeof(swp_entry_t), slots = kvcalloc(SWAP_SLOTS_CACHE_SIZE, sizeof(swp_entry_t),
...@@ -213,7 +213,7 @@ static void __drain_swap_slots_cache(unsigned int type) ...@@ -213,7 +213,7 @@ static void __drain_swap_slots_cache(unsigned int type)
* this function can be invoked in the cpu * this function can be invoked in the cpu
* hot plug path: * hot plug path:
* cpu_up -> lock cpu_hotplug -> cpu hotplug state callback * cpu_up -> lock cpu_hotplug -> cpu hotplug state callback
* -> memory allocation -> direct reclaim -> get_swap_page * -> memory allocation -> direct reclaim -> folio_alloc_swap
* -> drain_swap_slots_cache * -> drain_swap_slots_cache
* *
* Hence the loop over current online cpu below could miss cpu that * Hence the loop over current online cpu below could miss cpu that
...@@ -301,16 +301,16 @@ int free_swap_slot(swp_entry_t entry) ...@@ -301,16 +301,16 @@ int free_swap_slot(swp_entry_t entry)
return 0; return 0;
} }
swp_entry_t get_swap_page(struct page *page) swp_entry_t folio_alloc_swap(struct folio *folio)
{ {
swp_entry_t entry; swp_entry_t entry;
struct swap_slots_cache *cache; struct swap_slots_cache *cache;
entry.val = 0; entry.val = 0;
if (PageTransHuge(page)) { if (folio_test_large(folio)) {
if (IS_ENABLED(CONFIG_THP_SWAP)) if (IS_ENABLED(CONFIG_THP_SWAP))
get_swap_pages(1, &entry, HPAGE_PMD_NR); get_swap_pages(1, &entry, folio_nr_pages(folio));
goto out; goto out;
} }
...@@ -344,8 +344,8 @@ swp_entry_t get_swap_page(struct page *page) ...@@ -344,8 +344,8 @@ swp_entry_t get_swap_page(struct page *page)
get_swap_pages(1, &entry, 1); get_swap_pages(1, &entry, 1);
out: out:
if (mem_cgroup_try_charge_swap(page, entry)) { if (mem_cgroup_try_charge_swap(folio, entry)) {
put_swap_page(page, entry); put_swap_page(&folio->page, entry);
entry.val = 0; entry.val = 0;
} }
return entry; return entry;
......
...@@ -184,13 +184,14 @@ void __delete_from_swap_cache(struct page *page, ...@@ -184,13 +184,14 @@ void __delete_from_swap_cache(struct page *page,
*/ */
int add_to_swap(struct page *page) int add_to_swap(struct page *page)
{ {
struct folio *folio = page_folio(page);
swp_entry_t entry; swp_entry_t entry;
int err; int err;
VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_PAGE(!PageLocked(page), page);
VM_BUG_ON_PAGE(!PageUptodate(page), page); VM_BUG_ON_PAGE(!PageUptodate(page), page);
entry = get_swap_page(page); entry = folio_alloc_swap(folio);
if (!entry.val) if (!entry.val)
return 0; return 0;
......
...@@ -77,9 +77,9 @@ static PLIST_HEAD(swap_active_head); ...@@ -77,9 +77,9 @@ static PLIST_HEAD(swap_active_head);
/* /*
* all available (active, not full) swap_info_structs * all available (active, not full) swap_info_structs
* protected with swap_avail_lock, ordered by priority. * protected with swap_avail_lock, ordered by priority.
* This is used by get_swap_page() instead of swap_active_head * This is used by folio_alloc_swap() instead of swap_active_head
* because swap_active_head includes all swap_info_structs, * because swap_active_head includes all swap_info_structs,
* but get_swap_page() doesn't need to look at full ones. * but folio_alloc_swap() doesn't need to look at full ones.
* This uses its own lock instead of swap_lock because when a * This uses its own lock instead of swap_lock because when a
* swap_info_struct changes between not-full/full, it needs to * swap_info_struct changes between not-full/full, it needs to
* add/remove itself to/from this list, but the swap_info_struct->lock * add/remove itself to/from this list, but the swap_info_struct->lock
...@@ -2109,11 +2109,12 @@ static int try_to_unuse(unsigned int type) ...@@ -2109,11 +2109,12 @@ static int try_to_unuse(unsigned int type)
* Under global memory pressure, swap entries can be reinserted back * Under global memory pressure, swap entries can be reinserted back
* into process space after the mmlist loop above passes over them. * into process space after the mmlist loop above passes over them.
* *
* Limit the number of retries? No: when mmget_not_zero() above fails, * Limit the number of retries? No: when mmget_not_zero()
* that mm is likely to be freeing swap from exit_mmap(), which proceeds * above fails, that mm is likely to be freeing swap from
* at its own independent pace; and even shmem_writepage() could have * exit_mmap(), which proceeds at its own independent pace;
* been preempted after get_swap_page(), temporarily hiding that swap. * and even shmem_writepage() could have been preempted after
* It's easy and robust (though cpu-intensive) just to keep retrying. * folio_alloc_swap(), temporarily hiding that swap. It's easy
* and robust (though cpu-intensive) just to keep retrying.
*/ */
if (READ_ONCE(si->inuse_pages)) { if (READ_ONCE(si->inuse_pages)) {
if (!signal_pending(current)) if (!signal_pending(current))
...@@ -2327,7 +2328,7 @@ static void _enable_swap_info(struct swap_info_struct *p) ...@@ -2327,7 +2328,7 @@ static void _enable_swap_info(struct swap_info_struct *p)
* which on removal of any swap_info_struct with an auto-assigned * which on removal of any swap_info_struct with an auto-assigned
* (i.e. negative) priority increments the auto-assigned priority * (i.e. negative) priority increments the auto-assigned priority
* of any lower-priority swap_info_structs. * of any lower-priority swap_info_structs.
* swap_avail_head needs to be priority ordered for get_swap_page(), * swap_avail_head needs to be priority ordered for folio_alloc_swap(),
* which allocates swap pages from the highest available priority * which allocates swap pages from the highest available priority
* swap_info_struct. * swap_info_struct.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment