1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/compiler.h>
3 #include <linux/kernel.h>
4 #include <linux/string.h>
5 #include <linux/zalloc.h>
17 #include "util.h" // rm_rf_perf_data()
21 #include <internal/lib.h>
23 static void close_dir(struct perf_data_file
*files
, int nr
)
27 zfree(&files
[nr
].path
);
32 void perf_data__close_dir(struct perf_data
*data
)
34 close_dir(data
->dir
.files
, data
->dir
.nr
);
37 int perf_data__create_dir(struct perf_data
*data
, int nr
)
39 enum rlimit_action set_rlimit
= NO_CHANGE
;
40 struct perf_data_file
*files
= NULL
;
43 if (WARN_ON(!data
->is_dir
))
46 files
= zalloc(nr
* sizeof(*files
));
50 for (i
= 0; i
< nr
; i
++) {
51 struct perf_data_file
*file
= &files
[i
];
53 ret
= asprintf(&file
->path
, "%s/data.%d", data
->path
, i
);
60 ret
= open(file
->path
, O_RDWR
|O_CREAT
|O_TRUNC
, S_IRUSR
|S_IWUSR
);
63 * If using parallel threads to collect data,
64 * perf record needs at least 6 fds per CPU.
65 * When we run out of them try to increase the limits.
67 if (errno
== EMFILE
&& rlimit__increase_nofile(&set_rlimit
))
73 set_rlimit
= NO_CHANGE
;
78 data
->dir
.version
= PERF_DIR_VERSION
;
79 data
->dir
.files
= files
;
88 int perf_data__open_dir(struct perf_data
*data
)
90 struct perf_data_file
*files
= NULL
;
97 * Directory containing a single regular perf data file which is already
98 * open, means there is nothing more to do here.
100 if (perf_data__is_single_file(data
))
103 if (WARN_ON(!data
->is_dir
))
106 /* The version is provided by DIR_FORMAT feature. */
107 if (WARN_ON(data
->dir
.version
!= PERF_DIR_VERSION
))
110 dir
= opendir(data
->path
);
114 while ((dent
= readdir(dir
)) != NULL
) {
115 struct perf_data_file
*file
;
119 snprintf(path
, sizeof(path
), "%s/%s", data
->path
, dent
->d_name
);
123 if (!S_ISREG(st
.st_mode
) || strncmp(dent
->d_name
, "data.", 5))
128 file
= realloc(files
, (nr
+ 1) * sizeof(*files
));
135 file
->path
= strdup(path
);
139 ret
= open(file
->path
, O_RDONLY
);
144 file
->size
= st
.st_size
;
151 data
->dir
.files
= files
;
157 close_dir(files
, nr
);
161 int perf_data__update_dir(struct perf_data
*data
)
165 if (WARN_ON(!data
->is_dir
))
168 for (i
= 0; i
< data
->dir
.nr
; i
++) {
169 struct perf_data_file
*file
= &data
->dir
.files
[i
];
172 if (fstat(file
->fd
, &st
))
175 file
->size
= st
.st_size
;
181 static bool check_pipe(struct perf_data
*data
)
184 bool is_pipe
= false;
185 int fd
= perf_data__is_read(data
) ?
186 STDIN_FILENO
: STDOUT_FILENO
;
189 if (!fstat(fd
, &st
) && S_ISFIFO(st
.st_mode
))
192 if (!strcmp(data
->path
, "-"))
197 if (data
->use_stdio
) {
200 mode
= perf_data__is_read(data
) ? "r" : "w";
201 data
->file
.fptr
= fdopen(fd
, mode
);
203 if (data
->file
.fptr
== NULL
) {
205 data
->use_stdio
= false;
209 * When is_pipe and data->file.fd is given, use given fd
210 * instead of STDIN_FILENO or STDOUT_FILENO
212 } else if (data
->file
.fd
<= 0) {
217 return data
->is_pipe
= is_pipe
;
220 static int check_backup(struct perf_data
*data
)
224 if (perf_data__is_read(data
))
227 if (!stat(data
->path
, &st
) && st
.st_size
) {
228 char oldname
[PATH_MAX
];
231 snprintf(oldname
, sizeof(oldname
), "%s.old",
234 ret
= rm_rf_perf_data(oldname
);
236 pr_err("Can't remove old data: %s (%s)\n",
238 "Unknown file found" : strerror(errno
),
243 if (rename(data
->path
, oldname
)) {
244 pr_err("Can't move data: %s (%s to %s)\n",
246 data
->path
, oldname
);
254 static bool is_dir(struct perf_data
*data
)
258 if (stat(data
->path
, &st
))
261 return (st
.st_mode
& S_IFMT
) == S_IFDIR
;
264 static int open_file_read(struct perf_data
*data
)
266 int flags
= data
->in_place_update
? O_RDWR
: O_RDONLY
;
269 char sbuf
[STRERR_BUFSIZE
];
271 fd
= open(data
->file
.path
, flags
);
275 pr_err("failed to open %s: %s", data
->file
.path
,
276 str_error_r(err
, sbuf
, sizeof(sbuf
)));
277 if (err
== ENOENT
&& !strcmp(data
->file
.path
, "perf.data"))
278 pr_err(" (try 'perf record' first)");
283 if (fstat(fd
, &st
) < 0)
286 if (!data
->force
&& st
.st_uid
&& (st
.st_uid
!= geteuid())) {
287 pr_err("File %s not owned by current user or root (use -f to override)\n",
293 pr_info("zero-sized data (%s), nothing to do!\n",
298 data
->file
.size
= st
.st_size
;
306 static int open_file_write(struct perf_data
*data
)
309 char sbuf
[STRERR_BUFSIZE
];
311 fd
= open(data
->file
.path
, O_CREAT
|O_RDWR
|O_TRUNC
|O_CLOEXEC
,
315 pr_err("failed to open %s : %s\n", data
->file
.path
,
316 str_error_r(errno
, sbuf
, sizeof(sbuf
)));
321 static int open_file(struct perf_data
*data
)
325 fd
= perf_data__is_read(data
) ?
326 open_file_read(data
) : open_file_write(data
);
329 zfree(&data
->file
.path
);
337 static int open_file_dup(struct perf_data
*data
)
339 data
->file
.path
= strdup(data
->path
);
340 if (!data
->file
.path
)
343 return open_file(data
);
346 static int open_dir(struct perf_data
*data
)
351 * So far we open only the header, so we can read the data version and
354 if (asprintf(&data
->file
.path
, "%s/data", data
->path
) < 0)
357 if (perf_data__is_write(data
) &&
358 mkdir(data
->path
, S_IRWXU
) < 0)
361 ret
= open_file(data
);
363 /* Cleanup whatever we managed to create so far. */
364 if (ret
&& perf_data__is_write(data
))
365 rm_rf_perf_data(data
->path
);
370 int perf_data__open(struct perf_data
*data
)
372 if (check_pipe(data
))
375 /* currently it allows stdio for pipe only */
376 data
->use_stdio
= false;
379 data
->path
= "perf.data";
381 if (check_backup(data
))
384 if (perf_data__is_read(data
))
385 data
->is_dir
= is_dir(data
);
387 return perf_data__is_dir(data
) ?
388 open_dir(data
) : open_file_dup(data
);
391 void perf_data__close(struct perf_data
*data
)
393 if (perf_data__is_dir(data
))
394 perf_data__close_dir(data
);
396 zfree(&data
->file
.path
);
399 fclose(data
->file
.fptr
);
401 close(data
->file
.fd
);
404 ssize_t
perf_data__read(struct perf_data
*data
, void *buf
, size_t size
)
406 if (data
->use_stdio
) {
407 if (fread(buf
, size
, 1, data
->file
.fptr
) == 1)
409 return feof(data
->file
.fptr
) ? 0 : -1;
411 return readn(data
->file
.fd
, buf
, size
);
414 ssize_t
perf_data_file__write(struct perf_data_file
*file
,
415 void *buf
, size_t size
)
417 return writen(file
->fd
, buf
, size
);
420 ssize_t
perf_data__write(struct perf_data
*data
,
421 void *buf
, size_t size
)
423 if (data
->use_stdio
) {
424 if (fwrite(buf
, size
, 1, data
->file
.fptr
) == 1)
428 return perf_data_file__write(&data
->file
, buf
, size
);
431 int perf_data__switch(struct perf_data
*data
,
433 size_t pos
, bool at_exit
,
438 if (perf_data__is_read(data
))
441 if (asprintf(new_filepath
, "%s.%s", data
->path
, postfix
) < 0)
445 * Only fire a warning, don't return error, continue fill
448 if (rename(data
->path
, *new_filepath
))
449 pr_warning("Failed to rename %s to %s\n", data
->path
, *new_filepath
);
452 close(data
->file
.fd
);
453 ret
= perf_data__open(data
);
457 if (lseek(data
->file
.fd
, pos
, SEEK_SET
) == (off_t
)-1) {
459 pr_debug("Failed to lseek to %zu: %s",
460 pos
, strerror(errno
));
469 unsigned long perf_data__size(struct perf_data
*data
)
471 u64 size
= data
->file
.size
;
474 if (perf_data__is_single_file(data
))
477 for (i
= 0; i
< data
->dir
.nr
; i
++) {
478 struct perf_data_file
*file
= &data
->dir
.files
[i
];
486 int perf_data__make_kcore_dir(struct perf_data
*data
, char *buf
, size_t buf_sz
)
493 ret
= snprintf(buf
, buf_sz
, "%s/kcore_dir", data
->path
);
494 if (ret
< 0 || (size_t)ret
>= buf_sz
)
497 return mkdir(buf
, S_IRWXU
);
500 bool has_kcore_dir(const char *path
)
502 struct dirent
*d
= ERR_PTR(-EINVAL
);
503 const char *name
= "kcore_dir";
504 DIR *dir
= opendir(path
);
505 size_t n
= strlen(name
);
509 while (d
&& !result
) {
511 result
= d
? strncmp(d
->d_name
, name
, n
) : false;
519 char *perf_data__kallsyms_name(struct perf_data
*data
)
527 if (asprintf(&kallsyms_name
, "%s/kcore_dir/kallsyms", data
->path
) < 0)
530 if (stat(kallsyms_name
, &st
)) {
535 return kallsyms_name
;
538 char *perf_data__guest_kallsyms_name(struct perf_data
*data
, pid_t machine_pid
)
546 if (asprintf(&kallsyms_name
, "%s/kcore_dir__%d/kallsyms", data
->path
, machine_pid
) < 0)
549 if (stat(kallsyms_name
, &st
)) {
554 return kallsyms_name
;
557 bool is_perf_data(const char *path
)
563 file
= fopen(path
, "r");
567 if (fread(&magic
, 1, 8, file
) < 8)
570 ret
= is_perf_magic(magic
);