Skip to content

Commit ca296d3

Browse files
mhiramatrostedt
authored andcommitted
tracing: ring_buffer: Rewind persistent ring buffer on reboot
Rewind persistent ring buffer pages which have been read in the previous boot. Those pages are highly possible to be lost before writing it to the disk if the previous kernel crashed. In this case, the trace data is kept on the persistent ring buffer, but it can not be read because its commit size has been reset after read. This skips clearing the commit size of each sub-buffer and recover it after reboot. Note: If you read the previous boot data via trace_pipe, that is not accessible in that time. But reboot without clearing (or reusing) the read data, the read data is recovered again in the next boot. Thus, when you read the previous boot data, clear it by `echo > trace`. Cc: Mathieu Desnoyers <[email protected]> Link: https://lore.kernel.org/174899582116.955054.773265393511190051.stgit@mhiramat.tok.corp.google.com Signed-off-by: Masami Hiramatsu (Google) <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent d7b8f8e commit ca296d3

File tree

1 file changed

+100
-3
lines changed

1 file changed

+100
-3
lines changed

kernel/trace/ring_buffer.c

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,13 @@ static inline void rb_inc_page(struct buffer_page **bpage)
13581358
*bpage = list_entry(p, struct buffer_page, list);
13591359
}
13601360

1361+
static inline void rb_dec_page(struct buffer_page **bpage)
1362+
{
1363+
struct list_head *p = rb_list_head((*bpage)->list.prev);
1364+
1365+
*bpage = list_entry(p, struct buffer_page, list);
1366+
}
1367+
13611368
static struct buffer_page *
13621369
rb_set_head_page(struct ring_buffer_per_cpu *cpu_buffer)
13631370
{
@@ -1866,10 +1873,11 @@ static int rb_validate_buffer(struct buffer_data_page *dpage, int cpu)
18661873
static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
18671874
{
18681875
struct ring_buffer_cpu_meta *meta = cpu_buffer->ring_meta;
1869-
struct buffer_page *head_page;
1876+
struct buffer_page *head_page, *orig_head;
18701877
unsigned long entry_bytes = 0;
18711878
unsigned long entries = 0;
18721879
int ret;
1880+
u64 ts;
18731881
int i;
18741882

18751883
if (!meta || !meta->head_buffer)
@@ -1885,8 +1893,98 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
18851893
entry_bytes += local_read(&cpu_buffer->reader_page->page->commit);
18861894
local_set(&cpu_buffer->reader_page->entries, ret);
18871895

1888-
head_page = cpu_buffer->head_page;
1896+
orig_head = head_page = cpu_buffer->head_page;
1897+
ts = head_page->page->time_stamp;
1898+
1899+
/*
1900+
* Try to rewind the head so that we can read the pages which already
1901+
* read in the previous boot.
1902+
*/
1903+
if (head_page == cpu_buffer->tail_page)
1904+
goto skip_rewind;
1905+
1906+
rb_dec_page(&head_page);
1907+
for (i = 0; i < meta->nr_subbufs + 1; i++, rb_dec_page(&head_page)) {
1908+
1909+
/* Rewind until tail (writer) page. */
1910+
if (head_page == cpu_buffer->tail_page)
1911+
break;
1912+
1913+
/* Ensure the page has older data than head. */
1914+
if (ts < head_page->page->time_stamp)
1915+
break;
1916+
1917+
ts = head_page->page->time_stamp;
1918+
/* Ensure the page has correct timestamp and some data. */
1919+
if (!ts || rb_page_commit(head_page) == 0)
1920+
break;
18891921

1922+
/* Stop rewind if the page is invalid. */
1923+
ret = rb_validate_buffer(head_page->page, cpu_buffer->cpu);
1924+
if (ret < 0)
1925+
break;
1926+
1927+
/* Recover the number of entries and update stats. */
1928+
local_set(&head_page->entries, ret);
1929+
if (ret)
1930+
local_inc(&cpu_buffer->pages_touched);
1931+
entries += ret;
1932+
entry_bytes += rb_page_commit(head_page);
1933+
}
1934+
if (i)
1935+
pr_info("Ring buffer [%d] rewound %d pages\n", cpu_buffer->cpu, i);
1936+
1937+
/* The last rewound page must be skipped. */
1938+
if (head_page != orig_head)
1939+
rb_inc_page(&head_page);
1940+
1941+
/*
1942+
* If the ring buffer was rewound, then inject the reader page
1943+
* into the location just before the original head page.
1944+
*/
1945+
if (head_page != orig_head) {
1946+
struct buffer_page *bpage = orig_head;
1947+
1948+
rb_dec_page(&bpage);
1949+
/*
1950+
* Insert the reader_page before the original head page.
1951+
* Since the list encode RB_PAGE flags, general list
1952+
* operations should be avoided.
1953+
*/
1954+
cpu_buffer->reader_page->list.next = &orig_head->list;
1955+
cpu_buffer->reader_page->list.prev = orig_head->list.prev;
1956+
orig_head->list.prev = &cpu_buffer->reader_page->list;
1957+
bpage->list.next = &cpu_buffer->reader_page->list;
1958+
1959+
/* Make the head_page the reader page */
1960+
cpu_buffer->reader_page = head_page;
1961+
bpage = head_page;
1962+
rb_inc_page(&head_page);
1963+
head_page->list.prev = bpage->list.prev;
1964+
rb_dec_page(&bpage);
1965+
bpage->list.next = &head_page->list;
1966+
rb_set_list_to_head(&bpage->list);
1967+
cpu_buffer->pages = &head_page->list;
1968+
1969+
cpu_buffer->head_page = head_page;
1970+
meta->head_buffer = (unsigned long)head_page->page;
1971+
1972+
/* Reset all the indexes */
1973+
bpage = cpu_buffer->reader_page;
1974+
meta->buffers[0] = rb_meta_subbuf_idx(meta, bpage->page);
1975+
bpage->id = 0;
1976+
1977+
for (i = 1, bpage = head_page; i < meta->nr_subbufs;
1978+
i++, rb_inc_page(&bpage)) {
1979+
meta->buffers[i] = rb_meta_subbuf_idx(meta, bpage->page);
1980+
bpage->id = i;
1981+
}
1982+
1983+
/* We'll restart verifying from orig_head */
1984+
head_page = orig_head;
1985+
}
1986+
1987+
skip_rewind:
18901988
/* If the commit_buffer is the reader page, update the commit page */
18911989
if (meta->commit_buffer == (unsigned long)cpu_buffer->reader_page->page) {
18921990
cpu_buffer->commit_page = cpu_buffer->reader_page;
@@ -5342,7 +5440,6 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
53425440
*/
53435441
local_set(&cpu_buffer->reader_page->write, 0);
53445442
local_set(&cpu_buffer->reader_page->entries, 0);
5345-
local_set(&cpu_buffer->reader_page->page->commit, 0);
53465443
cpu_buffer->reader_page->real_end = 0;
53475444

53485445
spin:

0 commit comments

Comments
 (0)