diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index ddccc0eb7390..6007f1844b01 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -43,6 +43,8 @@ struct perf_inject { bool have_auxtrace; bool strip; bool jit_mode; + bool in_place_update; + bool in_place_update_dry_run; const char *input_name; struct perf_data output; u64 bytes_written; @@ -701,7 +703,7 @@ static int __cmd_inject(struct perf_inject *inject) int ret = -EINVAL; struct perf_session *session = inject->session; struct perf_data *data_out = &inject->output; - int fd = perf_data__fd(data_out); + int fd = inject->in_place_update ? -1 : perf_data__fd(data_out); u64 output_data_offset; signal(SIGINT, sig_handler); @@ -759,14 +761,14 @@ static int __cmd_inject(struct perf_inject *inject) if (!inject->itrace_synth_opts.set) auxtrace_index__free(&session->auxtrace_index); - if (!data_out->is_pipe) + if (!data_out->is_pipe && !inject->in_place_update) lseek(fd, output_data_offset, SEEK_SET); ret = perf_session__process_events(session); if (ret) return ret; - if (!data_out->is_pipe) { + if (!data_out->is_pipe && !inject->in_place_update) { if (inject->build_ids) perf_header__set_feat(&session->header, HEADER_BUILD_ID); @@ -900,7 +902,23 @@ int cmd_inject(int argc, const char **argv) return -1; } - if (perf_data__open(&inject.output)) { + if (inject.in_place_update) { + if (!strcmp(inject.input_name, "-")) { + pr_err("Input file name required for in-place updating\n"); + return -1; + } + if (strcmp(inject.output.path, "-")) { + pr_err("Output file name must not be specified for in-place updating\n"); + return -1; + } + if (!data.force && !inject.in_place_update_dry_run) { + pr_err("The input file would be updated in place, " + "the --force option is required.\n"); + return -1; + } + if (!inject.in_place_update_dry_run) + data.in_place_update = true; + } else if (perf_data__open(&inject.output)) { perror("failed to create output file"); return -1; } diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 8fca4779ae6a..a9c102e8e3c0 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c @@ -240,11 +240,12 @@ static bool is_dir(struct perf_data *data) static int open_file_read(struct perf_data *data) { + int flags = data->in_place_update ? O_RDWR : O_RDONLY; struct stat st; int fd; char sbuf[STRERR_BUFSIZE]; - fd = open(data->file.path, O_RDONLY); + fd = open(data->file.path, flags); if (fd < 0) { int err = errno; diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h index 62a3e66fbee8..c9de82af5584 100644 --- a/tools/perf/util/data.h +++ b/tools/perf/util/data.h @@ -31,6 +31,7 @@ struct perf_data { bool is_dir; bool force; bool use_stdio; + bool in_place_update; enum perf_data_mode mode; struct { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index aa1e42518d37..02b13c7a23be 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -3814,6 +3814,11 @@ int perf_session__read_header(struct perf_session *session) if (perf_file_header__read(&f_header, header, fd) < 0) return -EINVAL; + if (header->needs_swap && data->in_place_update) { + pr_err("In-place update not supported when byte-swapping is required\n"); + 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. diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 106b3d60881a..0dbb4f2628f3 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -2155,6 +2155,7 @@ struct reader { u64 data_size; u64 data_offset; reader_cb_t process; + bool in_place_update; }; static int @@ -2188,7 +2189,9 @@ reader__process_events(struct reader *rd, struct perf_session *session, mmap_prot = PROT_READ; mmap_flags = MAP_SHARED; - if (session->header.needs_swap) { + if (rd->in_place_update) { + mmap_prot |= PROT_WRITE; + } else if (session->header.needs_swap) { mmap_prot |= PROT_WRITE; mmap_flags = MAP_PRIVATE; } @@ -2274,6 +2277,7 @@ static int __perf_session__process_events(struct perf_session *session) .data_size = session->header.data_size, .data_offset = session->header.data_offset, .process = process_simple, + .in_place_update = session->data->in_place_update, }; struct ordered_events *oe = &session->ordered_events; struct perf_tool *tool = session->tool;