* [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu()
2026-04-01 15:40 [PATCH] KVM: x86/xen: Fix sleeping lock in hard IRQ context on PREEMPT_RT Sean Christopherson
@ 2026-04-29 22:25 ` shaikh.kamal
2026-05-03 3:26 ` kernel test robot
2026-05-03 3:26 ` kernel test robot
0 siblings, 2 replies; 5+ messages in thread
From: shaikh.kamal @ 2026-04-29 22:25 UTC (permalink / raw)
To: Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, David Rientjes, Shakeel Butt,
linux-mm, linux-kernel, kvm, linux-rt-devel
Cc: pbonzini, skhan, me, syzbot+c3178b6b512446632bac, shaikh.kamal
When an mm undergoes OOM kill, the OOM reaper unmaps memory while
holding the mmap_lock. MMU notifier subscribers (notably KVM) need
to be informed so they can tear down their secondary mappings. The
current synchronous unregister path can deadlock on PREEMPT_RT
because synchronize_srcu() is called from contexts that cannot
safely sleep.
This patch implements the asynchronous cleanup design proposed by
Paolo Bonzini in v1 review: a new optional after_oom_unregister
callback in struct mmu_notifier_ops, invoked after the SRCU grace
period via call_srcu() so that no readers can still reference the
subscription when cleanup runs.
The flow is:
1. The OOM reaper calls mmu_notifier_oom_enter() from
__oom_reap_task_mm().
2. mmu_notifier_oom_enter() walks the subscription list and, for
each subscriber that provides after_oom_unregister, detaches
the subscription from the active list and schedules a
call_srcu() callback.
3. The deferred callback invokes after_oom_unregister once the
grace period has elapsed and all in-flight readers have
finished.
4. Subsystems waiting to free structures referenced by the
callback can call the new mmu_notifier_barrier() helper, which
wraps srcu_barrier() to wait for all outstanding callbacks
scheduled this way.
after_oom_unregister is mutually exclusive with alloc_notifier
because allocated notifiers can have additional outstanding
references that the OOM path cannot safely drop.
KVM is updated to provide after_oom_unregister, which clears
mn_active_invalidate_count, and to detect via hlist_unhashed() in
kvm_destroy_vm() when its subscription was already detached by the
OOM path; in that case it calls mmu_notifier_barrier() and drops
the mm reference rather than calling mmu_notifier_unregister().
Reported-by: syzbot+c3178b6b512446632bac@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c3178b6b512446632bac
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/all/20260209161527.31978-1-shaikhkamal2012@gmail.com/
Signed-off-by: shaikh.kamal <shaikhkamal2012@gmail.com>
---
include/linux/mmu_notifier.h | 10 +++
mm/mmu_notifier.c | 123 +++++++++++++++++++++++++++++++++++
mm/oom_kill.c | 3 +
virt/kvm/kvm_main.c | 27 +++++++-
4 files changed, 162 insertions(+), 1 deletion(-)
diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index 07a2bbaf86e9..0ccd590f55d3 100644
--- a/include/linux/mmu_notifier.h
+++ b/include/linux/mmu_notifier.h
@@ -88,6 +88,14 @@ struct mmu_notifier_ops {
void (*release)(struct mmu_notifier *subscription,
struct mm_struct *mm);
+ /*
+ * Any mmu notifier that defines this is automatically unregistered
+ * when its mm is the subject of an OOM kill. after_oom_unregister()
+ * is invoked after all other outstanding callbacks have terminated.
+ */
+ void (*after_oom_unregister)(struct mmu_notifier *subscription,
+ struct mm_struct *mm);
+
/*
* clear_flush_young is called after the VM is
* test-and-clearing the young/accessed bitflag in the
@@ -375,6 +383,8 @@ mmu_interval_check_retry(struct mmu_interval_notifier *interval_sub,
extern void __mmu_notifier_subscriptions_destroy(struct mm_struct *mm);
extern void __mmu_notifier_release(struct mm_struct *mm);
+void mmu_notifier_oom_enter(struct mm_struct *mm);
+extern void mmu_notifier_barrier(void);
extern int __mmu_notifier_clear_flush_young(struct mm_struct *mm,
unsigned long start,
unsigned long end);
diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
index a6cdf3674bdc..b8fa58fe6b7d 100644
--- a/mm/mmu_notifier.c
+++ b/mm/mmu_notifier.c
@@ -49,6 +49,37 @@ struct mmu_notifier_subscriptions {
struct hlist_head deferred_list;
};
+/*
+ * Callback structure for asynchronous OOM cleanup.
+ * Used with call_srcu() to defer after_oom_unregister callbacks
+ * until after SRCU grace period completes.
+ */
+struct mmu_notifier_oom_callback {
+ struct rcu_head rcu;
+ struct mmu_notifier *subscription;
+ struct mm_struct *mm;
+};
+
+/*
+ * Callback function invoked after SRCU grace period.
+ * Safely calls after_oom_unregister once all readers have finished.
+ */
+static void mmu_notifier_oom_callback_fn(struct rcu_head *rcu)
+{
+ struct mmu_notifier_oom_callback *cb =
+ container_of(rcu, struct mmu_notifier_oom_callback, rcu);
+
+ /* Safe - all SRCU readers have finished */
+ cb->subscription->ops->after_oom_unregister(cb->subscription, cb->mm);
+
+ /* Release mm reference taken when callback was scheduled */
+ WARN_ON_ONCE(atomic_read(&cb->mm->mm_count) <= 0);
+ mmdrop(cb->mm);
+
+ /* Free callback structure */
+ kfree(cb);
+}
+
/*
* This is a collision-retry read-side/write-side 'lock', a lot like a
* seqcount, however this allows multiple write-sides to hold it at
@@ -359,6 +390,85 @@ void __mmu_notifier_release(struct mm_struct *mm)
mn_hlist_release(subscriptions, mm);
}
+void mmu_notifier_oom_enter(struct mm_struct *mm)
+{
+ struct mmu_notifier_subscriptions *subscriptions =
+ mm->notifier_subscriptions;
+ struct mmu_notifier *subscription;
+ struct hlist_node *tmp;
+ HLIST_HEAD(oom_list);
+ int id;
+
+ if (!subscriptions)
+ return;
+
+ id = srcu_read_lock(&srcu);
+
+ /*
+ * Prevent further calls to the MMU notifier, except for
+ * release and after_oom_unregister.
+ */
+ spin_lock(&subscriptions->lock);
+ hlist_for_each_entry_safe(subscription, tmp,
+ &subscriptions->list, hlist) {
+ if (!subscription->ops->after_oom_unregister)
+ continue;
+
+ /*
+ * after_oom_unregister and alloc_notifier are incompatible,
+ * because there could be other references to allocated
+ * notifiers.
+ */
+ if (WARN_ON(subscription->ops->alloc_notifier))
+ continue;
+
+ hlist_del_init_rcu(&subscription->hlist);
+ hlist_add_head(&subscription->hlist, &oom_list);
+ }
+ spin_unlock(&subscriptions->lock);
+ hlist_for_each_entry(subscription, &oom_list, hlist)
+ if (subscription->ops->release)
+ subscription->ops->release(subscription, mm);
+
+ srcu_read_unlock(&srcu, id);
+
+ if (hlist_empty(&oom_list))
+ return;
+
+ hlist_for_each_entry_safe(subscription, tmp,
+ &oom_list, hlist) {
+ struct mmu_notifier_oom_callback *cb;
+ /*
+ * Remove from stack-based oom_list and reset hlist to unhashed state.
+ * This sets subscription->hlist.pprev = NULL, so future callers of
+ * mmu_notifier_unregister() (e.g. kvm_destroy_vm) will see
+ * hlist_unhashed() == true and take the safe path, avoiding
+ * use-after-free on the stack-allocated oom_list head.
+ */
+ hlist_del_init(&subscription->hlist);
+
+ /*
+ * GFP_ATOMIC failure is exceedingly rare. We cannot sleep
+ * here (would reintroduce the deadlock this patch fixes)
+ * and cannot call after_oom_unregister synchronously
+ * without first waiting for SRCU readers. The subscriber
+ * will not receive after_oom_unregister but cleanup will
+ * eventually happen via the unregister path.
+ */
+ cb = kmalloc(sizeof(*cb), GFP_ATOMIC);
+ if (!cb)
+ continue;
+
+ cb->subscription = subscription;
+ cb->mm = mm;
+ mmgrab(mm);
+
+ /* Schedule callback - returns immediately */
+ call_srcu(&srcu, &cb->rcu, mmu_notifier_oom_callback_fn);
+ }
+
+}
+
/*
* If no young bitflag is supported by the hardware, ->clear_flush_young can
* unmap the address and return 1 or 0 depending if the mapping previously
@@ -1096,3 +1206,16 @@ void mmu_notifier_synchronize(void)
synchronize_srcu(&srcu);
}
EXPORT_SYMBOL_GPL(mmu_notifier_synchronize);
+
+/**
+ * mmu_notifier_barrier - Wait for all pending MMU notifier callbacks
+ *
+ * Waits for all call_srcu() callbacks scheduled by mmu_notifier_oom_enter()
+ * to complete. Used by subsystems during cleanup to prevent use-after-free
+ * when destroying structures accessed by the callbacks.
+ */
+void mmu_notifier_barrier(void)
+{
+ srcu_barrier(&srcu);
+}
+EXPORT_SYMBOL_GPL(mmu_notifier_barrier);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 5c6c95c169ee..029e041afc57 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -519,6 +519,9 @@ static bool __oom_reap_task_mm(struct mm_struct *mm)
bool ret = true;
MA_STATE(mas, &mm->mm_mt, ULONG_MAX, ULONG_MAX);
+ /* Notify MMU notifiers about the OOM event */
+ mmu_notifier_oom_enter(mm);
+
/*
* Tell all users of get_user/copy_from_user etc... that the content
* is no longer stable. No barriers really needed because unmapping
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 1bc1da66b4b0..a2df83d3b413 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -885,6 +885,24 @@ static void kvm_mmu_notifier_release(struct mmu_notifier *mn,
srcu_read_unlock(&kvm->srcu, idx);
}
+static void kvm_mmu_notifier_after_oom_unregister(struct mmu_notifier *mn,
+ struct mm_struct *mm)
+{
+ struct kvm *kvm;
+
+ kvm = mmu_notifier_to_kvm(mn);
+
+ /*
+ * At this point the unregister has completed and all other callbacks
+ * have terminated. Clean up any unbalanced invalidation counts.
+ */
+ WARN_ON(rcuwait_active(&kvm->mn_memslots_update_rcuwait));
+ if (kvm->mn_active_invalidate_count)
+ kvm->mn_active_invalidate_count = 0;
+ else
+ WARN_ON(kvm->mmu_invalidate_in_progress);
+}
+
static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
.invalidate_range_start = kvm_mmu_notifier_invalidate_range_start,
.invalidate_range_end = kvm_mmu_notifier_invalidate_range_end,
@@ -892,6 +910,7 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
.clear_young = kvm_mmu_notifier_clear_young,
.test_young = kvm_mmu_notifier_test_young,
.release = kvm_mmu_notifier_release,
+ .after_oom_unregister = kvm_mmu_notifier_after_oom_unregister,
};
static int kvm_init_mmu_notifier(struct kvm *kvm)
@@ -1280,7 +1299,13 @@ static void kvm_destroy_vm(struct kvm *kvm)
kvm->buses[i] = NULL;
}
kvm_coalesced_mmio_free(kvm);
- mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
+ if (hlist_unhashed(&kvm->mmu_notifier.hlist)) {
+ /* Subscription removed by OOM. Wait for async callback. */
+ mmu_notifier_barrier();
+ mmdrop(kvm->mm);
+ } else {
+ mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
+ }
/*
* At this point, pending calls to invalidate_range_start()
* have completed but no more MMU notifiers will run, so
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu()
@ 2026-04-30 4:48 shaikh.kamal
0 siblings, 0 replies; 5+ messages in thread
From: shaikh.kamal @ 2026-04-30 4:48 UTC (permalink / raw)
To: Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, David Rientjes, Shakeel Butt,
linux-mm, linux-kernel, kvm, linux-rt-devel
Cc: pbonzini, skhan, me, shaikh.kamal, syzbot+c3178b6b512446632bac
When an mm undergoes OOM kill, the OOM reaper unmaps memory while
holding the mmap_lock. MMU notifier subscribers (notably KVM) need
to be informed so they can tear down their secondary mappings. The
current synchronous unregister path can deadlock on PREEMPT_RT
because synchronize_srcu() is called from contexts that cannot
safely sleep.
This patch implements the asynchronous cleanup design proposed by
Paolo Bonzini in v1 review: a new optional after_oom_unregister
callback in struct mmu_notifier_ops, invoked after the SRCU grace
period via call_srcu() so that no readers can still reference the
subscription when cleanup runs.
The flow is:
1. The OOM reaper calls mmu_notifier_oom_enter() from
__oom_reap_task_mm().
2. mmu_notifier_oom_enter() walks the subscription list and, for
each subscriber that provides after_oom_unregister, detaches
the subscription from the active list and schedules a
call_srcu() callback.
3. The deferred callback invokes after_oom_unregister once the
grace period has elapsed and all in-flight readers have
finished.
4. Subsystems waiting to free structures referenced by the
callback can call the new mmu_notifier_barrier() helper, which
wraps srcu_barrier() to wait for all outstanding callbacks
scheduled this way.
after_oom_unregister is mutually exclusive with alloc_notifier
because allocated notifiers can have additional outstanding
references that the OOM path cannot safely drop.
KVM is updated to provide after_oom_unregister, which clears
mn_active_invalidate_count, and to detect via hlist_unhashed() in
kvm_destroy_vm() when its subscription was already detached by the
OOM path; in that case it calls mmu_notifier_barrier() and drops
the mm reference rather than calling mmu_notifier_unregister().
Reported-by: syzbot+c3178b6b512446632bac@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c3178b6b512446632bac
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/all/20260209161527.31978-1-shaikhkamal2012@gmail.com/
Signed-off-by: shaikh.kamal <shaikhkamal2012@gmail.com>
---
include/linux/mmu_notifier.h | 10 +++
mm/mmu_notifier.c | 123 +++++++++++++++++++++++++++++++++++
mm/oom_kill.c | 3 +
virt/kvm/kvm_main.c | 27 +++++++-
4 files changed, 162 insertions(+), 1 deletion(-)
diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index 07a2bbaf86e9..0ccd590f55d3 100644
--- a/include/linux/mmu_notifier.h
+++ b/include/linux/mmu_notifier.h
@@ -88,6 +88,14 @@ struct mmu_notifier_ops {
void (*release)(struct mmu_notifier *subscription,
struct mm_struct *mm);
+ /*
+ * Any mmu notifier that defines this is automatically unregistered
+ * when its mm is the subject of an OOM kill. after_oom_unregister()
+ * is invoked after all other outstanding callbacks have terminated.
+ */
+ void (*after_oom_unregister)(struct mmu_notifier *subscription,
+ struct mm_struct *mm);
+
/*
* clear_flush_young is called after the VM is
* test-and-clearing the young/accessed bitflag in the
@@ -375,6 +383,8 @@ mmu_interval_check_retry(struct mmu_interval_notifier *interval_sub,
extern void __mmu_notifier_subscriptions_destroy(struct mm_struct *mm);
extern void __mmu_notifier_release(struct mm_struct *mm);
+void mmu_notifier_oom_enter(struct mm_struct *mm);
+extern void mmu_notifier_barrier(void);
extern int __mmu_notifier_clear_flush_young(struct mm_struct *mm,
unsigned long start,
unsigned long end);
diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
index a6cdf3674bdc..b8fa58fe6b7d 100644
--- a/mm/mmu_notifier.c
+++ b/mm/mmu_notifier.c
@@ -49,6 +49,37 @@ struct mmu_notifier_subscriptions {
struct hlist_head deferred_list;
};
+/*
+ * Callback structure for asynchronous OOM cleanup.
+ * Used with call_srcu() to defer after_oom_unregister callbacks
+ * until after SRCU grace period completes.
+ */
+struct mmu_notifier_oom_callback {
+ struct rcu_head rcu;
+ struct mmu_notifier *subscription;
+ struct mm_struct *mm;
+};
+
+/*
+ * Callback function invoked after SRCU grace period.
+ * Safely calls after_oom_unregister once all readers have finished.
+ */
+static void mmu_notifier_oom_callback_fn(struct rcu_head *rcu)
+{
+ struct mmu_notifier_oom_callback *cb =
+ container_of(rcu, struct mmu_notifier_oom_callback, rcu);
+
+ /* Safe - all SRCU readers have finished */
+ cb->subscription->ops->after_oom_unregister(cb->subscription, cb->mm);
+
+ /* Release mm reference taken when callback was scheduled */
+ WARN_ON_ONCE(atomic_read(&cb->mm->mm_count) <= 0);
+ mmdrop(cb->mm);
+
+ /* Free callback structure */
+ kfree(cb);
+}
+
/*
* This is a collision-retry read-side/write-side 'lock', a lot like a
* seqcount, however this allows multiple write-sides to hold it at
@@ -359,6 +390,85 @@ void __mmu_notifier_release(struct mm_struct *mm)
mn_hlist_release(subscriptions, mm);
}
+void mmu_notifier_oom_enter(struct mm_struct *mm)
+{
+ struct mmu_notifier_subscriptions *subscriptions =
+ mm->notifier_subscriptions;
+ struct mmu_notifier *subscription;
+ struct hlist_node *tmp;
+ HLIST_HEAD(oom_list);
+ int id;
+
+ if (!subscriptions)
+ return;
+
+ id = srcu_read_lock(&srcu);
+
+ /*
+ * Prevent further calls to the MMU notifier, except for
+ * release and after_oom_unregister.
+ */
+ spin_lock(&subscriptions->lock);
+ hlist_for_each_entry_safe(subscription, tmp,
+ &subscriptions->list, hlist) {
+ if (!subscription->ops->after_oom_unregister)
+ continue;
+
+ /*
+ * after_oom_unregister and alloc_notifier are incompatible,
+ * because there could be other references to allocated
+ * notifiers.
+ */
+ if (WARN_ON(subscription->ops->alloc_notifier))
+ continue;
+
+ hlist_del_init_rcu(&subscription->hlist);
+ hlist_add_head(&subscription->hlist, &oom_list);
+ }
+ spin_unlock(&subscriptions->lock);
+ hlist_for_each_entry(subscription, &oom_list, hlist)
+ if (subscription->ops->release)
+ subscription->ops->release(subscription, mm);
+
+ srcu_read_unlock(&srcu, id);
+
+ if (hlist_empty(&oom_list))
+ return;
+
+ hlist_for_each_entry_safe(subscription, tmp,
+ &oom_list, hlist) {
+ struct mmu_notifier_oom_callback *cb;
+ /*
+ * Remove from stack-based oom_list and reset hlist to unhashed state.
+ * This sets subscription->hlist.pprev = NULL, so future callers of
+ * mmu_notifier_unregister() (e.g. kvm_destroy_vm) will see
+ * hlist_unhashed() == true and take the safe path, avoiding
+ * use-after-free on the stack-allocated oom_list head.
+ */
+ hlist_del_init(&subscription->hlist);
+
+ /*
+ * GFP_ATOMIC failure is exceedingly rare. We cannot sleep
+ * here (would reintroduce the deadlock this patch fixes)
+ * and cannot call after_oom_unregister synchronously
+ * without first waiting for SRCU readers. The subscriber
+ * will not receive after_oom_unregister but cleanup will
+ * eventually happen via the unregister path.
+ */
+ cb = kmalloc(sizeof(*cb), GFP_ATOMIC);
+ if (!cb)
+ continue;
+
+ cb->subscription = subscription;
+ cb->mm = mm;
+ mmgrab(mm);
+
+ /* Schedule callback - returns immediately */
+ call_srcu(&srcu, &cb->rcu, mmu_notifier_oom_callback_fn);
+ }
+
+}
+
/*
* If no young bitflag is supported by the hardware, ->clear_flush_young can
* unmap the address and return 1 or 0 depending if the mapping previously
@@ -1096,3 +1206,16 @@ void mmu_notifier_synchronize(void)
synchronize_srcu(&srcu);
}
EXPORT_SYMBOL_GPL(mmu_notifier_synchronize);
+
+/**
+ * mmu_notifier_barrier - Wait for all pending MMU notifier callbacks
+ *
+ * Waits for all call_srcu() callbacks scheduled by mmu_notifier_oom_enter()
+ * to complete. Used by subsystems during cleanup to prevent use-after-free
+ * when destroying structures accessed by the callbacks.
+ */
+void mmu_notifier_barrier(void)
+{
+ srcu_barrier(&srcu);
+}
+EXPORT_SYMBOL_GPL(mmu_notifier_barrier);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 5c6c95c169ee..029e041afc57 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -519,6 +519,9 @@ static bool __oom_reap_task_mm(struct mm_struct *mm)
bool ret = true;
MA_STATE(mas, &mm->mm_mt, ULONG_MAX, ULONG_MAX);
+ /* Notify MMU notifiers about the OOM event */
+ mmu_notifier_oom_enter(mm);
+
/*
* Tell all users of get_user/copy_from_user etc... that the content
* is no longer stable. No barriers really needed because unmapping
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 1bc1da66b4b0..a2df83d3b413 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -885,6 +885,24 @@ static void kvm_mmu_notifier_release(struct mmu_notifier *mn,
srcu_read_unlock(&kvm->srcu, idx);
}
+static void kvm_mmu_notifier_after_oom_unregister(struct mmu_notifier *mn,
+ struct mm_struct *mm)
+{
+ struct kvm *kvm;
+
+ kvm = mmu_notifier_to_kvm(mn);
+
+ /*
+ * At this point the unregister has completed and all other callbacks
+ * have terminated. Clean up any unbalanced invalidation counts.
+ */
+ WARN_ON(rcuwait_active(&kvm->mn_memslots_update_rcuwait));
+ if (kvm->mn_active_invalidate_count)
+ kvm->mn_active_invalidate_count = 0;
+ else
+ WARN_ON(kvm->mmu_invalidate_in_progress);
+}
+
static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
.invalidate_range_start = kvm_mmu_notifier_invalidate_range_start,
.invalidate_range_end = kvm_mmu_notifier_invalidate_range_end,
@@ -892,6 +910,7 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
.clear_young = kvm_mmu_notifier_clear_young,
.test_young = kvm_mmu_notifier_test_young,
.release = kvm_mmu_notifier_release,
+ .after_oom_unregister = kvm_mmu_notifier_after_oom_unregister,
};
static int kvm_init_mmu_notifier(struct kvm *kvm)
@@ -1280,7 +1299,13 @@ static void kvm_destroy_vm(struct kvm *kvm)
kvm->buses[i] = NULL;
}
kvm_coalesced_mmio_free(kvm);
- mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
+ if (hlist_unhashed(&kvm->mmu_notifier.hlist)) {
+ /* Subscription removed by OOM. Wait for async callback. */
+ mmu_notifier_barrier();
+ mmdrop(kvm->mm);
+ } else {
+ mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
+ }
/*
* At this point, pending calls to invalidate_range_start()
* have completed but no more MMU notifiers will run, so
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu()
2026-03-30 11:24 [PATCH] KVM: mmu_notifier: make mn_invalidate_lock non-sleeping for non-blocking invalidations Paolo Bonzini
@ 2026-04-30 14:17 ` shaikh.kamal
0 siblings, 0 replies; 5+ messages in thread
From: shaikh.kamal @ 2026-04-30 14:17 UTC (permalink / raw)
To: Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, David Rientjes, Shakeel Butt,
linux-mm, linux-kernel, kvm, linux-rt-devel
Cc: pbonzini, skhan, me, shaikh.kamal, syzbot+c3178b6b512446632bac
When an mm undergoes OOM kill, the OOM reaper unmaps memory while
holding the mmap_lock. MMU notifier subscribers (notably KVM) need
to be informed so they can tear down their secondary mappings. The
current synchronous unregister path can deadlock on PREEMPT_RT
because synchronize_srcu() is called from contexts that cannot
safely sleep.
This patch implements the asynchronous cleanup design proposed by
Paolo Bonzini in v1 review: a new optional after_oom_unregister
callback in struct mmu_notifier_ops, invoked after the SRCU grace
period via call_srcu() so that no readers can still reference the
subscription when cleanup runs.
The flow is:
1. The OOM reaper calls mmu_notifier_oom_enter() from
__oom_reap_task_mm().
2. mmu_notifier_oom_enter() walks the subscription list and, for
each subscriber that provides after_oom_unregister, detaches
the subscription from the active list and schedules a
call_srcu() callback.
3. The deferred callback invokes after_oom_unregister once the
grace period has elapsed and all in-flight readers have
finished.
4. Subsystems waiting to free structures referenced by the
callback can call the new mmu_notifier_barrier() helper, which
wraps srcu_barrier() to wait for all outstanding callbacks
scheduled this way.
after_oom_unregister is mutually exclusive with alloc_notifier
because allocated notifiers can have additional outstanding
references that the OOM path cannot safely drop.
KVM is updated to provide after_oom_unregister, which clears
mn_active_invalidate_count, and to detect via hlist_unhashed() in
kvm_destroy_vm() when its subscription was already detached by the
OOM path; in that case it calls mmu_notifier_barrier() and drops
the mm reference rather than calling mmu_notifier_unregister().
Reported-by: syzbot+c3178b6b512446632bac@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c3178b6b512446632bac
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/all/20260209161527.31978-1-shaikhkamal2012@gmail.com/
Signed-off-by: shaikh.kamal <shaikhkamal2012@gmail.com>
---
include/linux/mmu_notifier.h | 10 +++
mm/mmu_notifier.c | 123 +++++++++++++++++++++++++++++++++++
mm/oom_kill.c | 3 +
virt/kvm/kvm_main.c | 27 +++++++-
4 files changed, 162 insertions(+), 1 deletion(-)
diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index 07a2bbaf86e9..0ccd590f55d3 100644
--- a/include/linux/mmu_notifier.h
+++ b/include/linux/mmu_notifier.h
@@ -88,6 +88,14 @@ struct mmu_notifier_ops {
void (*release)(struct mmu_notifier *subscription,
struct mm_struct *mm);
+ /*
+ * Any mmu notifier that defines this is automatically unregistered
+ * when its mm is the subject of an OOM kill. after_oom_unregister()
+ * is invoked after all other outstanding callbacks have terminated.
+ */
+ void (*after_oom_unregister)(struct mmu_notifier *subscription,
+ struct mm_struct *mm);
+
/*
* clear_flush_young is called after the VM is
* test-and-clearing the young/accessed bitflag in the
@@ -375,6 +383,8 @@ mmu_interval_check_retry(struct mmu_interval_notifier *interval_sub,
extern void __mmu_notifier_subscriptions_destroy(struct mm_struct *mm);
extern void __mmu_notifier_release(struct mm_struct *mm);
+void mmu_notifier_oom_enter(struct mm_struct *mm);
+extern void mmu_notifier_barrier(void);
extern int __mmu_notifier_clear_flush_young(struct mm_struct *mm,
unsigned long start,
unsigned long end);
diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
index a6cdf3674bdc..b8fa58fe6b7d 100644
--- a/mm/mmu_notifier.c
+++ b/mm/mmu_notifier.c
@@ -49,6 +49,37 @@ struct mmu_notifier_subscriptions {
struct hlist_head deferred_list;
};
+/*
+ * Callback structure for asynchronous OOM cleanup.
+ * Used with call_srcu() to defer after_oom_unregister callbacks
+ * until after SRCU grace period completes.
+ */
+struct mmu_notifier_oom_callback {
+ struct rcu_head rcu;
+ struct mmu_notifier *subscription;
+ struct mm_struct *mm;
+};
+
+/*
+ * Callback function invoked after SRCU grace period.
+ * Safely calls after_oom_unregister once all readers have finished.
+ */
+static void mmu_notifier_oom_callback_fn(struct rcu_head *rcu)
+{
+ struct mmu_notifier_oom_callback *cb =
+ container_of(rcu, struct mmu_notifier_oom_callback, rcu);
+
+ /* Safe - all SRCU readers have finished */
+ cb->subscription->ops->after_oom_unregister(cb->subscription, cb->mm);
+
+ /* Release mm reference taken when callback was scheduled */
+ WARN_ON_ONCE(atomic_read(&cb->mm->mm_count) <= 0);
+ mmdrop(cb->mm);
+
+ /* Free callback structure */
+ kfree(cb);
+}
+
/*
* This is a collision-retry read-side/write-side 'lock', a lot like a
* seqcount, however this allows multiple write-sides to hold it at
@@ -359,6 +390,85 @@ void __mmu_notifier_release(struct mm_struct *mm)
mn_hlist_release(subscriptions, mm);
}
+void mmu_notifier_oom_enter(struct mm_struct *mm)
+{
+ struct mmu_notifier_subscriptions *subscriptions =
+ mm->notifier_subscriptions;
+ struct mmu_notifier *subscription;
+ struct hlist_node *tmp;
+ HLIST_HEAD(oom_list);
+ int id;
+
+ if (!subscriptions)
+ return;
+
+ id = srcu_read_lock(&srcu);
+
+ /*
+ * Prevent further calls to the MMU notifier, except for
+ * release and after_oom_unregister.
+ */
+ spin_lock(&subscriptions->lock);
+ hlist_for_each_entry_safe(subscription, tmp,
+ &subscriptions->list, hlist) {
+ if (!subscription->ops->after_oom_unregister)
+ continue;
+
+ /*
+ * after_oom_unregister and alloc_notifier are incompatible,
+ * because there could be other references to allocated
+ * notifiers.
+ */
+ if (WARN_ON(subscription->ops->alloc_notifier))
+ continue;
+
+ hlist_del_init_rcu(&subscription->hlist);
+ hlist_add_head(&subscription->hlist, &oom_list);
+ }
+ spin_unlock(&subscriptions->lock);
+ hlist_for_each_entry(subscription, &oom_list, hlist)
+ if (subscription->ops->release)
+ subscription->ops->release(subscription, mm);
+
+ srcu_read_unlock(&srcu, id);
+
+ if (hlist_empty(&oom_list))
+ return;
+
+ hlist_for_each_entry_safe(subscription, tmp,
+ &oom_list, hlist) {
+ struct mmu_notifier_oom_callback *cb;
+ /*
+ * Remove from stack-based oom_list and reset hlist to unhashed state.
+ * This sets subscription->hlist.pprev = NULL, so future callers of
+ * mmu_notifier_unregister() (e.g. kvm_destroy_vm) will see
+ * hlist_unhashed() == true and take the safe path, avoiding
+ * use-after-free on the stack-allocated oom_list head.
+ */
+ hlist_del_init(&subscription->hlist);
+
+ /*
+ * GFP_ATOMIC failure is exceedingly rare. We cannot sleep
+ * here (would reintroduce the deadlock this patch fixes)
+ * and cannot call after_oom_unregister synchronously
+ * without first waiting for SRCU readers. The subscriber
+ * will not receive after_oom_unregister but cleanup will
+ * eventually happen via the unregister path.
+ */
+ cb = kmalloc(sizeof(*cb), GFP_ATOMIC);
+ if (!cb)
+ continue;
+
+ cb->subscription = subscription;
+ cb->mm = mm;
+ mmgrab(mm);
+
+ /* Schedule callback - returns immediately */
+ call_srcu(&srcu, &cb->rcu, mmu_notifier_oom_callback_fn);
+ }
+
+}
+
/*
* If no young bitflag is supported by the hardware, ->clear_flush_young can
* unmap the address and return 1 or 0 depending if the mapping previously
@@ -1096,3 +1206,16 @@ void mmu_notifier_synchronize(void)
synchronize_srcu(&srcu);
}
EXPORT_SYMBOL_GPL(mmu_notifier_synchronize);
+
+/**
+ * mmu_notifier_barrier - Wait for all pending MMU notifier callbacks
+ *
+ * Waits for all call_srcu() callbacks scheduled by mmu_notifier_oom_enter()
+ * to complete. Used by subsystems during cleanup to prevent use-after-free
+ * when destroying structures accessed by the callbacks.
+ */
+void mmu_notifier_barrier(void)
+{
+ srcu_barrier(&srcu);
+}
+EXPORT_SYMBOL_GPL(mmu_notifier_barrier);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 5c6c95c169ee..029e041afc57 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -519,6 +519,9 @@ static bool __oom_reap_task_mm(struct mm_struct *mm)
bool ret = true;
MA_STATE(mas, &mm->mm_mt, ULONG_MAX, ULONG_MAX);
+ /* Notify MMU notifiers about the OOM event */
+ mmu_notifier_oom_enter(mm);
+
/*
* Tell all users of get_user/copy_from_user etc... that the content
* is no longer stable. No barriers really needed because unmapping
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 1bc1da66b4b0..a2df83d3b413 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -885,6 +885,24 @@ static void kvm_mmu_notifier_release(struct mmu_notifier *mn,
srcu_read_unlock(&kvm->srcu, idx);
}
+static void kvm_mmu_notifier_after_oom_unregister(struct mmu_notifier *mn,
+ struct mm_struct *mm)
+{
+ struct kvm *kvm;
+
+ kvm = mmu_notifier_to_kvm(mn);
+
+ /*
+ * At this point the unregister has completed and all other callbacks
+ * have terminated. Clean up any unbalanced invalidation counts.
+ */
+ WARN_ON(rcuwait_active(&kvm->mn_memslots_update_rcuwait));
+ if (kvm->mn_active_invalidate_count)
+ kvm->mn_active_invalidate_count = 0;
+ else
+ WARN_ON(kvm->mmu_invalidate_in_progress);
+}
+
static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
.invalidate_range_start = kvm_mmu_notifier_invalidate_range_start,
.invalidate_range_end = kvm_mmu_notifier_invalidate_range_end,
@@ -892,6 +910,7 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
.clear_young = kvm_mmu_notifier_clear_young,
.test_young = kvm_mmu_notifier_test_young,
.release = kvm_mmu_notifier_release,
+ .after_oom_unregister = kvm_mmu_notifier_after_oom_unregister,
};
static int kvm_init_mmu_notifier(struct kvm *kvm)
@@ -1280,7 +1299,13 @@ static void kvm_destroy_vm(struct kvm *kvm)
kvm->buses[i] = NULL;
}
kvm_coalesced_mmio_free(kvm);
- mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
+ if (hlist_unhashed(&kvm->mmu_notifier.hlist)) {
+ /* Subscription removed by OOM. Wait for async callback. */
+ mmu_notifier_barrier();
+ mmdrop(kvm->mm);
+ } else {
+ mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
+ }
/*
* At this point, pending calls to invalidate_range_start()
* have completed but no more MMU notifiers will run, so
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu()
2026-04-29 22:25 ` [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu() shaikh.kamal
@ 2026-05-03 3:26 ` kernel test robot
2026-05-03 3:26 ` kernel test robot
1 sibling, 0 replies; 5+ messages in thread
From: kernel test robot @ 2026-05-03 3:26 UTC (permalink / raw)
To: shaikh.kamal, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, David Rientjes,
Shakeel Butt, linux-mm, linux-kernel, kvm, linux-rt-devel
Cc: llvm, oe-kbuild-all, pbonzini, skhan, me,
syzbot+c3178b6b512446632bac, shaikh.kamal
Hi shaikh.kamal,
kernel test robot noticed the following build errors:
[auto build test ERROR on v7.0]
[cannot apply to akpm-mm/mm-everything kvm/queue kvm/next kvm/linux-next v7.1-rc1 linus/master next-20260430]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/shaikh-kamal/mm-mmu_notifier-Add-async-OOM-cleanup-via-call_srcu/20260430-202943
base: v7.0
patch link: https://lore.kernel.org/r/20260429222548.25475-1-shaikhkamal2012%40gmail.com
patch subject: [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu()
config: hexagon-allnoconfig (https://download.01.org/0day-ci/archive/20260503/202605031115.qmkkOLQc-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 5bac06718f502014fade905512f1d26d578a18f3)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260503/202605031115.qmkkOLQc-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605031115.qmkkOLQc-lkp@intel.com/
All errors (new ones prefixed by >>):
>> mm/oom_kill.c:523:2: error: call to undeclared function 'mmu_notifier_oom_enter'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
523 | mmu_notifier_oom_enter(mm);
| ^
mm/oom_kill.c:523:2: note: did you mean 'mmu_notifier_release'?
include/linux/mmu_notifier.h:610:20: note: 'mmu_notifier_release' declared here
610 | static inline void mmu_notifier_release(struct mm_struct *mm)
| ^
mm/oom_kill.c:511:28: warning: variable 'oom_reaper_th' set but not used [-Wunused-but-set-global]
511 | static struct task_struct *oom_reaper_th;
| ^
1 warning and 1 error generated.
vim +/mmu_notifier_oom_enter +523 mm/oom_kill.c
515
516 static bool __oom_reap_task_mm(struct mm_struct *mm)
517 {
518 struct vm_area_struct *vma;
519 bool ret = true;
520 MA_STATE(mas, &mm->mm_mt, ULONG_MAX, ULONG_MAX);
521
522 /* Notify MMU notifiers about the OOM event */
> 523 mmu_notifier_oom_enter(mm);
524
525 /*
526 * Tell all users of get_user/copy_from_user etc... that the content
527 * is no longer stable. No barriers really needed because unmapping
528 * should imply barriers already and the reader would hit a page fault
529 * if it stumbled over a reaped memory.
530 */
531 mm_flags_set(MMF_UNSTABLE, mm);
532
533 /*
534 * It might start racing with the dying task and compete for shared
535 * resources - e.g. page table lock contention has been observed.
536 * Reduce those races by reaping the oom victim from the other end
537 * of the address space.
538 */
539 mas_for_each_rev(&mas, vma, 0) {
540 if (vma->vm_flags & (VM_HUGETLB|VM_PFNMAP))
541 continue;
542
543 /*
544 * Only anonymous pages have a good chance to be dropped
545 * without additional steps which we cannot afford as we
546 * are OOM already.
547 *
548 * We do not even care about fs backed pages because all
549 * which are reclaimable have already been reclaimed and
550 * we do not want to block exit_mmap by keeping mm ref
551 * count elevated without a good reason.
552 */
553 if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED)) {
554 struct mmu_notifier_range range;
555 struct mmu_gather tlb;
556
557 mmu_notifier_range_init(&range, MMU_NOTIFY_UNMAP, 0,
558 mm, vma->vm_start,
559 vma->vm_end);
560 tlb_gather_mmu(&tlb, mm);
561 if (mmu_notifier_invalidate_range_start_nonblock(&range)) {
562 tlb_finish_mmu(&tlb);
563 ret = false;
564 continue;
565 }
566 unmap_page_range(&tlb, vma, range.start, range.end, NULL);
567 mmu_notifier_invalidate_range_end(&range);
568 tlb_finish_mmu(&tlb);
569 }
570 }
571
572 return ret;
573 }
574
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu()
2026-04-29 22:25 ` [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu() shaikh.kamal
2026-05-03 3:26 ` kernel test robot
@ 2026-05-03 3:26 ` kernel test robot
1 sibling, 0 replies; 5+ messages in thread
From: kernel test robot @ 2026-05-03 3:26 UTC (permalink / raw)
To: shaikh.kamal, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, David Rientjes,
Shakeel Butt, linux-mm, linux-kernel, kvm, linux-rt-devel
Cc: oe-kbuild-all, pbonzini, skhan, me, syzbot+c3178b6b512446632bac,
shaikh.kamal
Hi shaikh.kamal,
kernel test robot noticed the following build errors:
[auto build test ERROR on v7.0]
[cannot apply to akpm-mm/mm-everything kvm/queue kvm/next kvm/linux-next v7.1-rc1 linus/master next-20260430]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/shaikh-kamal/mm-mmu_notifier-Add-async-OOM-cleanup-via-call_srcu/20260430-202943
base: v7.0
patch link: https://lore.kernel.org/r/20260429222548.25475-1-shaikhkamal2012%40gmail.com
patch subject: [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu()
config: arc-allnoconfig (https://download.01.org/0day-ci/archive/20260503/202605031109.uxckW5L3-lkp@intel.com/config)
compiler: arc-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260503/202605031109.uxckW5L3-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605031109.uxckW5L3-lkp@intel.com/
All errors (new ones prefixed by >>):
mm/oom_kill.c: In function '__oom_reap_task_mm':
>> mm/oom_kill.c:523:9: error: implicit declaration of function 'mmu_notifier_oom_enter'; did you mean 'mmu_notifier_release'? [-Wimplicit-function-declaration]
523 | mmu_notifier_oom_enter(mm);
| ^~~~~~~~~~~~~~~~~~~~~~
| mmu_notifier_release
vim +523 mm/oom_kill.c
515
516 static bool __oom_reap_task_mm(struct mm_struct *mm)
517 {
518 struct vm_area_struct *vma;
519 bool ret = true;
520 MA_STATE(mas, &mm->mm_mt, ULONG_MAX, ULONG_MAX);
521
522 /* Notify MMU notifiers about the OOM event */
> 523 mmu_notifier_oom_enter(mm);
524
525 /*
526 * Tell all users of get_user/copy_from_user etc... that the content
527 * is no longer stable. No barriers really needed because unmapping
528 * should imply barriers already and the reader would hit a page fault
529 * if it stumbled over a reaped memory.
530 */
531 mm_flags_set(MMF_UNSTABLE, mm);
532
533 /*
534 * It might start racing with the dying task and compete for shared
535 * resources - e.g. page table lock contention has been observed.
536 * Reduce those races by reaping the oom victim from the other end
537 * of the address space.
538 */
539 mas_for_each_rev(&mas, vma, 0) {
540 if (vma->vm_flags & (VM_HUGETLB|VM_PFNMAP))
541 continue;
542
543 /*
544 * Only anonymous pages have a good chance to be dropped
545 * without additional steps which we cannot afford as we
546 * are OOM already.
547 *
548 * We do not even care about fs backed pages because all
549 * which are reclaimable have already been reclaimed and
550 * we do not want to block exit_mmap by keeping mm ref
551 * count elevated without a good reason.
552 */
553 if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED)) {
554 struct mmu_notifier_range range;
555 struct mmu_gather tlb;
556
557 mmu_notifier_range_init(&range, MMU_NOTIFY_UNMAP, 0,
558 mm, vma->vm_start,
559 vma->vm_end);
560 tlb_gather_mmu(&tlb, mm);
561 if (mmu_notifier_invalidate_range_start_nonblock(&range)) {
562 tlb_finish_mmu(&tlb);
563 ret = false;
564 continue;
565 }
566 unmap_page_range(&tlb, vma, range.start, range.end, NULL);
567 mmu_notifier_invalidate_range_end(&range);
568 tlb_finish_mmu(&tlb);
569 }
570 }
571
572 return ret;
573 }
574
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-03 3:27 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-30 4:48 [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu() shaikh.kamal
-- strict thread matches above, loose matches on Subject: below --
2026-04-01 15:40 [PATCH] KVM: x86/xen: Fix sleeping lock in hard IRQ context on PREEMPT_RT Sean Christopherson
2026-04-29 22:25 ` [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu() shaikh.kamal
2026-05-03 3:26 ` kernel test robot
2026-05-03 3:26 ` kernel test robot
2026-03-30 11:24 [PATCH] KVM: mmu_notifier: make mn_invalidate_lock non-sleeping for non-blocking invalidations Paolo Bonzini
2026-04-30 14:17 ` [PATCH v2 1/1] mm/mmu_notifier: Add async OOM cleanup via call_srcu() shaikh.kamal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox