Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 2ec41967189c ("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>

authored by

Ankit Agrawal and committed by
Andrew Morton
e6dbcb7c 70138034

+20 -11
+2
include/linux/memory-failure.h
··· 9 9 struct pfn_address_space { 10 10 struct interval_tree_node node; 11 11 struct address_space *mapping; 12 + int (*pfn_to_vma_pgoff)(struct vm_area_struct *vma, 13 + unsigned long pfn, pgoff_t *pgoff); 12 14 }; 13 15 14 16 int register_pfn_address_space(struct pfn_address_space *pfn_space);
+18 -11
mm/memory-failure.c
··· 2161 2161 { 2162 2162 guard(mutex)(&pfn_space_lock); 2163 2163 2164 + if (!pfn_space->pfn_to_vma_pgoff) 2165 + return -EINVAL; 2166 + 2164 2167 if (interval_tree_iter_first(&pfn_space_itree, 2165 2168 pfn_space->node.start, 2166 2169 pfn_space->node.last)) ··· 2186 2183 } 2187 2184 EXPORT_SYMBOL_GPL(unregister_pfn_address_space); 2188 2185 2189 - static void add_to_kill_pfn(struct task_struct *tsk, 2190 - struct vm_area_struct *vma, 2191 - struct list_head *to_kill, 2192 - unsigned long pfn) 2186 + static void add_to_kill_pgoff(struct task_struct *tsk, 2187 + struct vm_area_struct *vma, 2188 + struct list_head *to_kill, 2189 + pgoff_t pgoff) 2193 2190 { 2194 2191 struct to_kill *tk; 2195 2192 ··· 2200 2197 } 2201 2198 2202 2199 /* Check for pgoff not backed by struct page */ 2203 - tk->addr = vma_address(vma, pfn, 1); 2200 + tk->addr = vma_address(vma, pgoff, 1); 2204 2201 tk->size_shift = PAGE_SHIFT; 2205 2202 2206 2203 if (tk->addr == -EFAULT) 2207 2204 pr_info("Unable to find address %lx in %s\n", 2208 - pfn, tsk->comm); 2205 + pgoff, tsk->comm); 2209 2206 2210 2207 get_task_struct(tsk); 2211 2208 tk->tsk = tsk; ··· 2215 2212 /* 2216 2213 * Collect processes when the error hit a PFN not backed by struct page. 2217 2214 */ 2218 - static void collect_procs_pfn(struct address_space *mapping, 2215 + static void collect_procs_pfn(struct pfn_address_space *pfn_space, 2219 2216 unsigned long pfn, struct list_head *to_kill) 2220 2217 { 2221 2218 struct vm_area_struct *vma; 2222 2219 struct task_struct *tsk; 2220 + struct address_space *mapping = pfn_space->mapping; 2223 2221 2224 2222 i_mmap_lock_read(mapping); 2225 2223 rcu_read_lock(); ··· 2230 2226 t = task_early_kill(tsk, true); 2231 2227 if (!t) 2232 2228 continue; 2233 - vma_interval_tree_foreach(vma, &mapping->i_mmap, pfn, pfn) { 2234 - if (vma->vm_mm == t->mm) 2235 - add_to_kill_pfn(t, vma, to_kill, pfn); 2229 + vma_interval_tree_foreach(vma, &mapping->i_mmap, 0, ULONG_MAX) { 2230 + pgoff_t pgoff; 2231 + 2232 + if (vma->vm_mm == t->mm && 2233 + !pfn_space->pfn_to_vma_pgoff(vma, pfn, &pgoff)) 2234 + add_to_kill_pgoff(t, vma, to_kill, pgoff); 2236 2235 } 2237 2236 } 2238 2237 rcu_read_unlock(); ··· 2271 2264 struct pfn_address_space *pfn_space = 2272 2265 container_of(node, struct pfn_address_space, node); 2273 2266 2274 - collect_procs_pfn(pfn_space->mapping, pfn, &tokill); 2267 + collect_procs_pfn(pfn_space, pfn, &tokill); 2275 2268 2276 2269 mf_handled = true; 2277 2270 }