diff options
Diffstat (limited to 'mm/memcontrol.c')
| -rw-r--r-- | mm/memcontrol.c | 190 |
1 files changed, 83 insertions, 107 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index c9ebec98e92a..9cbd40ebccd1 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
| @@ -132,15 +132,11 @@ static const char * const mem_cgroup_lru_names[] = { | |||
| 132 | * their hierarchy representation | 132 | * their hierarchy representation |
| 133 | */ | 133 | */ |
| 134 | 134 | ||
| 135 | struct mem_cgroup_tree_per_zone { | 135 | struct mem_cgroup_tree_per_node { |
| 136 | struct rb_root rb_root; | 136 | struct rb_root rb_root; |
| 137 | spinlock_t lock; | 137 | spinlock_t lock; |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | struct mem_cgroup_tree_per_node { | ||
| 141 | struct mem_cgroup_tree_per_zone rb_tree_per_zone[MAX_NR_ZONES]; | ||
| 142 | }; | ||
| 143 | |||
| 144 | struct mem_cgroup_tree { | 140 | struct mem_cgroup_tree { |
| 145 | struct mem_cgroup_tree_per_node *rb_tree_per_node[MAX_NUMNODES]; | 141 | struct mem_cgroup_tree_per_node *rb_tree_per_node[MAX_NUMNODES]; |
| 146 | }; | 142 | }; |
| @@ -374,37 +370,35 @@ ino_t page_cgroup_ino(struct page *page) | |||
| 374 | return ino; | 370 | return ino; |
| 375 | } | 371 | } |
| 376 | 372 | ||
| 377 | static struct mem_cgroup_per_zone * | 373 | static struct mem_cgroup_per_node * |
| 378 | mem_cgroup_page_zoneinfo(struct mem_cgroup *memcg, struct page *page) | 374 | mem_cgroup_page_nodeinfo(struct mem_cgroup *memcg, struct page *page) |
| 379 | { | 375 | { |
| 380 | int nid = page_to_nid(page); | 376 | int nid = page_to_nid(page); |
| 381 | int zid = page_zonenum(page); | ||
| 382 | 377 | ||
| 383 | return &memcg->nodeinfo[nid]->zoneinfo[zid]; | 378 | return memcg->nodeinfo[nid]; |
| 384 | } | 379 | } |
| 385 | 380 | ||
| 386 | static struct mem_cgroup_tree_per_zone * | 381 | static struct mem_cgroup_tree_per_node * |
| 387 | soft_limit_tree_node_zone(int nid, int zid) | 382 | soft_limit_tree_node(int nid) |
| 388 | { | 383 | { |
| 389 | return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid]; | 384 | return soft_limit_tree.rb_tree_per_node[nid]; |
| 390 | } | 385 | } |
| 391 | 386 | ||
| 392 | static struct mem_cgroup_tree_per_zone * | 387 | static struct mem_cgroup_tree_per_node * |
| 393 | soft_limit_tree_from_page(struct page *page) | 388 | soft_limit_tree_from_page(struct page *page) |
| 394 | { | 389 | { |
| 395 | int nid = page_to_nid(page); | 390 | int nid = page_to_nid(page); |
| 396 | int zid = page_zonenum(page); | ||
| 397 | 391 | ||
| 398 | return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid]; | 392 | return soft_limit_tree.rb_tree_per_node[nid]; |
| 399 | } | 393 | } |
| 400 | 394 | ||
| 401 | static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz, | 395 | static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_node *mz, |
| 402 | struct mem_cgroup_tree_per_zone *mctz, | 396 | struct mem_cgroup_tree_per_node *mctz, |
| 403 | unsigned long new_usage_in_excess) | 397 | unsigned long new_usage_in_excess) |
| 404 | { | 398 | { |
| 405 | struct rb_node **p = &mctz->rb_root.rb_node; | 399 | struct rb_node **p = &mctz->rb_root.rb_node; |
| 406 | struct rb_node *parent = NULL; | 400 | struct rb_node *parent = NULL; |
| 407 | struct mem_cgroup_per_zone *mz_node; | 401 | struct mem_cgroup_per_node *mz_node; |
| 408 | 402 | ||
| 409 | if (mz->on_tree) | 403 | if (mz->on_tree) |
| 410 | return; | 404 | return; |
| @@ -414,7 +408,7 @@ static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz, | |||
| 414 | return; | 408 | return; |
| 415 | while (*p) { | 409 | while (*p) { |
| 416 | parent = *p; | 410 | parent = *p; |
| 417 | mz_node = rb_entry(parent, struct mem_cgroup_per_zone, | 411 | mz_node = rb_entry(parent, struct mem_cgroup_per_node, |
| 418 | tree_node); | 412 | tree_node); |
| 419 | if (mz->usage_in_excess < mz_node->usage_in_excess) | 413 | if (mz->usage_in_excess < mz_node->usage_in_excess) |
| 420 | p = &(*p)->rb_left; | 414 | p = &(*p)->rb_left; |
| @@ -430,8 +424,8 @@ static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz, | |||
| 430 | mz->on_tree = true; | 424 | mz->on_tree = true; |
| 431 | } | 425 | } |
| 432 | 426 | ||
| 433 | static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz, | 427 | static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_node *mz, |
| 434 | struct mem_cgroup_tree_per_zone *mctz) | 428 | struct mem_cgroup_tree_per_node *mctz) |
| 435 | { | 429 | { |
| 436 | if (!mz->on_tree) | 430 | if (!mz->on_tree) |
| 437 | return; | 431 | return; |
| @@ -439,8 +433,8 @@ static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz, | |||
| 439 | mz->on_tree = false; | 433 | mz->on_tree = false; |
| 440 | } | 434 | } |
| 441 | 435 | ||
| 442 | static void mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz, | 436 | static void mem_cgroup_remove_exceeded(struct mem_cgroup_per_node *mz, |
| 443 | struct mem_cgroup_tree_per_zone *mctz) | 437 | struct mem_cgroup_tree_per_node *mctz) |
| 444 | { | 438 | { |
| 445 | unsigned long flags; | 439 | unsigned long flags; |
| 446 | 440 | ||
| @@ -464,8 +458,8 @@ static unsigned long soft_limit_excess(struct mem_cgroup *memcg) | |||
| 464 | static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) | 458 | static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) |
| 465 | { | 459 | { |
| 466 | unsigned long excess; | 460 | unsigned long excess; |
| 467 | struct mem_cgroup_per_zone *mz; | 461 | struct mem_cgroup_per_node *mz; |
| 468 | struct mem_cgroup_tree_per_zone *mctz; | 462 | struct mem_cgroup_tree_per_node *mctz; |
| 469 | 463 | ||
| 470 | mctz = soft_limit_tree_from_page(page); | 464 | mctz = soft_limit_tree_from_page(page); |
| 471 | /* | 465 | /* |
| @@ -473,7 +467,7 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) | |||
| 473 | * because their event counter is not touched. | 467 | * because their event counter is not touched. |
| 474 | */ | 468 | */ |
| 475 | for (; memcg; memcg = parent_mem_cgroup(memcg)) { | 469 | for (; memcg; memcg = parent_mem_cgroup(memcg)) { |
| 476 | mz = mem_cgroup_page_zoneinfo(memcg, page); | 470 | mz = mem_cgroup_page_nodeinfo(memcg, page); |
| 477 | excess = soft_limit_excess(memcg); | 471 | excess = soft_limit_excess(memcg); |
| 478 | /* | 472 | /* |
| 479 | * We have to update the tree if mz is on RB-tree or | 473 | * We have to update the tree if mz is on RB-tree or |
| @@ -498,24 +492,22 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) | |||
| 498 | 492 | ||
| 499 | static void mem_cgroup_remove_from_trees(struct mem_cgroup *memcg) | 493 | static void mem_cgroup_remove_from_trees(struct mem_cgroup *memcg) |
| 500 | { | 494 | { |
| 501 | struct mem_cgroup_tree_per_zone *mctz; | 495 | struct mem_cgroup_tree_per_node *mctz; |
| 502 | struct mem_cgroup_per_zone *mz; | 496 | struct mem_cgroup_per_node *mz; |
| 503 | int nid, zid; | 497 | int nid; |
| 504 | 498 | ||
| 505 | for_each_node(nid) { | 499 | for_each_node(nid) { |
| 506 | for (zid = 0; zid < MAX_NR_ZONES; zid++) { | 500 | mz = mem_cgroup_nodeinfo(memcg, nid); |
| 507 | mz = &memcg->nodeinfo[nid]->zoneinfo[zid]; | 501 | mctz = soft_limit_tree_node(nid); |
| 508 | mctz = soft_limit_tree_node_zone(nid, zid); | 502 | mem_cgroup_remove_exceeded(mz, mctz); |
| 509 | mem_cgroup_remove_exceeded(mz, mctz); | ||
| 510 | } | ||
| 511 | } | 503 | } |
| 512 | } | 504 | } |
| 513 | 505 | ||
| 514 | static struct mem_cgroup_per_zone * | 506 | static struct mem_cgroup_per_node * |
| 515 | __mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz) | 507 | __mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_node *mctz) |
| 516 | { | 508 | { |
| 517 | struct rb_node *rightmost = NULL; | 509 | struct rb_node *rightmost = NULL; |
| 518 | struct mem_cgroup_per_zone *mz; | 510 | struct mem_cgroup_per_node *mz; |
| 519 | 511 | ||
| 520 | retry: | 512 | retry: |
| 521 | mz = NULL; | 513 | mz = NULL; |
| @@ -523,7 +515,7 @@ retry: | |||
| 523 | if (!rightmost) | 515 | if (!rightmost) |
| 524 | goto done; /* Nothing to reclaim from */ | 516 | goto done; /* Nothing to reclaim from */ |
| 525 | 517 | ||
| 526 | mz = rb_entry(rightmost, struct mem_cgroup_per_zone, tree_node); | 518 | mz = rb_entry(rightmost, struct mem_cgroup_per_node, tree_node); |
| 527 | /* | 519 | /* |
| 528 | * Remove the node now but someone else can add it back, | 520 | * Remove the node now but someone else can add it back, |
| 529 | * we will to add it back at the end of reclaim to its correct | 521 | * we will to add it back at the end of reclaim to its correct |
| @@ -537,10 +529,10 @@ done: | |||
| 537 | return mz; | 529 | return mz; |
| 538 | } | 530 | } |
| 539 | 531 | ||
| 540 | static struct mem_cgroup_per_zone * | 532 | static struct mem_cgroup_per_node * |
| 541 | mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz) | 533 | mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_node *mctz) |
| 542 | { | 534 | { |
| 543 | struct mem_cgroup_per_zone *mz; | 535 | struct mem_cgroup_per_node *mz; |
| 544 | 536 | ||
| 545 | spin_lock_irq(&mctz->lock); | 537 | spin_lock_irq(&mctz->lock); |
| 546 | mz = __mem_cgroup_largest_soft_limit_node(mctz); | 538 | mz = __mem_cgroup_largest_soft_limit_node(mctz); |
| @@ -634,20 +626,16 @@ unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg, | |||
| 634 | int nid, unsigned int lru_mask) | 626 | int nid, unsigned int lru_mask) |
| 635 | { | 627 | { |
| 636 | unsigned long nr = 0; | 628 | unsigned long nr = 0; |
| 637 | int zid; | 629 | struct mem_cgroup_per_node *mz; |
| 630 | enum lru_list lru; | ||
| 638 | 631 | ||
| 639 | VM_BUG_ON((unsigned)nid >= nr_node_ids); | 632 | VM_BUG_ON((unsigned)nid >= nr_node_ids); |
| 640 | 633 | ||
| 641 | for (zid = 0; zid < MAX_NR_ZONES; zid++) { | 634 | for_each_lru(lru) { |
| 642 | struct mem_cgroup_per_zone *mz; | 635 | if (!(BIT(lru) & lru_mask)) |
| 643 | enum lru_list lru; | 636 | continue; |
| 644 | 637 | mz = mem_cgroup_nodeinfo(memcg, nid); | |
| 645 | for_each_lru(lru) { | 638 | nr += mz->lru_size[lru]; |
| 646 | if (!(BIT(lru) & lru_mask)) | ||
| 647 | continue; | ||
| 648 | mz = &memcg->nodeinfo[nid]->zoneinfo[zid]; | ||
| 649 | nr += mz->lru_size[lru]; | ||
| 650 | } | ||
| 651 | } | 639 | } |
| 652 | return nr; | 640 | return nr; |
| 653 | } | 641 | } |
| @@ -800,9 +788,9 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root, | |||
| 800 | rcu_read_lock(); | 788 | rcu_read_lock(); |
| 801 | 789 | ||
| 802 | if (reclaim) { | 790 | if (reclaim) { |
| 803 | struct mem_cgroup_per_zone *mz; | 791 | struct mem_cgroup_per_node *mz; |
| 804 | 792 | ||
| 805 | mz = mem_cgroup_zone_zoneinfo(root, reclaim->zone); | 793 | mz = mem_cgroup_nodeinfo(root, reclaim->pgdat->node_id); |
| 806 | iter = &mz->iter[reclaim->priority]; | 794 | iter = &mz->iter[reclaim->priority]; |
| 807 | 795 | ||
| 808 | if (prev && reclaim->generation != iter->generation) | 796 | if (prev && reclaim->generation != iter->generation) |
| @@ -901,19 +889,17 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg) | |||
| 901 | { | 889 | { |
| 902 | struct mem_cgroup *memcg = dead_memcg; | 890 | struct mem_cgroup *memcg = dead_memcg; |
| 903 | struct mem_cgroup_reclaim_iter *iter; | 891 | struct mem_cgroup_reclaim_iter *iter; |
| 904 | struct mem_cgroup_per_zone *mz; | 892 | struct mem_cgroup_per_node *mz; |
| 905 | int nid, zid; | 893 | int nid; |
| 906 | int i; | 894 | int i; |
| 907 | 895 | ||
| 908 | while ((memcg = parent_mem_cgroup(memcg))) { | 896 | while ((memcg = parent_mem_cgroup(memcg))) { |
| 909 | for_each_node(nid) { | 897 | for_each_node(nid) { |
| 910 | for (zid = 0; zid < MAX_NR_ZONES; zid++) { | 898 | mz = mem_cgroup_nodeinfo(memcg, nid); |
| 911 | mz = &memcg->nodeinfo[nid]->zoneinfo[zid]; | 899 | for (i = 0; i <= DEF_PRIORITY; i++) { |
| 912 | for (i = 0; i <= DEF_PRIORITY; i++) { | 900 | iter = &mz->iter[i]; |
| 913 | iter = &mz->iter[i]; | 901 | cmpxchg(&iter->position, |
| 914 | cmpxchg(&iter->position, | 902 | dead_memcg, NULL); |
| 915 | dead_memcg, NULL); | ||
| 916 | } | ||
| 917 | } | 903 | } |
| 918 | } | 904 | } |
| 919 | } | 905 | } |
| @@ -945,7 +931,7 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg) | |||
| 945 | */ | 931 | */ |
| 946 | struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgdat) | 932 | struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgdat) |
| 947 | { | 933 | { |
| 948 | struct mem_cgroup_per_zone *mz; | 934 | struct mem_cgroup_per_node *mz; |
| 949 | struct mem_cgroup *memcg; | 935 | struct mem_cgroup *memcg; |
| 950 | struct lruvec *lruvec; | 936 | struct lruvec *lruvec; |
| 951 | 937 | ||
| @@ -962,7 +948,7 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgd | |||
| 962 | if (!memcg) | 948 | if (!memcg) |
| 963 | memcg = root_mem_cgroup; | 949 | memcg = root_mem_cgroup; |
| 964 | 950 | ||
| 965 | mz = mem_cgroup_page_zoneinfo(memcg, page); | 951 | mz = mem_cgroup_page_nodeinfo(memcg, page); |
| 966 | lruvec = &mz->lruvec; | 952 | lruvec = &mz->lruvec; |
| 967 | out: | 953 | out: |
| 968 | /* | 954 | /* |
| @@ -989,7 +975,7 @@ out: | |||
| 989 | void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, | 975 | void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, |
| 990 | enum zone_type zid, int nr_pages) | 976 | enum zone_type zid, int nr_pages) |
| 991 | { | 977 | { |
| 992 | struct mem_cgroup_per_zone *mz; | 978 | struct mem_cgroup_per_node *mz; |
| 993 | unsigned long *lru_size; | 979 | unsigned long *lru_size; |
| 994 | long size; | 980 | long size; |
| 995 | bool empty; | 981 | bool empty; |
| @@ -999,7 +985,7 @@ void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, | |||
| 999 | if (mem_cgroup_disabled()) | 985 | if (mem_cgroup_disabled()) |
| 1000 | return; | 986 | return; |
| 1001 | 987 | ||
| 1002 | mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec); | 988 | mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec); |
| 1003 | lru_size = mz->lru_size + lru; | 989 | lru_size = mz->lru_size + lru; |
| 1004 | empty = list_empty(lruvec->lists + lru); | 990 | empty = list_empty(lruvec->lists + lru); |
| 1005 | 991 | ||
| @@ -1392,7 +1378,7 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *memcg) | |||
| 1392 | #endif | 1378 | #endif |
| 1393 | 1379 | ||
| 1394 | static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg, | 1380 | static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg, |
| 1395 | struct zone *zone, | 1381 | pg_data_t *pgdat, |
| 1396 | gfp_t gfp_mask, | 1382 | gfp_t gfp_mask, |
| 1397 | unsigned long *total_scanned) | 1383 | unsigned long *total_scanned) |
| 1398 | { | 1384 | { |
| @@ -1402,7 +1388,7 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg, | |||
| 1402 | unsigned long excess; | 1388 | unsigned long excess; |
| 1403 | unsigned long nr_scanned; | 1389 | unsigned long nr_scanned; |
| 1404 | struct mem_cgroup_reclaim_cookie reclaim = { | 1390 | struct mem_cgroup_reclaim_cookie reclaim = { |
| 1405 | .zone = zone, | 1391 | .pgdat = pgdat, |
| 1406 | .priority = 0, | 1392 | .priority = 0, |
| 1407 | }; | 1393 | }; |
| 1408 | 1394 | ||
| @@ -1433,7 +1419,7 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg, | |||
| 1433 | continue; | 1419 | continue; |
| 1434 | } | 1420 | } |
| 1435 | total += mem_cgroup_shrink_node(victim, gfp_mask, false, | 1421 | total += mem_cgroup_shrink_node(victim, gfp_mask, false, |
| 1436 | zone, &nr_scanned); | 1422 | pgdat, &nr_scanned); |
| 1437 | *total_scanned += nr_scanned; | 1423 | *total_scanned += nr_scanned; |
| 1438 | if (!soft_limit_excess(root_memcg)) | 1424 | if (!soft_limit_excess(root_memcg)) |
| 1439 | break; | 1425 | break; |
| @@ -2560,22 +2546,22 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg, | |||
| 2560 | return ret; | 2546 | return ret; |
| 2561 | } | 2547 | } |
| 2562 | 2548 | ||
| 2563 | unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, | 2549 | unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order, |
| 2564 | gfp_t gfp_mask, | 2550 | gfp_t gfp_mask, |
| 2565 | unsigned long *total_scanned) | 2551 | unsigned long *total_scanned) |
| 2566 | { | 2552 | { |
| 2567 | unsigned long nr_reclaimed = 0; | 2553 | unsigned long nr_reclaimed = 0; |
| 2568 | struct mem_cgroup_per_zone *mz, *next_mz = NULL; | 2554 | struct mem_cgroup_per_node *mz, *next_mz = NULL; |
| 2569 | unsigned long reclaimed; | 2555 | unsigned long reclaimed; |
| 2570 | int loop = 0; | 2556 | int loop = 0; |
| 2571 | struct mem_cgroup_tree_per_zone *mctz; | 2557 | struct mem_cgroup_tree_per_node *mctz; |
| 2572 | unsigned long excess; | 2558 | unsigned long excess; |
| 2573 | unsigned long nr_scanned; | 2559 | unsigned long nr_scanned; |
| 2574 | 2560 | ||
| 2575 | if (order > 0) | 2561 | if (order > 0) |
| 2576 | return 0; | 2562 | return 0; |
| 2577 | 2563 | ||
| 2578 | mctz = soft_limit_tree_node_zone(zone_to_nid(zone), zone_idx(zone)); | 2564 | mctz = soft_limit_tree_node(pgdat->node_id); |
| 2579 | /* | 2565 | /* |
| 2580 | * This loop can run a while, specially if mem_cgroup's continuously | 2566 | * This loop can run a while, specially if mem_cgroup's continuously |
| 2581 | * keep exceeding their soft limit and putting the system under | 2567 | * keep exceeding their soft limit and putting the system under |
| @@ -2590,7 +2576,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, | |||
| 2590 | break; | 2576 | break; |
| 2591 | 2577 | ||
| 2592 | nr_scanned = 0; | 2578 | nr_scanned = 0; |
| 2593 | reclaimed = mem_cgroup_soft_reclaim(mz->memcg, zone, | 2579 | reclaimed = mem_cgroup_soft_reclaim(mz->memcg, pgdat, |
| 2594 | gfp_mask, &nr_scanned); | 2580 | gfp_mask, &nr_scanned); |
| 2595 | nr_reclaimed += reclaimed; | 2581 | nr_reclaimed += reclaimed; |
| 2596 | *total_scanned += nr_scanned; | 2582 | *total_scanned += nr_scanned; |
| @@ -3211,22 +3197,21 @@ static int memcg_stat_show(struct seq_file *m, void *v) | |||
| 3211 | 3197 | ||
| 3212 | #ifdef CONFIG_DEBUG_VM | 3198 | #ifdef CONFIG_DEBUG_VM |
| 3213 | { | 3199 | { |
| 3214 | int nid, zid; | 3200 | pg_data_t *pgdat; |
| 3215 | struct mem_cgroup_per_zone *mz; | 3201 | struct mem_cgroup_per_node *mz; |
| 3216 | struct zone_reclaim_stat *rstat; | 3202 | struct zone_reclaim_stat *rstat; |
| 3217 | unsigned long recent_rotated[2] = {0, 0}; | 3203 | unsigned long recent_rotated[2] = {0, 0}; |
| 3218 | unsigned long recent_scanned[2] = {0, 0}; | 3204 | unsigned long recent_scanned[2] = {0, 0}; |
| 3219 | 3205 | ||
| 3220 | for_each_online_node(nid) | 3206 | for_each_online_pgdat(pgdat) { |
| 3221 | for (zid = 0; zid < MAX_NR_ZONES; zid++) { | 3207 | mz = mem_cgroup_nodeinfo(memcg, pgdat->node_id); |
| 3222 | mz = &memcg->nodeinfo[nid]->zoneinfo[zid]; | 3208 | rstat = &mz->lruvec.reclaim_stat; |
| 3223 | rstat = &mz->lruvec.reclaim_stat; | ||
| 3224 | 3209 | ||
| 3225 | recent_rotated[0] += rstat->recent_rotated[0]; | 3210 | recent_rotated[0] += rstat->recent_rotated[0]; |
| 3226 | recent_rotated[1] += rstat->recent_rotated[1]; | 3211 | recent_rotated[1] += rstat->recent_rotated[1]; |
| 3227 | recent_scanned[0] += rstat->recent_scanned[0]; | 3212 | recent_scanned[0] += rstat->recent_scanned[0]; |
| 3228 | recent_scanned[1] += rstat->recent_scanned[1]; | 3213 | recent_scanned[1] += rstat->recent_scanned[1]; |
| 3229 | } | 3214 | } |
| 3230 | seq_printf(m, "recent_rotated_anon %lu\n", recent_rotated[0]); | 3215 | seq_printf(m, "recent_rotated_anon %lu\n", recent_rotated[0]); |
| 3231 | seq_printf(m, "recent_rotated_file %lu\n", recent_rotated[1]); | 3216 | seq_printf(m, "recent_rotated_file %lu\n", recent_rotated[1]); |
| 3232 | seq_printf(m, "recent_scanned_anon %lu\n", recent_scanned[0]); | 3217 | seq_printf(m, "recent_scanned_anon %lu\n", recent_scanned[0]); |
| @@ -4106,11 +4091,10 @@ struct mem_cgroup *mem_cgroup_from_id(unsigned short id) | |||
| 4106 | return idr_find(&mem_cgroup_idr, id); | 4091 | return idr_find(&mem_cgroup_idr, id); |
| 4107 | } | 4092 | } |
| 4108 | 4093 | ||
| 4109 | static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) | 4094 | static int alloc_mem_cgroup_per_node_info(struct mem_cgroup *memcg, int node) |
| 4110 | { | 4095 | { |
| 4111 | struct mem_cgroup_per_node *pn; | 4096 | struct mem_cgroup_per_node *pn; |
| 4112 | struct mem_cgroup_per_zone *mz; | 4097 | int tmp = node; |
| 4113 | int zone, tmp = node; | ||
| 4114 | /* | 4098 | /* |
| 4115 | * This routine is called against possible nodes. | 4099 | * This routine is called against possible nodes. |
| 4116 | * But it's BUG to call kmalloc() against offline node. | 4100 | * But it's BUG to call kmalloc() against offline node. |
| @@ -4125,18 +4109,16 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) | |||
| 4125 | if (!pn) | 4109 | if (!pn) |
| 4126 | return 1; | 4110 | return 1; |
| 4127 | 4111 | ||
| 4128 | for (zone = 0; zone < MAX_NR_ZONES; zone++) { | 4112 | lruvec_init(&pn->lruvec); |
| 4129 | mz = &pn->zoneinfo[zone]; | 4113 | pn->usage_in_excess = 0; |
| 4130 | lruvec_init(&mz->lruvec); | 4114 | pn->on_tree = false; |
| 4131 | mz->usage_in_excess = 0; | 4115 | pn->memcg = memcg; |
| 4132 | mz->on_tree = false; | 4116 | |
| 4133 | mz->memcg = memcg; | ||
| 4134 | } | ||
| 4135 | memcg->nodeinfo[node] = pn; | 4117 | memcg->nodeinfo[node] = pn; |
| 4136 | return 0; | 4118 | return 0; |
| 4137 | } | 4119 | } |
| 4138 | 4120 | ||
| 4139 | static void free_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) | 4121 | static void free_mem_cgroup_per_node_info(struct mem_cgroup *memcg, int node) |
| 4140 | { | 4122 | { |
| 4141 | kfree(memcg->nodeinfo[node]); | 4123 | kfree(memcg->nodeinfo[node]); |
| 4142 | } | 4124 | } |
| @@ -4147,7 +4129,7 @@ static void mem_cgroup_free(struct mem_cgroup *memcg) | |||
| 4147 | 4129 | ||
| 4148 | memcg_wb_domain_exit(memcg); | 4130 | memcg_wb_domain_exit(memcg); |
| 4149 | for_each_node(node) | 4131 | for_each_node(node) |
| 4150 | free_mem_cgroup_per_zone_info(memcg, node); | 4132 | free_mem_cgroup_per_node_info(memcg, node); |
| 4151 | free_percpu(memcg->stat); | 4133 | free_percpu(memcg->stat); |
| 4152 | kfree(memcg); | 4134 | kfree(memcg); |
| 4153 | } | 4135 | } |
| @@ -4176,7 +4158,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void) | |||
| 4176 | goto fail; | 4158 | goto fail; |
| 4177 | 4159 | ||
| 4178 | for_each_node(node) | 4160 | for_each_node(node) |
| 4179 | if (alloc_mem_cgroup_per_zone_info(memcg, node)) | 4161 | if (alloc_mem_cgroup_per_node_info(memcg, node)) |
| 4180 | goto fail; | 4162 | goto fail; |
| 4181 | 4163 | ||
| 4182 | if (memcg_wb_domain_init(memcg, GFP_KERNEL)) | 4164 | if (memcg_wb_domain_init(memcg, GFP_KERNEL)) |
| @@ -5779,18 +5761,12 @@ static int __init mem_cgroup_init(void) | |||
| 5779 | 5761 | ||
| 5780 | for_each_node(node) { | 5762 | for_each_node(node) { |
| 5781 | struct mem_cgroup_tree_per_node *rtpn; | 5763 | struct mem_cgroup_tree_per_node *rtpn; |
| 5782 | int zone; | ||
| 5783 | 5764 | ||
| 5784 | rtpn = kzalloc_node(sizeof(*rtpn), GFP_KERNEL, | 5765 | rtpn = kzalloc_node(sizeof(*rtpn), GFP_KERNEL, |
| 5785 | node_online(node) ? node : NUMA_NO_NODE); | 5766 | node_online(node) ? node : NUMA_NO_NODE); |
| 5786 | 5767 | ||
| 5787 | for (zone = 0; zone < MAX_NR_ZONES; zone++) { | 5768 | rtpn->rb_root = RB_ROOT; |
| 5788 | struct mem_cgroup_tree_per_zone *rtpz; | 5769 | spin_lock_init(&rtpn->lock); |
| 5789 | |||
| 5790 | rtpz = &rtpn->rb_tree_per_zone[zone]; | ||
| 5791 | rtpz->rb_root = RB_ROOT; | ||
| 5792 | spin_lock_init(&rtpz->lock); | ||
| 5793 | } | ||
| 5794 | soft_limit_tree.rb_tree_per_node[node] = rtpn; | 5770 | soft_limit_tree.rb_tree_per_node[node] = rtpn; |
| 5795 | } | 5771 | } |
| 5796 | 5772 | ||
