diff options
| -rw-r--r-- | fs/exec.c | 2 | ||||
| -rw-r--r-- | kernel/cgroup.c | 5 | ||||
| -rw-r--r-- | kernel/exit.c | 12 | ||||
| -rw-r--r-- | mm/memcontrol.c | 17 |
4 files changed, 31 insertions, 5 deletions
| @@ -752,11 +752,11 @@ static int exec_mmap(struct mm_struct *mm) | |||
| 752 | tsk->active_mm = mm; | 752 | tsk->active_mm = mm; |
| 753 | activate_mm(active_mm, mm); | 753 | activate_mm(active_mm, mm); |
| 754 | task_unlock(tsk); | 754 | task_unlock(tsk); |
| 755 | mm_update_next_owner(old_mm); | ||
| 756 | arch_pick_mmap_layout(mm); | 755 | arch_pick_mmap_layout(mm); |
| 757 | if (old_mm) { | 756 | if (old_mm) { |
| 758 | up_read(&old_mm->mmap_sem); | 757 | up_read(&old_mm->mmap_sem); |
| 759 | BUG_ON(active_mm != old_mm); | 758 | BUG_ON(active_mm != old_mm); |
| 759 | mm_update_next_owner(old_mm); | ||
| 760 | mmput(old_mm); | 760 | mmput(old_mm); |
| 761 | return 0; | 761 | return 0; |
| 762 | } | 762 | } |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 13932abde159..a0123d75ec9a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -2738,14 +2738,15 @@ void cgroup_fork_callbacks(struct task_struct *child) | |||
| 2738 | */ | 2738 | */ |
| 2739 | void cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new) | 2739 | void cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new) |
| 2740 | { | 2740 | { |
| 2741 | struct cgroup *oldcgrp, *newcgrp; | 2741 | struct cgroup *oldcgrp, *newcgrp = NULL; |
| 2742 | 2742 | ||
| 2743 | if (need_mm_owner_callback) { | 2743 | if (need_mm_owner_callback) { |
| 2744 | int i; | 2744 | int i; |
| 2745 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { | 2745 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { |
| 2746 | struct cgroup_subsys *ss = subsys[i]; | 2746 | struct cgroup_subsys *ss = subsys[i]; |
| 2747 | oldcgrp = task_cgroup(old, ss->subsys_id); | 2747 | oldcgrp = task_cgroup(old, ss->subsys_id); |
| 2748 | newcgrp = task_cgroup(new, ss->subsys_id); | 2748 | if (new) |
| 2749 | newcgrp = task_cgroup(new, ss->subsys_id); | ||
| 2749 | if (oldcgrp == newcgrp) | 2750 | if (oldcgrp == newcgrp) |
| 2750 | continue; | 2751 | continue; |
| 2751 | if (ss->mm_owner_changed) | 2752 | if (ss->mm_owner_changed) |
diff --git a/kernel/exit.c b/kernel/exit.c index 16395644a98f..85a83c831856 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,6 +625,16 @@ 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: |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index c0500e4d3a2f..36896f3eb7f5 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
| @@ -250,6 +250,14 @@ static struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont) | |||
| 250 | 250 | ||
| 251 | struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p) | 251 | struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p) |
| 252 | { | 252 | { |
| 253 | /* | ||
| 254 | * mm_update_next_owner() may clear mm->owner to NULL | ||
| 255 | * if it races with swapoff, page migration, etc. | ||
| 256 | * So this can be called with p == NULL. | ||
| 257 | */ | ||
| 258 | if (unlikely(!p)) | ||
| 259 | return NULL; | ||
| 260 | |||
| 253 | return container_of(task_subsys_state(p, mem_cgroup_subsys_id), | 261 | return container_of(task_subsys_state(p, mem_cgroup_subsys_id), |
| 254 | struct mem_cgroup, css); | 262 | struct mem_cgroup, css); |
| 255 | } | 263 | } |
| @@ -549,6 +557,11 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm, | |||
| 549 | if (likely(!memcg)) { | 557 | if (likely(!memcg)) { |
| 550 | rcu_read_lock(); | 558 | rcu_read_lock(); |
| 551 | mem = mem_cgroup_from_task(rcu_dereference(mm->owner)); | 559 | mem = mem_cgroup_from_task(rcu_dereference(mm->owner)); |
| 560 | if (unlikely(!mem)) { | ||
| 561 | rcu_read_unlock(); | ||
| 562 | kmem_cache_free(page_cgroup_cache, pc); | ||
| 563 | return 0; | ||
| 564 | } | ||
| 552 | /* | 565 | /* |
| 553 | * For every charge from the cgroup, increment reference count | 566 | * For every charge from the cgroup, increment reference count |
| 554 | */ | 567 | */ |
| @@ -801,6 +814,10 @@ int mem_cgroup_shrink_usage(struct mm_struct *mm, gfp_t gfp_mask) | |||
| 801 | 814 | ||
| 802 | rcu_read_lock(); | 815 | rcu_read_lock(); |
| 803 | mem = mem_cgroup_from_task(rcu_dereference(mm->owner)); | 816 | mem = mem_cgroup_from_task(rcu_dereference(mm->owner)); |
| 817 | if (unlikely(!mem)) { | ||
| 818 | rcu_read_unlock(); | ||
| 819 | return 0; | ||
| 820 | } | ||
| 804 | css_get(&mem->css); | 821 | css_get(&mem->css); |
| 805 | rcu_read_unlock(); | 822 | rcu_read_unlock(); |
| 806 | 823 | ||
