-
Notifications
You must be signed in to change notification settings - Fork 105
[Deepin-Kernel-SIG] [linux 6.12-y] [Openeuler] [Maillist] [PATCH v3] mm: convert mm's rss stats to use atomic mode #1412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: linux-6.12.y
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2644,7 +2644,19 @@ static inline bool get_user_page_fast_only(unsigned long addr, | |||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| static inline unsigned long get_mm_counter(struct mm_struct *mm, int member) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return percpu_counter_read_positive(&mm->rss_stat[member]); | ||||||||||||||||||||||||||
| struct percpu_counter *fbc = &mm->rss_stat[member]; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if (percpu_counter_initialized(fbc)) | ||||||||||||||||||||||||||
| return percpu_counter_read_positive(fbc); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| long val = percpu_counter_atomic_read(fbc); | ||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||
| * counter is updated in asynchronous manner and may go to minus. | ||||||||||||||||||||||||||
| * But it's never be expected number for users. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| if (val < 0) | ||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||
| return (unsigned long)val; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| static inline unsigned long get_mm_counter_sum(struct mm_struct *mm, int member) | ||||||||||||||||||||||||||
|
|
@@ -2656,7 +2668,12 @@ void mm_trace_rss_stat(struct mm_struct *mm, int member); | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| static inline void add_mm_counter(struct mm_struct *mm, int member, long value) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| percpu_counter_add(&mm->rss_stat[member], value); | ||||||||||||||||||||||||||
| struct percpu_counter *fbc = &mm->rss_stat[member]; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if (percpu_counter_initialized(fbc)) | ||||||||||||||||||||||||||
| percpu_counter_add(fbc, value); | ||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||
| percpu_counter_atomic_add(fbc, value); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| mm_trace_rss_stat(mm, member); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
@@ -2670,9 +2687,37 @@ static inline void inc_mm_counter(struct mm_struct *mm, int member) | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| static inline void dec_mm_counter(struct mm_struct *mm, int member) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| percpu_counter_dec(&mm->rss_stat[member]); | ||||||||||||||||||||||||||
| add_mm_counter(mm, member, -1); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| mm_trace_rss_stat(mm, member); | ||||||||||||||||||||||||||
| static inline s64 mm_counter_sum(struct mm_struct *mm, int member) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| struct percpu_counter *fbc = &mm->rss_stat[member]; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if (percpu_counter_initialized(fbc)) | ||||||||||||||||||||||||||
| return percpu_counter_sum(fbc); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return percpu_counter_atomic_read(fbc); | ||||||||||||||||||||||||||
opsiff marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| static inline s64 mm_counter_sum_positive(struct mm_struct *mm, int member) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| struct percpu_counter *fbc = &mm->rss_stat[member]; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if (percpu_counter_initialized(fbc)) | ||||||||||||||||||||||||||
| return percpu_counter_sum_positive(fbc); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return percpu_counter_atomic_read(fbc); | ||||||||||||||||||||||||||
|
Comment on lines
+2706
to
+2710
|
||||||||||||||||||||||||||
| if (percpu_counter_initialized(fbc)) | |
| return percpu_counter_sum_positive(fbc); | |
| return percpu_counter_atomic_read(fbc); | |
| s64 sum; | |
| if (percpu_counter_initialized(fbc)) | |
| return percpu_counter_sum_positive(fbc); | |
| sum = percpu_counter_atomic_read(fbc); | |
| return sum < 0 ? 0 : sum; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For atomic mode counters,
percpu_counter_atomic_readcan return negative values, butmm_counter_sum_positiveshould return only positive values (as the name implies). The percpu mode usespercpu_counter_sum_positivewhich clamps to 0, but the atomic mode path doesn't apply this logic. Consider using max(0, percpu_counter_atomic_read(fbc)) to ensure consistency.
这个函数只在include/trace/events/kmem.h里面使用
opsiff marked this conversation as resolved.
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -187,7 +187,7 @@ EXPORT_SYMBOL(__percpu_counter_sum); | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
| /* | |
| * Initialize an array of percpu counters. | |
| * | |
| * @switch_mode: when true, the caller is converting an existing | |
| * atomic-mode counter to percpu mode. In that case, the existing | |
| * global count in @fbc[i].count must be preserved and therefore | |
| * is not reset to @amount. | |
| */ |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When switching from atomic mode to percpu mode, the existing value in count_atomic needs to be migrated to the percpu counter's count field. Currently, when switch_mode is true, fbc[i].count is not initialized at all, which means the accumulated atomic count value is lost. The function should read the current atomic64_read(&fbc[i].count_atomic) value and assign it to fbc[i].count before switching modes to preserve the accumulated RSS statistics.
| fbc[i].count = amount; | |
| fbc[i].count = amount; | |
| else | |
| fbc[i].count = atomic64_read(&fbc[i].count_atomic); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
count 和 count_atomic 是 union,它们在内存中是重叠的。不需要这个操作
opsiff marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a potential race condition here. The check at line 331 and line 336 both use percpu_counter_initialized(fbc) without proper synchronization between them. If two threads call this function simultaneously, both could see the counter as uninitialized and attempt to initialize it, leading to a memory leak or inconsistent state. Consider using atomic compare-and-swap or ensuring this function is only called under appropriate locks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
考虑调用的地方是第一次初始化的时候才会percpu_counter_initialized,第一次初始化的时候是fork,始终为单线程进入此处初始化后才可能多线程。
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code uses inconsistent indentation with tabs mixed in. The function parameters and code within the function should use consistent indentation matching the rest of the file (tabs for indentation).
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mode switching in percpu_counter_switch_to_pcpu_many has inadequate synchronization. While it disables preemption and interrupts, there's no memory barrier after the percpu allocation and before other CPUs can observe the new counters pointer. This could lead to other CPUs seeing a non-NULL counters pointer before the percpu memory is fully initialized. An smp_wmb() should be added after successful initialization and smp_rmb() in code paths that check percpu_counter_initialized().
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using local_irq_save with GFP_ATOMIC for percpu allocation is problematic. The allocation uses GFP_ATOMIC which can fail more easily than GFP_KERNEL. Since this is called from copy_mm which is in process context and can sleep, a better approach would be to do the allocation without disabling interrupts (using GFP_KERNEL), then use a lock to atomically check if initialization is still needed and set the counters pointer. The current approach makes memory allocation more likely to fail and returns -ENOMEM to the thread creation, which is unnecessarily fragile.
| unsigned long flags; | |
| int ret = 0; | |
| if (percpu_counter_initialized(fbc)) | |
| return 0; | |
| preempt_disable(); | |
| local_irq_save(flags); | |
| if (likely(!percpu_counter_initialized(fbc))) | |
| ret = __percpu_counter_init_many(fbc, 0, | |
| GFP_ATOMIC|__GFP_NOWARN|__GFP_ZERO, | |
| nr_counters, &__key, true); | |
| local_irq_restore(flags); | |
| preempt_enable(); | |
| int ret = 0; | |
| if (percpu_counter_initialized(fbc)) | |
| return 0; | |
| if (likely(!percpu_counter_initialized(fbc))) | |
| ret = __percpu_counter_init_many(fbc, 0, | |
| GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO, | |
| nr_counters, &__key, true); |
Uh oh!
There was an error while loading. Please reload this page.