Commit cbc2bd98 authored by Kairui Song's avatar Kairui Song Committed by Andrew Morton
Browse files

swap: avoid holding swap reference in swap_cache_get_folio

All its callers either already hold a reference to, or lock the swap
device while calling this function.  There is only one exception in
shmem_swapin_folio, just make this caller also hold a reference of the
swap device, so this helper can be simplified and saves a few cycles.

This also provides finer control of error handling in shmem_swapin_folio,
on race (with swap off), it can just try again.  For invalid swap entry,
it can fail with a proper error code.

Link: https://lkml.kernel.org/r/20221219185840.25441-5-ryncsn@gmail.com


Signed-off-by: default avatarKairui Song <kasong@tencent.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: "Huang, Ying" <ying.huang@intel.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 16ba391e
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -1739,6 +1739,7 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
	struct address_space *mapping = inode->i_mapping;
	struct shmem_inode_info *info = SHMEM_I(inode);
	struct mm_struct *charge_mm = vma ? vma->vm_mm : NULL;
	struct swap_info_struct *si;
	struct folio *folio = NULL;
	swp_entry_t swap;
	int error;
@@ -1750,6 +1751,14 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
	if (is_swapin_error_entry(swap))
		return -EIO;

	si = get_swap_device(swap);
	if (!si) {
		if (!shmem_confirm_swap(mapping, index, swap))
			return -EEXIST;
		else
			return -EINVAL;
	}

	/* Look it up and read it in.. */
	folio = swap_cache_get_folio(swap, NULL, 0);
	if (!folio) {
@@ -1810,6 +1819,7 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
	delete_from_swap_cache(folio);
	folio_mark_dirty(folio);
	swap_free(swap);
	put_swap_device(si);

	*foliop = folio;
	return 0;
@@ -1823,6 +1833,7 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
		folio_unlock(folio);
		folio_put(folio);
	}
	put_swap_device(si);

	return error;
}
+2 −6
Original line number Diff line number Diff line
@@ -321,19 +321,15 @@ static inline bool swap_use_vma_readahead(void)
 * unlocked and with its refcount incremented - we rely on the kernel
 * lock getting page table operations atomic even if we drop the folio
 * lock before returning.
 *
 * Caller must lock the swap device or hold a reference to keep it valid.
 */
struct folio *swap_cache_get_folio(swp_entry_t entry,
		struct vm_area_struct *vma, unsigned long addr)
{
	struct folio *folio;
	struct swap_info_struct *si;

	si = get_swap_device(entry);
	if (!si)
		return NULL;
	folio = filemap_get_folio(swap_address_space(entry), swp_offset(entry));
	put_swap_device(si);

	if (folio) {
		bool vma_ra = swap_use_vma_readahead();
		bool readahead;