[PATCH v11 4/5] ring-buffer: Skip invalid sub-buffers when rewinding persistent ring buffer

Masami Hiramatsu (Google) posted 5 patches 2 weeks, 4 days ago
There is a newer version of this series
[PATCH v11 4/5] ring-buffer: Skip invalid sub-buffers when rewinding persistent ring buffer
Posted by Masami Hiramatsu (Google) 2 weeks, 4 days ago
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Skip invalid sub-buffers when rewinding the persistent ring buffer
instead of stopping the rewinding the ring buffer. The skipped
buffers are cleared.

To ensure the rewinding stops at the unused page, this also clears
buffer_data_page::time_stamp when tracing resets the buffer. This
allows us to identify unused pages and empty pages.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v11:
   - Reset timestamp when the buffer is invalid.
   - When rewinding, skip subbuf page if timestamp is wrong and
     check timestamp after validating buffer data page.
 Changes in v10:
   - Newly added.
---
 0 files changed

diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 67826021867b..b436d2982c5e 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -363,6 +363,7 @@ struct buffer_page {
 static void rb_init_page(struct buffer_data_page *bpage)
 {
 	local_set(&bpage->commit, 0);
+	bpage->time_stamp = 0;
 }
 
 static __always_inline unsigned int rb_page_commit(struct buffer_page *bpage)
@@ -1878,12 +1879,14 @@ static int rb_read_data_buffer(struct buffer_data_page *dpage, int tail, int cpu
 	return events;
 }
 
-static int rb_validate_buffer(struct buffer_data_page *dpage, int cpu,
+static int rb_validate_buffer(struct buffer_page *bpage, int cpu,
 			      struct ring_buffer_cpu_meta *meta)
 {
+	struct buffer_data_page *dpage = bpage->page;
 	unsigned long long ts;
 	unsigned long tail;
 	u64 delta;
+	int ret = -1;
 
 	/*
 	 * When a sub-buffer is recovered from a read, the commit value may
@@ -1892,9 +1895,17 @@ static int rb_validate_buffer(struct buffer_data_page *dpage, int cpu,
 	 * subbuf_size is considered invalid.
 	 */
 	tail = local_read(&dpage->commit) & ~RB_MISSED_MASK;
-	if (tail > meta->subbuf_size)
-		return -1;
-	return rb_read_data_buffer(dpage, tail, cpu, &ts, &delta);
+	if (tail <= meta->subbuf_size)
+		ret = rb_read_data_buffer(dpage, tail, cpu, &ts, &delta);
+
+	if (ret < 0) {
+		local_set(&bpage->entries, 0);
+		local_set(&bpage->page->commit, 0);
+	} else {
+		local_set(&bpage->entries, ret);
+	}
+
+	return ret;
 }
 
 /* If the meta data has been validated, now validate the events */
@@ -1915,18 +1926,14 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
 	orig_head = head_page = cpu_buffer->head_page;
 
 	/* Do the reader page first */
-	ret = rb_validate_buffer(cpu_buffer->reader_page->page, cpu_buffer->cpu, meta);
+	ret = rb_validate_buffer(cpu_buffer->reader_page, cpu_buffer->cpu, meta);
 	if (ret < 0) {
 		pr_info("Ring buffer meta [%d] invalid reader page detected\n",
 			cpu_buffer->cpu);
 		discarded++;
-		/* Instead of discard whole ring buffer, discard only this sub-buffer. */
-		local_set(&cpu_buffer->reader_page->entries, 0);
-		local_set(&cpu_buffer->reader_page->page->commit, 0);
 	} else {
 		entries += ret;
 		entry_bytes += rb_page_size(cpu_buffer->reader_page);
-		local_set(&cpu_buffer->reader_page->entries, ret);
 	}
 
 	ts = head_page->page->time_stamp;
@@ -1945,26 +1952,33 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
 		if (head_page == cpu_buffer->tail_page)
 			break;
 
-		/* Ensure the page has older data than head. */
-		if (ts < head_page->page->time_stamp)
+		/* Rewind until unused page (no timestamp, no commit). */
+		if (!head_page->page->time_stamp && rb_page_commit(head_page) == 0)
 			break;
 
-		ts = head_page->page->time_stamp;
-		/* Ensure the page has correct timestamp and some data. */
-		if (!ts || rb_page_commit(head_page) == 0)
-			break;
-
-		/* Stop rewind if the page is invalid. */
-		ret = rb_validate_buffer(head_page->page, cpu_buffer->cpu, meta);
-		if (ret < 0)
-			break;
-
-		/* Recover the number of entries and update stats. */
-		local_set(&head_page->entries, ret);
-		if (ret)
-			local_inc(&cpu_buffer->pages_touched);
-		entries += ret;
-		entry_bytes += rb_page_commit(head_page);
+		/*
+		 * Skip if the page is invalid, or its timestamp is newer than the
+		 * previous valid page.
+		 */
+		ret = rb_validate_buffer(head_page, cpu_buffer->cpu, meta);
+		if (ret >= 0 && ts < head_page->page->time_stamp) {
+			local_set(&bpage->entries, 0);
+			local_set(&bpage->page->commit, 0);
+			head_page->page->time_stamp = ts;
+			ret = -1;
+		}
+		if (ret < 0) {
+			if (!discarded)
+				pr_info("Ring buffer meta [%d] invalid buffer page detected\n",
+					cpu_buffer->cpu);
+			discarded++;
+		} else {
+			entries += ret;
+			entry_bytes += rb_page_size(head_page);
+			if (ret > 0)
+				local_inc(&cpu_buffer->pages_touched);
+			ts = head_page->page->time_stamp;
+		}
 	}
 	if (i)
 		pr_info("Ring buffer [%d] rewound %d pages\n", cpu_buffer->cpu, i);
@@ -2034,15 +2048,12 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
 		if (head_page == cpu_buffer->reader_page)
 			continue;
 
-		ret = rb_validate_buffer(head_page->page, cpu_buffer->cpu, meta);
+		ret = rb_validate_buffer(head_page, cpu_buffer->cpu, meta);
 		if (ret < 0) {
 			if (!discarded)
 				pr_info("Ring buffer meta [%d] invalid buffer page detected\n",
 					cpu_buffer->cpu);
 			discarded++;
-			/* Instead of discard whole ring buffer, discard only this sub-buffer. */
-			local_set(&head_page->entries, 0);
-			local_set(&head_page->page->commit, 0);
 		} else {
 			/* If the buffer has content, update pages_touched */
 			if (ret)
@@ -2050,7 +2061,6 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
 
 			entries += ret;
 			entry_bytes += rb_page_size(head_page);
-			local_set(&head_page->entries, ret);
 		}
 		if (head_page == cpu_buffer->commit_page)
 			break;
@@ -2081,7 +2091,7 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
 	/* Reset all the subbuffers */
 	for (i = 0; i < meta->nr_subbufs - 1; i++, rb_inc_page(&head_page)) {
 		local_set(&head_page->entries, 0);
-		local_set(&head_page->page->commit, 0);
+		rb_init_page(head_page->page);
 	}
 }
Re: [PATCH v11 4/5] ring-buffer: Skip invalid sub-buffers when rewinding persistent ring buffer
Posted by kernel test robot 2 weeks ago
Hi Masami,

kernel test robot noticed the following build errors:

[auto build test ERROR on trace/for-next]
[also build test ERROR on geert-m68k/for-next geert-m68k/for-linus openrisc/for-next deller-parisc/for-next powerpc/next powerpc/fixes s390/features uml/next tip/x86/core uml/fixes v7.0-rc4 next-20260320]
[cannot apply to linus/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Masami-Hiramatsu-Google/ring-buffer-Fix-to-update-per-subbuf-entries-of-persistent-ring-buffer/20260322-122412
base:   https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace for-next
patch link:    https://lore.kernel.org/r/177391156211.193994.7531495945584650297.stgit%40mhiramat.tok.corp.google.com
patch subject: [PATCH v11 4/5] ring-buffer: Skip invalid sub-buffers when rewinding persistent ring buffer
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20260323/202603230725.uMAZiKJx-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260323/202603230725.uMAZiKJx-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603230725.uMAZiKJx-lkp@intel.com/

All errors (new ones prefixed by >>):

>> kernel/trace/ring_buffer.c:1965:15: error: use of undeclared identifier 'bpage'
    1965 |                         local_set(&bpage->entries, 0);
         |                                    ^
   kernel/trace/ring_buffer.c:1966:15: error: use of undeclared identifier 'bpage'
    1966 |                         local_set(&bpage->page->commit, 0);
         |                                    ^
   2 errors generated.


vim +/bpage +1965 kernel/trace/ring_buffer.c

  1910	
  1911	/* If the meta data has been validated, now validate the events */
  1912	static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
  1913	{
  1914		struct ring_buffer_cpu_meta *meta = cpu_buffer->ring_meta;
  1915		struct buffer_page *head_page, *orig_head;
  1916		unsigned long entry_bytes = 0;
  1917		unsigned long entries = 0;
  1918		int discarded = 0;
  1919		int ret;
  1920		u64 ts;
  1921		int i;
  1922	
  1923		if (!meta || !meta->head_buffer)
  1924			return;
  1925	
  1926		orig_head = head_page = cpu_buffer->head_page;
  1927	
  1928		/* Do the reader page first */
  1929		ret = rb_validate_buffer(cpu_buffer->reader_page, cpu_buffer->cpu, meta);
  1930		if (ret < 0) {
  1931			pr_info("Ring buffer meta [%d] invalid reader page detected\n",
  1932				cpu_buffer->cpu);
  1933			discarded++;
  1934		} else {
  1935			entries += ret;
  1936			entry_bytes += rb_page_size(cpu_buffer->reader_page);
  1937		}
  1938	
  1939		ts = head_page->page->time_stamp;
  1940	
  1941		/*
  1942		 * Try to rewind the head so that we can read the pages which already
  1943		 * read in the previous boot.
  1944		 */
  1945		if (head_page == cpu_buffer->tail_page)
  1946			goto skip_rewind;
  1947	
  1948		rb_dec_page(&head_page);
  1949		for (i = 0; i < meta->nr_subbufs + 1; i++, rb_dec_page(&head_page)) {
  1950	
  1951			/* Rewind until tail (writer) page. */
  1952			if (head_page == cpu_buffer->tail_page)
  1953				break;
  1954	
  1955			/* Rewind until unused page (no timestamp, no commit). */
  1956			if (!head_page->page->time_stamp && rb_page_commit(head_page) == 0)
  1957				break;
  1958	
  1959			/*
  1960			 * Skip if the page is invalid, or its timestamp is newer than the
  1961			 * previous valid page.
  1962			 */
  1963			ret = rb_validate_buffer(head_page, cpu_buffer->cpu, meta);
  1964			if (ret >= 0 && ts < head_page->page->time_stamp) {
> 1965				local_set(&bpage->entries, 0);
  1966				local_set(&bpage->page->commit, 0);
  1967				head_page->page->time_stamp = ts;
  1968				ret = -1;
  1969			}
  1970			if (ret < 0) {
  1971				if (!discarded)
  1972					pr_info("Ring buffer meta [%d] invalid buffer page detected\n",
  1973						cpu_buffer->cpu);
  1974				discarded++;
  1975			} else {
  1976				entries += ret;
  1977				entry_bytes += rb_page_size(head_page);
  1978				if (ret > 0)
  1979					local_inc(&cpu_buffer->pages_touched);
  1980				ts = head_page->page->time_stamp;
  1981			}
  1982		}
  1983		if (i)
  1984			pr_info("Ring buffer [%d] rewound %d pages\n", cpu_buffer->cpu, i);
  1985	
  1986		/* The last rewound page must be skipped. */
  1987		if (head_page != orig_head)
  1988			rb_inc_page(&head_page);
  1989	
  1990		/*
  1991		 * If the ring buffer was rewound, then inject the reader page
  1992		 * into the location just before the original head page.
  1993		 */
  1994		if (head_page != orig_head) {
  1995			struct buffer_page *bpage = orig_head;
  1996	
  1997			rb_dec_page(&bpage);
  1998			/*
  1999			 * Insert the reader_page before the original head page.
  2000			 * Since the list encode RB_PAGE flags, general list
  2001			 * operations should be avoided.
  2002			 */
  2003			cpu_buffer->reader_page->list.next = &orig_head->list;
  2004			cpu_buffer->reader_page->list.prev = orig_head->list.prev;
  2005			orig_head->list.prev = &cpu_buffer->reader_page->list;
  2006			bpage->list.next = &cpu_buffer->reader_page->list;
  2007	
  2008			/* Make the head_page the reader page */
  2009			cpu_buffer->reader_page = head_page;
  2010			bpage = head_page;
  2011			rb_inc_page(&head_page);
  2012			head_page->list.prev = bpage->list.prev;
  2013			rb_dec_page(&bpage);
  2014			bpage->list.next = &head_page->list;
  2015			rb_set_list_to_head(&bpage->list);
  2016			cpu_buffer->pages = &head_page->list;
  2017	
  2018			cpu_buffer->head_page = head_page;
  2019			meta->head_buffer = (unsigned long)head_page->page;
  2020	
  2021			/* Reset all the indexes */
  2022			bpage = cpu_buffer->reader_page;
  2023			meta->buffers[0] = rb_meta_subbuf_idx(meta, bpage->page);
  2024			bpage->id = 0;
  2025	
  2026			for (i = 1, bpage = head_page; i < meta->nr_subbufs;
  2027			     i++, rb_inc_page(&bpage)) {
  2028				meta->buffers[i] = rb_meta_subbuf_idx(meta, bpage->page);
  2029				bpage->id = i;
  2030			}
  2031	
  2032			/* We'll restart verifying from orig_head */
  2033			head_page = orig_head;
  2034		}
  2035	
  2036	 skip_rewind:
  2037		/* If the commit_buffer is the reader page, update the commit page */
  2038		if (meta->commit_buffer == (unsigned long)cpu_buffer->reader_page->page) {
  2039			cpu_buffer->commit_page = cpu_buffer->reader_page;
  2040			/* Nothing more to do, the only page is the reader page */
  2041			goto done;
  2042		}
  2043	
  2044		/* Iterate until finding the commit page */
  2045		for (i = 0; i < meta->nr_subbufs + 1; i++, rb_inc_page(&head_page)) {
  2046	
  2047			/* Reader page has already been done */
  2048			if (head_page == cpu_buffer->reader_page)
  2049				continue;
  2050	
  2051			ret = rb_validate_buffer(head_page, cpu_buffer->cpu, meta);
  2052			if (ret < 0) {
  2053				if (!discarded)
  2054					pr_info("Ring buffer meta [%d] invalid buffer page detected\n",
  2055						cpu_buffer->cpu);
  2056				discarded++;
  2057			} else {
  2058				/* If the buffer has content, update pages_touched */
  2059				if (ret)
  2060					local_inc(&cpu_buffer->pages_touched);
  2061	
  2062				entries += ret;
  2063				entry_bytes += rb_page_size(head_page);
  2064			}
  2065			if (head_page == cpu_buffer->commit_page)
  2066				break;
  2067		}
  2068	
  2069		if (head_page != cpu_buffer->commit_page) {
  2070			pr_info("Ring buffer meta [%d] commit page not found\n",
  2071				cpu_buffer->cpu);
  2072			goto invalid;
  2073		}
  2074	 done:
  2075		local_set(&cpu_buffer->entries, entries);
  2076		local_set(&cpu_buffer->entries_bytes, entry_bytes);
  2077	
  2078		pr_info("Ring buffer meta [%d] is from previous boot! (%d pages discarded)\n",
  2079			cpu_buffer->cpu, discarded);
  2080		return;
  2081	
  2082	 invalid:
  2083		/* The content of the buffers are invalid, reset the meta data */
  2084		meta->head_buffer = 0;
  2085		meta->commit_buffer = 0;
  2086	
  2087		/* Reset the reader page */
  2088		local_set(&cpu_buffer->reader_page->entries, 0);
  2089		local_set(&cpu_buffer->reader_page->page->commit, 0);
  2090	
  2091		/* Reset all the subbuffers */
  2092		for (i = 0; i < meta->nr_subbufs - 1; i++, rb_inc_page(&head_page)) {
  2093			local_set(&head_page->entries, 0);
  2094			rb_init_page(head_page->page);
  2095		}
  2096	}
  2097	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH v11 4/5] ring-buffer: Skip invalid sub-buffers when rewinding persistent ring buffer
Posted by Masami Hiramatsu (Google) 2 weeks ago
On Mon, 23 Mar 2026 07:18:07 +0800
kernel test robot <lkp@intel.com> wrote:

> Hi Masami,
> 
> kernel test robot noticed the following build errors:
> 
> [auto build test ERROR on trace/for-next]
> [also build test ERROR on geert-m68k/for-next geert-m68k/for-linus openrisc/for-next deller-parisc/for-next powerpc/next powerpc/fixes s390/features uml/next tip/x86/core uml/fixes v7.0-rc4 next-20260320]
> [cannot apply to linus/master]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Masami-Hiramatsu-Google/ring-buffer-Fix-to-update-per-subbuf-entries-of-persistent-ring-buffer/20260322-122412
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace for-next
> patch link:    https://lore.kernel.org/r/177391156211.193994.7531495945584650297.stgit%40mhiramat.tok.corp.google.com
> patch subject: [PATCH v11 4/5] ring-buffer: Skip invalid sub-buffers when rewinding persistent ring buffer
> config: x86_64-kexec (https://download.01.org/0day-ci/archive/20260323/202603230725.uMAZiKJx-lkp@intel.com/config)
> compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260323/202603230725.uMAZiKJx-lkp@intel.com/reproduce)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202603230725.uMAZiKJx-lkp@intel.com/
> 
> All errors (new ones prefixed by >>):
> 
> >> kernel/trace/ring_buffer.c:1965:15: error: use of undeclared identifier 'bpage'
>     1965 |                         local_set(&bpage->entries, 0);
>          |                                    ^
>    kernel/trace/ring_buffer.c:1966:15: error: use of undeclared identifier 'bpage'
>     1966 |                         local_set(&bpage->page->commit, 0);
>          |                                    ^
>    2 errors generated.
> 
> 
> vim +/bpage +1965 kernel/trace/ring_buffer.c
> 
>   1910	
>   1911	/* If the meta data has been validated, now validate the events */
>   1912	static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
>   1913	{
>   1914		struct ring_buffer_cpu_meta *meta = cpu_buffer->ring_meta;
>   1915		struct buffer_page *head_page, *orig_head;
>   1916		unsigned long entry_bytes = 0;
>   1917		unsigned long entries = 0;
>   1918		int discarded = 0;
>   1919		int ret;
>   1920		u64 ts;
>   1921		int i;
>   1922	
>   1923		if (!meta || !meta->head_buffer)
>   1924			return;
>   1925	
>   1926		orig_head = head_page = cpu_buffer->head_page;
>   1927	
>   1928		/* Do the reader page first */
>   1929		ret = rb_validate_buffer(cpu_buffer->reader_page, cpu_buffer->cpu, meta);
>   1930		if (ret < 0) {
>   1931			pr_info("Ring buffer meta [%d] invalid reader page detected\n",
>   1932				cpu_buffer->cpu);
>   1933			discarded++;
>   1934		} else {
>   1935			entries += ret;
>   1936			entry_bytes += rb_page_size(cpu_buffer->reader_page);
>   1937		}
>   1938	
>   1939		ts = head_page->page->time_stamp;
>   1940	
>   1941		/*
>   1942		 * Try to rewind the head so that we can read the pages which already
>   1943		 * read in the previous boot.
>   1944		 */
>   1945		if (head_page == cpu_buffer->tail_page)
>   1946			goto skip_rewind;
>   1947	
>   1948		rb_dec_page(&head_page);
>   1949		for (i = 0; i < meta->nr_subbufs + 1; i++, rb_dec_page(&head_page)) {
>   1950	
>   1951			/* Rewind until tail (writer) page. */
>   1952			if (head_page == cpu_buffer->tail_page)
>   1953				break;
>   1954	
>   1955			/* Rewind until unused page (no timestamp, no commit). */
>   1956			if (!head_page->page->time_stamp && rb_page_commit(head_page) == 0)
>   1957				break;
>   1958	
>   1959			/*
>   1960			 * Skip if the page is invalid, or its timestamp is newer than the
>   1961			 * previous valid page.
>   1962			 */
>   1963			ret = rb_validate_buffer(head_page, cpu_buffer->cpu, meta);
>   1964			if (ret >= 0 && ts < head_page->page->time_stamp) {
> > 1965				local_set(&bpage->entries, 0);
>   1966				local_set(&bpage->page->commit, 0);

Ooops, sorry, I made a copy & paste mistake. this should be head_page->entries and head_page->page_commit.
Let me send v12 on the latest tracing/fixes.

Thanks,

>   1967				head_page->page->time_stamp = ts;
>   1968				ret = -1;
>   1969			}
>   1970			if (ret < 0) {
>   1971				if (!discarded)
>   1972					pr_info("Ring buffer meta [%d] invalid buffer page detected\n",
>   1973						cpu_buffer->cpu);
>   1974				discarded++;
>   1975			} else {
>   1976				entries += ret;
>   1977				entry_bytes += rb_page_size(head_page);
>   1978				if (ret > 0)
>   1979					local_inc(&cpu_buffer->pages_touched);
>   1980				ts = head_page->page->time_stamp;
>   1981			}
>   1982		}
>   1983		if (i)
>   1984			pr_info("Ring buffer [%d] rewound %d pages\n", cpu_buffer->cpu, i);
>   1985	
>   1986		/* The last rewound page must be skipped. */
>   1987		if (head_page != orig_head)
>   1988			rb_inc_page(&head_page);
>   1989	
>   1990		/*
>   1991		 * If the ring buffer was rewound, then inject the reader page
>   1992		 * into the location just before the original head page.
>   1993		 */
>   1994		if (head_page != orig_head) {
>   1995			struct buffer_page *bpage = orig_head;
>   1996	
>   1997			rb_dec_page(&bpage);
>   1998			/*
>   1999			 * Insert the reader_page before the original head page.
>   2000			 * Since the list encode RB_PAGE flags, general list
>   2001			 * operations should be avoided.
>   2002			 */
>   2003			cpu_buffer->reader_page->list.next = &orig_head->list;
>   2004			cpu_buffer->reader_page->list.prev = orig_head->list.prev;
>   2005			orig_head->list.prev = &cpu_buffer->reader_page->list;
>   2006			bpage->list.next = &cpu_buffer->reader_page->list;
>   2007	
>   2008			/* Make the head_page the reader page */
>   2009			cpu_buffer->reader_page = head_page;
>   2010			bpage = head_page;
>   2011			rb_inc_page(&head_page);
>   2012			head_page->list.prev = bpage->list.prev;
>   2013			rb_dec_page(&bpage);
>   2014			bpage->list.next = &head_page->list;
>   2015			rb_set_list_to_head(&bpage->list);
>   2016			cpu_buffer->pages = &head_page->list;
>   2017	
>   2018			cpu_buffer->head_page = head_page;
>   2019			meta->head_buffer = (unsigned long)head_page->page;
>   2020	
>   2021			/* Reset all the indexes */
>   2022			bpage = cpu_buffer->reader_page;
>   2023			meta->buffers[0] = rb_meta_subbuf_idx(meta, bpage->page);
>   2024			bpage->id = 0;
>   2025	
>   2026			for (i = 1, bpage = head_page; i < meta->nr_subbufs;
>   2027			     i++, rb_inc_page(&bpage)) {
>   2028				meta->buffers[i] = rb_meta_subbuf_idx(meta, bpage->page);
>   2029				bpage->id = i;
>   2030			}
>   2031	
>   2032			/* We'll restart verifying from orig_head */
>   2033			head_page = orig_head;
>   2034		}
>   2035	
>   2036	 skip_rewind:
>   2037		/* If the commit_buffer is the reader page, update the commit page */
>   2038		if (meta->commit_buffer == (unsigned long)cpu_buffer->reader_page->page) {
>   2039			cpu_buffer->commit_page = cpu_buffer->reader_page;
>   2040			/* Nothing more to do, the only page is the reader page */
>   2041			goto done;
>   2042		}
>   2043	
>   2044		/* Iterate until finding the commit page */
>   2045		for (i = 0; i < meta->nr_subbufs + 1; i++, rb_inc_page(&head_page)) {
>   2046	
>   2047			/* Reader page has already been done */
>   2048			if (head_page == cpu_buffer->reader_page)
>   2049				continue;
>   2050	
>   2051			ret = rb_validate_buffer(head_page, cpu_buffer->cpu, meta);
>   2052			if (ret < 0) {
>   2053				if (!discarded)
>   2054					pr_info("Ring buffer meta [%d] invalid buffer page detected\n",
>   2055						cpu_buffer->cpu);
>   2056				discarded++;
>   2057			} else {
>   2058				/* If the buffer has content, update pages_touched */
>   2059				if (ret)
>   2060					local_inc(&cpu_buffer->pages_touched);
>   2061	
>   2062				entries += ret;
>   2063				entry_bytes += rb_page_size(head_page);
>   2064			}
>   2065			if (head_page == cpu_buffer->commit_page)
>   2066				break;
>   2067		}
>   2068	
>   2069		if (head_page != cpu_buffer->commit_page) {
>   2070			pr_info("Ring buffer meta [%d] commit page not found\n",
>   2071				cpu_buffer->cpu);
>   2072			goto invalid;
>   2073		}
>   2074	 done:
>   2075		local_set(&cpu_buffer->entries, entries);
>   2076		local_set(&cpu_buffer->entries_bytes, entry_bytes);
>   2077	
>   2078		pr_info("Ring buffer meta [%d] is from previous boot! (%d pages discarded)\n",
>   2079			cpu_buffer->cpu, discarded);
>   2080		return;
>   2081	
>   2082	 invalid:
>   2083		/* The content of the buffers are invalid, reset the meta data */
>   2084		meta->head_buffer = 0;
>   2085		meta->commit_buffer = 0;
>   2086	
>   2087		/* Reset the reader page */
>   2088		local_set(&cpu_buffer->reader_page->entries, 0);
>   2089		local_set(&cpu_buffer->reader_page->page->commit, 0);
>   2090	
>   2091		/* Reset all the subbuffers */
>   2092		for (i = 0; i < meta->nr_subbufs - 1; i++, rb_inc_page(&head_page)) {
>   2093			local_set(&head_page->entries, 0);
>   2094			rb_init_page(head_page->page);
>   2095		}
>   2096	}
>   2097	
> 
> -- 
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki
> 


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>
Re: [PATCH v11 4/5] ring-buffer: Skip invalid sub-buffers when rewinding persistent ring buffer
Posted by kernel test robot 2 weeks, 1 day ago
Hi Masami,

kernel test robot noticed the following build errors:

[auto build test ERROR on trace/for-next]
[also build test ERROR on geert-m68k/for-next geert-m68k/for-linus openrisc/for-next deller-parisc/for-next powerpc/next powerpc/fixes s390/features uml/next tip/x86/core linus/master uml/fixes v7.0-rc4 next-20260320]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Masami-Hiramatsu-Google/ring-buffer-Fix-to-update-per-subbuf-entries-of-persistent-ring-buffer/20260322-122412
base:   https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace for-next
patch link:    https://lore.kernel.org/r/177391156211.193994.7531495945584650297.stgit%40mhiramat.tok.corp.google.com
patch subject: [PATCH v11 4/5] ring-buffer: Skip invalid sub-buffers when rewinding persistent ring buffer
config: arc-defconfig (https://download.01.org/0day-ci/archive/20260322/202603221806.j3AZggGX-lkp@intel.com/config)
compiler: arc-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260322/202603221806.j3AZggGX-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603221806.j3AZggGX-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from ./arch/arc/include/generated/asm/local.h:1,
                    from include/linux/ring_buffer_types.h:5,
                    from kernel/trace/ring_buffer.c:7:
   kernel/trace/ring_buffer.c: In function 'rb_meta_validate_events':
>> kernel/trace/ring_buffer.c:1965:36: error: 'bpage' undeclared (first use in this function); did you mean 'page'?
    1965 |                         local_set(&bpage->entries, 0);
         |                                    ^~~~~
   include/asm-generic/local.h:30:44: note: in definition of macro 'local_set'
      30 | #define local_set(l,i)  atomic_long_set((&(l)->a),(i))
         |                                            ^
   kernel/trace/ring_buffer.c:1965:36: note: each undeclared identifier is reported only once for each function it appears in
    1965 |                         local_set(&bpage->entries, 0);
         |                                    ^~~~~
   include/asm-generic/local.h:30:44: note: in definition of macro 'local_set'
      30 | #define local_set(l,i)  atomic_long_set((&(l)->a),(i))
         |                                            ^


vim +1965 kernel/trace/ring_buffer.c

  1910	
  1911	/* If the meta data has been validated, now validate the events */
  1912	static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
  1913	{
  1914		struct ring_buffer_cpu_meta *meta = cpu_buffer->ring_meta;
  1915		struct buffer_page *head_page, *orig_head;
  1916		unsigned long entry_bytes = 0;
  1917		unsigned long entries = 0;
  1918		int discarded = 0;
  1919		int ret;
  1920		u64 ts;
  1921		int i;
  1922	
  1923		if (!meta || !meta->head_buffer)
  1924			return;
  1925	
  1926		orig_head = head_page = cpu_buffer->head_page;
  1927	
  1928		/* Do the reader page first */
  1929		ret = rb_validate_buffer(cpu_buffer->reader_page, cpu_buffer->cpu, meta);
  1930		if (ret < 0) {
  1931			pr_info("Ring buffer meta [%d] invalid reader page detected\n",
  1932				cpu_buffer->cpu);
  1933			discarded++;
  1934		} else {
  1935			entries += ret;
  1936			entry_bytes += rb_page_size(cpu_buffer->reader_page);
  1937		}
  1938	
  1939		ts = head_page->page->time_stamp;
  1940	
  1941		/*
  1942		 * Try to rewind the head so that we can read the pages which already
  1943		 * read in the previous boot.
  1944		 */
  1945		if (head_page == cpu_buffer->tail_page)
  1946			goto skip_rewind;
  1947	
  1948		rb_dec_page(&head_page);
  1949		for (i = 0; i < meta->nr_subbufs + 1; i++, rb_dec_page(&head_page)) {
  1950	
  1951			/* Rewind until tail (writer) page. */
  1952			if (head_page == cpu_buffer->tail_page)
  1953				break;
  1954	
  1955			/* Rewind until unused page (no timestamp, no commit). */
  1956			if (!head_page->page->time_stamp && rb_page_commit(head_page) == 0)
  1957				break;
  1958	
  1959			/*
  1960			 * Skip if the page is invalid, or its timestamp is newer than the
  1961			 * previous valid page.
  1962			 */
  1963			ret = rb_validate_buffer(head_page, cpu_buffer->cpu, meta);
  1964			if (ret >= 0 && ts < head_page->page->time_stamp) {
> 1965				local_set(&bpage->entries, 0);
  1966				local_set(&bpage->page->commit, 0);
  1967				head_page->page->time_stamp = ts;
  1968				ret = -1;
  1969			}
  1970			if (ret < 0) {
  1971				if (!discarded)
  1972					pr_info("Ring buffer meta [%d] invalid buffer page detected\n",
  1973						cpu_buffer->cpu);
  1974				discarded++;
  1975			} else {
  1976				entries += ret;
  1977				entry_bytes += rb_page_size(head_page);
  1978				if (ret > 0)
  1979					local_inc(&cpu_buffer->pages_touched);
  1980				ts = head_page->page->time_stamp;
  1981			}
  1982		}
  1983		if (i)
  1984			pr_info("Ring buffer [%d] rewound %d pages\n", cpu_buffer->cpu, i);
  1985	
  1986		/* The last rewound page must be skipped. */
  1987		if (head_page != orig_head)
  1988			rb_inc_page(&head_page);
  1989	
  1990		/*
  1991		 * If the ring buffer was rewound, then inject the reader page
  1992		 * into the location just before the original head page.
  1993		 */
  1994		if (head_page != orig_head) {
  1995			struct buffer_page *bpage = orig_head;
  1996	
  1997			rb_dec_page(&bpage);
  1998			/*
  1999			 * Insert the reader_page before the original head page.
  2000			 * Since the list encode RB_PAGE flags, general list
  2001			 * operations should be avoided.
  2002			 */
  2003			cpu_buffer->reader_page->list.next = &orig_head->list;
  2004			cpu_buffer->reader_page->list.prev = orig_head->list.prev;
  2005			orig_head->list.prev = &cpu_buffer->reader_page->list;
  2006			bpage->list.next = &cpu_buffer->reader_page->list;
  2007	
  2008			/* Make the head_page the reader page */
  2009			cpu_buffer->reader_page = head_page;
  2010			bpage = head_page;
  2011			rb_inc_page(&head_page);
  2012			head_page->list.prev = bpage->list.prev;
  2013			rb_dec_page(&bpage);
  2014			bpage->list.next = &head_page->list;
  2015			rb_set_list_to_head(&bpage->list);
  2016			cpu_buffer->pages = &head_page->list;
  2017	
  2018			cpu_buffer->head_page = head_page;
  2019			meta->head_buffer = (unsigned long)head_page->page;
  2020	
  2021			/* Reset all the indexes */
  2022			bpage = cpu_buffer->reader_page;
  2023			meta->buffers[0] = rb_meta_subbuf_idx(meta, bpage->page);
  2024			bpage->id = 0;
  2025	
  2026			for (i = 1, bpage = head_page; i < meta->nr_subbufs;
  2027			     i++, rb_inc_page(&bpage)) {
  2028				meta->buffers[i] = rb_meta_subbuf_idx(meta, bpage->page);
  2029				bpage->id = i;
  2030			}
  2031	
  2032			/* We'll restart verifying from orig_head */
  2033			head_page = orig_head;
  2034		}
  2035	
  2036	 skip_rewind:
  2037		/* If the commit_buffer is the reader page, update the commit page */
  2038		if (meta->commit_buffer == (unsigned long)cpu_buffer->reader_page->page) {
  2039			cpu_buffer->commit_page = cpu_buffer->reader_page;
  2040			/* Nothing more to do, the only page is the reader page */
  2041			goto done;
  2042		}
  2043	
  2044		/* Iterate until finding the commit page */
  2045		for (i = 0; i < meta->nr_subbufs + 1; i++, rb_inc_page(&head_page)) {
  2046	
  2047			/* Reader page has already been done */
  2048			if (head_page == cpu_buffer->reader_page)
  2049				continue;
  2050	
  2051			ret = rb_validate_buffer(head_page, cpu_buffer->cpu, meta);
  2052			if (ret < 0) {
  2053				if (!discarded)
  2054					pr_info("Ring buffer meta [%d] invalid buffer page detected\n",
  2055						cpu_buffer->cpu);
  2056				discarded++;
  2057			} else {
  2058				/* If the buffer has content, update pages_touched */
  2059				if (ret)
  2060					local_inc(&cpu_buffer->pages_touched);
  2061	
  2062				entries += ret;
  2063				entry_bytes += rb_page_size(head_page);
  2064			}
  2065			if (head_page == cpu_buffer->commit_page)
  2066				break;
  2067		}
  2068	
  2069		if (head_page != cpu_buffer->commit_page) {
  2070			pr_info("Ring buffer meta [%d] commit page not found\n",
  2071				cpu_buffer->cpu);
  2072			goto invalid;
  2073		}
  2074	 done:
  2075		local_set(&cpu_buffer->entries, entries);
  2076		local_set(&cpu_buffer->entries_bytes, entry_bytes);
  2077	
  2078		pr_info("Ring buffer meta [%d] is from previous boot! (%d pages discarded)\n",
  2079			cpu_buffer->cpu, discarded);
  2080		return;
  2081	
  2082	 invalid:
  2083		/* The content of the buffers are invalid, reset the meta data */
  2084		meta->head_buffer = 0;
  2085		meta->commit_buffer = 0;
  2086	
  2087		/* Reset the reader page */
  2088		local_set(&cpu_buffer->reader_page->entries, 0);
  2089		local_set(&cpu_buffer->reader_page->page->commit, 0);
  2090	
  2091		/* Reset all the subbuffers */
  2092		for (i = 0; i < meta->nr_subbufs - 1; i++, rb_inc_page(&head_page)) {
  2093			local_set(&head_page->entries, 0);
  2094			rb_init_page(head_page->page);
  2095		}
  2096	}
  2097	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki