IB/hfi1: Make use of mm consistent
The hfi1 driver registers a mmu_notifier callback when /dev/hfi1_* is opened, and unregisters it when the device is closed. The driver incorrectly assumes that the close will always happen from the same context as the open. In particular, closes due to SIGKILL or OOM killer activity may happen from a different context. In these cases, the wrong mm is passed to mmu_notifier_unregister(), which causes improper reference counting for the victim mm, and eventual memory corruption. Preserve the mm for all open file descriptors and use this mm rather than current->mm for memory operations for the lifetime of that fd. Note: this patch leaves 1 use of current->mm in place. This use is removed in a follow on patch because other functional changes were required prior to that use being removed. If registration fails, there is no reason to keep the handler object around. Free the handler object rather than add it to the list to prevent any mmu_notifier operations, including unregister, when registration fails. Suggested-by: Jim Foraker <foraker1@llnl.gov> Reviewed-by: Dean Luick <dean.luick@intel.com> Signed-off-by: Ira Weiny <ira.weiny@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
Este cometimento está contido em:

cometido por
Doug Ledford

ascendente
7b3256e331
cometimento
3faa3d9a30
@@ -58,6 +58,7 @@ struct mmu_rb_handler {
|
||||
struct rb_root *root;
|
||||
spinlock_t lock; /* protect the RB tree */
|
||||
struct mmu_rb_ops *ops;
|
||||
struct mm_struct *mm;
|
||||
};
|
||||
|
||||
static LIST_HEAD(mmu_rb_handlers);
|
||||
@@ -95,9 +96,11 @@ static unsigned long mmu_node_last(struct mmu_rb_node *node)
|
||||
return PAGE_ALIGN(node->addr + node->len) - 1;
|
||||
}
|
||||
|
||||
int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops)
|
||||
int hfi1_mmu_rb_register(struct mm_struct *mm, struct rb_root *root,
|
||||
struct mmu_rb_ops *ops)
|
||||
{
|
||||
struct mmu_rb_handler *handlr;
|
||||
int ret;
|
||||
|
||||
handlr = kmalloc(sizeof(*handlr), GFP_KERNEL);
|
||||
if (!handlr)
|
||||
@@ -108,11 +111,19 @@ int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops)
|
||||
INIT_HLIST_NODE(&handlr->mn.hlist);
|
||||
spin_lock_init(&handlr->lock);
|
||||
handlr->mn.ops = &mn_opts;
|
||||
handlr->mm = mm;
|
||||
|
||||
ret = mmu_notifier_register(&handlr->mn, handlr->mm);
|
||||
if (ret) {
|
||||
kfree(handlr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock(&mmu_rb_lock);
|
||||
list_add_tail_rcu(&handlr->list, &mmu_rb_handlers);
|
||||
spin_unlock(&mmu_rb_lock);
|
||||
|
||||
return mmu_notifier_register(&handlr->mn, current->mm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hfi1_mmu_rb_unregister(struct rb_root *root)
|
||||
@@ -126,8 +137,7 @@ void hfi1_mmu_rb_unregister(struct rb_root *root)
|
||||
return;
|
||||
|
||||
/* Unregister first so we don't get any more notifications. */
|
||||
if (current->mm)
|
||||
mmu_notifier_unregister(&handler->mn, current->mm);
|
||||
mmu_notifier_unregister(&handler->mn, handler->mm);
|
||||
|
||||
spin_lock(&mmu_rb_lock);
|
||||
list_del_rcu(&handler->list);
|
||||
|
Criar uma nova questão referindo esta
Bloquear um utilizador