@@ -1129,14 +1129,52 @@ err:
tracecmd_warning("can't set kptr_restrict");
}
+static int copy_to_temp_fd(const char *path, tsize_t *size)
+{
+ char temp_path[] = "/tmp/trace_XXXXXX";
+ char buf[BUFSIZ];
+ int fd, temp_fd;
+ stsize_t r;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ goto fail;
+
+ temp_fd = mkstemp(temp_path);
+ if (temp_fd < 0)
+ goto fail_close;
+ unlink(temp_path);
+
+ *size = 0;
+ for (;;) {
+ r = read(fd, buf, sizeof(buf));
+ if (r == 0)
+ break;
+ if (r < 0 || __do_write_check(temp_fd, buf, r))
+ goto fail_close_temp;
+ *size += r;
+ }
+
+ if (lseek(temp_fd, 0, SEEK_SET) == (off_t)-1)
+ goto fail_close_temp;
+
+ close(fd);
+ return temp_fd;
+
+fail_close_temp:
+ close(temp_fd);
+fail_close:
+ close(fd);
+fail:
+ return -1;
+}
+
static int read_proc_kallsyms(struct tracecmd_output *handle, bool compress)
{
enum tracecmd_section_flags flags = 0;
- unsigned int size, check_size, endian4;
const char *path = "/proc/kallsyms";
- tsize_t offset;
- struct stat st;
- int ret;
+ tsize_t check_size, offset, size;
+ int endian4, fd, ret;
if (!tcmd_check_out_state(handle, TRACECMD_FILE_KALLSYMS)) {
tracecmd_warning("Cannot read kallsyms, unexpected state 0x%X",
@@ -1155,36 +1193,36 @@ static int read_proc_kallsyms(struct tracecmd_output *handle, bool compress)
return -1;
tcmd_out_compression_start(handle, compress);
- ret = stat(path, &st);
- if (ret < 0) {
+ set_proc_kptr_restrict(0);
+ fd = copy_to_temp_fd(path, &size);
+ set_proc_kptr_restrict(1);
+ if (fd < 0) {
/* not found */
size = 0;
endian4 = convert_endian_4(handle, size);
ret = tcmd_do_write_check(handle, &endian4, 4);
goto out;
}
- size = get_size(path);
endian4 = convert_endian_4(handle, size);
ret = tcmd_do_write_check(handle, &endian4, 4);
if (ret)
- goto out;
+ goto out_close;
- set_proc_kptr_restrict(0);
- check_size = copy_file(handle, path);
+ check_size = copy_file_fd(handle, fd, 0);
if (size != check_size) {
errno = EINVAL;
tracecmd_warning("error in size of file '%s'", path);
- set_proc_kptr_restrict(1);
ret = -1;
- goto out;
+ goto out_close;
}
- set_proc_kptr_restrict(1);
ret = tcmd_out_compression_end(handle, compress);
if (ret)
- goto out;
+ goto out_close;
ret = tcmd_out_update_section_header(handle, offset);
+out_close:
+ close(fd);
out:
if (!ret)
handle->file_state = TRACECMD_FILE_KALLSYMS;
Running BPF selftests under trace-cmd intermittently fails with: error in size of file '/proc/kallsyms' This is because these selftests load and unload BPF programs. bpf_prog_put() uses workqueues and RCU, so these programs disappear from /proc/kallsyms after a delay. trace-cmd reads /proc/kallsyms twice: the first time to compute its size, and the second time to copy it into the trace file. If the resulting sizes don't match, which is what happens in this case, recording fails. Fix by first copying /proc/kallsyms into a temporary file, and then into the trace file. An alternative would be to read it into a malloc()-ed buffer, but this would increase trace-cmd memory usage, since /proc/kallsyms can be a few dozen megabytes large. In case /tmp is tmpfs, both solutions are almost equivalent. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> --- lib/trace-cmd/trace-output.c | 66 ++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 14 deletions(-)