resource.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * KUnit resource API for test managed resources (allocations, etc.).
  4. *
  5. * Copyright (C) 2022, Google LLC.
  6. * Author: Daniel Latypov <dlatypov@google.com>
  7. */
  8. #include <kunit/resource.h>
  9. #include <kunit/test.h>
  10. #include <linux/kref.h>
  11. /*
  12. * Used for static resources and when a kunit_resource * has been created by
  13. * kunit_alloc_resource(). When an init function is supplied, @data is passed
  14. * into the init function; otherwise, we simply set the resource data field to
  15. * the data value passed in. Doesn't initialize res->should_kfree.
  16. */
  17. int __kunit_add_resource(struct kunit *test,
  18. kunit_resource_init_t init,
  19. kunit_resource_free_t free,
  20. struct kunit_resource *res,
  21. void *data)
  22. {
  23. int ret = 0;
  24. unsigned long flags;
  25. res->free = free;
  26. kref_init(&res->refcount);
  27. if (init) {
  28. ret = init(res, data);
  29. if (ret)
  30. return ret;
  31. } else {
  32. res->data = data;
  33. }
  34. spin_lock_irqsave(&test->lock, flags);
  35. list_add_tail(&res->node, &test->resources);
  36. /* refcount for list is established by kref_init() */
  37. spin_unlock_irqrestore(&test->lock, flags);
  38. return ret;
  39. }
  40. EXPORT_SYMBOL_GPL(__kunit_add_resource);
  41. void kunit_remove_resource(struct kunit *test, struct kunit_resource *res)
  42. {
  43. unsigned long flags;
  44. bool was_linked;
  45. spin_lock_irqsave(&test->lock, flags);
  46. was_linked = !list_empty(&res->node);
  47. list_del_init(&res->node);
  48. spin_unlock_irqrestore(&test->lock, flags);
  49. if (was_linked)
  50. kunit_put_resource(res);
  51. }
  52. EXPORT_SYMBOL_GPL(kunit_remove_resource);
  53. int kunit_destroy_resource(struct kunit *test, kunit_resource_match_t match,
  54. void *match_data)
  55. {
  56. struct kunit_resource *res = kunit_find_resource(test, match,
  57. match_data);
  58. if (!res)
  59. return -ENOENT;
  60. kunit_remove_resource(test, res);
  61. /* We have a reference also via _find(); drop it. */
  62. kunit_put_resource(res);
  63. return 0;
  64. }
  65. EXPORT_SYMBOL_GPL(kunit_destroy_resource);
  66. struct kunit_action_ctx {
  67. struct kunit_resource res;
  68. kunit_action_t *func;
  69. void *ctx;
  70. };
  71. static void __kunit_action_free(struct kunit_resource *res)
  72. {
  73. struct kunit_action_ctx *action_ctx = container_of(res, struct kunit_action_ctx, res);
  74. action_ctx->func(action_ctx->ctx);
  75. }
  76. int kunit_add_action(struct kunit *test, void (*action)(void *), void *ctx)
  77. {
  78. struct kunit_action_ctx *action_ctx;
  79. KUNIT_ASSERT_NOT_NULL_MSG(test, action, "Tried to action a NULL function!");
  80. action_ctx = kzalloc_obj(*action_ctx);
  81. if (!action_ctx)
  82. return -ENOMEM;
  83. action_ctx->func = action;
  84. action_ctx->ctx = ctx;
  85. action_ctx->res.should_kfree = true;
  86. /* As init is NULL, this cannot fail. */
  87. __kunit_add_resource(test, NULL, __kunit_action_free, &action_ctx->res, action_ctx);
  88. return 0;
  89. }
  90. EXPORT_SYMBOL_GPL(kunit_add_action);
  91. int kunit_add_action_or_reset(struct kunit *test, void (*action)(void *),
  92. void *ctx)
  93. {
  94. int res = kunit_add_action(test, action, ctx);
  95. if (res)
  96. action(ctx);
  97. return res;
  98. }
  99. EXPORT_SYMBOL_GPL(kunit_add_action_or_reset);
  100. static bool __kunit_action_match(struct kunit *test,
  101. struct kunit_resource *res, void *match_data)
  102. {
  103. struct kunit_action_ctx *match_ctx = (struct kunit_action_ctx *)match_data;
  104. struct kunit_action_ctx *res_ctx = container_of(res, struct kunit_action_ctx, res);
  105. /* Make sure this is a free function. */
  106. if (res->free != __kunit_action_free)
  107. return false;
  108. /* Both the function and context data should match. */
  109. return (match_ctx->func == res_ctx->func) && (match_ctx->ctx == res_ctx->ctx);
  110. }
  111. void kunit_remove_action(struct kunit *test,
  112. kunit_action_t *action,
  113. void *ctx)
  114. {
  115. struct kunit_action_ctx match_ctx;
  116. struct kunit_resource *res;
  117. match_ctx.func = action;
  118. match_ctx.ctx = ctx;
  119. res = kunit_find_resource(test, __kunit_action_match, &match_ctx);
  120. if (res) {
  121. /* Remove the free function so we don't run the action. */
  122. res->free = NULL;
  123. kunit_remove_resource(test, res);
  124. kunit_put_resource(res);
  125. }
  126. }
  127. EXPORT_SYMBOL_GPL(kunit_remove_action);
  128. void kunit_release_action(struct kunit *test,
  129. kunit_action_t *action,
  130. void *ctx)
  131. {
  132. struct kunit_action_ctx match_ctx;
  133. struct kunit_resource *res;
  134. match_ctx.func = action;
  135. match_ctx.ctx = ctx;
  136. res = kunit_find_resource(test, __kunit_action_match, &match_ctx);
  137. if (res) {
  138. kunit_remove_resource(test, res);
  139. /* We have to put() this here, else free won't be called. */
  140. kunit_put_resource(res);
  141. }
  142. }
  143. EXPORT_SYMBOL_GPL(kunit_release_action);