LCOV - code coverage report
Current view: top level - lib/kunit - resource.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 31 63 49.2 %
Date: 2023-08-24 13:40:31 Functions: 4 9 44.4 %

          Line data    Source code
       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             : 
       9             : #include <kunit/resource.h>
      10             : #include <kunit/test.h>
      11             : #include <linux/kref.h>
      12             : 
      13             : /*
      14             :  * Used for static resources and when a kunit_resource * has been created by
      15             :  * kunit_alloc_resource().  When an init function is supplied, @data is passed
      16             :  * into the init function; otherwise, we simply set the resource data field to
      17             :  * the data value passed in. Doesn't initialize res->should_kfree.
      18             :  */
      19           0 : int __kunit_add_resource(struct kunit *test,
      20             :                          kunit_resource_init_t init,
      21             :                          kunit_resource_free_t free,
      22             :                          struct kunit_resource *res,
      23             :                          void *data)
      24             : {
      25         308 :         int ret = 0;
      26             :         unsigned long flags;
      27             : 
      28         308 :         res->free = free;
      29         616 :         kref_init(&res->refcount);
      30             : 
      31           0 :         if (init) {
      32           0 :                 ret = init(res, data);
      33           0 :                 if (ret)
      34             :                         return ret;
      35             :         } else {
      36         308 :                 res->data = data;
      37             :         }
      38             : 
      39         308 :         spin_lock_irqsave(&test->lock, flags);
      40         616 :         list_add_tail(&res->node, &test->resources);
      41             :         /* refcount for list is established by kref_init() */
      42         616 :         spin_unlock_irqrestore(&test->lock, flags);
      43             : 
      44           0 :         return ret;
      45             : }
      46             : EXPORT_SYMBOL_GPL(__kunit_add_resource);
      47             : 
      48         308 : void kunit_remove_resource(struct kunit *test, struct kunit_resource *res)
      49             : {
      50             :         unsigned long flags;
      51             :         bool was_linked;
      52             : 
      53         308 :         spin_lock_irqsave(&test->lock, flags);
      54         616 :         was_linked = !list_empty(&res->node);
      55         616 :         list_del_init(&res->node);
      56         616 :         spin_unlock_irqrestore(&test->lock, flags);
      57             : 
      58         308 :         if (was_linked)
      59             :                 kunit_put_resource(res);
      60         308 : }
      61             : EXPORT_SYMBOL_GPL(kunit_remove_resource);
      62             : 
      63           0 : int kunit_destroy_resource(struct kunit *test, kunit_resource_match_t match,
      64             :                            void *match_data)
      65             : {
      66           0 :         struct kunit_resource *res = kunit_find_resource(test, match,
      67             :                                                          match_data);
      68             : 
      69           0 :         if (!res)
      70             :                 return -ENOENT;
      71             : 
      72           0 :         kunit_remove_resource(test, res);
      73             : 
      74             :         /* We have a reference also via _find(); drop it. */
      75           0 :         kunit_put_resource(res);
      76             : 
      77           0 :         return 0;
      78             : }
      79             : EXPORT_SYMBOL_GPL(kunit_destroy_resource);
      80             : 
      81             : struct kunit_action_ctx {
      82             :         struct kunit_resource res;
      83             :         kunit_action_t *func;
      84             :         void *ctx;
      85             : };
      86             : 
      87         308 : static void __kunit_action_free(struct kunit_resource *res)
      88             : {
      89         308 :         struct kunit_action_ctx *action_ctx = container_of(res, struct kunit_action_ctx, res);
      90             : 
      91         308 :         action_ctx->func(action_ctx->ctx);
      92         308 : }
      93             : 
      94             : 
      95         308 : int kunit_add_action(struct kunit *test, void (*action)(void *), void *ctx)
      96             : {
      97             :         struct kunit_action_ctx *action_ctx;
      98             : 
      99         308 :         KUNIT_ASSERT_NOT_NULL_MSG(test, action, "Tried to action a NULL function!");
     100             : 
     101         308 :         action_ctx = kzalloc(sizeof(*action_ctx), GFP_KERNEL);
     102         308 :         if (!action_ctx)
     103             :                 return -ENOMEM;
     104             : 
     105         308 :         action_ctx->func = action;
     106         308 :         action_ctx->ctx = ctx;
     107             : 
     108         308 :         action_ctx->res.should_kfree = true;
     109             :         /* As init is NULL, this cannot fail. */
     110         616 :         __kunit_add_resource(test, NULL, __kunit_action_free, &action_ctx->res, action_ctx);
     111             : 
     112         308 :         return 0;
     113             : }
     114             : EXPORT_SYMBOL_GPL(kunit_add_action);
     115             : 
     116         308 : int kunit_add_action_or_reset(struct kunit *test, void (*action)(void *),
     117             :                               void *ctx)
     118             : {
     119         308 :         int res = kunit_add_action(test, action, ctx);
     120             : 
     121         308 :         if (res)
     122           0 :                 action(ctx);
     123         308 :         return res;
     124             : }
     125             : EXPORT_SYMBOL_GPL(kunit_add_action_or_reset);
     126             : 
     127           0 : static bool __kunit_action_match(struct kunit *test,
     128             :                                 struct kunit_resource *res, void *match_data)
     129             : {
     130           0 :         struct kunit_action_ctx *match_ctx = (struct kunit_action_ctx *)match_data;
     131           0 :         struct kunit_action_ctx *res_ctx = container_of(res, struct kunit_action_ctx, res);
     132             : 
     133             :         /* Make sure this is a free function. */
     134           0 :         if (res->free != __kunit_action_free)
     135             :                 return false;
     136             : 
     137             :         /* Both the function and context data should match. */
     138           0 :         return (match_ctx->func == res_ctx->func) && (match_ctx->ctx == res_ctx->ctx);
     139             : }
     140             : 
     141           0 : void kunit_remove_action(struct kunit *test,
     142             :                         kunit_action_t *action,
     143             :                         void *ctx)
     144             : {
     145             :         struct kunit_action_ctx match_ctx;
     146             :         struct kunit_resource *res;
     147             : 
     148           0 :         match_ctx.func = action;
     149           0 :         match_ctx.ctx = ctx;
     150             : 
     151           0 :         res = kunit_find_resource(test, __kunit_action_match, &match_ctx);
     152           0 :         if (res) {
     153             :                 /* Remove the free function so we don't run the action. */
     154           0 :                 res->free = NULL;
     155           0 :                 kunit_remove_resource(test, res);
     156             :                 kunit_put_resource(res);
     157             :         }
     158           0 : }
     159             : EXPORT_SYMBOL_GPL(kunit_remove_action);
     160             : 
     161           0 : void kunit_release_action(struct kunit *test,
     162             :                          kunit_action_t *action,
     163             :                          void *ctx)
     164             : {
     165             :         struct kunit_action_ctx match_ctx;
     166             :         struct kunit_resource *res;
     167             : 
     168           0 :         match_ctx.func = action;
     169           0 :         match_ctx.ctx = ctx;
     170             : 
     171           0 :         res = kunit_find_resource(test, __kunit_action_match, &match_ctx);
     172           0 :         if (res) {
     173           0 :                 kunit_remove_resource(test, res);
     174             :                 /* We have to put() this here, else free won't be called. */
     175             :                 kunit_put_resource(res);
     176             :         }
     177           0 : }
     178             : EXPORT_SYMBOL_GPL(kunit_release_action);

Generated by: LCOV version 1.14