summaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/hfi1/mmu_rb.h
diff options
context:
space:
mode:
authorDean Luick <dean.luick@intel.com>2016-07-28 15:21:24 -0400
committerDoug Ledford <dledford@redhat.com>2016-08-02 22:46:21 -0400
commitb85ced91511f6c3add9a74ae13e12ba568bfa1af (patch)
tree89d9b322fe8eb281242f8f3af740d485d5dc446e /drivers/infiniband/hw/hfi1/mmu_rb.h
parentb7df192f74a8cde22f6dc0680a2daa40540ed72f (diff)
downloadlinux-b85ced91511f6c3add9a74ae13e12ba568bfa1af.tar.bz2
IB/hfi1: Consistently call ops->remove outside spinlock
The ops->remove() callback was called by hfi1_mmu_unregister() with a NULL mm argument while holding a spinlock. In the case of sdma_rb_remove() this caused it to pass current->mm to hfi1_release_user_pages() This had 2 problems. First this would attempt to acquire the mmap_sem under a spin lock. Second the use of current->mm is not always guaranteed to be the proper mm when the fd is being closed. Rather than depend on this implicit behavior we move all calls to ops->remove outside of the spinlock. This also allows the correct mm to be used in the remove callback without fear of deadlock. Because the MMU notifier is not guaranteed to hold mm->mmap_sem, but usually does, we must delay all remove callbacks until out of the notifier, when the callbacks can take the mmap_sem if they need to. Code comments were added to clarify what the expectations are for the users of the mmu rb tree. Suggested-by: Jim Foraker <foraker1@llnl.gov> Reviewed-by: Ira Weiny <ira.weiny@intel.com> Signed-off-by: Dean Luick <dean.luick@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
Diffstat (limited to 'drivers/infiniband/hw/hfi1/mmu_rb.h')
-rw-r--r--drivers/infiniband/hw/hfi1/mmu_rb.h5
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/hfi1/mmu_rb.h b/drivers/infiniband/hw/hfi1/mmu_rb.h
index 09e5888c0818..e4f853fa91e6 100644
--- a/drivers/infiniband/hw/hfi1/mmu_rb.h
+++ b/drivers/infiniband/hw/hfi1/mmu_rb.h
@@ -57,6 +57,10 @@ struct mmu_rb_node {
struct list_head list;
};
+/*
+ * NOTE: filter, insert, invalidate, and evict must not sleep. Only remove is
+ * allowed to sleep.
+ */
struct mmu_rb_ops {
bool (*filter)(struct mmu_rb_node *node, unsigned long addr,
unsigned long len);
@@ -70,6 +74,7 @@ struct mmu_rb_ops {
int hfi1_mmu_rb_register(void *ops_arg, struct mm_struct *mm,
struct mmu_rb_ops *ops,
+ struct workqueue_struct *wq,
struct mmu_rb_handler **handler);
void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler);
int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler,