summaryrefslogtreecommitdiff
path: root/mm/memory-failure.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memory-failure.c')
-rw-r--r--mm/memory-failure.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index a0d9b4ac7d54..4f9b61f4a668 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -678,7 +678,7 @@ static void add_to_kill_fsdax(struct task_struct *tsk, struct page *p,
*/
static void collect_procs_fsdax(struct page *page,
struct address_space *mapping, pgoff_t pgoff,
- struct list_head *to_kill)
+ struct list_head *to_kill, bool pre_remove)
{
struct vm_area_struct *vma;
struct task_struct *tsk;
@@ -686,8 +686,15 @@ static void collect_procs_fsdax(struct page *page,
i_mmap_lock_read(mapping);
rcu_read_lock();
for_each_process(tsk) {
- struct task_struct *t = task_early_kill(tsk, true);
+ struct task_struct *t = tsk;
+ /*
+ * Search for all tasks while MF_MEM_PRE_REMOVE is set, because
+ * the current may not be the one accessing the fsdax page.
+ * Otherwise, search for the current task.
+ */
+ if (!pre_remove)
+ t = task_early_kill(tsk, true);
if (!t)
continue;
vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
@@ -1793,6 +1800,7 @@ int mf_dax_kill_procs(struct address_space *mapping, pgoff_t index,
dax_entry_t cookie;
struct page *page;
size_t end = index + count;
+ bool pre_remove = mf_flags & MF_MEM_PRE_REMOVE;
mf_flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
@@ -1804,9 +1812,14 @@ int mf_dax_kill_procs(struct address_space *mapping, pgoff_t index,
if (!page)
goto unlock;
- SetPageHWPoison(page);
+ if (!pre_remove)
+ SetPageHWPoison(page);
- collect_procs_fsdax(page, mapping, index, &to_kill);
+ /*
+ * The pre_remove case is revoking access, the memory is still
+ * good and could theoretically be put back into service.
+ */
+ collect_procs_fsdax(page, mapping, index, &to_kill, pre_remove);
unmap_and_kill(&to_kill, page_to_pfn(page), mapping,
index, mf_flags);
unlock: