Skip to content

Commit

Permalink
mm: factor helpers for memory_failure_dev_pagemap
Browse files Browse the repository at this point in the history
memory_failure_dev_pagemap code is a bit complex before introduce RMAP
feature for fsdax.  So it is needed to factor some helper functions to
simplify these code.

[akpm@linux-foundation.org: fix CONFIG_HUGETLB_PAGE=n build]
[zhengbin13@huawei.com: fix redefinition of mf_generic_kill_procs]
  Link: https://lkml.kernel.org/r/20220628112143.1170473-1-zhengbin13@huawei.com
Link: https://lkml.kernel.org/r/20220603053738.1218681-3-ruansy.fnst@fujitsu.com
Signed-off-by: Shiyang Ruan <ruansy.fnst@fujitsu.com>
Signed-off-by: Zheng Bin <zhengbin13@huawei.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Dan Williams <dan.j.wiliams@intel.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Goldwyn Rodrigues <rgoldwyn@suse.com>
Cc: Goldwyn Rodrigues <rgoldwyn@suse.de>
Cc: Jane Chu <jane.chu@oracle.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Naoya Horiguchi <naoya.horiguchi@nec.com>
Cc: Ritesh Harjani <riteshh@linux.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
  • Loading branch information
irides authored and akpm00 committed Jul 18, 2022
1 parent 8012b86 commit 00cc790
Showing 1 changed file with 95 additions and 76 deletions.
171 changes: 95 additions & 76 deletions mm/memory-failure.c
Original file line number Diff line number Diff line change
Expand Up @@ -1499,6 +1499,95 @@ static int try_to_split_thp_page(struct page *page, const char *msg)
return 0;
}

static void unmap_and_kill(struct list_head *to_kill, unsigned long pfn,
struct address_space *mapping, pgoff_t index, int flags)
{
struct to_kill *tk;
unsigned long size = 0;

list_for_each_entry(tk, to_kill, nd)
if (tk->size_shift)
size = max(size, 1UL << tk->size_shift);

if (size) {
/*
* Unmap the largest mapping to avoid breaking up device-dax
* mappings which are constant size. The actual size of the
* mapping being torn down is communicated in siginfo, see
* kill_proc()
*/
loff_t start = (index << PAGE_SHIFT) & ~(size - 1);

unmap_mapping_range(mapping, start, size, 0);
}

kill_procs(to_kill, flags & MF_MUST_KILL, false, pfn, flags);
}

static int mf_generic_kill_procs(unsigned long long pfn, int flags,
struct dev_pagemap *pgmap)
{
struct page *page = pfn_to_page(pfn);
LIST_HEAD(to_kill);
dax_entry_t cookie;
int rc = 0;

/*
* Pages instantiated by device-dax (not filesystem-dax)
* may be compound pages.
*/
page = compound_head(page);

/*
* Prevent the inode from being freed while we are interrogating
* the address_space, typically this would be handled by
* lock_page(), but dax pages do not use the page lock. This
* also prevents changes to the mapping of this pfn until
* poison signaling is complete.
*/
cookie = dax_lock_page(page);
if (!cookie)
return -EBUSY;

if (hwpoison_filter(page)) {
rc = -EOPNOTSUPP;
goto unlock;
}

switch (pgmap->type) {
case MEMORY_DEVICE_PRIVATE:
case MEMORY_DEVICE_COHERENT:
/*
* TODO: Handle device pages which may need coordination
* with device-side memory.
*/
rc = -ENXIO;
goto unlock;
default:
break;
}

/*
* Use this flag as an indication that the dax page has been
* remapped UC to prevent speculative consumption of poison.
*/
SetPageHWPoison(page);

/*
* Unlike System-RAM there is no possibility to swap in a
* different physical page at a given virtual address, so all
* userspace consumption of ZONE_DEVICE memory necessitates
* SIGBUS (i.e. MF_MUST_KILL)
*/
flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
collect_procs(page, &to_kill, true);

unmap_and_kill(&to_kill, pfn, page->mapping, page->index, flags);
unlock:
dax_unlock_page(page, cookie);
return rc;
}

/*
* Called from hugetlb code with hugetlb_lock held.
*
Expand Down Expand Up @@ -1634,23 +1723,20 @@ static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb
unlock_page(head);
return res;
}

#else
static inline int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb)
{
return 0;
}
#endif

#endif /* CONFIG_HUGETLB_PAGE */

static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
struct dev_pagemap *pgmap)
{
struct page *page = pfn_to_page(pfn);
unsigned long size = 0;
struct to_kill *tk;
LIST_HEAD(tokill);
int rc = -EBUSY;
loff_t start;
dax_entry_t cookie;
int rc = -ENXIO;

if (flags & MF_COUNT_INCREASED)
/*
Expand All @@ -1659,77 +1745,10 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
put_page(page);

/* device metadata space is not recoverable */
if (!pgmap_pfn_valid(pgmap, pfn)) {
rc = -ENXIO;
if (!pgmap_pfn_valid(pgmap, pfn))
goto out;
}

/*
* Pages instantiated by device-dax (not filesystem-dax)
* may be compound pages.
*/
page = compound_head(page);

/*
* Prevent the inode from being freed while we are interrogating
* the address_space, typically this would be handled by
* lock_page(), but dax pages do not use the page lock. This
* also prevents changes to the mapping of this pfn until
* poison signaling is complete.
*/
cookie = dax_lock_page(page);
if (!cookie)
goto out;

if (hwpoison_filter(page)) {
rc = -EOPNOTSUPP;
goto unlock;
}

switch (pgmap->type) {
case MEMORY_DEVICE_PRIVATE:
case MEMORY_DEVICE_COHERENT:
/*
* TODO: Handle device pages which may need coordination
* with device-side memory.
*/
goto unlock;
default:
break;
}

/*
* Use this flag as an indication that the dax page has been
* remapped UC to prevent speculative consumption of poison.
*/
SetPageHWPoison(page);

/*
* Unlike System-RAM there is no possibility to swap in a
* different physical page at a given virtual address, so all
* userspace consumption of ZONE_DEVICE memory necessitates
* SIGBUS (i.e. MF_MUST_KILL)
*/
flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
collect_procs(page, &tokill, true);

list_for_each_entry(tk, &tokill, nd)
if (tk->size_shift)
size = max(size, 1UL << tk->size_shift);
if (size) {
/*
* Unmap the largest mapping to avoid breaking up
* device-dax mappings which are constant size. The
* actual size of the mapping being torn down is
* communicated in siginfo, see kill_proc()
*/
start = (page->index << PAGE_SHIFT) & ~(size - 1);
unmap_mapping_range(page->mapping, start, size, 0);
}
kill_procs(&tokill, true, false, pfn, flags);
rc = 0;
unlock:
dax_unlock_page(page, cookie);
rc = mf_generic_kill_procs(pfn, flags, pgmap);
out:
/* drop pgmap ref acquired in caller */
put_dev_pagemap(pgmap);
Expand Down

0 comments on commit 00cc790

Please sign in to comment.