1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * in kernel monitor support: allows rv to control in-kernel monitors. 4 * 5 * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 6 */ 7 #include <getopt.h> 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <string.h> 11 #include <errno.h> 12 #include <unistd.h> 13 #include <dirent.h> 14 15 #include <trace.h> 16 #include <utils.h> 17 #include <rv.h> 18 19 static int config_has_id; 20 static int config_is_container; 21 static int config_my_pid; 22 static int config_trace; 23 24 static char *config_initial_reactor; 25 static char *config_reactor; 26 27 /* 28 * __ikm_read_enable - reads monitor's enable status 29 * 30 * __does not log errors. 31 * 32 * Returns the current status, or -1 if the monitor does not exist, 33 * __hence not logging errors. 34 */ 35 static int __ikm_read_enable(char *monitor_name) 36 { 37 char path[MAX_PATH]; 38 long long enabled; 39 int retval; 40 41 snprintf(path, MAX_PATH, "rv/monitors/%s/enable", monitor_name); 42 43 retval = tracefs_instance_file_read_number(NULL, path, &enabled); 44 if (retval < 0) 45 return -1; 46 47 return enabled; 48 } 49 50 /* 51 * __ikm_find_monitor - find the full name of a possibly nested module 52 * 53 * __does not log errors. 54 * 55 * Returns 1 if we found the monitor, -1 on error and 0 if it does not exist. 56 * The string out_name is populated with the full name, which can be 57 * equal to monitor_name or container/monitor_name if nested 58 */ 59 static int __ikm_find_monitor_name(char *monitor_name, char *out_name) 60 { 61 char *available_monitors, *cursor, *line; 62 int len = strlen(monitor_name); 63 int found = 0; 64 65 available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL); 66 if (!available_monitors) 67 return -1; 68 69 config_is_container = 0; 70 cursor = available_monitors; 71 while ((line = strsep(&cursor, "\n"))) { 72 char *colon = strchr(line, ':'); 73 74 if (strcmp(line, monitor_name) && (!colon || strcmp(colon + 1, monitor_name))) 75 continue; 76 77 strncpy(out_name, line, 2 * MAX_DA_NAME_LEN); 78 out_name[2 * MAX_DA_NAME_LEN - 1] = '\0'; 79 80 if (colon) { 81 out_name[colon - line] = '/'; 82 } else { 83 /* If there are children, they are on the next line. */ 84 line = strsep(&cursor, "\n"); 85 if (line && !strncmp(line, monitor_name, len) && line[len] == ':') 86 config_is_container = 1; 87 } 88 89 found = 1; 90 break; 91 } 92 93 free(available_monitors); 94 return found; 95 } 96 97 /* 98 * ikm_read_enable - reads monitor's enable status 99 * 100 * Returns the current status, or -1 on error. 101 */ 102 static int ikm_read_enable(char *monitor_name) 103 { 104 int enabled; 105 106 enabled = __ikm_read_enable(monitor_name); 107 if (enabled < 0) { 108 err_msg("ikm: fail read enabled: %d\n", enabled); 109 return -1; 110 } 111 112 debug_msg("ikm: read enabled: %d\n", enabled); 113 114 return enabled; 115 } 116 117 /* 118 * ikm_write_enable - write to the monitor's enable file 119 * 120 * Return the number of bytes written, -1 on error. 121 */ 122 static int ikm_write_enable(char *monitor_name, char *enable_disable) 123 { 124 char path[MAX_PATH]; 125 int retval; 126 127 debug_msg("ikm: writing enabled: %s\n", enable_disable); 128 129 snprintf(path, MAX_PATH, "rv/monitors/%s/enable", monitor_name); 130 retval = tracefs_instance_file_write(NULL, path, enable_disable); 131 if (retval < strlen(enable_disable)) { 132 err_msg("ikm: writing enabled: %s\n", enable_disable); 133 return -1; 134 } 135 136 return retval; 137 } 138 139 /* 140 * ikm_enable - enable a monitor 141 * 142 * Returns -1 on failure. Success otherwise. 143 */ 144 static int ikm_enable(char *monitor_name) 145 { 146 return ikm_write_enable(monitor_name, "1"); 147 } 148 149 /* 150 * ikm_disable - disable a monitor 151 * 152 * Returns -1 on failure. Success otherwise. 153 */ 154 static int ikm_disable(char *monitor_name) 155 { 156 return ikm_write_enable(monitor_name, "0"); 157 } 158 159 /* 160 * ikm_read_desc - read monitors' description 161 * 162 * Return a dynamically allocated string with the monitor's 163 * description, NULL otherwise. 164 */ 165 static char *ikm_read_desc(char *monitor_name) 166 { 167 char path[MAX_PATH]; 168 char *desc; 169 170 snprintf(path, MAX_PATH, "rv/monitors/%s/desc", monitor_name); 171 desc = tracefs_instance_file_read(NULL, path, NULL); 172 if (!desc) { 173 err_msg("ikm: error reading monitor %s desc\n", monitor_name); 174 return NULL; 175 } 176 177 *strstr(desc, "\n") = '\0'; 178 179 return desc; 180 } 181 182 /* 183 * ikm_fill_monitor_definition - fill monitor's definition 184 * 185 * Returns -1 on error, 1 if the monitor does not belong in the container, 0 otherwise. 186 * container can be NULL 187 */ 188 static int ikm_fill_monitor_definition(char *name, struct monitor *ikm, char *container) 189 { 190 int enabled; 191 char *desc, *nested_name; 192 193 nested_name = strstr(name, ":"); 194 if (nested_name) { 195 /* it belongs in container if it starts with "container:" */ 196 if (container && strstr(name, container) != name) 197 return 1; 198 *nested_name = '/'; 199 ++nested_name; 200 ikm->nested = 1; 201 } else { 202 if (container) 203 return 1; 204 nested_name = name; 205 ikm->nested = 0; 206 } 207 208 enabled = ikm_read_enable(name); 209 if (enabled < 0) { 210 err_msg("ikm: monitor %s fail to read enable file, bug?\n", name); 211 return -1; 212 } 213 214 desc = ikm_read_desc(name); 215 if (!desc) { 216 err_msg("ikm: monitor %s does not have desc file, bug?\n", name); 217 return -1; 218 } 219 220 strncpy(ikm->name, nested_name, sizeof(ikm->name) - 1); 221 ikm->name[sizeof(ikm->name) - 1] = '\0'; 222 ikm->enabled = enabled; 223 strncpy(ikm->desc, desc, sizeof(ikm->desc) - 1); 224 ikm->desc[sizeof(ikm->desc) - 1] = '\0'; 225 free(desc); 226 227 return 0; 228 } 229 230 /* 231 * ikm_write_reactor - switch the reactor to *reactor 232 * 233 * Return the number or characters written, -1 on error. 234 */ 235 static int ikm_write_reactor(char *monitor_name, char *reactor) 236 { 237 char path[MAX_PATH]; 238 int retval; 239 240 snprintf(path, MAX_PATH, "rv/monitors/%s/reactors", monitor_name); 241 retval = tracefs_instance_file_write(NULL, path, reactor); 242 debug_msg("ikm: write \"%s\" reactors: %d\n", reactor, retval); 243 244 return retval; 245 } 246 247 /* 248 * ikm_read_reactor - read the reactors file 249 * 250 * Returns a dynamically allocated string with monitor's 251 * available reactors, or NULL on error. 252 */ 253 static char *ikm_read_reactor(char *monitor_name) 254 { 255 char path[MAX_PATH]; 256 char *reactors; 257 258 snprintf(path, MAX_PATH, "rv/monitors/%s/reactors", monitor_name); 259 reactors = tracefs_instance_file_read(NULL, path, NULL); 260 if (!reactors) { 261 err_msg("ikm: fail reading monitor's %s reactors file\n", monitor_name); 262 return NULL; 263 } 264 265 return reactors; 266 } 267 268 /* 269 * ikm_get_current_reactor - get the current enabled reactor 270 * 271 * Reads the reactors file and find the currently enabled 272 * [reactor]. 273 * 274 * Returns a dynamically allocated memory with the current 275 * reactor. NULL otherwise. 276 */ 277 static char *ikm_get_current_reactor(char *monitor_name) 278 { 279 char *reactors = ikm_read_reactor(monitor_name); 280 char *curr_reactor = NULL; 281 char *start; 282 char *end; 283 284 if (!reactors) 285 return NULL; 286 287 start = strstr(reactors, "["); 288 if (!start) 289 goto out_free; 290 291 start++; 292 293 end = strstr(start, "]"); 294 if (!end) 295 goto out_free; 296 297 *end = '\0'; 298 299 curr_reactor = calloc(strlen(start) + 1, sizeof(char)); 300 if (!curr_reactor) 301 goto out_free; 302 303 strncpy(curr_reactor, start, strlen(start)); 304 debug_msg("ikm: read current reactor %s\n", curr_reactor); 305 306 out_free: 307 free(reactors); 308 309 return curr_reactor; 310 } 311 312 static int ikm_has_id(char *monitor_name) 313 { 314 char path[MAX_PATH]; 315 char *format; 316 int has_id; 317 318 snprintf(path, MAX_PATH, "events/rv/event_%s/format", monitor_name); 319 format = tracefs_instance_file_read(NULL, path, NULL); 320 if (!format) { 321 err_msg("ikm: fail reading monitor's %s format event file\n", monitor_name); 322 return -1; 323 } 324 325 /* print fmt: "%d: %s x %s -> %s %s", REC->id, ... */ 326 has_id = !!strstr(format, "REC->id"); 327 328 debug_msg("ikm: monitor %s has id: %s\n", monitor_name, has_id ? "yes" : "no"); 329 330 free(format); 331 332 return has_id; 333 } 334 335 /** 336 * ikm_list_monitors - list all available monitors 337 * 338 * Returns 0 on success, -1 otherwise. 339 */ 340 int ikm_list_monitors(char *container) 341 { 342 char *available_monitors; 343 struct monitor ikm = {0}; 344 char *curr, *next; 345 int retval, list_monitor = 0; 346 347 available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL); 348 349 if (!available_monitors) { 350 err_msg("ikm: available monitors is not available, is CONFIG_RV enabled?\n"); 351 return -1; 352 } 353 354 curr = available_monitors; 355 do { 356 next = strstr(curr, "\n"); 357 *next = '\0'; 358 359 retval = ikm_fill_monitor_definition(curr, &ikm, container); 360 if (retval < 0) 361 err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr); 362 363 if (!retval) { 364 int indent = ikm.nested && !container; 365 366 list_monitor = 1; 367 printf("%s%-*s %s %s\n", indent ? " - " : "", 368 indent ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN, 369 ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]"); 370 } 371 curr = ++next; 372 373 } while (strlen(curr)); 374 375 if (!list_monitor) { 376 if (container) 377 printf("-- No monitor found in container %s --\n", container); 378 else 379 printf("-- No monitor found --\n"); 380 } 381 382 free(available_monitors); 383 384 return 0; 385 } 386 387 static void ikm_print_header(struct trace_seq *s) 388 { 389 trace_seq_printf(s, "%16s-%-8s %5s %5s ", "<TASK>", "PID", "[CPU]", "TYPE"); 390 if (config_has_id) 391 trace_seq_printf(s, "%8s ", "ID"); 392 393 trace_seq_printf(s, "%24s x %-24s -> %-24s %s\n", 394 "STATE", 395 "EVENT", 396 "NEXT_STATE", 397 "FINAL"); 398 399 trace_seq_printf(s, "%16s %-8s %5s %5s ", " | ", " | ", " | ", " | "); 400 401 if (config_has_id) 402 trace_seq_printf(s, "%8s ", " | "); 403 404 trace_seq_printf(s, "%24s %-24s %-24s %s\n", 405 " | ", 406 " | ", 407 " | ", 408 "|"); 409 410 } 411 412 /* 413 * ikm_event_handler - callback to handle event events 414 * 415 * Called any time a rv:"monitor"_event events is generated. 416 * It parses and prints event. 417 */ 418 static int 419 ikm_event_handler(struct trace_seq *s, struct tep_record *record, 420 struct tep_event *trace_event, void *context) 421 { 422 /* if needed: struct trace_instance *inst = context; */ 423 char *state, *event, *next_state; 424 unsigned long long final_state; 425 unsigned long long pid; 426 unsigned long long id; 427 int val; 428 bool missing_id; 429 430 if (config_has_id) 431 missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1); 432 433 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); 434 435 if (config_has_id && (config_my_pid == id)) 436 return 0; 437 else if (config_my_pid == pid) 438 return 0; 439 440 tep_print_event(trace_event->tep, s, record, "%16s-%-8d [%.3d] ", 441 TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU); 442 443 if (config_is_container) 444 tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); 445 else 446 trace_seq_printf(s, "event "); 447 448 if (config_has_id) { 449 if (missing_id) 450 /* placeholder if we are dealing with a mixed-type container*/ 451 trace_seq_printf(s, " "); 452 else 453 trace_seq_printf(s, "%8llu ", id); 454 } 455 456 state = tep_get_field_raw(s, trace_event, "state", record, &val, 0); 457 event = tep_get_field_raw(s, trace_event, "event", record, &val, 0); 458 next_state = tep_get_field_raw(s, trace_event, "next_state", record, &val, 0); 459 tep_get_field_val(s, trace_event, "final_state", record, &final_state, 1); 460 461 trace_seq_printf(s, "%24s x %-24s -> %-24s %s\n", 462 state, 463 event, 464 next_state, 465 final_state ? "Y" : "N"); 466 467 trace_seq_do_printf(s); 468 trace_seq_reset(s); 469 470 return 0; 471 } 472 473 /* 474 * ikm_error_handler - callback to handle error events 475 * 476 * Called any time a rv:"monitor"_errors events is generated. 477 * It parses and prints event. 478 */ 479 static int 480 ikm_error_handler(struct trace_seq *s, struct tep_record *record, 481 struct tep_event *trace_event, void *context) 482 { 483 unsigned long long pid, id; 484 int cpu = record->cpu; 485 char *state, *event; 486 int val; 487 bool missing_id; 488 489 if (config_has_id) 490 missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1); 491 492 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); 493 494 if (config_has_id && config_my_pid == id) 495 return 0; 496 else if (config_my_pid == pid) 497 return 0; 498 499 trace_seq_printf(s, "%8lld [%03d] ", pid, cpu); 500 501 if (config_is_container) 502 tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); 503 else 504 trace_seq_printf(s, "error "); 505 506 if (config_has_id) { 507 if (missing_id) 508 /* placeholder if we are dealing with a mixed-type container*/ 509 trace_seq_printf(s, " "); 510 else 511 trace_seq_printf(s, "%8llu ", id); 512 } 513 514 state = tep_get_field_raw(s, trace_event, "state", record, &val, 0); 515 event = tep_get_field_raw(s, trace_event, "event", record, &val, 0); 516 517 trace_seq_printf(s, "%24s x %s\n", state, event); 518 519 trace_seq_do_printf(s); 520 trace_seq_reset(s); 521 522 return 0; 523 } 524 525 static int ikm_enable_trace_events(char *monitor_name, struct trace_instance *inst) 526 { 527 char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */ 528 int retval; 529 530 snprintf(event, sizeof(event), "event_%s", monitor_name); 531 retval = tracefs_event_enable(inst->inst, "rv", event); 532 if (retval) 533 return -1; 534 535 tep_register_event_handler(inst->tep, -1, "rv", event, 536 ikm_event_handler, NULL); 537 538 snprintf(event, sizeof(event), "error_%s", monitor_name); 539 retval = tracefs_event_enable(inst->inst, "rv", event); 540 if (retval) 541 return -1; 542 543 tep_register_event_handler(inst->tep, -1, "rv", event, 544 ikm_error_handler, NULL); 545 546 /* set if at least 1 monitor has id in case of a container */ 547 config_has_id = ikm_has_id(monitor_name); 548 if (config_has_id < 0) 549 return -1; 550 551 552 return 0; 553 } 554 555 static int ikm_enable_trace_container(char *monitor_name, 556 struct trace_instance *inst) 557 { 558 DIR *dp; 559 char *abs_path, rv_path[MAX_PATH]; 560 struct dirent *ep; 561 int retval = 0; 562 563 snprintf(rv_path, MAX_PATH, "rv/monitors/%s", monitor_name); 564 abs_path = tracefs_instance_get_file(NULL, rv_path); 565 if (!abs_path) 566 return -1; 567 dp = opendir(abs_path); 568 if (!dp) 569 goto out_free; 570 571 while (!retval && (ep = readdir(dp))) { 572 if (ep->d_type != DT_DIR || ep->d_name[0] == '.') 573 continue; 574 retval = ikm_enable_trace_events(ep->d_name, inst); 575 } 576 577 closedir(dp); 578 out_free: 579 free(abs_path); 580 return retval; 581 } 582 583 /* 584 * ikm_setup_trace_instance - set up a tracing instance to collect data 585 * 586 * Create a trace instance, enable rv: events and enable the trace. 587 * 588 * Returns the trace_instance * with all set, NULL otherwise. 589 */ 590 static struct trace_instance *ikm_setup_trace_instance(char *monitor_name) 591 { 592 struct trace_instance *inst; 593 int retval; 594 595 if (!config_trace) 596 return NULL; 597 598 /* alloc data */ 599 inst = calloc(1, sizeof(*inst)); 600 if (!inst) { 601 err_msg("ikm: failed to allocate trace instance"); 602 goto out_err; 603 } 604 605 retval = trace_instance_init(inst, monitor_name); 606 if (retval) 607 goto out_free; 608 609 if (config_is_container) 610 retval = ikm_enable_trace_container(monitor_name, inst); 611 else 612 retval = ikm_enable_trace_events(monitor_name, inst); 613 if (retval) 614 goto out_inst; 615 616 /* ready to enable */ 617 tracefs_trace_on(inst->inst); 618 619 return inst; 620 621 out_inst: 622 trace_instance_destroy(inst); 623 out_free: 624 free(inst); 625 out_err: 626 return NULL; 627 } 628 629 /** 630 * ikm_destroy_trace_instance - destroy a previously created instance 631 */ 632 static void ikm_destroy_trace_instance(struct trace_instance *inst) 633 { 634 if (!inst) 635 return; 636 637 trace_instance_destroy(inst); 638 free(inst); 639 } 640 641 /* 642 * ikm_usage_print_reactors - print all available reactors, one per line. 643 */ 644 static void ikm_usage_print_reactors(void) 645 { 646 char *reactors = tracefs_instance_file_read(NULL, "rv/available_reactors", NULL); 647 char *start, *end; 648 649 if (!reactors) 650 return; 651 652 fprintf(stderr, " available reactors:"); 653 654 start = reactors; 655 end = strstr(start, "\n"); 656 657 while (end) { 658 *end = '\0'; 659 660 fprintf(stderr, " %s", start); 661 662 start = ++end; 663 end = strstr(start, "\n"); 664 } 665 666 fprintf(stderr, "\n"); 667 } 668 /* 669 * ikm_usage - print usage 670 */ 671 static void ikm_usage(int exit_val, char *monitor_name, const char *fmt, ...) 672 { 673 674 char message[1024]; 675 va_list ap; 676 int i; 677 678 static const char *const usage[] = { 679 "", 680 " -h/--help: print this menu and the reactor list", 681 " -r/--reactor 'reactor': enables the 'reactor'", 682 " -s/--self: when tracing (-t), also trace rv command", 683 " -t/--trace: trace monitor's event", 684 " -v/--verbose: print debug messages", 685 "", 686 NULL, 687 }; 688 689 va_start(ap, fmt); 690 vsnprintf(message, sizeof(message), fmt, ap); 691 va_end(ap); 692 693 fprintf(stderr, " %s\n", message); 694 695 fprintf(stderr, "\n usage: rv mon %s [-h] [-q] [-r reactor] [-s] [-v]", monitor_name); 696 697 for (i = 0; usage[i]; i++) 698 fprintf(stderr, "%s\n", usage[i]); 699 700 ikm_usage_print_reactors(); 701 exit(exit_val); 702 } 703 704 /* 705 * parse_arguments - parse arguments and set config 706 */ 707 static int parse_arguments(char *monitor_name, int argc, char **argv) 708 { 709 int c, retval; 710 711 config_my_pid = getpid(); 712 713 while (1) { 714 static struct option long_options[] = { 715 {"help", no_argument, 0, 'h'}, 716 {"reactor", required_argument, 0, 'r'}, 717 {"self", no_argument, 0, 's'}, 718 {"trace", no_argument, 0, 't'}, 719 {"verbose", no_argument, 0, 'v'}, 720 {0, 0, 0, 0} 721 }; 722 723 /* getopt_long stores the option index here. */ 724 int option_index = 0; 725 726 c = getopt_long(argc, argv, "hr:stv", long_options, &option_index); 727 728 /* detect the end of the options. */ 729 if (c == -1) 730 break; 731 732 switch (c) { 733 case 'h': 734 ikm_usage(0, monitor_name, "help:"); 735 break; 736 case 'r': 737 config_reactor = optarg; 738 break; 739 case 's': 740 config_my_pid = -1; 741 break; 742 case 't': 743 config_trace = 1; 744 break; 745 case 'v': 746 config_debug = 1; 747 break; 748 } 749 } 750 751 if (config_reactor) { 752 config_initial_reactor = ikm_get_current_reactor(monitor_name); 753 if (!config_initial_reactor) 754 ikm_usage(1, monitor_name, 755 "ikm: failed to read current reactor, are reactors enabled?"); 756 757 retval = ikm_write_reactor(monitor_name, config_reactor); 758 if (retval <= 0) 759 ikm_usage(1, monitor_name, 760 "ikm: failed to set %s reactor, is it available?", 761 config_reactor); 762 } 763 764 debug_msg("ikm: my pid is %d\n", config_my_pid); 765 766 return 0; 767 } 768 769 /** 770 * ikm_run_monitor - apply configs and run the monitor 771 * 772 * Returns 1 if a monitor was found an executed, 0 if no 773 * monitors were found, or -1 on error. 774 */ 775 int ikm_run_monitor(char *monitor_name, int argc, char **argv) 776 { 777 struct trace_instance *inst = NULL; 778 char *nested_name, full_name[2*MAX_DA_NAME_LEN]; 779 int retval; 780 781 nested_name = strstr(monitor_name, ":"); 782 if (nested_name) 783 ++nested_name; 784 else 785 nested_name = monitor_name; 786 787 retval = __ikm_find_monitor_name(monitor_name, full_name); 788 if (!retval) 789 return 0; 790 if (retval < 0) { 791 err_msg("ikm: error finding monitor %s\n", nested_name); 792 return -1; 793 } 794 795 retval = __ikm_read_enable(full_name); 796 if (retval) { 797 err_msg("ikm: monitor %s (in-kernel) is already enabled\n", nested_name); 798 return -1; 799 } 800 801 /* we should be good to go */ 802 retval = parse_arguments(full_name, argc, argv); 803 if (retval) 804 ikm_usage(1, nested_name, "ikm: failed parsing arguments"); 805 806 if (config_trace) { 807 inst = ikm_setup_trace_instance(nested_name); 808 if (!inst) 809 return -1; 810 } 811 812 retval = ikm_enable(full_name); 813 if (retval < 0) 814 goto out_free_instance; 815 816 if (config_trace) 817 ikm_print_header(inst->seq); 818 819 while (!should_stop()) { 820 if (config_trace) { 821 retval = tracefs_iterate_raw_events(inst->tep, 822 inst->inst, 823 NULL, 824 0, 825 collect_registered_events, 826 inst); 827 if (retval) { 828 err_msg("ikm: error reading trace buffer\n"); 829 break; 830 } 831 } 832 833 sleep(1); 834 } 835 836 ikm_disable(full_name); 837 ikm_destroy_trace_instance(inst); 838 839 if (config_reactor && config_initial_reactor) 840 ikm_write_reactor(full_name, config_initial_reactor); 841 842 return 1; 843 844 out_free_instance: 845 ikm_destroy_trace_instance(inst); 846 if (config_reactor && config_initial_reactor) 847 ikm_write_reactor(full_name, config_initial_reactor); 848 return -1; 849 } 850