]>
Commit | Line | Data |
---|---|---|
914cc63e BH |
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/test.h> | |
359a3760 | 10 | #include <kunit/test-bug.h> |
914cc63e | 11 | #include <linux/kernel.h> |
d4cdd146 | 12 | #include <linux/kref.h> |
5f3e0620 | 13 | #include <linux/sched/debug.h> |
83c4e7a0 | 14 | #include <linux/sched.h> |
914cc63e | 15 | |
e2219db2 | 16 | #include "debugfs.h" |
109fb06f | 17 | #include "string-stream.h" |
9bbb11c6 | 18 | #include "try-catch-impl.h" |
109fb06f | 19 | |
359a3760 UG |
20 | #if IS_BUILTIN(CONFIG_KUNIT) |
21 | /* | |
22 | * Fail the current test and print an error message to the log. | |
23 | */ | |
24 | void __kunit_fail_current_test(const char *file, int line, const char *fmt, ...) | |
25 | { | |
26 | va_list args; | |
27 | int len; | |
28 | char *buffer; | |
29 | ||
30 | if (!current->kunit_test) | |
31 | return; | |
32 | ||
33 | kunit_set_failure(current->kunit_test); | |
34 | ||
35 | /* kunit_err() only accepts literals, so evaluate the args first. */ | |
36 | va_start(args, fmt); | |
37 | len = vsnprintf(NULL, 0, fmt, args) + 1; | |
38 | va_end(args); | |
39 | ||
40 | buffer = kunit_kmalloc(current->kunit_test, len, GFP_KERNEL); | |
41 | if (!buffer) | |
42 | return; | |
43 | ||
44 | va_start(args, fmt); | |
45 | vsnprintf(buffer, len, fmt, args); | |
46 | va_end(args); | |
47 | ||
48 | kunit_err(current->kunit_test, "%s:%d: %s", file, line, buffer); | |
49 | kunit_kfree(current->kunit_test, buffer); | |
50 | } | |
51 | EXPORT_SYMBOL_GPL(__kunit_fail_current_test); | |
52 | #endif | |
53 | ||
e2219db2 AM |
54 | /* |
55 | * Append formatted message to log, size of which is limited to | |
56 | * KUNIT_LOG_SIZE bytes (including null terminating byte). | |
57 | */ | |
58 | void kunit_log_append(char *log, const char *fmt, ...) | |
59 | { | |
60 | char line[KUNIT_LOG_SIZE]; | |
61 | va_list args; | |
62 | int len_left; | |
63 | ||
64 | if (!log) | |
65 | return; | |
66 | ||
67 | len_left = KUNIT_LOG_SIZE - strlen(log) - 1; | |
68 | if (len_left <= 0) | |
69 | return; | |
70 | ||
71 | va_start(args, fmt); | |
72 | vsnprintf(line, sizeof(line), fmt, args); | |
73 | va_end(args); | |
74 | ||
75 | strncat(log, line, len_left); | |
76 | } | |
77 | EXPORT_SYMBOL_GPL(kunit_log_append); | |
78 | ||
79 | size_t kunit_suite_num_test_cases(struct kunit_suite *suite) | |
914cc63e BH |
80 | { |
81 | struct kunit_case *test_case; | |
82 | size_t len = 0; | |
83 | ||
e2219db2 | 84 | kunit_suite_for_each_test_case(suite, test_case) |
914cc63e BH |
85 | len++; |
86 | ||
87 | return len; | |
88 | } | |
e2219db2 | 89 | EXPORT_SYMBOL_GPL(kunit_suite_num_test_cases); |
914cc63e BH |
90 | |
91 | static void kunit_print_subtest_start(struct kunit_suite *suite) | |
92 | { | |
c3bba690 AM |
93 | kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "# Subtest: %s", |
94 | suite->name); | |
95 | kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "1..%zd", | |
e2219db2 | 96 | kunit_suite_num_test_cases(suite)); |
914cc63e BH |
97 | } |
98 | ||
e2219db2 AM |
99 | static void kunit_print_ok_not_ok(void *test_or_suite, |
100 | bool is_test, | |
6d2426b2 | 101 | enum kunit_status status, |
914cc63e | 102 | size_t test_number, |
6d2426b2 DG |
103 | const char *description, |
104 | const char *directive) | |
914cc63e | 105 | { |
e2219db2 AM |
106 | struct kunit_suite *suite = is_test ? NULL : test_or_suite; |
107 | struct kunit *test = is_test ? test_or_suite : NULL; | |
6d2426b2 | 108 | const char *directive_header = (status == KUNIT_SKIPPED) ? " # SKIP " : ""; |
914cc63e | 109 | |
e2219db2 AM |
110 | /* |
111 | * We do not log the test suite results as doing so would | |
112 | * mean debugfs display would consist of the test suite | |
113 | * description and status prior to individual test results. | |
114 | * Hence directly printk the suite status, and we will | |
115 | * separately seq_printf() the suite status for the debugfs | |
116 | * representation. | |
117 | */ | |
118 | if (suite) | |
6d2426b2 DG |
119 | pr_info("%s %zd - %s%s%s\n", |
120 | kunit_status_to_ok_not_ok(status), | |
121 | test_number, description, directive_header, | |
122 | (status == KUNIT_SKIPPED) ? directive : ""); | |
914cc63e | 123 | else |
6d2426b2 DG |
124 | kunit_log(KERN_INFO, test, |
125 | KUNIT_SUBTEST_INDENT "%s %zd - %s%s%s", | |
126 | kunit_status_to_ok_not_ok(status), | |
127 | test_number, description, directive_header, | |
128 | (status == KUNIT_SKIPPED) ? directive : ""); | |
914cc63e BH |
129 | } |
130 | ||
6d2426b2 | 131 | enum kunit_status kunit_suite_has_succeeded(struct kunit_suite *suite) |
914cc63e BH |
132 | { |
133 | const struct kunit_case *test_case; | |
6d2426b2 | 134 | enum kunit_status status = KUNIT_SKIPPED; |
914cc63e | 135 | |
e2219db2 | 136 | kunit_suite_for_each_test_case(suite, test_case) { |
6d2426b2 DG |
137 | if (test_case->status == KUNIT_FAILURE) |
138 | return KUNIT_FAILURE; | |
139 | else if (test_case->status == KUNIT_SUCCESS) | |
140 | status = KUNIT_SUCCESS; | |
e2219db2 | 141 | } |
914cc63e | 142 | |
6d2426b2 | 143 | return status; |
914cc63e | 144 | } |
e2219db2 | 145 | EXPORT_SYMBOL_GPL(kunit_suite_has_succeeded); |
914cc63e BH |
146 | |
147 | static void kunit_print_subtest_end(struct kunit_suite *suite) | |
148 | { | |
149 | static size_t kunit_suite_counter = 1; | |
150 | ||
e2219db2 | 151 | kunit_print_ok_not_ok((void *)suite, false, |
914cc63e BH |
152 | kunit_suite_has_succeeded(suite), |
153 | kunit_suite_counter++, | |
6d2426b2 DG |
154 | suite->name, |
155 | suite->status_comment); | |
914cc63e BH |
156 | } |
157 | ||
e2219db2 AM |
158 | unsigned int kunit_test_case_num(struct kunit_suite *suite, |
159 | struct kunit_case *test_case) | |
914cc63e | 160 | { |
e2219db2 AM |
161 | struct kunit_case *tc; |
162 | unsigned int i = 1; | |
163 | ||
164 | kunit_suite_for_each_test_case(suite, tc) { | |
165 | if (tc == test_case) | |
166 | return i; | |
167 | i++; | |
168 | } | |
169 | ||
170 | return 0; | |
914cc63e | 171 | } |
e2219db2 | 172 | EXPORT_SYMBOL_GPL(kunit_test_case_num); |
914cc63e | 173 | |
73cda7bb BH |
174 | static void kunit_print_string_stream(struct kunit *test, |
175 | struct string_stream *stream) | |
176 | { | |
177 | struct string_stream_fragment *fragment; | |
178 | char *buf; | |
179 | ||
e2219db2 AM |
180 | if (string_stream_is_empty(stream)) |
181 | return; | |
182 | ||
73cda7bb BH |
183 | buf = string_stream_get_string(stream); |
184 | if (!buf) { | |
185 | kunit_err(test, | |
186 | "Could not allocate buffer, dumping stream:\n"); | |
187 | list_for_each_entry(fragment, &stream->fragments, node) { | |
741a98d0 | 188 | kunit_err(test, "%s", fragment->fragment); |
73cda7bb BH |
189 | } |
190 | kunit_err(test, "\n"); | |
191 | } else { | |
741a98d0 | 192 | kunit_err(test, "%s", buf); |
73cda7bb BH |
193 | kunit_kfree(test, buf); |
194 | } | |
195 | } | |
196 | ||
197 | static void kunit_fail(struct kunit *test, struct kunit_assert *assert) | |
198 | { | |
199 | struct string_stream *stream; | |
200 | ||
201 | kunit_set_failure(test); | |
202 | ||
203 | stream = alloc_string_stream(test, GFP_KERNEL); | |
204 | if (!stream) { | |
205 | WARN(true, | |
206 | "Could not allocate stream to print failed assertion in %s:%d\n", | |
207 | assert->file, | |
208 | assert->line); | |
209 | return; | |
210 | } | |
211 | ||
212 | assert->format(assert, stream); | |
213 | ||
214 | kunit_print_string_stream(test, stream); | |
215 | ||
216 | WARN_ON(string_stream_destroy(stream)); | |
217 | } | |
218 | ||
5f3e0620 BH |
219 | static void __noreturn kunit_abort(struct kunit *test) |
220 | { | |
221 | kunit_try_catch_throw(&test->try_catch); /* Does not return. */ | |
222 | ||
223 | /* | |
224 | * Throw could not abort from test. | |
225 | * | |
226 | * XXX: we should never reach this line! As kunit_try_catch_throw is | |
227 | * marked __noreturn. | |
228 | */ | |
229 | WARN_ONCE(true, "Throw could not abort from test!\n"); | |
230 | } | |
231 | ||
73cda7bb BH |
232 | void kunit_do_assertion(struct kunit *test, |
233 | struct kunit_assert *assert, | |
234 | bool pass, | |
235 | const char *fmt, ...) | |
236 | { | |
237 | va_list args; | |
238 | ||
239 | if (pass) | |
240 | return; | |
241 | ||
242 | va_start(args, fmt); | |
243 | ||
244 | assert->message.fmt = fmt; | |
245 | assert->message.va = &args; | |
246 | ||
247 | kunit_fail(test, assert); | |
248 | ||
249 | va_end(args); | |
5f3e0620 BH |
250 | |
251 | if (assert->type == KUNIT_ASSERTION) | |
252 | kunit_abort(test); | |
73cda7bb | 253 | } |
c475c77d | 254 | EXPORT_SYMBOL_GPL(kunit_do_assertion); |
73cda7bb | 255 | |
e2219db2 | 256 | void kunit_init_test(struct kunit *test, const char *name, char *log) |
914cc63e | 257 | { |
0a756853 BH |
258 | spin_lock_init(&test->lock); |
259 | INIT_LIST_HEAD(&test->resources); | |
914cc63e | 260 | test->name = name; |
e2219db2 AM |
261 | test->log = log; |
262 | if (test->log) | |
263 | test->log[0] = '\0'; | |
6d2426b2 DG |
264 | test->status = KUNIT_SUCCESS; |
265 | test->status_comment[0] = '\0'; | |
914cc63e | 266 | } |
c475c77d | 267 | EXPORT_SYMBOL_GPL(kunit_init_test); |
914cc63e BH |
268 | |
269 | /* | |
5f3e0620 | 270 | * Initializes and runs test case. Does not clean up or do post validations. |
914cc63e | 271 | */ |
5f3e0620 BH |
272 | static void kunit_run_case_internal(struct kunit *test, |
273 | struct kunit_suite *suite, | |
274 | struct kunit_case *test_case) | |
914cc63e | 275 | { |
914cc63e BH |
276 | if (suite->init) { |
277 | int ret; | |
278 | ||
5f3e0620 | 279 | ret = suite->init(test); |
914cc63e | 280 | if (ret) { |
5f3e0620 BH |
281 | kunit_err(test, "failed to initialize: %d\n", ret); |
282 | kunit_set_failure(test); | |
914cc63e BH |
283 | return; |
284 | } | |
285 | } | |
286 | ||
5f3e0620 BH |
287 | test_case->run_case(test); |
288 | } | |
289 | ||
290 | static void kunit_case_internal_cleanup(struct kunit *test) | |
291 | { | |
292 | kunit_cleanup(test); | |
293 | } | |
914cc63e | 294 | |
5f3e0620 BH |
295 | /* |
296 | * Performs post validations and cleanup after a test case was run. | |
297 | * XXX: Should ONLY BE CALLED AFTER kunit_run_case_internal! | |
298 | */ | |
299 | static void kunit_run_case_cleanup(struct kunit *test, | |
300 | struct kunit_suite *suite) | |
301 | { | |
914cc63e | 302 | if (suite->exit) |
5f3e0620 BH |
303 | suite->exit(test); |
304 | ||
305 | kunit_case_internal_cleanup(test); | |
306 | } | |
307 | ||
308 | struct kunit_try_catch_context { | |
309 | struct kunit *test; | |
310 | struct kunit_suite *suite; | |
311 | struct kunit_case *test_case; | |
312 | }; | |
313 | ||
314 | static void kunit_try_run_case(void *data) | |
315 | { | |
316 | struct kunit_try_catch_context *ctx = data; | |
317 | struct kunit *test = ctx->test; | |
318 | struct kunit_suite *suite = ctx->suite; | |
319 | struct kunit_case *test_case = ctx->test_case; | |
320 | ||
83c4e7a0 | 321 | current->kunit_test = test; |
83c4e7a0 | 322 | |
5f3e0620 BH |
323 | /* |
324 | * kunit_run_case_internal may encounter a fatal error; if it does, | |
325 | * abort will be called, this thread will exit, and finally the parent | |
326 | * thread will resume control and handle any necessary clean up. | |
327 | */ | |
328 | kunit_run_case_internal(test, suite, test_case); | |
329 | /* This line may never be reached. */ | |
330 | kunit_run_case_cleanup(test, suite); | |
331 | } | |
332 | ||
333 | static void kunit_catch_run_case(void *data) | |
334 | { | |
335 | struct kunit_try_catch_context *ctx = data; | |
336 | struct kunit *test = ctx->test; | |
337 | struct kunit_suite *suite = ctx->suite; | |
338 | int try_exit_code = kunit_try_catch_get_result(&test->try_catch); | |
339 | ||
340 | if (try_exit_code) { | |
341 | kunit_set_failure(test); | |
342 | /* | |
343 | * Test case could not finish, we have no idea what state it is | |
344 | * in, so don't do clean up. | |
345 | */ | |
346 | if (try_exit_code == -ETIMEDOUT) { | |
347 | kunit_err(test, "test case timed out\n"); | |
348 | /* | |
349 | * Unknown internal error occurred preventing test case from | |
350 | * running, so there is nothing to clean up. | |
351 | */ | |
352 | } else { | |
353 | kunit_err(test, "internal error occurred preventing test case from running: %d\n", | |
354 | try_exit_code); | |
355 | } | |
356 | return; | |
357 | } | |
358 | ||
359 | /* | |
360 | * Test case was run, but aborted. It is the test case's business as to | |
361 | * whether it failed or not, we just need to clean up. | |
362 | */ | |
363 | kunit_run_case_cleanup(test, suite); | |
364 | } | |
365 | ||
366 | /* | |
367 | * Performs all logic to run a test case. It also catches most errors that | |
368 | * occur in a test case and reports them as failures. | |
369 | */ | |
370 | static void kunit_run_case_catch_errors(struct kunit_suite *suite, | |
fadb08e7 AR |
371 | struct kunit_case *test_case, |
372 | struct kunit *test) | |
5f3e0620 BH |
373 | { |
374 | struct kunit_try_catch_context context; | |
375 | struct kunit_try_catch *try_catch; | |
5f3e0620 | 376 | |
fadb08e7 AR |
377 | kunit_init_test(test, test_case->name, test_case->log); |
378 | try_catch = &test->try_catch; | |
914cc63e | 379 | |
5f3e0620 | 380 | kunit_try_catch_init(try_catch, |
fadb08e7 | 381 | test, |
5f3e0620 BH |
382 | kunit_try_run_case, |
383 | kunit_catch_run_case); | |
fadb08e7 | 384 | context.test = test; |
5f3e0620 BH |
385 | context.suite = suite; |
386 | context.test_case = test_case; | |
387 | kunit_try_catch_run(try_catch, &context); | |
0a756853 | 388 | |
6d2426b2 DG |
389 | /* Propagate the parameter result to the test case. */ |
390 | if (test->status == KUNIT_FAILURE) | |
391 | test_case->status = KUNIT_FAILURE; | |
392 | else if (test_case->status != KUNIT_FAILURE && test->status == KUNIT_SUCCESS) | |
393 | test_case->status = KUNIT_SUCCESS; | |
914cc63e BH |
394 | } |
395 | ||
396 | int kunit_run_tests(struct kunit_suite *suite) | |
397 | { | |
fadb08e7 | 398 | char param_desc[KUNIT_PARAM_DESC_SIZE]; |
914cc63e | 399 | struct kunit_case *test_case; |
914cc63e BH |
400 | |
401 | kunit_print_subtest_start(suite); | |
402 | ||
fadb08e7 AR |
403 | kunit_suite_for_each_test_case(suite, test_case) { |
404 | struct kunit test = { .param_value = NULL, .param_index = 0 }; | |
6d2426b2 | 405 | test_case->status = KUNIT_SKIPPED; |
fadb08e7 AR |
406 | |
407 | if (test_case->generate_params) { | |
408 | /* Get initial param. */ | |
409 | param_desc[0] = '\0'; | |
410 | test.param_value = test_case->generate_params(NULL, param_desc); | |
411 | } | |
412 | ||
413 | do { | |
414 | kunit_run_case_catch_errors(suite, test_case, &test); | |
fadb08e7 AR |
415 | |
416 | if (test_case->generate_params) { | |
417 | if (param_desc[0] == '\0') { | |
418 | snprintf(param_desc, sizeof(param_desc), | |
419 | "param-%d", test.param_index); | |
420 | } | |
421 | ||
422 | kunit_log(KERN_INFO, &test, | |
423 | KUNIT_SUBTEST_INDENT | |
424 | "# %s: %s %d - %s", | |
425 | test_case->name, | |
6d2426b2 | 426 | kunit_status_to_ok_not_ok(test.status), |
fadb08e7 AR |
427 | test.param_index + 1, param_desc); |
428 | ||
429 | /* Get next param. */ | |
430 | param_desc[0] = '\0'; | |
431 | test.param_value = test_case->generate_params(test.param_value, param_desc); | |
432 | test.param_index++; | |
433 | } | |
434 | } while (test.param_value); | |
435 | ||
6d2426b2 | 436 | kunit_print_ok_not_ok(&test, true, test_case->status, |
fadb08e7 | 437 | kunit_test_case_num(suite, test_case), |
6d2426b2 DG |
438 | test_case->name, |
439 | test.status_comment); | |
fadb08e7 | 440 | } |
914cc63e BH |
441 | |
442 | kunit_print_subtest_end(suite); | |
443 | ||
444 | return 0; | |
445 | } | |
c475c77d | 446 | EXPORT_SYMBOL_GPL(kunit_run_tests); |
914cc63e | 447 | |
e2219db2 AM |
448 | static void kunit_init_suite(struct kunit_suite *suite) |
449 | { | |
450 | kunit_debugfs_create_suite(suite); | |
6d2426b2 | 451 | suite->status_comment[0] = '\0'; |
e2219db2 AM |
452 | } |
453 | ||
aac35468 | 454 | int __kunit_test_suites_init(struct kunit_suite * const * const suites) |
e2219db2 AM |
455 | { |
456 | unsigned int i; | |
457 | ||
458 | for (i = 0; suites[i] != NULL; i++) { | |
459 | kunit_init_suite(suites[i]); | |
460 | kunit_run_tests(suites[i]); | |
461 | } | |
462 | return 0; | |
463 | } | |
464 | EXPORT_SYMBOL_GPL(__kunit_test_suites_init); | |
465 | ||
466 | static void kunit_exit_suite(struct kunit_suite *suite) | |
467 | { | |
468 | kunit_debugfs_destroy_suite(suite); | |
469 | } | |
470 | ||
471 | void __kunit_test_suites_exit(struct kunit_suite **suites) | |
472 | { | |
473 | unsigned int i; | |
474 | ||
475 | for (i = 0; suites[i] != NULL; i++) | |
476 | kunit_exit_suite(suites[i]); | |
477 | } | |
478 | EXPORT_SYMBOL_GPL(__kunit_test_suites_exit); | |
479 | ||
d4cdd146 AM |
480 | /* |
481 | * Used for static resources and when a kunit_resource * has been created by | |
482 | * kunit_alloc_resource(). When an init function is supplied, @data is passed | |
483 | * into the init function; otherwise, we simply set the resource data field to | |
484 | * the data value passed in. | |
485 | */ | |
486 | int kunit_add_resource(struct kunit *test, | |
487 | kunit_resource_init_t init, | |
488 | kunit_resource_free_t free, | |
489 | struct kunit_resource *res, | |
490 | void *data) | |
0a756853 | 491 | { |
d4cdd146 | 492 | int ret = 0; |
26c6cb7c | 493 | unsigned long flags; |
0a756853 | 494 | |
d4cdd146 AM |
495 | res->free = free; |
496 | kref_init(&res->refcount); | |
0a756853 | 497 | |
d4cdd146 AM |
498 | if (init) { |
499 | ret = init(res, data); | |
500 | if (ret) | |
501 | return ret; | |
502 | } else { | |
503 | res->data = data; | |
504 | } | |
0a756853 | 505 | |
26c6cb7c | 506 | spin_lock_irqsave(&test->lock, flags); |
0a756853 | 507 | list_add_tail(&res->node, &test->resources); |
d4cdd146 | 508 | /* refcount for list is established by kref_init() */ |
26c6cb7c | 509 | spin_unlock_irqrestore(&test->lock, flags); |
0a756853 | 510 | |
d4cdd146 | 511 | return ret; |
0a756853 | 512 | } |
d4cdd146 | 513 | EXPORT_SYMBOL_GPL(kunit_add_resource); |
0a756853 | 514 | |
725aca95 AM |
515 | int kunit_add_named_resource(struct kunit *test, |
516 | kunit_resource_init_t init, | |
517 | kunit_resource_free_t free, | |
518 | struct kunit_resource *res, | |
519 | const char *name, | |
520 | void *data) | |
521 | { | |
522 | struct kunit_resource *existing; | |
523 | ||
524 | if (!name) | |
525 | return -EINVAL; | |
526 | ||
527 | existing = kunit_find_named_resource(test, name); | |
528 | if (existing) { | |
529 | kunit_put_resource(existing); | |
530 | return -EEXIST; | |
531 | } | |
532 | ||
533 | res->name = name; | |
534 | ||
535 | return kunit_add_resource(test, init, free, res, data); | |
536 | } | |
537 | EXPORT_SYMBOL_GPL(kunit_add_named_resource); | |
538 | ||
d4cdd146 AM |
539 | struct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test, |
540 | kunit_resource_init_t init, | |
541 | kunit_resource_free_t free, | |
542 | gfp_t internal_gfp, | |
543 | void *data) | |
0a756853 | 544 | { |
d4cdd146 AM |
545 | struct kunit_resource *res; |
546 | int ret; | |
0a756853 | 547 | |
d4cdd146 AM |
548 | res = kzalloc(sizeof(*res), internal_gfp); |
549 | if (!res) | |
550 | return NULL; | |
0a756853 | 551 | |
d4cdd146 AM |
552 | ret = kunit_add_resource(test, init, free, res, data); |
553 | if (!ret) { | |
554 | /* | |
555 | * bump refcount for get; kunit_resource_put() should be called | |
556 | * when done. | |
557 | */ | |
558 | kunit_get_resource(res); | |
559 | return res; | |
0a756853 | 560 | } |
0a756853 BH |
561 | return NULL; |
562 | } | |
d4cdd146 | 563 | EXPORT_SYMBOL_GPL(kunit_alloc_and_get_resource); |
0a756853 | 564 | |
d4cdd146 | 565 | void kunit_remove_resource(struct kunit *test, struct kunit_resource *res) |
0a756853 | 566 | { |
26c6cb7c VB |
567 | unsigned long flags; |
568 | ||
569 | spin_lock_irqsave(&test->lock, flags); | |
d4cdd146 | 570 | list_del(&res->node); |
26c6cb7c | 571 | spin_unlock_irqrestore(&test->lock, flags); |
d4cdd146 | 572 | kunit_put_resource(res); |
0a756853 | 573 | } |
d4cdd146 | 574 | EXPORT_SYMBOL_GPL(kunit_remove_resource); |
0a756853 | 575 | |
d4cdd146 | 576 | int kunit_destroy_resource(struct kunit *test, kunit_resource_match_t match, |
0a756853 BH |
577 | void *match_data) |
578 | { | |
d4cdd146 AM |
579 | struct kunit_resource *res = kunit_find_resource(test, match, |
580 | match_data); | |
0a756853 | 581 | |
d4cdd146 | 582 | if (!res) |
0a756853 BH |
583 | return -ENOENT; |
584 | ||
d4cdd146 AM |
585 | kunit_remove_resource(test, res); |
586 | ||
587 | /* We have a reference also via _find(); drop it. */ | |
588 | kunit_put_resource(res); | |
589 | ||
0a756853 BH |
590 | return 0; |
591 | } | |
d4cdd146 | 592 | EXPORT_SYMBOL_GPL(kunit_destroy_resource); |
0a756853 | 593 | |
7122debb DL |
594 | struct kunit_kmalloc_array_params { |
595 | size_t n; | |
0a756853 BH |
596 | size_t size; |
597 | gfp_t gfp; | |
598 | }; | |
599 | ||
7122debb | 600 | static int kunit_kmalloc_array_init(struct kunit_resource *res, void *context) |
0a756853 | 601 | { |
7122debb | 602 | struct kunit_kmalloc_array_params *params = context; |
0a756853 | 603 | |
7122debb | 604 | res->data = kmalloc_array(params->n, params->size, params->gfp); |
d4cdd146 | 605 | if (!res->data) |
0a756853 BH |
606 | return -ENOMEM; |
607 | ||
608 | return 0; | |
609 | } | |
610 | ||
7122debb | 611 | static void kunit_kmalloc_array_free(struct kunit_resource *res) |
0a756853 | 612 | { |
d4cdd146 | 613 | kfree(res->data); |
0a756853 BH |
614 | } |
615 | ||
7122debb | 616 | void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp) |
0a756853 | 617 | { |
7122debb | 618 | struct kunit_kmalloc_array_params params = { |
0a756853 | 619 | .size = size, |
7122debb | 620 | .n = n, |
0a756853 BH |
621 | .gfp = gfp |
622 | }; | |
623 | ||
624 | return kunit_alloc_resource(test, | |
7122debb DL |
625 | kunit_kmalloc_array_init, |
626 | kunit_kmalloc_array_free, | |
0a756853 BH |
627 | gfp, |
628 | ¶ms); | |
629 | } | |
7122debb | 630 | EXPORT_SYMBOL_GPL(kunit_kmalloc_array); |
0a756853 BH |
631 | |
632 | void kunit_kfree(struct kunit *test, const void *ptr) | |
633 | { | |
d4cdd146 | 634 | struct kunit_resource *res; |
0a756853 | 635 | |
d4cdd146 AM |
636 | res = kunit_find_resource(test, kunit_resource_instance_match, |
637 | (void *)ptr); | |
638 | ||
639 | /* | |
640 | * Removing the resource from the list of resources drops the | |
641 | * reference count to 1; the final put will trigger the free. | |
642 | */ | |
643 | kunit_remove_resource(test, res); | |
644 | ||
645 | kunit_put_resource(res); | |
0a756853 | 646 | |
0a756853 | 647 | } |
c475c77d | 648 | EXPORT_SYMBOL_GPL(kunit_kfree); |
0a756853 BH |
649 | |
650 | void kunit_cleanup(struct kunit *test) | |
651 | { | |
d4cdd146 | 652 | struct kunit_resource *res; |
26c6cb7c | 653 | unsigned long flags; |
0a756853 BH |
654 | |
655 | /* | |
656 | * test->resources is a stack - each allocation must be freed in the | |
657 | * reverse order from which it was added since one resource may depend | |
658 | * on another for its entire lifetime. | |
659 | * Also, we cannot use the normal list_for_each constructs, even the | |
660 | * safe ones because *arbitrary* nodes may be deleted when | |
661 | * kunit_resource_free is called; the list_for_each_safe variants only | |
662 | * protect against the current node being deleted, not the next. | |
663 | */ | |
664 | while (true) { | |
26c6cb7c | 665 | spin_lock_irqsave(&test->lock, flags); |
0a756853 | 666 | if (list_empty(&test->resources)) { |
26c6cb7c | 667 | spin_unlock_irqrestore(&test->lock, flags); |
0a756853 BH |
668 | break; |
669 | } | |
d4cdd146 AM |
670 | res = list_last_entry(&test->resources, |
671 | struct kunit_resource, | |
672 | node); | |
673 | /* | |
674 | * Need to unlock here as a resource may remove another | |
675 | * resource, and this can't happen if the test->lock | |
676 | * is held. | |
677 | */ | |
26c6cb7c | 678 | spin_unlock_irqrestore(&test->lock, flags); |
d4cdd146 | 679 | kunit_remove_resource(test, res); |
0a756853 | 680 | } |
83c4e7a0 | 681 | current->kunit_test = NULL; |
0a756853 | 682 | } |
c475c77d | 683 | EXPORT_SYMBOL_GPL(kunit_cleanup); |
9fe124bf AM |
684 | |
685 | static int __init kunit_init(void) | |
686 | { | |
e2219db2 AM |
687 | kunit_debugfs_init(); |
688 | ||
9fe124bf AM |
689 | return 0; |
690 | } | |
691 | late_initcall(kunit_init); | |
692 | ||
693 | static void __exit kunit_exit(void) | |
694 | { | |
e2219db2 | 695 | kunit_debugfs_cleanup(); |
9fe124bf AM |
696 | } |
697 | module_exit(kunit_exit); | |
698 | ||
699 | MODULE_LICENSE("GPL v2"); |