Handle the file descriptor statedump
[lttngtop.git] / src / iostreamtop.c
CommitLineData
1fc22eb4
JD
1/*
2 * Copyright (C) 2011 Mathieu Bain <mathieu.bain@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
71bd7ce1
AM
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1fc22eb4
JD
16 */
17
b093de8a
MB
18#include <stdlib.h>
19#include <unistd.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <string.h>
1fc22eb4
JD
23#include <babeltrace/babeltrace.h>
24
25#include "lttngtoptypes.h"
26#include "common.h"
27#include "iostreamtop.h"
28
b093de8a
MB
29void add_file(struct processtop *proc, struct files *file, int fd)
30{
ceb3a221 31 struct files *tmp_file;
59288610 32 struct processtop *parent;
ceb3a221
MB
33 int size;
34
35 size = proc->process_files_table->len;
59288610
MB
36 parent = proc->threadparent;
37 if (parent)
38 insert_file(parent, fd);
ceb3a221 39 if (size <= fd) {
b093de8a
MB
40 g_ptr_array_set_size(proc->process_files_table, fd);
41 g_ptr_array_add(proc->process_files_table, file);
42 } else {
ceb3a221
MB
43 tmp_file = g_ptr_array_index(proc->process_files_table, fd);
44 if (tmp_file == NULL)
45 g_ptr_array_index(proc->process_files_table, fd) = file;
46 else {
47 if (strcmp(tmp_file->name, file->name) != 0) {
48 size = proc->process_files_table->len;
49 g_ptr_array_set_size(proc->process_files_table,
59288610 50 size+1);
ceb3a221
MB
51 g_ptr_array_index(proc->process_files_table,
52 size) = tmp_file;
53 g_ptr_array_index(proc->process_files_table,
54 fd) = file;
55 } else
56 tmp_file->flag = __NR_open;
57 }
b093de8a 58 }
59288610
MB
59 /*
60 * The file may have be created in the parent
61 */
62 if (file->flag == -1) {
63 file->fd = fd;
64 file->flag = __NR_open;
65 lttngtop.nbfiles++;
66 lttngtop.nbnewfiles++;
67 }
b093de8a
MB
68}
69
59288610
MB
70/*
71 * Edit the file
72 * Called by handled_statedump_filename
73 */
ceb3a221
MB
74void edit_file(struct processtop *proc, struct files *file, int fd)
75{
76 int size = proc->process_files_table->len;
77 struct files *tmpfile;
78
59288610
MB
79 if (fd >= size) {
80 add_file(proc, file, fd);
81 } else {
ceb3a221 82 tmpfile = g_ptr_array_index(proc->process_files_table, fd);
59288610
MB
83 if (tmpfile) {
84 tmpfile->name = strdup(file->name);
85 free(file);
86 } else
87 add_file(proc, file, fd);
ceb3a221
MB
88 }
89}
b093de8a
MB
90
91void insert_file(struct processtop *proc, int fd)
92{
93 struct files *tmp;
59288610
MB
94 struct files *tmp_parent;
95 struct processtop *parent;
b093de8a 96
59288610
MB
97 if (fd < 0)
98 return;
b093de8a
MB
99 if (fd >= proc->process_files_table->len) {
100 tmp = g_new0(struct files, 1);
101 tmp->name = "Unknown";
ceb3a221
MB
102 tmp->read = 0;
103 tmp->write = 0;
104 tmp->fd = fd;
59288610 105 tmp->flag = -1;
b093de8a
MB
106 add_file(proc, tmp, fd);
107 } else {
b093de8a
MB
108 tmp = g_ptr_array_index(proc->process_files_table, fd);
109 if (tmp == NULL) {
110 tmp = g_new0(struct files, 1);
111 tmp->name = "Unknown";
112 tmp->read = 0;
113 tmp->write = 0;
114 tmp->fd = fd;
59288610 115 tmp->flag = -1;
b093de8a 116 add_file(proc, tmp, fd);
59288610
MB
117 } else {
118 parent = proc->threadparent;
119 if (parent) {
120 tmp_parent = g_ptr_array_index(
121 parent->process_files_table, fd);
122 if (tmp_parent &&
123 (strcmp(tmp->name, tmp_parent->name)) != 0)
124 tmp->name = strdup(tmp_parent->name);
125 }
b093de8a
MB
126 }
127 }
128}
129
130void close_file(struct processtop *proc, int fd)
ceb3a221
MB
131{
132 struct files *file;
133
ceb3a221 134 file = get_file(proc, fd);
e05a35a6 135 if (file != NULL) {
ceb3a221 136 file->flag = __NR_close;
e05a35a6
JD
137 lttngtop.nbfiles--;
138 }
139 lttngtop.nbclosedfiles++;
ceb3a221
MB
140}
141
142struct files *get_file(struct processtop *proc, int fd)
b093de8a
MB
143{
144 int len;
ceb3a221 145 struct files *tmp = NULL;
b093de8a
MB
146
147 len = proc->process_files_table->len;
148
149 /*
150 * It is possible that a file was open before taking the trace
151 * and its fd could be greater than all of the others fd
152 * used by the process
153 */
ceb3a221
MB
154 if (fd < len && fd >= 0)
155 tmp = g_ptr_array_index(proc->process_files_table, fd);
b093de8a 156
b093de8a
MB
157 return tmp;
158}
159
160void show_table(GPtrArray *tab)
161{
162 int i;
163 struct files *file;
164
165 for (i = 0 ; i < tab->len; i++) {
166 file = g_ptr_array_index(tab, i);
167 if (file == NULL)
168 fprintf(stderr, "NULL, ");
169 else
170 fprintf(stderr, "%s, ", file->name);
171 }
172 fprintf(stderr, "]\n\n");
173}
1fc22eb4 174
ceb3a221
MB
175void show_history(struct file_history *history)
176{
177 struct file_history *tmp = history;
178
179 while (tmp != NULL) {
180 fprintf(stderr, "fd = %d, name = %s\n", tmp->file->fd,
181 tmp->file->name);
182 tmp = tmp->next;
183 }
184
185}
186
1fc22eb4 187int update_iostream_ret(struct lttngtop *ctx, int tid, char *comm,
d67167cd 188 unsigned long timestamp, uint64_t cpu_id, int ret)
1fc22eb4
JD
189{
190 struct processtop *tmp;
b093de8a 191 struct files *tmpfile;
1fc22eb4
JD
192 int err = 0;
193
194 tmp = get_proc(ctx, tid, comm, timestamp);
b093de8a
MB
195
196 if (tmp->syscall_info != NULL) {
197 if (tmp->syscall_info->type == __NR_read
198 && ret > 0) {
199 tmp->totalfileread += ret;
200 tmp->fileread += ret;
201 tmpfile = get_file(tmp, tmp->syscall_info->fd);
202 tmpfile->read += ret;
203 } else if (tmp->syscall_info->type == __NR_write
204 && ret > 0) {
205 tmp->totalfilewrite += ret;
206 tmp->filewrite += ret;
207 tmpfile = get_file(tmp, tmp->syscall_info->fd);
208 tmpfile->write += ret;
209 } else if (tmp->syscall_info->type == __NR_open
210 && ret > 0) {
ceb3a221
MB
211 tmpfile = tmp->files_history->file;
212 add_file(tmp, tmpfile, ret);
213 tmpfile->fd = ret;
b093de8a 214 } else {
1fc22eb4
JD
215 err = -1;
216 }
b093de8a
MB
217 g_free(tmp->syscall_info);
218 tmp->syscall_info = NULL;
219 }
1fc22eb4
JD
220 return err;
221}
222
d67167cd 223struct syscalls *create_syscall_info(unsigned int type, uint64_t cpu_id,
b093de8a
MB
224 unsigned int tid, int fd)
225{
226 struct syscalls *syscall_info;
227
228 syscall_info = g_new0(struct syscalls, 1);
229 syscall_info->type = type;
230 syscall_info->cpu_id = cpu_id;
231 syscall_info->tid = tid;
232 syscall_info->fd = fd;
233
234 return syscall_info;
235}
236
237struct file_history *create_file(struct file_history *history, char *file_name)
238{
239 struct files *new_file;
240 struct file_history *new_history;
241
242 new_file = g_new0(struct files, 1);
243 new_history = g_new0(struct file_history, 1);
244 new_file->name = strdup(file_name);
245 new_file->read = 0;
246 new_file->write = 0;
59288610 247 new_file->flag = -1;
b093de8a
MB
248 new_history->file = new_file;
249 new_history->next = history;
250
251 return new_history;
252}
253
1fc22eb4
JD
254enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
255 void *private_data)
256{
3ba84bed 257 const struct definition *scope;
1fc22eb4
JD
258 unsigned long timestamp;
259 char *comm;
260 uint64_t ret, tid;
d67167cd 261 uint64_t cpu_id;
1fc22eb4
JD
262
263 timestamp = bt_ctf_get_timestamp(call_data);
264 if (timestamp == -1ULL)
265 goto error;
266
1dec520a
JD
267 comm = get_context_comm(call_data);
268 tid = get_context_tid(call_data);
1fc22eb4
JD
269
270 scope = bt_ctf_get_top_level_scope(call_data,
271 BT_EVENT_FIELDS);
272 ret = bt_ctf_get_int64(bt_ctf_get_field(call_data,
273 scope, "_ret"));
274 if (bt_ctf_field_get_error()) {
275 fprintf(stderr, "Missing ret context info\n");
276 goto error;
277 }
278
d67167cd 279 cpu_id = get_cpu_id(call_data);
1fc22eb4
JD
280
281 /*
b093de8a
MB
282 * if we encounter an exit_syscall and
283 * it is not for a syscall read or write
1fc22eb4
JD
284 * we just abort the execution of this callback
285 */
286 if ((update_iostream_ret(&lttngtop, tid, comm, timestamp, cpu_id, ret)) < 0)
287 return BT_CB_ERROR_CONTINUE;
288
289 return BT_CB_OK;
290
291error:
292 return BT_CB_ERROR_STOP;
293}
294
295
296enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
297 void *private_data)
298{
3ba84bed 299 const struct definition *scope;
1fc22eb4 300 struct processtop *tmp;
1fc22eb4
JD
301 unsigned long timestamp;
302 uint64_t cpu_id;
59288610 303 int64_t tid, pid;
b093de8a 304 int fd;
1fc22eb4
JD
305
306 timestamp = bt_ctf_get_timestamp(call_data);
307 if (timestamp == -1ULL)
308 goto error;
309
1dec520a 310 tid = get_context_tid(call_data);
d67167cd 311 cpu_id = get_cpu_id(call_data);
1fc22eb4 312
59288610
MB
313 pid = get_context_pid(call_data);
314
b093de8a
MB
315 scope = bt_ctf_get_top_level_scope(call_data,
316 BT_EVENT_FIELDS);
317 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
318 scope, "_fd"));
319 if (bt_ctf_field_get_error()) {
320 fprintf(stderr, "Missing fd context info\n");
321 goto error;
322 }
323
59288610 324 tmp = get_proc_pid(&lttngtop, tid, pid, timestamp);
b093de8a
MB
325 tmp->syscall_info = create_syscall_info(__NR_write, cpu_id, tid, fd);
326
327 insert_file(tmp, fd);
1fc22eb4
JD
328
329 return BT_CB_OK;
330
331error:
332 return BT_CB_ERROR_STOP;
333}
334
335enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
336 void *private_data)
337{
338 struct processtop *tmp;
3ba84bed 339 const struct definition *scope;
1fc22eb4
JD
340 unsigned long timestamp;
341 uint64_t cpu_id;
59288610 342 int64_t tid, pid;
b093de8a 343 int fd;
1fc22eb4
JD
344
345 timestamp = bt_ctf_get_timestamp(call_data);
346 if (timestamp == -1ULL)
347 goto error;
348
1dec520a 349 tid = get_context_tid(call_data);
d67167cd 350 cpu_id = get_cpu_id(call_data);
1fc22eb4 351
59288610
MB
352 pid = get_context_pid(call_data);
353
b093de8a
MB
354 scope = bt_ctf_get_top_level_scope(call_data,
355 BT_EVENT_FIELDS);
356 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
357 scope, "_fd"));
358 if (bt_ctf_field_get_error()) {
359 fprintf(stderr, "Missing fd context info\n");
360 goto error;
361 }
362
59288610 363 tmp = get_proc_pid(&lttngtop, tid, pid, timestamp);
b093de8a
MB
364 tmp->syscall_info = create_syscall_info(__NR_read, cpu_id, tid, fd);
365
366 insert_file(tmp, fd);
367
368 return BT_CB_OK;
369
370error:
371 return BT_CB_ERROR_STOP;
372}
373
374
375enum bt_cb_ret handle_sys_open(struct bt_ctf_event *call_data,
376 void *private_data)
377{
378
379 struct processtop *tmp;
3ba84bed 380 const struct definition *scope;
b093de8a
MB
381 unsigned long timestamp;
382 uint64_t cpu_id;
59288610 383 int64_t tid, pid;
b093de8a
MB
384 char *file;
385
386 timestamp = bt_ctf_get_timestamp(call_data);
387 if (timestamp == -1ULL)
388 goto error;
389
1dec520a 390 tid = get_context_tid(call_data);
d67167cd 391 cpu_id = get_cpu_id(call_data);
b093de8a 392
59288610
MB
393 pid = get_context_pid(call_data);
394
b093de8a
MB
395 scope = bt_ctf_get_top_level_scope(call_data,
396 BT_EVENT_FIELDS);
397 file = bt_ctf_get_string(bt_ctf_get_field(call_data,
398 scope, "_filename"));
399 if (bt_ctf_field_get_error()) {
ceb3a221 400 fprintf(stderr, "Missing file name context info\n");
b093de8a
MB
401 goto error;
402 }
403
59288610 404 tmp = get_proc_pid(&lttngtop, tid, pid, timestamp);
b093de8a
MB
405 tmp->syscall_info = create_syscall_info(__NR_open, cpu_id, tid, -1);
406
407 tmp->files_history = create_file(tmp->files_history, file);
1fc22eb4
JD
408
409 return BT_CB_OK;
410
411error:
412 return BT_CB_ERROR_STOP;
413}
414
b093de8a
MB
415
416enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
417 void *private_data)
418{
3ba84bed 419 const struct definition *scope;
b093de8a 420 unsigned long timestamp;
59288610 421 int64_t tid, pid;
b093de8a 422 struct processtop *tmp;
b093de8a
MB
423 int fd;
424
425 timestamp = bt_ctf_get_timestamp(call_data);
426 if (timestamp == -1ULL)
427 goto error;
428
1dec520a 429 tid = get_context_tid(call_data);
b093de8a 430
59288610
MB
431 pid = get_context_pid(call_data);
432
b093de8a
MB
433 scope = bt_ctf_get_top_level_scope(call_data,
434 BT_EVENT_FIELDS);
435 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
436 scope, "_fd"));
437 if (bt_ctf_field_get_error()) {
438 fprintf(stderr, "Missing fd context info\n");
439 goto error;
440 }
441
59288610 442 tmp = get_proc_pid(&lttngtop, tid, pid, timestamp);
ceb3a221 443
b093de8a
MB
444 close_file(tmp, fd);
445
446 return BT_CB_OK;
447
448error:
449 return BT_CB_ERROR_STOP;
450}
59288610 451
ceb3a221
MB
452enum bt_cb_ret handle_statedump_file_descriptor(struct bt_ctf_event *call_data,
453 void *private_data)
454{
59288610
MB
455 const struct definition *scope;
456 struct processtop *parent;
ceb3a221
MB
457 struct files *file;
458 unsigned long timestamp;
59288610
MB
459 int64_t pid;
460 char *file_name;
ceb3a221
MB
461 int fd;
462
463 timestamp = bt_ctf_get_timestamp(call_data);
464 if (timestamp == -1ULL)
465 goto error;
466
ceb3a221
MB
467 scope = bt_ctf_get_top_level_scope(call_data,
468 BT_EVENT_FIELDS);
59288610
MB
469 pid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
470 scope, "_pid"));
ceb3a221
MB
471 if (bt_ctf_field_get_error()) {
472 fprintf(stderr, "Missing tid context info\n");
473 goto error;
474 }
475
476 scope = bt_ctf_get_top_level_scope(call_data,
477 BT_EVENT_FIELDS);
59288610 478 fd = bt_ctf_get_int64(bt_ctf_get_field(call_data,
ceb3a221
MB
479 scope, "_fd"));
480 if (bt_ctf_field_get_error()) {
481 fprintf(stderr, "Missing fd context info\n");
482 goto error;
483 }
484
485 scope = bt_ctf_get_top_level_scope(call_data,
486 BT_EVENT_FIELDS);
487 file_name = bt_ctf_get_string(bt_ctf_get_field(call_data,
488 scope, "_filename"));
489 if (bt_ctf_field_get_error()) {
490 fprintf(stderr, "Missing file name context info\n");
491 goto error;
492 }
493
59288610
MB
494 parent = get_proc_pid(&lttngtop, pid, pid, timestamp);
495 parent->files_history = create_file(parent->files_history, file_name);
496 file = parent->files_history->file;
497 edit_file(parent, file, fd);
ceb3a221
MB
498
499 return BT_CB_OK;
500
501error:
502 return BT_CB_ERROR_STOP;
503}
This page took 0.044396 seconds and 4 git commands to generate.