|
@@ -71,6 +71,7 @@ static inline void mmu_notifier_range_start(struct mmu_notifier *,
|
|
|
struct mm_struct *,
|
|
|
unsigned long, unsigned long);
|
|
|
static void mmu_notifier_mem_invalidate(struct mmu_notifier *,
|
|
|
+ struct mm_struct *,
|
|
|
unsigned long, unsigned long);
|
|
|
static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *,
|
|
|
unsigned long, unsigned long);
|
|
@@ -137,7 +138,7 @@ void hfi1_mmu_rb_unregister(struct rb_root *root)
|
|
|
rbnode = rb_entry(node, struct mmu_rb_node, node);
|
|
|
rb_erase(node, root);
|
|
|
if (handler->ops->remove)
|
|
|
- handler->ops->remove(root, rbnode, false);
|
|
|
+ handler->ops->remove(root, rbnode, NULL);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -176,7 +177,7 @@ unlock:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-/* Caller must host handler lock */
|
|
|
+/* Caller must hold handler lock */
|
|
|
static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler,
|
|
|
unsigned long addr,
|
|
|
unsigned long len)
|
|
@@ -200,15 +201,21 @@ static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler,
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
+/* Caller must *not* hold handler lock. */
|
|
|
static void __mmu_rb_remove(struct mmu_rb_handler *handler,
|
|
|
- struct mmu_rb_node *node, bool arg)
|
|
|
+ struct mmu_rb_node *node, struct mm_struct *mm)
|
|
|
{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
/* Validity of handler and node pointers has been checked by caller. */
|
|
|
hfi1_cdbg(MMU, "Removing node addr 0x%llx, len %u", node->addr,
|
|
|
node->len);
|
|
|
+ spin_lock_irqsave(&handler->lock, flags);
|
|
|
__mmu_int_rb_remove(node, handler->root);
|
|
|
+ spin_unlock_irqrestore(&handler->lock, flags);
|
|
|
+
|
|
|
if (handler->ops->remove)
|
|
|
- handler->ops->remove(handler->root, node, arg);
|
|
|
+ handler->ops->remove(handler->root, node, mm);
|
|
|
}
|
|
|
|
|
|
struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *root, unsigned long addr,
|
|
@@ -231,14 +238,11 @@ struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *root, unsigned long addr,
|
|
|
void hfi1_mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node)
|
|
|
{
|
|
|
struct mmu_rb_handler *handler = find_mmu_handler(root);
|
|
|
- unsigned long flags;
|
|
|
|
|
|
if (!handler || !node)
|
|
|
return;
|
|
|
|
|
|
- spin_lock_irqsave(&handler->lock, flags);
|
|
|
- __mmu_rb_remove(handler, node, false);
|
|
|
- spin_unlock_irqrestore(&handler->lock, flags);
|
|
|
+ __mmu_rb_remove(handler, node, NULL);
|
|
|
}
|
|
|
|
|
|
static struct mmu_rb_handler *find_mmu_handler(struct rb_root *root)
|
|
@@ -260,7 +264,7 @@ unlock:
|
|
|
static inline void mmu_notifier_page(struct mmu_notifier *mn,
|
|
|
struct mm_struct *mm, unsigned long addr)
|
|
|
{
|
|
|
- mmu_notifier_mem_invalidate(mn, addr, addr + PAGE_SIZE);
|
|
|
+ mmu_notifier_mem_invalidate(mn, mm, addr, addr + PAGE_SIZE);
|
|
|
}
|
|
|
|
|
|
static inline void mmu_notifier_range_start(struct mmu_notifier *mn,
|
|
@@ -268,25 +272,31 @@ static inline void mmu_notifier_range_start(struct mmu_notifier *mn,
|
|
|
unsigned long start,
|
|
|
unsigned long end)
|
|
|
{
|
|
|
- mmu_notifier_mem_invalidate(mn, start, end);
|
|
|
+ mmu_notifier_mem_invalidate(mn, mm, start, end);
|
|
|
}
|
|
|
|
|
|
static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn,
|
|
|
+ struct mm_struct *mm,
|
|
|
unsigned long start, unsigned long end)
|
|
|
{
|
|
|
struct mmu_rb_handler *handler =
|
|
|
container_of(mn, struct mmu_rb_handler, mn);
|
|
|
struct rb_root *root = handler->root;
|
|
|
- struct mmu_rb_node *node;
|
|
|
+ struct mmu_rb_node *node, *ptr = NULL;
|
|
|
unsigned long flags;
|
|
|
|
|
|
spin_lock_irqsave(&handler->lock, flags);
|
|
|
- for (node = __mmu_int_rb_iter_first(root, start, end - 1); node;
|
|
|
- node = __mmu_int_rb_iter_next(node, start, end - 1)) {
|
|
|
+ for (node = __mmu_int_rb_iter_first(root, start, end - 1);
|
|
|
+ node; node = ptr) {
|
|
|
+ /* Guard against node removal. */
|
|
|
+ ptr = __mmu_int_rb_iter_next(node, start, end - 1);
|
|
|
hfi1_cdbg(MMU, "Invalidating node addr 0x%llx, len %u",
|
|
|
node->addr, node->len);
|
|
|
- if (handler->ops->invalidate(root, node))
|
|
|
- __mmu_rb_remove(handler, node, true);
|
|
|
+ if (handler->ops->invalidate(root, node)) {
|
|
|
+ spin_unlock_irqrestore(&handler->lock, flags);
|
|
|
+ __mmu_rb_remove(handler, node, mm);
|
|
|
+ spin_lock_irqsave(&handler->lock, flags);
|
|
|
+ }
|
|
|
}
|
|
|
spin_unlock_irqrestore(&handler->lock, flags);
|
|
|
}
|