diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 16395644a98f..0ef4673e351b 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -583,8 +583,6 @@ mm_need_new_owner(struct mm_struct *mm, struct task_struct *p) | |||
583 | * If there are other users of the mm and the owner (us) is exiting | 583 | * If there are other users of the mm and the owner (us) is exiting |
584 | * we need to find a new owner to take on the responsibility. | 584 | * we need to find a new owner to take on the responsibility. |
585 | */ | 585 | */ |
586 | if (!mm) | ||
587 | return 0; | ||
588 | if (atomic_read(&mm->mm_users) <= 1) | 586 | if (atomic_read(&mm->mm_users) <= 1) |
589 | return 0; | 587 | return 0; |
590 | if (mm->owner != p) | 588 | if (mm->owner != p) |
@@ -627,29 +625,38 @@ retry: | |||
627 | } while_each_thread(g, c); | 625 | } while_each_thread(g, c); |
628 | 626 | ||
629 | read_unlock(&tasklist_lock); | 627 | read_unlock(&tasklist_lock); |
628 | /* | ||
629 | * We found no owner yet mm_users > 1: this implies that we are | ||
630 | * most likely racing with swapoff (try_to_unuse()) or /proc or | ||
631 | * ptrace or page migration (get_task_mm()). Mark owner as NULL, | ||
632 | * so that subsystems can understand the callback and take action. | ||
633 | */ | ||
634 | down_write(&mm->mmap_sem); | ||
635 | cgroup_mm_owner_callbacks(mm->owner, NULL); | ||
636 | mm->owner = NULL; | ||
637 | up_write(&mm->mmap_sem); | ||
630 | return; | 638 | return; |
631 | 639 | ||
632 | assign_new_owner: | 640 | assign_new_owner: |
633 | BUG_ON(c == p); | 641 | BUG_ON(c == p); |
634 | get_task_struct(c); | 642 | get_task_struct(c); |
643 | read_unlock(&tasklist_lock); | ||
644 | down_write(&mm->mmap_sem); | ||
635 | /* | 645 | /* |
636 | * The task_lock protects c->mm from changing. | 646 | * The task_lock protects c->mm from changing. |
637 | * We always want mm->owner->mm == mm | 647 | * We always want mm->owner->mm == mm |
638 | */ | 648 | */ |
639 | task_lock(c); | 649 | task_lock(c); |
640 | /* | ||
641 | * Delay read_unlock() till we have the task_lock() | ||
642 | * to ensure that c does not slip away underneath us | ||
643 | */ | ||
644 | read_unlock(&tasklist_lock); | ||
645 | if (c->mm != mm) { | 650 | if (c->mm != mm) { |
646 | task_unlock(c); | 651 | task_unlock(c); |
652 | up_write(&mm->mmap_sem); | ||
647 | put_task_struct(c); | 653 | put_task_struct(c); |
648 | goto retry; | 654 | goto retry; |
649 | } | 655 | } |
650 | cgroup_mm_owner_callbacks(mm->owner, c); | 656 | cgroup_mm_owner_callbacks(mm->owner, c); |
651 | mm->owner = c; | 657 | mm->owner = c; |
652 | task_unlock(c); | 658 | task_unlock(c); |
659 | up_write(&mm->mmap_sem); | ||
653 | put_task_struct(c); | 660 | put_task_struct(c); |
654 | } | 661 | } |
655 | #endif /* CONFIG_MM_OWNER */ | 662 | #endif /* CONFIG_MM_OWNER */ |