|
@@ -699,6 +699,26 @@ void __mmdrop(struct mm_struct *mm)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(__mmdrop);
|
|
|
|
|
|
+static inline void __mmput(struct mm_struct *mm)
|
|
|
+{
|
|
|
+ VM_BUG_ON(atomic_read(&mm->mm_users));
|
|
|
+
|
|
|
+ uprobe_clear_state(mm);
|
|
|
+ exit_aio(mm);
|
|
|
+ ksm_exit(mm);
|
|
|
+ khugepaged_exit(mm); /* must run before exit_mmap */
|
|
|
+ exit_mmap(mm);
|
|
|
+ set_mm_exe_file(mm, NULL);
|
|
|
+ if (!list_empty(&mm->mmlist)) {
|
|
|
+ spin_lock(&mmlist_lock);
|
|
|
+ list_del(&mm->mmlist);
|
|
|
+ spin_unlock(&mmlist_lock);
|
|
|
+ }
|
|
|
+ if (mm->binfmt)
|
|
|
+ module_put(mm->binfmt->module);
|
|
|
+ mmdrop(mm);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Decrement the use count and release all resources for an mm.
|
|
|
*/
|
|
@@ -706,24 +726,24 @@ void mmput(struct mm_struct *mm)
|
|
|
{
|
|
|
might_sleep();
|
|
|
|
|
|
+ if (atomic_dec_and_test(&mm->mm_users))
|
|
|
+ __mmput(mm);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(mmput);
|
|
|
+
|
|
|
+static void mmput_async_fn(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct mm_struct *mm = container_of(work, struct mm_struct, async_put_work);
|
|
|
+ __mmput(mm);
|
|
|
+}
|
|
|
+
|
|
|
+void mmput_async(struct mm_struct *mm)
|
|
|
+{
|
|
|
if (atomic_dec_and_test(&mm->mm_users)) {
|
|
|
- uprobe_clear_state(mm);
|
|
|
- exit_aio(mm);
|
|
|
- ksm_exit(mm);
|
|
|
- khugepaged_exit(mm); /* must run before exit_mmap */
|
|
|
- exit_mmap(mm);
|
|
|
- set_mm_exe_file(mm, NULL);
|
|
|
- if (!list_empty(&mm->mmlist)) {
|
|
|
- spin_lock(&mmlist_lock);
|
|
|
- list_del(&mm->mmlist);
|
|
|
- spin_unlock(&mmlist_lock);
|
|
|
- }
|
|
|
- if (mm->binfmt)
|
|
|
- module_put(mm->binfmt->module);
|
|
|
- mmdrop(mm);
|
|
|
+ INIT_WORK(&mm->async_put_work, mmput_async_fn);
|
|
|
+ schedule_work(&mm->async_put_work);
|
|
|
}
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(mmput);
|
|
|
|
|
|
/**
|
|
|
* set_mm_exe_file - change a reference to the mm's executable file
|