Commit 67caea1f authored by Mitko Haralanov's avatar Mitko Haralanov Committed by Doug Ledford

IB/hfi1: Improve performance of interval RB trees

The interval RB tree management functions use handlers to
store user-specific callback for the various tree operations.
These handlers are put on a doubly-linked list. When a RB
tree function is called, the list is searched for the handler
of the particular tree.

The list which holds the handlers is modified very rarely - when
a handler is created and when a handler is removed. On the other
hand, it is searched very often. This a perfect usage scenario
for RCU.

The result is a much lower overhead of traversing the list as most
of the time no locking will be required.
Reviewed-by: default avatarDean Luick <dean.luick@intel.com>
Reviewed-by: default avatarMike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: default avatarMitko Haralanov <mitko.haralanov@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent b96b0404
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
* *
*/ */
#include <linux/list.h> #include <linux/list.h>
#include <linux/rculist.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
#include <linux/interval_tree_generic.h> #include <linux/interval_tree_generic.h>
...@@ -97,7 +98,6 @@ static unsigned long mmu_node_last(struct mmu_rb_node *node) ...@@ -97,7 +98,6 @@ static unsigned long mmu_node_last(struct mmu_rb_node *node)
int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops) int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops)
{ {
struct mmu_rb_handler *handlr; struct mmu_rb_handler *handlr;
unsigned long flags;
if (!ops->invalidate) if (!ops->invalidate)
return -EINVAL; return -EINVAL;
...@@ -111,9 +111,9 @@ int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops) ...@@ -111,9 +111,9 @@ int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops)
INIT_HLIST_NODE(&handlr->mn.hlist); INIT_HLIST_NODE(&handlr->mn.hlist);
spin_lock_init(&handlr->lock); spin_lock_init(&handlr->lock);
handlr->mn.ops = &mn_opts; handlr->mn.ops = &mn_opts;
spin_lock_irqsave(&mmu_rb_lock, flags); spin_lock(&mmu_rb_lock);
list_add_tail(&handlr->list, &mmu_rb_handlers); list_add_tail_rcu(&handlr->list, &mmu_rb_handlers);
spin_unlock_irqrestore(&mmu_rb_lock, flags); spin_unlock(&mmu_rb_lock);
return mmu_notifier_register(&handlr->mn, current->mm); return mmu_notifier_register(&handlr->mn, current->mm);
} }
...@@ -130,9 +130,10 @@ void hfi1_mmu_rb_unregister(struct rb_root *root) ...@@ -130,9 +130,10 @@ void hfi1_mmu_rb_unregister(struct rb_root *root)
if (current->mm) if (current->mm)
mmu_notifier_unregister(&handler->mn, current->mm); mmu_notifier_unregister(&handler->mn, current->mm);
spin_lock_irqsave(&mmu_rb_lock, flags); spin_lock(&mmu_rb_lock);
list_del(&handler->list); list_del_rcu(&handler->list);
spin_unlock_irqrestore(&mmu_rb_lock, flags); spin_unlock(&mmu_rb_lock);
synchronize_rcu();
spin_lock_irqsave(&handler->lock, flags); spin_lock_irqsave(&handler->lock, flags);
if (!RB_EMPTY_ROOT(root)) { if (!RB_EMPTY_ROOT(root)) {
...@@ -271,16 +272,15 @@ void hfi1_mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node) ...@@ -271,16 +272,15 @@ void hfi1_mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node)
static struct mmu_rb_handler *find_mmu_handler(struct rb_root *root) static struct mmu_rb_handler *find_mmu_handler(struct rb_root *root)
{ {
struct mmu_rb_handler *handler; struct mmu_rb_handler *handler;
unsigned long flags;
spin_lock_irqsave(&mmu_rb_lock, flags); rcu_read_lock();
list_for_each_entry(handler, &mmu_rb_handlers, list) { list_for_each_entry_rcu(handler, &mmu_rb_handlers, list) {
if (handler->root == root) if (handler->root == root)
goto unlock; goto unlock;
} }
handler = NULL; handler = NULL;
unlock: unlock:
spin_unlock_irqrestore(&mmu_rb_lock, flags); rcu_read_unlock();
return handler; return handler;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment