Subject: EMM: Require single threaded execution for register and unregister We can avoid the concurrency issues arising at registration if we only allow registration of notifiers when the process has only a single thread. That even allows to avoid the use of rcu. Signed-off-by: Christoph Lameter --- mm/rmap.c | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) Index: linux-2.6/mm/rmap.c =================================================================== --- linux-2.6.orig/mm/rmap.c 2008-04-02 13:53:46.002473685 -0700 +++ linux-2.6/mm/rmap.c 2008-04-02 14:10:20.535752527 -0700 @@ -286,20 +286,44 @@ void emm_notifier_release(struct mm_stru } } -/* Register a notifier */ +/* + * Register a notifier + * + * Process must be single threaded. + */ void emm_notifier_register(struct emm_notifier *e, struct mm_struct *mm) { + BUG_ON(atomic_read(&mm->mm_users) != 1); + e->next = mm->emm_notifier; - /* - * The update to emm_notifier (e->next) must be visible - * before the pointer becomes visible. - * rcu_assign_pointer() does exactly what we need. - */ - rcu_assign_pointer(mm->emm_notifier, e); + mm->emm_notifier = e; } EXPORT_SYMBOL_GPL(emm_notifier_register); /* + * Unregister a notifier + * + * Process must be single threaded + */ +void emm_notifier_unregister(struct emm_notifier *e, struct mm_struct *mm) +{ + struct emm_notifier *p = mm->emm_notifier; + + BUG_ON(atomic_read(&mm->mm_users) != 1); + + if (e == p) + mm->emm_notifier = e->next; + else { + while (p->next != e) + p = p->next; + + p->next = e->next; + } + e->callback(e, mm, emm_release, 0, TASK_SIZE); +} +EXPORT_SYMBOL_GPL(emm_notifier_unregister); + +/* * Perform a callback * * The return of this function is either a negative error of the first @@ -309,7 +333,7 @@ EXPORT_SYMBOL_GPL(emm_notifier_register) int __emm_notify(struct mm_struct *mm, enum emm_operation op, unsigned long start, unsigned long end) { - struct emm_notifier *e = rcu_dereference(mm->emm_notifier); + struct emm_notifier *e = mm->emm_notifier; int x; int result = 0; @@ -335,7 +359,7 @@ int __emm_notify(struct mm_struct *mm, e * emm_notifier contents (e) must be fetched after * the retrival of the pointer to the notifier. */ - e = rcu_dereference(e->next); + e = e->next; } return result; }