Skip to content

Commit be55257

Browse files
groeckrostedt
authored andcommitted
ftrace: Do not over-allocate ftrace memory
The pg_remaining calculation in ftrace_process_locs() assumes that ENTRIES_PER_PAGE multiplied by 2^order equals the actual capacity of the allocated page group. However, ENTRIES_PER_PAGE is PAGE_SIZE / ENTRY_SIZE (integer division). When PAGE_SIZE is not a multiple of ENTRY_SIZE (e.g. 4096 / 24 = 170 with remainder 16), high-order allocations (like 256 pages) have significantly more capacity than 256 * 170. This leads to pg_remaining being underestimated, which in turn makes skip (derived from skipped - pg_remaining) larger than expected, causing the WARN(skip != remaining) to trigger. Extra allocated pages for ftrace: 2 with 654 skipped WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7295 ftrace_process_locs+0x5bf/0x5e0 A similar problem in ftrace_allocate_records() can result in allocating too many pages. This can trigger the second warning in ftrace_process_locs(). Extra allocated pages for ftrace WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7276 ftrace_process_locs+0x548/0x580 Use the actual capacity of a page group to determine the number of pages to allocate. Have ftrace_allocate_pages() return the number of allocated pages to avoid having to calculate it. Use the actual page group capacity when validating the number of unused pages due to skipped entries. Drop the definition of ENTRIES_PER_PAGE since it is no longer used. Cc: stable@vger.kernel.org Fixes: 4a3efc6 ("ftrace: Update the mcount_loc check of skipped entries") Link: https://patch.msgid.link/20260113152243.3557219-1-linux@roeck-us.net Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 0f61b18 commit be55257

1 file changed

Lines changed: 15 additions & 14 deletions

File tree

kernel/trace/ftrace.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,7 +1148,6 @@ struct ftrace_page {
11481148
};
11491149

11501150
#define ENTRY_SIZE sizeof(struct dyn_ftrace)
1151-
#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE)
11521151

11531152
static struct ftrace_page *ftrace_pages_start;
11541153
static struct ftrace_page *ftrace_pages;
@@ -3834,7 +3833,8 @@ static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs)
38343833
return 0;
38353834
}
38363835

3837-
static int ftrace_allocate_records(struct ftrace_page *pg, int count)
3836+
static int ftrace_allocate_records(struct ftrace_page *pg, int count,
3837+
unsigned long *num_pages)
38383838
{
38393839
int order;
38403840
int pages;
@@ -3844,7 +3844,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
38443844
return -EINVAL;
38453845

38463846
/* We want to fill as much as possible, with no empty pages */
3847-
pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE);
3847+
pages = DIV_ROUND_UP(count * ENTRY_SIZE, PAGE_SIZE);
38483848
order = fls(pages) - 1;
38493849

38503850
again:
@@ -3859,6 +3859,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
38593859
}
38603860

38613861
ftrace_number_of_pages += 1 << order;
3862+
*num_pages += 1 << order;
38623863
ftrace_number_of_groups++;
38633864

38643865
cnt = (PAGE_SIZE << order) / ENTRY_SIZE;
@@ -3887,12 +3888,14 @@ static void ftrace_free_pages(struct ftrace_page *pages)
38873888
}
38883889

38893890
static struct ftrace_page *
3890-
ftrace_allocate_pages(unsigned long num_to_init)
3891+
ftrace_allocate_pages(unsigned long num_to_init, unsigned long *num_pages)
38913892
{
38923893
struct ftrace_page *start_pg;
38933894
struct ftrace_page *pg;
38943895
int cnt;
38953896

3897+
*num_pages = 0;
3898+
38963899
if (!num_to_init)
38973900
return NULL;
38983901

@@ -3906,7 +3909,7 @@ ftrace_allocate_pages(unsigned long num_to_init)
39063909
* waste as little space as possible.
39073910
*/
39083911
for (;;) {
3909-
cnt = ftrace_allocate_records(pg, num_to_init);
3912+
cnt = ftrace_allocate_records(pg, num_to_init, num_pages);
39103913
if (cnt < 0)
39113914
goto free_pages;
39123915

@@ -7192,8 +7195,6 @@ static int ftrace_process_locs(struct module *mod,
71927195
if (!count)
71937196
return 0;
71947197

7195-
pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE);
7196-
71977198
/*
71987199
* Sorting mcount in vmlinux at build time depend on
71997200
* CONFIG_BUILDTIME_MCOUNT_SORT, while mcount loc in
@@ -7206,7 +7207,7 @@ static int ftrace_process_locs(struct module *mod,
72067207
test_is_sorted(start, count);
72077208
}
72087209

7209-
start_pg = ftrace_allocate_pages(count);
7210+
start_pg = ftrace_allocate_pages(count, &pages);
72107211
if (!start_pg)
72117212
return -ENOMEM;
72127213

@@ -7305,27 +7306,27 @@ static int ftrace_process_locs(struct module *mod,
73057306
/* We should have used all pages unless we skipped some */
73067307
if (pg_unuse) {
73077308
unsigned long pg_remaining, remaining = 0;
7308-
unsigned long skip;
7309+
long skip;
73097310

73107311
/* Count the number of entries unused and compare it to skipped. */
7311-
pg_remaining = (ENTRIES_PER_PAGE << pg->order) - pg->index;
7312+
pg_remaining = (PAGE_SIZE << pg->order) / ENTRY_SIZE - pg->index;
73127313

73137314
if (!WARN(skipped < pg_remaining, "Extra allocated pages for ftrace")) {
73147315

73157316
skip = skipped - pg_remaining;
73167317

7317-
for (pg = pg_unuse; pg; pg = pg->next)
7318+
for (pg = pg_unuse; pg && skip > 0; pg = pg->next) {
73187319
remaining += 1 << pg->order;
7320+
skip -= (PAGE_SIZE << pg->order) / ENTRY_SIZE;
7321+
}
73197322

73207323
pages -= remaining;
73217324

7322-
skip = DIV_ROUND_UP(skip, ENTRIES_PER_PAGE);
7323-
73247325
/*
73257326
* Check to see if the number of pages remaining would
73267327
* just fit the number of entries skipped.
73277328
*/
7328-
WARN(skip != remaining, "Extra allocated pages for ftrace: %lu with %lu skipped",
7329+
WARN(pg || skip > 0, "Extra allocated pages for ftrace: %lu with %lu skipped",
73297330
remaining, skipped);
73307331
}
73317332
/* Need to synchronize with ftrace_location_range() */

0 commit comments

Comments
 (0)