hc
2024-05-10 9999e48639b3cecb08ffb37358bcba3b48161b29
kernel/tools/perf/util/data.c
....@@ -1,16 +1,165 @@
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
+ closedir(dir);
131
+ if (!files)
132
+ return -EINVAL;
133
+
134
+ data->dir.files = files;
135
+ data->dir.nr = nr;
136
+ return 0;
137
+
138
+out_err:
139
+ closedir(dir);
140
+ close_dir(files, nr);
141
+ return ret;
142
+}
143
+
144
+int perf_data__update_dir(struct perf_data *data)
145
+{
146
+ int i;
147
+
148
+ if (WARN_ON(!data->is_dir))
149
+ return -EINVAL;
150
+
151
+ for (i = 0; i < data->dir.nr; i++) {
152
+ struct perf_data_file *file = &data->dir.files[i];
153
+ struct stat st;
154
+
155
+ if (fstat(file->fd, &st))
156
+ return -1;
157
+
158
+ file->size = st.st_size;
159
+ }
160
+
161
+ return 0;
162
+}
14163
15164 static bool check_pipe(struct perf_data *data)
16165 {
....@@ -19,11 +168,11 @@
19168 int fd = perf_data__is_read(data) ?
20169 STDIN_FILENO : STDOUT_FILENO;
21170
22
- if (!data->file.path) {
171
+ if (!data->path) {
23172 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
24173 is_pipe = true;
25174 } else {
26
- if (!strcmp(data->file.path, "-"))
175
+ if (!strcmp(data->path, "-"))
27176 is_pipe = true;
28177 }
29178
....@@ -37,16 +186,44 @@
37186 {
38187 struct stat st;
39188
40
- if (!stat(data->file.path, &st) && st.st_size) {
41
- /* TODO check errors properly */
189
+ if (perf_data__is_read(data))
190
+ return 0;
191
+
192
+ if (!stat(data->path, &st) && st.st_size) {
42193 char oldname[PATH_MAX];
194
+ int ret;
195
+
43196 snprintf(oldname, sizeof(oldname), "%s.old",
44
- data->file.path);
45
- unlink(oldname);
46
- rename(data->file.path, oldname);
197
+ data->path);
198
+
199
+ ret = rm_rf_perf_data(oldname);
200
+ if (ret) {
201
+ pr_err("Can't remove old data: %s (%s)\n",
202
+ ret == -2 ?
203
+ "Unknown file found" : strerror(errno),
204
+ oldname);
205
+ return -1;
206
+ }
207
+
208
+ if (rename(data->path, oldname)) {
209
+ pr_err("Can't move data: %s (%s to %s)\n",
210
+ strerror(errno),
211
+ data->path, oldname);
212
+ return -1;
213
+ }
47214 }
48215
49216 return 0;
217
+}
218
+
219
+static bool is_dir(struct perf_data *data)
220
+{
221
+ struct stat st;
222
+
223
+ if (stat(data->path, &st))
224
+ return false;
225
+
226
+ return (st.st_mode & S_IFMT) == S_IFDIR;
50227 }
51228
52229 static int open_file_read(struct perf_data *data)
....@@ -82,7 +259,7 @@
82259 goto out_close;
83260 }
84261
85
- data->size = st.st_size;
262
+ data->file.size = st.st_size;
86263 return fd;
87264
88265 out_close:
....@@ -94,9 +271,6 @@
94271 {
95272 int fd;
96273 char sbuf[STRERR_BUFSIZE];
97
-
98
- if (check_backup(data))
99
- return -1;
100274
101275 fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
102276 S_IRUSR|S_IWUSR);
....@@ -115,8 +289,46 @@
115289 fd = perf_data__is_read(data) ?
116290 open_file_read(data) : open_file_write(data);
117291
292
+ if (fd < 0) {
293
+ zfree(&data->file.path);
294
+ return -1;
295
+ }
296
+
118297 data->file.fd = fd;
119
- return fd < 0 ? -1 : 0;
298
+ return 0;
299
+}
300
+
301
+static int open_file_dup(struct perf_data *data)
302
+{
303
+ data->file.path = strdup(data->path);
304
+ if (!data->file.path)
305
+ return -ENOMEM;
306
+
307
+ return open_file(data);
308
+}
309
+
310
+static int open_dir(struct perf_data *data)
311
+{
312
+ int ret;
313
+
314
+ /*
315
+ * So far we open only the header, so we can read the data version and
316
+ * layout.
317
+ */
318
+ if (asprintf(&data->file.path, "%s/data", data->path) < 0)
319
+ return -1;
320
+
321
+ if (perf_data__is_write(data) &&
322
+ mkdir(data->path, S_IRWXU) < 0)
323
+ return -1;
324
+
325
+ ret = open_file(data);
326
+
327
+ /* Cleanup whatever we managed to create so far. */
328
+ if (ret && perf_data__is_write(data))
329
+ rm_rf_perf_data(data->path);
330
+
331
+ return ret;
120332 }
121333
122334 int perf_data__open(struct perf_data *data)
....@@ -124,14 +336,25 @@
124336 if (check_pipe(data))
125337 return 0;
126338
127
- if (!data->file.path)
128
- data->file.path = "perf.data";
339
+ if (!data->path)
340
+ data->path = "perf.data";
129341
130
- return open_file(data);
342
+ if (check_backup(data))
343
+ return -1;
344
+
345
+ if (perf_data__is_read(data))
346
+ data->is_dir = is_dir(data);
347
+
348
+ return perf_data__is_dir(data) ?
349
+ open_dir(data) : open_file_dup(data);
131350 }
132351
133352 void perf_data__close(struct perf_data *data)
134353 {
354
+ if (perf_data__is_dir(data))
355
+ perf_data__close_dir(data);
356
+
357
+ zfree(&data->file.path);
135358 close(data->file.fd);
136359 }
137360
....@@ -149,9 +372,9 @@
149372
150373 int perf_data__switch(struct perf_data *data,
151374 const char *postfix,
152
- size_t pos, bool at_exit)
375
+ size_t pos, bool at_exit,
376
+ char **new_filepath)
153377 {
154
- char *new_filepath;
155378 int ret;
156379
157380 if (check_pipe(data))
....@@ -159,15 +382,15 @@
159382 if (perf_data__is_read(data))
160383 return -EINVAL;
161384
162
- if (asprintf(&new_filepath, "%s.%s", data->file.path, postfix) < 0)
385
+ if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0)
163386 return -ENOMEM;
164387
165388 /*
166389 * Only fire a warning, don't return error, continue fill
167390 * original file.
168391 */
169
- if (rename(data->file.path, new_filepath))
170
- pr_warning("Failed to rename %s to %s\n", data->file.path, new_filepath);
392
+ if (rename(data->path, *new_filepath))
393
+ pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath);
171394
172395 if (!at_exit) {
173396 close(data->file.fd);
....@@ -184,6 +407,55 @@
184407 }
185408 ret = data->file.fd;
186409 out:
187
- free(new_filepath);
188410 return ret;
189411 }
412
+
413
+unsigned long perf_data__size(struct perf_data *data)
414
+{
415
+ u64 size = data->file.size;
416
+ int i;
417
+
418
+ if (perf_data__is_single_file(data))
419
+ return size;
420
+
421
+ for (i = 0; i < data->dir.nr; i++) {
422
+ struct perf_data_file *file = &data->dir.files[i];
423
+
424
+ size += file->size;
425
+ }
426
+
427
+ return size;
428
+}
429
+
430
+int perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz)
431
+{
432
+ int ret;
433
+
434
+ if (!data->is_dir)
435
+ return -1;
436
+
437
+ ret = snprintf(buf, buf_sz, "%s/kcore_dir", data->path);
438
+ if (ret < 0 || (size_t)ret >= buf_sz)
439
+ return -1;
440
+
441
+ return mkdir(buf, S_IRWXU);
442
+}
443
+
444
+char *perf_data__kallsyms_name(struct perf_data *data)
445
+{
446
+ char *kallsyms_name;
447
+ struct stat st;
448
+
449
+ if (!data->is_dir)
450
+ return NULL;
451
+
452
+ if (asprintf(&kallsyms_name, "%s/kcore_dir/kallsyms", data->path) < 0)
453
+ return NULL;
454
+
455
+ if (stat(kallsyms_name, &st)) {
456
+ free(kallsyms_name);
457
+ return NULL;
458
+ }
459
+
460
+ return kallsyms_name;
461
+}