mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-04 04:06:26 +00:00
mm: factor helpers for memory_failure_dev_pagemap
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>
This commit is contained in:
parent
8012b86608
commit
00cc790e00
@ -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.
|
||||
*
|
||||
@ -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)
|
||||
/*
|
||||
@ -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;
|
||||
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)
|
||||
if (!pgmap_pfn_valid(pgmap, pfn))
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user