Skip to content

Commit e6dbcb7

Browse files
ankita-nvakpm00
authored andcommitted
mm: fixup pfnmap memory failure handling to use pgoff
The memory failure handling implementation for the PFNMAP memory with no struct pages is faulty. The VA of the mapping is determined based on the the PFN. It should instead be based on the file mapping offset. At the occurrence of poison, the memory_failure_pfn is triggered on the poisoned PFN. Introduce a callback function that allows mm to translate the PFN to the corresponding file page offset. The kernel module using the registration API must implement the callback function and provide the translation. The translated value is then used to determine the VA information and sending the SIGBUS to the usermode process mapped to the poisoned PFN. The callback is also useful for the driver to be notified of the poisoned PFN, which may then track it. Link: https://lkml.kernel.org/r/20251211070603.338701-2-ankita@nvidia.com Fixes: 2ec4196 ("mm: handle poisoning of pfn without struct pages") Signed-off-by: Ankit Agrawal <ankita@nvidia.com> Suggested-by: Jason Gunthorpe <jgg@nvidia.com> Cc: Kevin Tian <kevin.tian@intel.com> Cc: Matthew R. Ochs <mochs@nvidia.com> Cc: Miaohe Lin <linmiaohe@huawei.com> Cc: Naoya Horiguchi <nao.horiguchi@gmail.com> Cc: Neo Jia <cjia@nvidia.com> Cc: Vikram Sethi <vsethi@nvidia.com> Cc: Yishai Hadas <yishaih@nvidia.com> Cc: Zhi Wang <zhiw@nvidia.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 7013803 commit e6dbcb7

2 files changed

Lines changed: 20 additions & 11 deletions

File tree

include/linux/memory-failure.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ struct pfn_address_space;
99
struct pfn_address_space {
1010
struct interval_tree_node node;
1111
struct address_space *mapping;
12+
int (*pfn_to_vma_pgoff)(struct vm_area_struct *vma,
13+
unsigned long pfn, pgoff_t *pgoff);
1214
};
1315

1416
int register_pfn_address_space(struct pfn_address_space *pfn_space);

mm/memory-failure.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2161,6 +2161,9 @@ int register_pfn_address_space(struct pfn_address_space *pfn_space)
21612161
{
21622162
guard(mutex)(&pfn_space_lock);
21632163

2164+
if (!pfn_space->pfn_to_vma_pgoff)
2165+
return -EINVAL;
2166+
21642167
if (interval_tree_iter_first(&pfn_space_itree,
21652168
pfn_space->node.start,
21662169
pfn_space->node.last))
@@ -2183,10 +2186,10 @@ void unregister_pfn_address_space(struct pfn_address_space *pfn_space)
21832186
}
21842187
EXPORT_SYMBOL_GPL(unregister_pfn_address_space);
21852188

2186-
static void add_to_kill_pfn(struct task_struct *tsk,
2187-
struct vm_area_struct *vma,
2188-
struct list_head *to_kill,
2189-
unsigned long pfn)
2189+
static void add_to_kill_pgoff(struct task_struct *tsk,
2190+
struct vm_area_struct *vma,
2191+
struct list_head *to_kill,
2192+
pgoff_t pgoff)
21902193
{
21912194
struct to_kill *tk;
21922195

@@ -2197,12 +2200,12 @@ static void add_to_kill_pfn(struct task_struct *tsk,
21972200
}
21982201

21992202
/* Check for pgoff not backed by struct page */
2200-
tk->addr = vma_address(vma, pfn, 1);
2203+
tk->addr = vma_address(vma, pgoff, 1);
22012204
tk->size_shift = PAGE_SHIFT;
22022205

22032206
if (tk->addr == -EFAULT)
22042207
pr_info("Unable to find address %lx in %s\n",
2205-
pfn, tsk->comm);
2208+
pgoff, tsk->comm);
22062209

22072210
get_task_struct(tsk);
22082211
tk->tsk = tsk;
@@ -2212,11 +2215,12 @@ static void add_to_kill_pfn(struct task_struct *tsk,
22122215
/*
22132216
* Collect processes when the error hit a PFN not backed by struct page.
22142217
*/
2215-
static void collect_procs_pfn(struct address_space *mapping,
2218+
static void collect_procs_pfn(struct pfn_address_space *pfn_space,
22162219
unsigned long pfn, struct list_head *to_kill)
22172220
{
22182221
struct vm_area_struct *vma;
22192222
struct task_struct *tsk;
2223+
struct address_space *mapping = pfn_space->mapping;
22202224

22212225
i_mmap_lock_read(mapping);
22222226
rcu_read_lock();
@@ -2226,9 +2230,12 @@ static void collect_procs_pfn(struct address_space *mapping,
22262230
t = task_early_kill(tsk, true);
22272231
if (!t)
22282232
continue;
2229-
vma_interval_tree_foreach(vma, &mapping->i_mmap, pfn, pfn) {
2230-
if (vma->vm_mm == t->mm)
2231-
add_to_kill_pfn(t, vma, to_kill, pfn);
2233+
vma_interval_tree_foreach(vma, &mapping->i_mmap, 0, ULONG_MAX) {
2234+
pgoff_t pgoff;
2235+
2236+
if (vma->vm_mm == t->mm &&
2237+
!pfn_space->pfn_to_vma_pgoff(vma, pfn, &pgoff))
2238+
add_to_kill_pgoff(t, vma, to_kill, pgoff);
22322239
}
22332240
}
22342241
rcu_read_unlock();
@@ -2264,7 +2271,7 @@ static int memory_failure_pfn(unsigned long pfn, int flags)
22642271
struct pfn_address_space *pfn_space =
22652272
container_of(node, struct pfn_address_space, node);
22662273

2267-
collect_procs_pfn(pfn_space->mapping, pfn, &tokill);
2274+
collect_procs_pfn(pfn_space, pfn, &tokill);
22682275

22692276
mf_handled = true;
22702277
}

0 commit comments

Comments
 (0)