summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitko Haralanov <mitko.haralanov@intel.com>2016-04-12 20:46:35 +0300
committerDoug Ledford <dledford@redhat.com>2016-04-28 23:32:26 +0300
commit782f6697d20d180843565ac93726f5ec6c7ec8ce (patch)
treefdb34256820e83a1a21994a628f74c198520c811
parent0ad2d3d05b4a597d1f2e239dcc6ab537cc3eeacb (diff)
downloadlinux-782f6697d20d180843565ac93726f5ec6c7ec8ce.tar.xz
IB/hfi1: Protect the interval RB tree when cleaning up
The current implementation of the clean up function for the interval RB trees has two flaws which may cause problems in cases of concurrent executing of the function and MMU notifier. The flaws were due to the fact that deregistration of the MMU callbacks was done after the tree was emptied and, furthermore, the tree was not being locked. This commit fixes both of these flaws by, first, switch the order of operations, and, second, locking the tree while traversing it to prevent any other operations. Reviewed-by: Dean Luick <dean.luick@intel.com> Signed-off-by: Mitko Haralanov <mitko.haralanov@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r--drivers/staging/rdma/hfi1/mmu_rb.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/drivers/staging/rdma/hfi1/mmu_rb.c b/drivers/staging/rdma/hfi1/mmu_rb.c
index b3f0682a36c9..72b6d70ae2b5 100644
--- a/drivers/staging/rdma/hfi1/mmu_rb.c
+++ b/drivers/staging/rdma/hfi1/mmu_rb.c
@@ -126,10 +126,15 @@ void hfi1_mmu_rb_unregister(struct rb_root *root)
if (!handler)
return;
+ /* Unregister first so we don't get any more notifications. */
+ if (current->mm)
+ mmu_notifier_unregister(&handler->mn, current->mm);
+
spin_lock_irqsave(&mmu_rb_lock, flags);
list_del(&handler->list);
spin_unlock_irqrestore(&mmu_rb_lock, flags);
+ spin_lock_irqsave(&handler->lock, flags);
if (!RB_EMPTY_ROOT(root)) {
struct rb_node *node;
struct mmu_rb_node *rbnode;
@@ -141,9 +146,8 @@ void hfi1_mmu_rb_unregister(struct rb_root *root)
handler->ops->remove(root, rbnode, NULL);
}
}
+ spin_unlock_irqrestore(&handler->lock, flags);
- if (current->mm)
- mmu_notifier_unregister(&handler->mn, current->mm);
kfree(handler);
}