perf session: Fix infinite loop on invalid perf.data file

perf-record updates the header in the perf.data file at termination.
Without this update perf-report (and other processing built-ins) it
caused an infinite loop when perf report (or something like) called.

This is because the algorithm in __perf_session__process_events()
depends on the data_size which is read from file header.  Use file size
directly instead in this case to do the best-effort processing.

Signed-off-by: Namhyung Kim <[email protected]>
Tested-by: David Ahern <[email protected]>
Tested-by: Sonny Rao <[email protected]>
Acked-by: Ingo Molnar <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Sonny Rao <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: David Ahern <[email protected]>
[ Reworded warning as per Ingo Molnar suggestion, replaces 'perf.data'
  with session->filename, to precisely identify the data file involved ]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
This commit is contained in:
Namhyung Kim 2013-09-30 17:19:48 +09:00 • committed by Arnaldo Carvalho de Melo
commit b314e5cfd1
2 changed files with 13 additions and 1 deletions

View file

@ -2768,6 +2768,18 @@ int perf_session__read_header(struct perf_session *session)
if (perf_file_header__read(&f_header, header, fd) < 0)
return -EINVAL;
/*
* Sanity check that perf.data was written cleanly; data size is
* initialized to 0 and updated only if the on_exit function is run.
* If data size is still 0 then the file contains only partial
* information. Just warn user and process it as much as it can.
*/
if (f_header.data.size == 0) {
pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
"Was the 'perf record' command properly terminated?\n",
session->filename);
}
nr_attrs = f_header.attrs.size / f_header.attr_size;
lseek(fd, f_header.attrs.offset, SEEK_SET);

View file

@ -1312,7 +1312,7 @@ int __perf_session__process_events(struct perf_session *session,
file_offset = page_offset;
head = data_offset - page_offset;
if (data_offset + data_size < file_size)
if (data_size && (data_offset + data_size < file_size))
file_size = data_offset + data_size;
progress_next = file_size / 16;