1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Base unit test (KUnit) API. 4 * 5 * Copyright (C) 2019, Google LLC. 6 * Author: Brendan Higgins <brendanhiggins@google.com> 7 */ 8 9 #include <kunit/resource.h> 10 #include <kunit/test.h> 11 #include <kunit/test-bug.h> 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/moduleparam.h> 15 #include <linux/panic.h> 16 #include <linux/sched/debug.h> 17 #include <linux/sched.h> 18 19 #include "debugfs.h" 20 #include "hooks-impl.h" 21 #include "string-stream.h" 22 #include "try-catch-impl.h" 23 24 /* 25 * Hook to fail the current test and print an error message to the log. 26 */ 27 void __printf(3, 4) __kunit_fail_current_test_impl(const char *file, int line, const char *fmt, ...) 28 { 29 va_list args; 30 int len; 31 char *buffer; 32 33 if (!current->kunit_test) 34 return; 35 36 kunit_set_failure(current->kunit_test); 37 38 /* kunit_err() only accepts literals, so evaluate the args first. */ 39 va_start(args, fmt); 40 len = vsnprintf(NULL, 0, fmt, args) + 1; 41 va_end(args); 42 43 buffer = kunit_kmalloc(current->kunit_test, len, GFP_KERNEL); 44 if (!buffer) 45 return; 46 47 va_start(args, fmt); 48 vsnprintf(buffer, len, fmt, args); 49 va_end(args); 50 51 kunit_err(current->kunit_test, "%s:%d: %s", file, line, buffer); 52 kunit_kfree(current->kunit_test, buffer); 53 } 54 55 /* 56 * Enable KUnit tests to run. 57 */ 58 #ifdef CONFIG_KUNIT_DEFAULT_ENABLED 59 static bool enable_param = true; 60 #else 61 static bool enable_param; 62 #endif 63 module_param_named(enable, enable_param, bool, 0); 64 MODULE_PARM_DESC(enable, "Enable KUnit tests"); 65 66 /* 67 * KUnit statistic mode: 68 * 0 - disabled 69 * 1 - only when there is more than one subtest 70 * 2 - enabled 71 */ 72 static int kunit_stats_enabled = 1; 73 module_param_named(stats_enabled, kunit_stats_enabled, int, 0644); 74 MODULE_PARM_DESC(stats_enabled, 75 "Print test stats: never (0), only for multiple subtests (1), or always (2)"); 76 77 struct kunit_result_stats { 78 unsigned long passed; 79 unsigned long skipped; 80 unsigned long failed; 81 unsigned long total; 82 }; 83 84 static bool kunit_should_print_stats(struct kunit_result_stats stats) 85 { 86 if (kunit_stats_enabled == 0) 87 return false; 88 89 if (kunit_stats_enabled == 2) 90 return true; 91 92 return (stats.total > 1); 93 } 94 95 static void kunit_print_test_stats(struct kunit *test, 96 struct kunit_result_stats stats) 97 { 98 if (!kunit_should_print_stats(stats)) 99 return; 100 101 kunit_log(KERN_INFO, test, 102 KUNIT_SUBTEST_INDENT 103 "# %s: pass:%lu fail:%lu skip:%lu total:%lu", 104 test->name, 105 stats.passed, 106 stats.failed, 107 stats.skipped, 108 stats.total); 109 } 110 111 /* 112 * Append formatted message to log, size of which is limited to 113 * KUNIT_LOG_SIZE bytes (including null terminating byte). 114 */ 115 void kunit_log_append(char *log, const char *fmt, ...) 116 { 117 char line[KUNIT_LOG_SIZE]; 118 va_list args; 119 int len_left; 120 121 if (!log) 122 return; 123 124 len_left = KUNIT_LOG_SIZE - strlen(log) - 1; 125 if (len_left <= 0) 126 return; 127 128 va_start(args, fmt); 129 vsnprintf(line, sizeof(line), fmt, args); 130 va_end(args); 131 132 strncat(log, line, len_left); 133 } 134 EXPORT_SYMBOL_GPL(kunit_log_append); 135 136 size_t kunit_suite_num_test_cases(struct kunit_suite *suite) 137 { 138 struct kunit_case *test_case; 139 size_t len = 0; 140 141 kunit_suite_for_each_test_case(suite, test_case) 142 len++; 143 144 return len; 145 } 146 EXPORT_SYMBOL_GPL(kunit_suite_num_test_cases); 147 148 static void kunit_print_suite_start(struct kunit_suite *suite) 149 { 150 kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "KTAP version 1\n"); 151 kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "# Subtest: %s", 152 suite->name); 153 kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "1..%zd", 154 kunit_suite_num_test_cases(suite)); 155 } 156 157 static void kunit_print_ok_not_ok(void *test_or_suite, 158 bool is_test, 159 enum kunit_status status, 160 size_t test_number, 161 const char *description, 162 const char *directive) 163 { 164 struct kunit_suite *suite = is_test ? NULL : test_or_suite; 165 struct kunit *test = is_test ? test_or_suite : NULL; 166 const char *directive_header = (status == KUNIT_SKIPPED) ? " # SKIP " : ""; 167 168 /* 169 * We do not log the test suite results as doing so would 170 * mean debugfs display would consist of the test suite 171 * description and status prior to individual test results. 172 * Hence directly printk the suite status, and we will 173 * separately seq_printf() the suite status for the debugfs 174 * representation. 175 */ 176 if (suite) 177 pr_info("%s %zd %s%s%s\n", 178 kunit_status_to_ok_not_ok(status), 179 test_number, description, directive_header, 180 (status == KUNIT_SKIPPED) ? directive : ""); 181 else 182 kunit_log(KERN_INFO, test, 183 KUNIT_SUBTEST_INDENT "%s %zd %s%s%s", 184 kunit_status_to_ok_not_ok(status), 185 test_number, description, directive_header, 186 (status == KUNIT_SKIPPED) ? directive : ""); 187 } 188 189 enum kunit_status kunit_suite_has_succeeded(struct kunit_suite *suite) 190 { 191 const struct kunit_case *test_case; 192 enum kunit_status status = KUNIT_SKIPPED; 193 194 if (suite->suite_init_err) 195 return KUNIT_FAILURE; 196 197 kunit_suite_for_each_test_case(suite, test_case) { 198 if (test_case->status == KUNIT_FAILURE) 199 return KUNIT_FAILURE; 200 else if (test_case->status == KUNIT_SUCCESS) 201 status = KUNIT_SUCCESS; 202 } 203 204 return status; 205 } 206 EXPORT_SYMBOL_GPL(kunit_suite_has_succeeded); 207 208 static size_t kunit_suite_counter = 1; 209 210 static void kunit_print_suite_end(struct kunit_suite *suite) 211 { 212 kunit_print_ok_not_ok((void *)suite, false, 213 kunit_suite_has_succeeded(suite), 214 kunit_suite_counter++, 215 suite->name, 216 suite->status_comment); 217 } 218 219 unsigned int kunit_test_case_num(struct kunit_suite *suite, 220 struct kunit_case *test_case) 221 { 222 struct kunit_case *tc; 223 unsigned int i = 1; 224 225 kunit_suite_for_each_test_case(suite, tc) { 226 if (tc == test_case) 227 return i; 228 i++; 229 } 230 231 return 0; 232 } 233 EXPORT_SYMBOL_GPL(kunit_test_case_num); 234 235 static void kunit_print_string_stream(struct kunit *test, 236 struct string_stream *stream) 237 { 238 struct string_stream_fragment *fragment; 239 char *buf; 240 241 if (string_stream_is_empty(stream)) 242 return; 243 244 buf = string_stream_get_string(stream); 245 if (!buf) { 246 kunit_err(test, 247 "Could not allocate buffer, dumping stream:\n"); 248 list_for_each_entry(fragment, &stream->fragments, node) { 249 kunit_err(test, "%s", fragment->fragment); 250 } 251 kunit_err(test, "\n"); 252 } else { 253 kunit_err(test, "%s", buf); 254 kunit_kfree(test, buf); 255 } 256 } 257 258 static void kunit_fail(struct kunit *test, const struct kunit_loc *loc, 259 enum kunit_assert_type type, const struct kunit_assert *assert, 260 assert_format_t assert_format, const struct va_format *message) 261 { 262 struct string_stream *stream; 263 264 kunit_set_failure(test); 265 266 stream = alloc_string_stream(test, GFP_KERNEL); 267 if (IS_ERR(stream)) { 268 WARN(true, 269 "Could not allocate stream to print failed assertion in %s:%d\n", 270 loc->file, 271 loc->line); 272 return; 273 } 274 275 kunit_assert_prologue(loc, type, stream); 276 assert_format(assert, message, stream); 277 278 kunit_print_string_stream(test, stream); 279 280 string_stream_destroy(stream); 281 } 282 283 static void __noreturn kunit_abort(struct kunit *test) 284 { 285 kunit_try_catch_throw(&test->try_catch); /* Does not return. */ 286 287 /* 288 * Throw could not abort from test. 289 * 290 * XXX: we should never reach this line! As kunit_try_catch_throw is 291 * marked __noreturn. 292 */ 293 WARN_ONCE(true, "Throw could not abort from test!\n"); 294 } 295 296 void kunit_do_failed_assertion(struct kunit *test, 297 const struct kunit_loc *loc, 298 enum kunit_assert_type type, 299 const struct kunit_assert *assert, 300 assert_format_t assert_format, 301 const char *fmt, ...) 302 { 303 va_list args; 304 struct va_format message; 305 va_start(args, fmt); 306 307 message.fmt = fmt; 308 message.va = &args; 309 310 kunit_fail(test, loc, type, assert, assert_format, &message); 311 312 va_end(args); 313 314 if (type == KUNIT_ASSERTION) 315 kunit_abort(test); 316 } 317 EXPORT_SYMBOL_GPL(kunit_do_failed_assertion); 318 319 void kunit_init_test(struct kunit *test, const char *name, char *log) 320 { 321 spin_lock_init(&test->lock); 322 INIT_LIST_HEAD(&test->resources); 323 test->name = name; 324 test->log = log; 325 if (test->log) 326 test->log[0] = '\0'; 327 test->status = KUNIT_SUCCESS; 328 test->status_comment[0] = '\0'; 329 } 330 EXPORT_SYMBOL_GPL(kunit_init_test); 331 332 /* 333 * Initializes and runs test case. Does not clean up or do post validations. 334 */ 335 static void kunit_run_case_internal(struct kunit *test, 336 struct kunit_suite *suite, 337 struct kunit_case *test_case) 338 { 339 if (suite->init) { 340 int ret; 341 342 ret = suite->init(test); 343 if (ret) { 344 kunit_err(test, "failed to initialize: %d\n", ret); 345 kunit_set_failure(test); 346 return; 347 } 348 } 349 350 test_case->run_case(test); 351 } 352 353 static void kunit_case_internal_cleanup(struct kunit *test) 354 { 355 kunit_cleanup(test); 356 } 357 358 /* 359 * Performs post validations and cleanup after a test case was run. 360 * XXX: Should ONLY BE CALLED AFTER kunit_run_case_internal! 361 */ 362 static void kunit_run_case_cleanup(struct kunit *test, 363 struct kunit_suite *suite) 364 { 365 if (suite->exit) 366 suite->exit(test); 367 368 kunit_case_internal_cleanup(test); 369 } 370 371 struct kunit_try_catch_context { 372 struct kunit *test; 373 struct kunit_suite *suite; 374 struct kunit_case *test_case; 375 }; 376 377 static void kunit_try_run_case(void *data) 378 { 379 struct kunit_try_catch_context *ctx = data; 380 struct kunit *test = ctx->test; 381 struct kunit_suite *suite = ctx->suite; 382 struct kunit_case *test_case = ctx->test_case; 383 384 current->kunit_test = test; 385 386 /* 387 * kunit_run_case_internal may encounter a fatal error; if it does, 388 * abort will be called, this thread will exit, and finally the parent 389 * thread will resume control and handle any necessary clean up. 390 */ 391 kunit_run_case_internal(test, suite, test_case); 392 /* This line may never be reached. */ 393 kunit_run_case_cleanup(test, suite); 394 } 395 396 static void kunit_catch_run_case(void *data) 397 { 398 struct kunit_try_catch_context *ctx = data; 399 struct kunit *test = ctx->test; 400 struct kunit_suite *suite = ctx->suite; 401 int try_exit_code = kunit_try_catch_get_result(&test->try_catch); 402 403 if (try_exit_code) { 404 kunit_set_failure(test); 405 /* 406 * Test case could not finish, we have no idea what state it is 407 * in, so don't do clean up. 408 */ 409 if (try_exit_code == -ETIMEDOUT) { 410 kunit_err(test, "test case timed out\n"); 411 /* 412 * Unknown internal error occurred preventing test case from 413 * running, so there is nothing to clean up. 414 */ 415 } else { 416 kunit_err(test, "internal error occurred preventing test case from running: %d\n", 417 try_exit_code); 418 } 419 return; 420 } 421 422 /* 423 * Test case was run, but aborted. It is the test case's business as to 424 * whether it failed or not, we just need to clean up. 425 */ 426 kunit_run_case_cleanup(test, suite); 427 } 428 429 /* 430 * Performs all logic to run a test case. It also catches most errors that 431 * occur in a test case and reports them as failures. 432 */ 433 static void kunit_run_case_catch_errors(struct kunit_suite *suite, 434 struct kunit_case *test_case, 435 struct kunit *test) 436 { 437 struct kunit_try_catch_context context; 438 struct kunit_try_catch *try_catch; 439 440 kunit_init_test(test, test_case->name, test_case->log); 441 try_catch = &test->try_catch; 442 443 kunit_try_catch_init(try_catch, 444 test, 445 kunit_try_run_case, 446 kunit_catch_run_case); 447 context.test = test; 448 context.suite = suite; 449 context.test_case = test_case; 450 kunit_try_catch_run(try_catch, &context); 451 452 /* Propagate the parameter result to the test case. */ 453 if (test->status == KUNIT_FAILURE) 454 test_case->status = KUNIT_FAILURE; 455 else if (test_case->status != KUNIT_FAILURE && test->status == KUNIT_SUCCESS) 456 test_case->status = KUNIT_SUCCESS; 457 } 458 459 static void kunit_print_suite_stats(struct kunit_suite *suite, 460 struct kunit_result_stats suite_stats, 461 struct kunit_result_stats param_stats) 462 { 463 if (kunit_should_print_stats(suite_stats)) { 464 kunit_log(KERN_INFO, suite, 465 "# %s: pass:%lu fail:%lu skip:%lu total:%lu", 466 suite->name, 467 suite_stats.passed, 468 suite_stats.failed, 469 suite_stats.skipped, 470 suite_stats.total); 471 } 472 473 if (kunit_should_print_stats(param_stats)) { 474 kunit_log(KERN_INFO, suite, 475 "# Totals: pass:%lu fail:%lu skip:%lu total:%lu", 476 param_stats.passed, 477 param_stats.failed, 478 param_stats.skipped, 479 param_stats.total); 480 } 481 } 482 483 static void kunit_update_stats(struct kunit_result_stats *stats, 484 enum kunit_status status) 485 { 486 switch (status) { 487 case KUNIT_SUCCESS: 488 stats->passed++; 489 break; 490 case KUNIT_SKIPPED: 491 stats->skipped++; 492 break; 493 case KUNIT_FAILURE: 494 stats->failed++; 495 break; 496 } 497 498 stats->total++; 499 } 500 501 static void kunit_accumulate_stats(struct kunit_result_stats *total, 502 struct kunit_result_stats add) 503 { 504 total->passed += add.passed; 505 total->skipped += add.skipped; 506 total->failed += add.failed; 507 total->total += add.total; 508 } 509 510 int kunit_run_tests(struct kunit_suite *suite) 511 { 512 char param_desc[KUNIT_PARAM_DESC_SIZE]; 513 struct kunit_case *test_case; 514 struct kunit_result_stats suite_stats = { 0 }; 515 struct kunit_result_stats total_stats = { 0 }; 516 517 /* Taint the kernel so we know we've run tests. */ 518 add_taint(TAINT_TEST, LOCKDEP_STILL_OK); 519 520 if (suite->suite_init) { 521 suite->suite_init_err = suite->suite_init(suite); 522 if (suite->suite_init_err) { 523 kunit_err(suite, KUNIT_SUBTEST_INDENT 524 "# failed to initialize (%d)", suite->suite_init_err); 525 goto suite_end; 526 } 527 } 528 529 kunit_print_suite_start(suite); 530 531 kunit_suite_for_each_test_case(suite, test_case) { 532 struct kunit test = { .param_value = NULL, .param_index = 0 }; 533 struct kunit_result_stats param_stats = { 0 }; 534 test_case->status = KUNIT_SKIPPED; 535 536 if (!test_case->generate_params) { 537 /* Non-parameterised test. */ 538 kunit_run_case_catch_errors(suite, test_case, &test); 539 kunit_update_stats(¶m_stats, test.status); 540 } else { 541 /* Get initial param. */ 542 param_desc[0] = '\0'; 543 test.param_value = test_case->generate_params(NULL, param_desc); 544 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT 545 "KTAP version 1\n"); 546 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT 547 "# Subtest: %s", test_case->name); 548 549 while (test.param_value) { 550 kunit_run_case_catch_errors(suite, test_case, &test); 551 552 if (param_desc[0] == '\0') { 553 snprintf(param_desc, sizeof(param_desc), 554 "param-%d", test.param_index); 555 } 556 557 kunit_log(KERN_INFO, &test, 558 KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT 559 "%s %d %s", 560 kunit_status_to_ok_not_ok(test.status), 561 test.param_index + 1, param_desc); 562 563 /* Get next param. */ 564 param_desc[0] = '\0'; 565 test.param_value = test_case->generate_params(test.param_value, param_desc); 566 test.param_index++; 567 568 kunit_update_stats(¶m_stats, test.status); 569 } 570 } 571 572 573 kunit_print_test_stats(&test, param_stats); 574 575 kunit_print_ok_not_ok(&test, true, test_case->status, 576 kunit_test_case_num(suite, test_case), 577 test_case->name, 578 test.status_comment); 579 580 kunit_update_stats(&suite_stats, test_case->status); 581 kunit_accumulate_stats(&total_stats, param_stats); 582 } 583 584 if (suite->suite_exit) 585 suite->suite_exit(suite); 586 587 kunit_print_suite_stats(suite, suite_stats, total_stats); 588 suite_end: 589 kunit_print_suite_end(suite); 590 591 return 0; 592 } 593 EXPORT_SYMBOL_GPL(kunit_run_tests); 594 595 static void kunit_init_suite(struct kunit_suite *suite) 596 { 597 kunit_debugfs_create_suite(suite); 598 suite->status_comment[0] = '\0'; 599 suite->suite_init_err = 0; 600 } 601 602 bool kunit_enabled(void) 603 { 604 return enable_param; 605 } 606 607 int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites) 608 { 609 unsigned int i; 610 611 if (!kunit_enabled() && num_suites > 0) { 612 pr_info("kunit: disabled\n"); 613 return 0; 614 } 615 616 static_branch_inc(&kunit_running); 617 618 for (i = 0; i < num_suites; i++) { 619 kunit_init_suite(suites[i]); 620 kunit_run_tests(suites[i]); 621 } 622 623 static_branch_dec(&kunit_running); 624 return 0; 625 } 626 EXPORT_SYMBOL_GPL(__kunit_test_suites_init); 627 628 static void kunit_exit_suite(struct kunit_suite *suite) 629 { 630 kunit_debugfs_destroy_suite(suite); 631 } 632 633 void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites) 634 { 635 unsigned int i; 636 637 if (!kunit_enabled()) 638 return; 639 640 for (i = 0; i < num_suites; i++) 641 kunit_exit_suite(suites[i]); 642 643 kunit_suite_counter = 1; 644 } 645 EXPORT_SYMBOL_GPL(__kunit_test_suites_exit); 646 647 #ifdef CONFIG_MODULES 648 static void kunit_module_init(struct module *mod) 649 { 650 __kunit_test_suites_init(mod->kunit_suites, mod->num_kunit_suites); 651 } 652 653 static void kunit_module_exit(struct module *mod) 654 { 655 __kunit_test_suites_exit(mod->kunit_suites, mod->num_kunit_suites); 656 } 657 658 static int kunit_module_notify(struct notifier_block *nb, unsigned long val, 659 void *data) 660 { 661 struct module *mod = data; 662 663 switch (val) { 664 case MODULE_STATE_LIVE: 665 kunit_module_init(mod); 666 break; 667 case MODULE_STATE_GOING: 668 kunit_module_exit(mod); 669 break; 670 case MODULE_STATE_COMING: 671 case MODULE_STATE_UNFORMED: 672 break; 673 } 674 675 return 0; 676 } 677 678 static struct notifier_block kunit_mod_nb = { 679 .notifier_call = kunit_module_notify, 680 .priority = 0, 681 }; 682 #endif 683 684 struct kunit_kmalloc_array_params { 685 size_t n; 686 size_t size; 687 gfp_t gfp; 688 }; 689 690 static int kunit_kmalloc_array_init(struct kunit_resource *res, void *context) 691 { 692 struct kunit_kmalloc_array_params *params = context; 693 694 res->data = kmalloc_array(params->n, params->size, params->gfp); 695 if (!res->data) 696 return -ENOMEM; 697 698 return 0; 699 } 700 701 static void kunit_kmalloc_array_free(struct kunit_resource *res) 702 { 703 kfree(res->data); 704 } 705 706 void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp) 707 { 708 struct kunit_kmalloc_array_params params = { 709 .size = size, 710 .n = n, 711 .gfp = gfp 712 }; 713 714 return kunit_alloc_resource(test, 715 kunit_kmalloc_array_init, 716 kunit_kmalloc_array_free, 717 gfp, 718 ¶ms); 719 } 720 EXPORT_SYMBOL_GPL(kunit_kmalloc_array); 721 722 static inline bool kunit_kfree_match(struct kunit *test, 723 struct kunit_resource *res, void *match_data) 724 { 725 /* Only match resources allocated with kunit_kmalloc() and friends. */ 726 return res->free == kunit_kmalloc_array_free && res->data == match_data; 727 } 728 729 void kunit_kfree(struct kunit *test, const void *ptr) 730 { 731 if (!ptr) 732 return; 733 734 if (kunit_destroy_resource(test, kunit_kfree_match, (void *)ptr)) 735 KUNIT_FAIL(test, "kunit_kfree: %px already freed or not allocated by kunit", ptr); 736 } 737 EXPORT_SYMBOL_GPL(kunit_kfree); 738 739 void kunit_cleanup(struct kunit *test) 740 { 741 struct kunit_resource *res; 742 unsigned long flags; 743 744 /* 745 * test->resources is a stack - each allocation must be freed in the 746 * reverse order from which it was added since one resource may depend 747 * on another for its entire lifetime. 748 * Also, we cannot use the normal list_for_each constructs, even the 749 * safe ones because *arbitrary* nodes may be deleted when 750 * kunit_resource_free is called; the list_for_each_safe variants only 751 * protect against the current node being deleted, not the next. 752 */ 753 while (true) { 754 spin_lock_irqsave(&test->lock, flags); 755 if (list_empty(&test->resources)) { 756 spin_unlock_irqrestore(&test->lock, flags); 757 break; 758 } 759 res = list_last_entry(&test->resources, 760 struct kunit_resource, 761 node); 762 /* 763 * Need to unlock here as a resource may remove another 764 * resource, and this can't happen if the test->lock 765 * is held. 766 */ 767 spin_unlock_irqrestore(&test->lock, flags); 768 kunit_remove_resource(test, res); 769 } 770 current->kunit_test = NULL; 771 } 772 EXPORT_SYMBOL_GPL(kunit_cleanup); 773 774 static int __init kunit_init(void) 775 { 776 /* Install the KUnit hook functions. */ 777 kunit_install_hooks(); 778 779 kunit_debugfs_init(); 780 #ifdef CONFIG_MODULES 781 return register_module_notifier(&kunit_mod_nb); 782 #else 783 return 0; 784 #endif 785 } 786 late_initcall(kunit_init); 787 788 static void __exit kunit_exit(void) 789 { 790 memset(&kunit_hooks, 0, sizeof(kunit_hooks)); 791 #ifdef CONFIG_MODULES 792 unregister_module_notifier(&kunit_mod_nb); 793 #endif 794 kunit_debugfs_cleanup(); 795 } 796 module_exit(kunit_exit); 797 798 MODULE_LICENSE("GPL v2"); 799