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 | |
| 389 | − * @node: node of the wanted lruvec | |
| 388 | + * mem_cgroup_lruvec - get the lru list vector for a memcg & node | |
| 390 | 389 | * @memcg: memcg of the wanted lruvec |
| 391 | 390 | * |
| 392 | − * Returns the lru list vector holding pages for a given @node or a given | |
| 393 | − * @memcg. This can be the node lruvec, if the memory controller is disabled. | |
| 391 | + * Returns the lru list vector holding pages for a given @memcg & | |
| 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, | |
| 396 | − struct mem_cgroup *memcg) | |
| 395 | +static inline struct lruvec *mem_cgroup_lruvec(struct mem_cgroup *memcg, | |
| 396 | + struct pglist_data *pgdat) | |
| 397 | 397 | { |
| 398 | 398 | struct mem_cgroup_per_node *mz; |
| 399 | 399 | struct lruvec *lruvec; |
| 400 | 400 | |
| 401 | 401 | if (mem_cgroup_disabled()) { |
| 402 | − lruvec = node_lruvec(pgdat); | |
| 402 | + lruvec = &pgdat->__lruvec; | |
| 403 | 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 | 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 | 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, | |
| 893 | − struct mem_cgroup *memcg) | |
| 892 | +static inline struct lruvec *mem_cgroup_lruvec(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 | 898 | static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page, |
| 899 | 899 | struct pglist_data *pgdat) |
| 900 | 900 | { |
| 901 | − return &pgdat->lruvec; | |
| 901 | + return &pgdat->__lruvec; | |
| 902 | 902 | } |
| 903 | 903 | |
| 904 | 904 | static inline bool mm_match_cgroup(struct mm_struct *mm, |
| @@ -777,7 +777,13 @@ typedef struct pglist_data { · 776 unmodified lines | ||
| 777 | 777 | #endif |
| 778 | 778 | |
| 779 | 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 | 788 | unsigned long flags; |
| 783 | 789 | |
| @@ -800,11 +806,6 @@ typedef struct pglist_data { · 16 unmodified lines | ||
| 800 | 806 | #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) |
| 801 | 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 | 809 | static inline unsigned long pgdat_end_pfn(pg_data_t *pgdat) |
| 809 | 810 | { |
| 810 | 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 | 843 | #ifdef CONFIG_MEMCG |
| 843 | 844 | return lruvec->pgdat; |
| 844 | 845 | #else |
| 845 | − return container_of(lruvec, struct pglist_data, lruvec); | |
| 846 | + return container_of(lruvec, struct pglist_data, __lruvec); | |
| 846 | 847 | #endif |
| 847 | 848 | } |
| 848 | 849 | |