Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

memcg: simplify force_empty and move_lists

As for force_empty, though this may not be the main topic here,
mem_cgroup_force_empty_list() can be implemented simpler. It is possible to
make the function just call mem_cgroup_uncharge_page() instead of releasing
page_cgroups by itself. The tip is to call get_page() before invoking
mem_cgroup_uncharge_page(), so the page won't be released during this
function.

Kamezawa-san points out that by the time mem_cgroup_uncharge_page() uncharges,
the page might have been reassigned to an lru of a different mem_cgroup, and
now be emptied from that; but Hugh claims that's okay, the end state is the
same as when it hasn't gone to another list.

And once force_empty stops taking lock_page_cgroup within mz->lru_lock,
mem_cgroup_move_lists() can be simplified to take mz->lru_lock directly while
holding page_cgroup lock (but still has to use try_lock_page_cgroup).

Signed-off-by: Hirokazu Takahashi <taka@valinux.co.jp>
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Balbir Singh <balbir@linux.vnet.ibm.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
Cc: Paul Menage <menage@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Hirokazu Takahashi and committed by
Linus Torvalds
9b3c0a07 2680eed7

+13 -49
+13 -49
mm/memcontrol.c
··· 353 353 void mem_cgroup_move_lists(struct page *page, bool active) 354 354 { 355 355 struct page_cgroup *pc; 356 - struct mem_cgroup *mem; 357 356 struct mem_cgroup_per_zone *mz; 358 357 unsigned long flags; 359 358 ··· 366 367 if (!try_lock_page_cgroup(page)) 367 368 return; 368 369 369 - /* 370 - * Now page_cgroup is stable, but we cannot acquire mz->lru_lock 371 - * while holding it, because mem_cgroup_force_empty_list does the 372 - * reverse. Get a hold on the mem_cgroup before unlocking, so that 373 - * the zoneinfo remains stable, then take mz->lru_lock; then check 374 - * that page still points to pc and pc (even if freed and reassigned 375 - * to that same page meanwhile) still points to the same mem_cgroup. 376 - * Then we know mz still points to the right spinlock, so it's safe 377 - * to move_lists (page->page_cgroup might be reset while we do so, but 378 - * that doesn't matter: pc->page is stable till we drop mz->lru_lock). 379 - * We're being a little naughty not to try_lock_page_cgroup again 380 - * inside there, but we are safe, aren't we? Aren't we? Whistle... 381 - */ 382 370 pc = page_get_page_cgroup(page); 383 371 if (pc) { 384 - mem = pc->mem_cgroup; 385 372 mz = page_cgroup_zoneinfo(pc); 386 - css_get(&mem->css); 387 - 388 - unlock_page_cgroup(page); 389 - 390 373 spin_lock_irqsave(&mz->lru_lock, flags); 391 - if (page_get_page_cgroup(page) == pc && pc->mem_cgroup == mem) 392 - __mem_cgroup_move_lists(pc, active); 374 + __mem_cgroup_move_lists(pc, active); 393 375 spin_unlock_irqrestore(&mz->lru_lock, flags); 394 - 395 - css_put(&mem->css); 396 - } else 397 - unlock_page_cgroup(page); 376 + } 377 + unlock_page_cgroup(page); 398 378 } 399 379 400 380 /* ··· 767 789 { 768 790 struct page_cgroup *pc; 769 791 struct page *page; 770 - int count; 792 + int count = FORCE_UNCHARGE_BATCH; 771 793 unsigned long flags; 772 794 struct list_head *list; 773 795 ··· 776 798 else 777 799 list = &mz->inactive_list; 778 800 779 - if (list_empty(list)) 780 - return; 781 - retry: 782 - count = FORCE_UNCHARGE_BATCH; 783 801 spin_lock_irqsave(&mz->lru_lock, flags); 784 - 785 - while (--count && !list_empty(list)) { 802 + while (!list_empty(list)) { 786 803 pc = list_entry(list->prev, struct page_cgroup, lru); 787 804 page = pc->page; 788 - lock_page_cgroup(page); 789 - if (page_get_page_cgroup(page) == pc) { 790 - page_assign_page_cgroup(page, NULL); 791 - unlock_page_cgroup(page); 792 - __mem_cgroup_remove_list(pc); 793 - res_counter_uncharge(&mem->res, PAGE_SIZE); 794 - css_put(&mem->css); 795 - kfree(pc); 796 - } else { 797 - /* racing uncharge: let page go then retry */ 798 - unlock_page_cgroup(page); 799 - break; 805 + get_page(page); 806 + spin_unlock_irqrestore(&mz->lru_lock, flags); 807 + mem_cgroup_uncharge_page(page); 808 + put_page(page); 809 + if (--count <= 0) { 810 + count = FORCE_UNCHARGE_BATCH; 811 + cond_resched(); 800 812 } 813 + spin_lock_irqsave(&mz->lru_lock, flags); 801 814 } 802 - 803 815 spin_unlock_irqrestore(&mz->lru_lock, flags); 804 - if (!list_empty(list)) { 805 - cond_resched(); 806 - goto retry; 807 - } 808 816 } 809 817 810 818 /*