hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/tools/perf/util/data.c
....@@ -1,16 +1,163 @@
11 // SPDX-License-Identifier: GPL-2.0
22 #include <linux/compiler.h>
33 #include <linux/kernel.h>
4
+#include <linux/string.h>
5
+#include <linux/zalloc.h>
46 #include <sys/types.h>
57 #include <sys/stat.h>
68 #include <errno.h>
79 #include <fcntl.h>
810 #include <unistd.h>
911 #include <string.h>
12
+#include <asm/bug.h>
13
+#include <dirent.h>
1014
1115 #include "data.h"
12
-#include "util.h"
16
+#include "util.h" // rm_rf_perf_data()
1317 #include "debug.h"
18
+#include "header.h"
19
+#include <internal/lib.h>
20
+
21
+static void close_dir(struct perf_data_file *files, int nr)
22
+{
23
+ while (--nr >= 0) {
24
+ close(files[nr].fd);
25
+ zfree(&files[nr].path);
26
+ }
27
+ free(files);
28
+}
29
+
30
+void perf_data__close_dir(struct perf_data *data)
31
+{
32
+ close_dir(data->dir.files, data->dir.nr);
33
+}
34
+
35
+int perf_data__create_dir(struct perf_data *data, int nr)
36
+{
37
+ struct perf_data_file *files = NULL;
38
+ int i, ret;
39
+
40
+ if (WARN_ON(!data->is_dir))
41
+ return -EINVAL;
42
+
43
+ files = zalloc(nr * sizeof(*files));
44
+ if (!files)
45
+ return -ENOMEM;
46
+
47
+ for (i = 0; i < nr; i++) {
48
+ struct perf_data_file *file = &files[i];
49
+
50
+ ret = asprintf(&file->path, "%s/data.%d", data->path, i);
51
+ if (ret < 0)
52
+ goto out_err;
53
+
54
+ ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
55
+ if (ret < 0)
56
+ goto out_err;
57
+
58
+ file->fd = ret;
59
+ }
60
+
61
+ data->dir.version = PERF_DIR_VERSION;
62
+ data->dir.files = files;
63
+ data->dir.nr = nr;
64
+ return 0;
65
+
66
+out_err:
67
+ close_dir(files, i);
68
+ return ret;
69
+}
70
+
71
+int perf_data__open_dir(struct perf_data *data)
72
+{
73
+ struct perf_data_file *files = NULL;
74
+ struct dirent *dent;
75
+ int ret = -1;
76
+ DIR *dir;
77
+ int nr = 0;
78
+
79
+ /*
80
+ * Directory containing a single regular perf data file which is already
81
+ * open, means there is nothing more to do here.
82
+ */
83
+ if (perf_data__is_single_file(data))
84
+ return 0;
85
+
86
+ if (WARN_ON(!data->is_dir))
87
+ return -EINVAL;
88
+
89
+ /* The version is provided by DIR_FORMAT feature. */
90
+ if (WARN_ON(data->dir.version != PERF_DIR_VERSION))
91
+ return -1;
92
+
93
+ dir = opendir(data->path);
94
+ if (!dir)
95
+ return -EINVAL;
96
+
97
+ while ((dent = readdir(dir)) != NULL) {
98
+ struct perf_data_file *file;
99
+ char path[PATH_MAX];
100
+ struct stat st;
101
+
102
+ snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name);
103
+ if (stat(path, &st))
104
+ continue;
105
+
106
+ if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data.", 5))
107
+ continue;
108
+
109
+ ret = -ENOMEM;
110
+
111
+ file = realloc(files, (nr + 1) * sizeof(*files));
112
+ if (!file)
113
+ goto out_err;
114
+
115
+ files = file;
116
+ file = &files[nr++];
117
+
118
+ file->path = strdup(path);
119
+ if (!file->path)
120
+ goto out_err;
121
+
122
+ ret = open(file->path, O_RDONLY);
123
+ if (ret < 0)
124
+ goto out_err;
125
+
126
+ file->fd = ret;
127
+ file->size = st.st_size;
128
+ }
129
+
130
+ if (!files)
131
+ return -EINVAL;
132
+
133
+ data->dir.files = files;
134
+ data->dir.nr = nr;
135
+ return 0;
136
+
137
+out_err:
138
+ close_dir(files, nr);
139
+ return ret;
140
+}
141
+
142
+int perf_data__update_dir(struct perf_data *data)
143
+{
144
+ int i;
145
+
146
+ if (WARN_ON(!data->is_dir))
147
+ return -EINVAL;
148
+
149
+ for (i = 0; i < data->dir.nr; i++) {
150
+ struct perf_data_file *file = &data->dir.files[i];
151
+ struct stat st;
152
+
153
+ if (fstat(file->fd, &st))
154
+ return -1;
155
+
156
+ file->size = st.st_size;
157
+ }
158
+
159
+ return 0;
160
+}
14161
15162 static bool check_pipe(struct perf_data *data)
16163 {
....@@ -19,11 +166,11 @@
19166 int fd = perf_data__is_read(data) ?
20167 STDIN_FILENO : STDOUT_FILENO;
21168
22
- if (!data->file.path) {
169
+ if (!data->path) {
23170 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
24171 is_pipe = true;
25172 } else {
26
- if (!strcmp(data->file.path, "-"))
173
+ if (!strcmp(data->path, "-"))
27174 is_pipe = true;
28175 }
29176
....@@ -37,16 +184,44 @@
37184 {
38185 struct stat st;
39186
40
- if (!stat(data->file.path, &st) && st.st_size) {
41
- /* TODO check errors properly */
187
+ if (perf_data__is_read(data))
188
+ return 0;
189
+
190
+ if (!stat(data->path, &st) && st.st_size) {
42191 char oldname[PATH_MAX];
192
+ int ret;
193
+
43194 snprintf(oldname, sizeof(oldname), "%s.old",
44
- data->file.path);
45
- unlink(oldname);
46
- rename(data->file.path, oldname);
195
+ data->path);
196
+
197
+ ret = rm_rf_perf_data(oldname);
198
+ if (ret) {
199
+ pr_err("Can't remove old data: %s (%s)\n",
200
+ ret == -2 ?
201
+ "Unknown file found" : strerror(errno),
202
+ oldname);
203
+ return -1;
204
+ }
205
+
206
+ if (rename(data->path, oldname)) {
207
+ pr_err("Can't move data: %s (%s to %s)\n",
208
+ strerror(errno),
209
+ data->path, oldname);
210
+ return -1;
211
+ }
47212 }
48213
49214 return 0;
215
+}
216
+
217
+static bool is_dir(struct perf_data *data)
218
+{
219
+ struct stat st;
220
+
221
+ if (stat(data->path, &st))
222
+ return false;
223
+
224
+ return (st.st_mode & S_IFMT) == S_IFDIR;
50225 }
51226
52227 static int open_file_read(struct perf_data *data)
....@@ -82,7 +257,7 @@
82257 goto out_close;
83258 }
84259
85
- data->size = st.st_size;
260
+ data->file.size = st.st_size;
86261 return fd;
87262
88263 out_close:
....@@ -94,9 +269,6 @@
94269 {
95270 int fd;
96271 char sbuf[STRERR_BUFSIZE];
97
-
98
- if (check_backup(data))
99
- return -1;
100272
101273 fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
102274 S_IRUSR|S_IWUSR);
....@@ -115,8 +287,46 @@
115287 fd = perf_data__is_read(data) ?
116288 open_file_read(data) : open_file_write(data);
117289
290
+ if (fd < 0) {
291
+ zfree(&data->file.path);
292
+ return -1;
293
+ }
294
+
118295 data->file.fd = fd;
119
- return fd < 0 ? -1 : 0;
296
+ return 0;
297
+}
298
+
299
+static int open_file_dup(struct perf_data *data)
300
+{
301
+ data->file.path = strdup(data->path);
302
+ if (!data->file.path)
303
+ return -ENOMEM;
304
+
305
+ return open_file(data);
306
+}
307
+
308
+static int open_dir(struct perf_data *data)
309
+{
310
+ int ret;
311
+
312
+ /*
313
+ * So far we open only the header, so we can read the data version and
314
+ * layout.
315
+ */
316
+ if (asprintf(&data->file.path, "%s/data", data->path) < 0)
317
+ return -1;
318
+
319
+ if (perf_data__is_write(data) &&
320
+ mkdir(data->path, S_IRWXU) < 0)
321
+ return -1;
322
+
323
+ ret = open_file(data);
324
+
325
+ /* Cleanup whatever we managed to create so far. */
326
+ if (ret && perf_data__is_write(data))
327
+ rm_rf_perf_data(data->path);
328
+
329
+ return ret;
120330 }
121331
122332 int perf_data__open(struct perf_data *data)
....@@ -124,14 +334,25 @@
124334 if (check_pipe(data))
125335 return 0;
126336
127
- if (!data->file.path)
128
- data->file.path = "perf.data";
337
+ if (!data->path)
338
+ data->path = "perf.data";
129339
130
- return open_file(data);
340
+ if (check_backup(data))
341
+ return -1;
342
+
343
+ if (perf_data__is_read(data))
344
+ data->is_dir = is_dir(data);
345
+
346
+ return perf_data__is_dir(data) ?
347
+ open_dir(data) : open_file_dup(data);
131348 }
132349
133350 void perf_data__close(struct perf_data *data)
134351 {
352
+ if (perf_data__is_dir(data))
353
+ perf_data__close_dir(data);
354
+
355
+ zfree(&data->file.path);
135356 close(data->file.fd);
136357 }
137358
....@@ -149,9 +370,9 @@
149370
150371 int perf_data__switch(struct perf_data *data,
151372 const char *postfix,
152
- size_t pos, bool at_exit)
373
+ size_t pos, bool at_exit,
374
+ char **new_filepath)
153375 {
154
- char *new_filepath;
155376 int ret;
156377
157378 if (check_pipe(data))
....@@ -159,15 +380,15 @@
159380 if (perf_data__is_read(data))
160381 return -EINVAL;
161382
162
- if (asprintf(&new_filepath, "%s.%s", data->file.path, postfix) < 0)
383
+ if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0)
163384 return -ENOMEM;
164385
165386 /*
166387 * Only fire a warning, don't return error, continue fill
167388 * original file.
168389 */
169
- if (rename(data->file.path, new_filepath))
170
- pr_warning("Failed to rename %s to %s\n", data->file.path, new_filepath);
390
+ if (rename(data->path, *new_filepath))
391
+ pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath);
171392
172393 if (!at_exit) {
173394 close(data->file.fd);
....@@ -184,6 +405,55 @@
184405 }
185406 ret = data->file.fd;
186407 out:
187
- free(new_filepath);
188408 return ret;
189409 }
410
+
411
+unsigned long perf_data__size(struct perf_data *data)
412
+{
413
+ u64 size = data->file.size;
414
+ int i;
415
+
416
+ if (perf_data__is_single_file(data))
417
+ return size;
418
+
419
+ for (i = 0; i < data->dir.nr; i++) {
420
+ struct perf_data_file *file = &data->dir.files[i];
421
+
422
+ size += file->size;
423
+ }
424
+
425
+ return size;
426
+}
427
+
428
+int perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz)
429
+{
430
+ int ret;
431
+
432
+ if (!data->is_dir)
433
+ return -1;
434
+
435
+ ret = snprintf(buf, buf_sz, "%s/kcore_dir", data->path);
436
+ if (ret < 0 || (size_t)ret >= buf_sz)
437
+ return -1;
438
+
439
+ return mkdir(buf, S_IRWXU);
440
+}
441
+
442
+char *perf_data__kallsyms_name(struct perf_data *data)
443
+{
444
+ char *kallsyms_name;
445
+ struct stat st;
446
+
447
+ if (!data->is_dir)
448
+ return NULL;
449
+
450
+ if (asprintf(&kallsyms_name, "%s/kcore_dir/kallsyms", data->path) < 0)
451
+ return NULL;
452
+
453
+ if (stat(kallsyms_name, &st)) {
454
+ free(kallsyms_name);
455
+ return NULL;
456
+ }
457
+
458
+ return kallsyms_name;
459
+}