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

Configure Feed

Select the types of activity you want to include in your feed.

mm: memcontrol: change val type to long in __mod_memcg_{lruvec_}state()

The __mod_memcg_state() and __mod_memcg_lruvec_state() functions are also
used to reparent non-hierarchical stats. In this scenario, the values
passed to them are accumulated statistics that might be extremely large
and exceed the upper limit of a 32-bit integer.

Change the val parameter type from int to long in these functions and
their corresponding tracepoints (memcg_rstat_stats) to prevent potential
overflow issues.

After that, in memcg_state_val_in_pages(), if the passed val is negative,
the expression val * unit / PAGE_SIZE could be implicitly converted to a
massive positive number when compared with 1UL in the max() macro. This
leads to returning an incorrect massive positive value.

Fix this by using abs(val) to calculate the magnitude first, and then
restoring the sign of the value before returning the result.
Additionally, use mult_frac() to prevent potential overflow during the
multiplication of val and unit.

Link: https://lore.kernel.org/70a9440e49c464b4dca88bcabc6b491bd335c9f0.1774604356.git.zhengqi.arch@bytedance.com
Signed-off-by: Qi Zheng <zhengqi.arch@bytedance.com>
Reported-by: Harry Yoo (Oracle) <harry@kernel.org>
Reviewed-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
Reviewed-by: Harry Yoo (Oracle) <harry@kernel.org>
Cc: Allen Pais <apais@linux.microsoft.com>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Imran Khan <imran.f.khan@oracle.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Kamalesh Babulal <kamalesh.babulal@oracle.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Michal Koutný <mkoutny@suse.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Usama Arif <usamaarif642@gmail.com>
Cc: Wei Xu <weixugc@google.com>
Cc: Yuanchu Xie <yuanchu@google.com>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Qi Zheng and committed by
Andrew Morton
85358bad 616795d7

+17 -11
+5 -5
include/trace/events/memcg.h
··· 11 11 12 12 DECLARE_EVENT_CLASS(memcg_rstat_stats, 13 13 14 - TP_PROTO(struct mem_cgroup *memcg, int item, int val), 14 + TP_PROTO(struct mem_cgroup *memcg, int item, long val), 15 15 16 16 TP_ARGS(memcg, item, val), 17 17 18 18 TP_STRUCT__entry( 19 19 __field(u64, id) 20 20 __field(int, item) 21 - __field(int, val) 21 + __field(long, val) 22 22 ), 23 23 24 24 TP_fast_assign( ··· 27 27 __entry->val = val; 28 28 ), 29 29 30 - TP_printk("memcg_id=%llu item=%d val=%d", 30 + TP_printk("memcg_id=%llu item=%d val=%ld", 31 31 __entry->id, __entry->item, __entry->val) 32 32 ); 33 33 34 34 DEFINE_EVENT(memcg_rstat_stats, mod_memcg_state, 35 35 36 - TP_PROTO(struct mem_cgroup *memcg, int item, int val), 36 + TP_PROTO(struct mem_cgroup *memcg, int item, long val), 37 37 38 38 TP_ARGS(memcg, item, val) 39 39 ); 40 40 41 41 DEFINE_EVENT(memcg_rstat_stats, mod_memcg_lruvec_state, 42 42 43 - TP_PROTO(struct mem_cgroup *memcg, int item, int val), 43 + TP_PROTO(struct mem_cgroup *memcg, int item, long val), 44 44 45 45 TP_ARGS(memcg, item, val) 46 46 );
+12 -6
mm/memcontrol.c
··· 527 527 528 528 #ifdef CONFIG_MEMCG_V1 529 529 static void __mod_memcg_lruvec_state(struct mem_cgroup_per_node *pn, 530 - enum node_stat_item idx, int val); 530 + enum node_stat_item idx, long val); 531 531 532 532 void reparent_memcg_lruvec_state_local(struct mem_cgroup *memcg, 533 533 struct mem_cgroup *parent, int idx) ··· 784 784 * Normalize the value passed into memcg_rstat_updated() to be in pages. Round 785 785 * up non-zero sub-page updates to 1 page as zero page updates are ignored. 786 786 */ 787 - static int memcg_state_val_in_pages(int idx, int val) 787 + static long memcg_state_val_in_pages(int idx, long val) 788 788 { 789 789 int unit = memcg_page_state_unit(idx); 790 + long res; 790 791 791 792 if (!val || unit == PAGE_SIZE) 792 793 return val; 793 - else 794 - return max(val * unit / PAGE_SIZE, 1UL); 794 + 795 + /* Get the absolute value of (val * unit / PAGE_SIZE). */ 796 + res = mult_frac(abs(val), unit, PAGE_SIZE); 797 + /* Round up zero values. */ 798 + res = res ? : 1; 799 + 800 + return val < 0 ? -res : res; 795 801 } 796 802 797 803 #ifdef CONFIG_MEMCG_V1 ··· 837 831 #endif 838 832 839 833 static void __mod_memcg_state(struct mem_cgroup *memcg, 840 - enum memcg_stat_item idx, int val) 834 + enum memcg_stat_item idx, long val) 841 835 { 842 836 int i = memcg_stats_index(idx); 843 837 int cpu; ··· 902 896 #endif 903 897 904 898 static void __mod_memcg_lruvec_state(struct mem_cgroup_per_node *pn, 905 - enum node_stat_item idx, int val) 899 + enum node_stat_item idx, long val) 906 900 { 907 901 struct mem_cgroup *memcg = pn->memcg; 908 902 int i = memcg_stats_index(idx);