There is a per-memcg lruvec and a NUMA node lruvec. Which one is being used is somewhat confusing right now, and it's easy to make mistakes - especially when it comes to global reclaim. How it works: when memory cgroups are enabled, we always use the root_mem_cgroup's per-node lruvecs. When memory cgroups are not compiled in or disabled at runtime, we use pgdat->lruvec. Document that in a comment. Due to the way the reclaim code is generalized, all lookups use the mem_cgroup_lruvec() helper function, and nobody should have to find the right lruvec manually right now. But to avoid future mistakes, rename the pgdat->lruvec member to pgdat->__lruvec and delete the convenience wrapper that suggests it's a commonly accessed member. While in this area, swap the mem_cgroup_lruvec() argument order. The name suggests a memcg operation, yet it takes a pgdat first and a memcg second. I have to double take every time I call this. Fix that.
Showing the changes to include/linux (2 of 7 files). Show all
Unified · Split
| @@ -385,21 +385,21 @@ mem_cgroup_nodeinfo(struct mem_cgroup *memcg, int nid) · 384 unmodified lines | |||
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | /** | 387 | /** |
| 388 | * mem_cgroup_lruvec - get the lru list vector for a node or a memcg zone | 388 | * mem_cgroup_lruvec - get the lru list vector for a memcg & node |
| 389 | * @node: node of the wanted lruvec | ||
| 390 | * @memcg: memcg of the wanted lruvec | 389 | * @memcg: memcg of the wanted lruvec |
| 391 | * | 390 | * |
| 392 | * Returns the lru list vector holding pages for a given @node or a given | 391 | * Returns the lru list vector holding pages for a given @memcg & |
| 393 | * @memcg. This can be the node lruvec, if the memory controller is disabled. | 392 | * @node combination. This can be the node lruvec, if the memory |
| 393 | * controller is disabled. | ||
| 394 | */ | 394 | */ |
| 395 | static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat, | 395 | static inline struct lruvec *mem_cgroup_lruvec(struct mem_cgroup *memcg, |
| 396 | struct mem_cgroup *memcg) | 396 | struct pglist_data *pgdat) |
| 397 | { | 397 | { |
| 398 | struct mem_cgroup_per_node *mz; | 398 | struct mem_cgroup_per_node *mz; |
| 399 | struct lruvec *lruvec; | 399 | struct lruvec *lruvec; |
| 400 | 400 | ||
| 401 | if (mem_cgroup_disabled()) { | 401 | if (mem_cgroup_disabled()) { |
| 402 | lruvec = node_lruvec(pgdat); | 402 | lruvec = &pgdat->__lruvec; |
| 403 | goto out; | 403 | goto out; |
| 404 | } | 404 | } |
| 405 | 405 | ||
| @@ -718,7 +718,7 @@ static inline void __mod_lruvec_page_state(struct page *page, · 312 unmodified lines | |||
| 718 | return; | 718 | return; |
| 719 | } | 719 | } |
| 720 | 720 | ||
| 721 | lruvec = mem_cgroup_lruvec(pgdat, page->mem_cgroup); | 721 | lruvec = mem_cgroup_lruvec(page->mem_cgroup, pgdat); |
| 722 | __mod_lruvec_state(lruvec, idx, val); | 722 | __mod_lruvec_state(lruvec, idx, val); |
| 723 | } | 723 | } |
| 724 | 724 | ||
| @@ -889,16 +889,16 @@ static inline void mem_cgroup_migrate(struct page *old, struct page *new) · 164 unmodified lines | |||
| 889 | { | 889 | { |
| 890 | } | 890 | } |
| 891 | 891 | ||
| 892 | static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat, | 892 | static inline struct lruvec *mem_cgroup_lruvec(struct mem_cgroup *memcg, |
| 893 | struct mem_cgroup *memcg) | 893 | struct pglist_data *pgdat) |
| 894 | { | 894 | { |
| 895 | return node_lruvec(pgdat); | 895 | return &pgdat->__lruvec; |
| 896 | } | 896 | } |
| 897 | 897 | ||
| 898 | static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page, | 898 | static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page, |
| 899 | struct pglist_data *pgdat) | 899 | struct pglist_data *pgdat) |
| 900 | { | 900 | { |
| 901 | return &pgdat->lruvec; | 901 | return &pgdat->__lruvec; |
| 902 | } | 902 | } |
| 903 | 903 | ||
| 904 | static inline bool mm_match_cgroup(struct mm_struct *mm, | 904 | static inline bool mm_match_cgroup(struct mm_struct *mm, |
| @@ -777,7 +777,13 @@ typedef struct pglist_data { · 776 unmodified lines | |||
| 777 | #endif | 777 | #endif |
| 778 | 778 | ||
| 779 | /* Fields commonly accessed by the page reclaim scanner */ | 779 | /* Fields commonly accessed by the page reclaim scanner */ |
| 780 | struct lruvec lruvec; | 780 | |
| 781 | /* | ||
| 782 | * NOTE: THIS IS UNUSED IF MEMCG IS ENABLED. | ||
| 783 | * | ||
| 784 | * Use mem_cgroup_lruvec() to look up lruvecs. | ||
| 785 | */ | ||
| 786 | struct lruvec __lruvec; | ||
| 781 | 787 | ||
| 782 | unsigned long flags; | 788 | unsigned long flags; |
| 783 | 789 | ||
| @@ -800,11 +806,6 @@ typedef struct pglist_data { · 16 unmodified lines | |||
| 800 | #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) | 806 | #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) |
| 801 | #define node_end_pfn(nid) pgdat_end_pfn(NODE_DATA(nid)) | 807 | #define node_end_pfn(nid) pgdat_end_pfn(NODE_DATA(nid)) |
| 802 | 808 | ||
| 803 | static inline struct lruvec *node_lruvec(struct pglist_data *pgdat) | ||
| 804 | { | ||
| 805 | return &pgdat->lruvec; | ||
| 806 | } | ||
| 807 | |||
| 808 | static inline unsigned long pgdat_end_pfn(pg_data_t *pgdat) | 809 | static inline unsigned long pgdat_end_pfn(pg_data_t *pgdat) |
| 809 | { | 810 | { |
| 810 | return pgdat->node_start_pfn + pgdat->node_spanned_pages; | 811 | return pgdat->node_start_pfn + pgdat->node_spanned_pages; |
| @@ -842,7 +843,7 @@ static inline struct pglist_data *lruvec_pgdat(struct lruvec *lruvec) · 31 unmodified lines | |||
| 842 | #ifdef CONFIG_MEMCG | 843 | #ifdef CONFIG_MEMCG |
| 843 | return lruvec->pgdat; | 844 | return lruvec->pgdat; |
| 844 | #else | 845 | #else |
| 845 | return container_of(lruvec, struct pglist_data, lruvec); | 846 | return container_of(lruvec, struct pglist_data, __lruvec); |
| 846 | #endif | 847 | #endif |
| 847 | } | 848 | } |
| 848 | 849 | ||