161695f8cSDaniel Latypov /* SPDX-License-Identifier: GPL-2.0 */ 261695f8cSDaniel Latypov /* 361695f8cSDaniel Latypov * KUnit resource API for test managed resources (allocations, etc.). 461695f8cSDaniel Latypov * 561695f8cSDaniel Latypov * Copyright (C) 2022, Google LLC. 661695f8cSDaniel Latypov * Author: Daniel Latypov <dlatypov@google.com> 761695f8cSDaniel Latypov */ 861695f8cSDaniel Latypov 961695f8cSDaniel Latypov #ifndef _KUNIT_RESOURCE_H 1061695f8cSDaniel Latypov #define _KUNIT_RESOURCE_H 1161695f8cSDaniel Latypov 1261695f8cSDaniel Latypov #include <kunit/test.h> 1361695f8cSDaniel Latypov 1461695f8cSDaniel Latypov #include <linux/kref.h> 1561695f8cSDaniel Latypov #include <linux/list.h> 1661695f8cSDaniel Latypov #include <linux/slab.h> 1761695f8cSDaniel Latypov #include <linux/spinlock.h> 1861695f8cSDaniel Latypov 1961695f8cSDaniel Latypov struct kunit_resource; 2061695f8cSDaniel Latypov 2161695f8cSDaniel Latypov typedef int (*kunit_resource_init_t)(struct kunit_resource *, void *); 2261695f8cSDaniel Latypov typedef void (*kunit_resource_free_t)(struct kunit_resource *); 2361695f8cSDaniel Latypov 2461695f8cSDaniel Latypov /** 2561695f8cSDaniel Latypov * struct kunit_resource - represents a *test managed resource* 2661695f8cSDaniel Latypov * @data: for the user to store arbitrary data. 2761695f8cSDaniel Latypov * @name: optional name 28*ad69172eSDavid Gow * @free: a user supplied function to free the resource. 2961695f8cSDaniel Latypov * 3061695f8cSDaniel Latypov * Represents a *test managed resource*, a resource which will automatically be 31*ad69172eSDavid Gow * cleaned up at the end of a test case. This cleanup is performed by the 'free' 32*ad69172eSDavid Gow * function. The struct kunit_resource itself is freed automatically with 33*ad69172eSDavid Gow * kfree() if it was allocated by KUnit (e.g., by kunit_alloc_resource()), but 34*ad69172eSDavid Gow * must be freed by the user otherwise. 3561695f8cSDaniel Latypov * 3661695f8cSDaniel Latypov * Resources are reference counted so if a resource is retrieved via 3761695f8cSDaniel Latypov * kunit_alloc_and_get_resource() or kunit_find_resource(), we need 3861695f8cSDaniel Latypov * to call kunit_put_resource() to reduce the resource reference count 3961695f8cSDaniel Latypov * when finished with it. Note that kunit_alloc_resource() does not require a 4061695f8cSDaniel Latypov * kunit_resource_put() because it does not retrieve the resource itself. 4161695f8cSDaniel Latypov * 4261695f8cSDaniel Latypov * Example: 4361695f8cSDaniel Latypov * 4461695f8cSDaniel Latypov * .. code-block:: c 4561695f8cSDaniel Latypov * 4661695f8cSDaniel Latypov * struct kunit_kmalloc_params { 4761695f8cSDaniel Latypov * size_t size; 4861695f8cSDaniel Latypov * gfp_t gfp; 4961695f8cSDaniel Latypov * }; 5061695f8cSDaniel Latypov * 5161695f8cSDaniel Latypov * static int kunit_kmalloc_init(struct kunit_resource *res, void *context) 5261695f8cSDaniel Latypov * { 5361695f8cSDaniel Latypov * struct kunit_kmalloc_params *params = context; 5461695f8cSDaniel Latypov * res->data = kmalloc(params->size, params->gfp); 5561695f8cSDaniel Latypov * 5661695f8cSDaniel Latypov * if (!res->data) 5761695f8cSDaniel Latypov * return -ENOMEM; 5861695f8cSDaniel Latypov * 5961695f8cSDaniel Latypov * return 0; 6061695f8cSDaniel Latypov * } 6161695f8cSDaniel Latypov * 6261695f8cSDaniel Latypov * static void kunit_kmalloc_free(struct kunit_resource *res) 6361695f8cSDaniel Latypov * { 6461695f8cSDaniel Latypov * kfree(res->data); 6561695f8cSDaniel Latypov * } 6661695f8cSDaniel Latypov * 6761695f8cSDaniel Latypov * void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp) 6861695f8cSDaniel Latypov * { 6961695f8cSDaniel Latypov * struct kunit_kmalloc_params params; 7061695f8cSDaniel Latypov * 7161695f8cSDaniel Latypov * params.size = size; 7261695f8cSDaniel Latypov * params.gfp = gfp; 7361695f8cSDaniel Latypov * 7461695f8cSDaniel Latypov * return kunit_alloc_resource(test, kunit_kmalloc_init, 7561695f8cSDaniel Latypov * kunit_kmalloc_free, ¶ms); 7661695f8cSDaniel Latypov * } 7761695f8cSDaniel Latypov * 7861695f8cSDaniel Latypov * Resources can also be named, with lookup/removal done on a name 7961695f8cSDaniel Latypov * basis also. kunit_add_named_resource(), kunit_find_named_resource() 8061695f8cSDaniel Latypov * and kunit_destroy_named_resource(). Resource names must be 8161695f8cSDaniel Latypov * unique within the test instance. 8261695f8cSDaniel Latypov */ 8361695f8cSDaniel Latypov struct kunit_resource { 8461695f8cSDaniel Latypov void *data; 8561695f8cSDaniel Latypov const char *name; 8661695f8cSDaniel Latypov kunit_resource_free_t free; 8761695f8cSDaniel Latypov 8861695f8cSDaniel Latypov /* private: internal use only. */ 8961695f8cSDaniel Latypov struct kref refcount; 9061695f8cSDaniel Latypov struct list_head node; 91*ad69172eSDavid Gow bool should_kfree; 9261695f8cSDaniel Latypov }; 9361695f8cSDaniel Latypov 9461695f8cSDaniel Latypov /** 9561695f8cSDaniel Latypov * kunit_get_resource() - Hold resource for use. Should not need to be used 9661695f8cSDaniel Latypov * by most users as we automatically get resources 9761695f8cSDaniel Latypov * retrieved by kunit_find_resource*(). 9861695f8cSDaniel Latypov * @res: resource 9961695f8cSDaniel Latypov */ 10061695f8cSDaniel Latypov static inline void kunit_get_resource(struct kunit_resource *res) 10161695f8cSDaniel Latypov { 10261695f8cSDaniel Latypov kref_get(&res->refcount); 10361695f8cSDaniel Latypov } 10461695f8cSDaniel Latypov 10561695f8cSDaniel Latypov /* 10661695f8cSDaniel Latypov * Called when refcount reaches zero via kunit_put_resource(); 10761695f8cSDaniel Latypov * should not be called directly. 10861695f8cSDaniel Latypov */ 10961695f8cSDaniel Latypov static inline void kunit_release_resource(struct kref *kref) 11061695f8cSDaniel Latypov { 11161695f8cSDaniel Latypov struct kunit_resource *res = container_of(kref, struct kunit_resource, 11261695f8cSDaniel Latypov refcount); 11361695f8cSDaniel Latypov 114*ad69172eSDavid Gow if (res->free) 11561695f8cSDaniel Latypov res->free(res); 116*ad69172eSDavid Gow 117*ad69172eSDavid Gow /* 'res' is valid here, as if should_kfree is set, res->free may not free 118*ad69172eSDavid Gow * 'res' itself, just res->data 119*ad69172eSDavid Gow */ 120*ad69172eSDavid Gow if (res->should_kfree) 12161695f8cSDaniel Latypov kfree(res); 12261695f8cSDaniel Latypov } 12361695f8cSDaniel Latypov 12461695f8cSDaniel Latypov /** 12561695f8cSDaniel Latypov * kunit_put_resource() - When caller is done with retrieved resource, 12661695f8cSDaniel Latypov * kunit_put_resource() should be called to drop 12761695f8cSDaniel Latypov * reference count. The resource list maintains 12861695f8cSDaniel Latypov * a reference count on resources, so if no users 12961695f8cSDaniel Latypov * are utilizing a resource and it is removed from 13061695f8cSDaniel Latypov * the resource list, it will be freed via the 13161695f8cSDaniel Latypov * associated free function (if any). Only 13261695f8cSDaniel Latypov * needs to be used if we alloc_and_get() or 13361695f8cSDaniel Latypov * find() resource. 13461695f8cSDaniel Latypov * @res: resource 13561695f8cSDaniel Latypov */ 13661695f8cSDaniel Latypov static inline void kunit_put_resource(struct kunit_resource *res) 13761695f8cSDaniel Latypov { 13861695f8cSDaniel Latypov kref_put(&res->refcount, kunit_release_resource); 13961695f8cSDaniel Latypov } 14061695f8cSDaniel Latypov 14161695f8cSDaniel Latypov /** 142*ad69172eSDavid Gow * __kunit_add_resource() - Internal helper to add a resource. 143*ad69172eSDavid Gow * 144*ad69172eSDavid Gow * res->should_kfree is not initialised. 145*ad69172eSDavid Gow * @test: The test context object. 146*ad69172eSDavid Gow * @init: a user-supplied function to initialize the result (if needed). If 147*ad69172eSDavid Gow * none is supplied, the resource data value is simply set to @data. 148*ad69172eSDavid Gow * If an init function is supplied, @data is passed to it instead. 149*ad69172eSDavid Gow * @free: a user-supplied function to free the resource (if needed). 150*ad69172eSDavid Gow * @res: The resource. 151*ad69172eSDavid Gow * @data: value to pass to init function or set in resource data field. 152*ad69172eSDavid Gow */ 153*ad69172eSDavid Gow int __kunit_add_resource(struct kunit *test, 154*ad69172eSDavid Gow kunit_resource_init_t init, 155*ad69172eSDavid Gow kunit_resource_free_t free, 156*ad69172eSDavid Gow struct kunit_resource *res, 157*ad69172eSDavid Gow void *data); 158*ad69172eSDavid Gow 159*ad69172eSDavid Gow /** 16061695f8cSDaniel Latypov * kunit_add_resource() - Add a *test managed resource*. 16161695f8cSDaniel Latypov * @test: The test context object. 16261695f8cSDaniel Latypov * @init: a user-supplied function to initialize the result (if needed). If 16361695f8cSDaniel Latypov * none is supplied, the resource data value is simply set to @data. 16461695f8cSDaniel Latypov * If an init function is supplied, @data is passed to it instead. 16561695f8cSDaniel Latypov * @free: a user-supplied function to free the resource (if needed). 16661695f8cSDaniel Latypov * @res: The resource. 16761695f8cSDaniel Latypov * @data: value to pass to init function or set in resource data field. 16861695f8cSDaniel Latypov */ 169*ad69172eSDavid Gow static inline int kunit_add_resource(struct kunit *test, 17061695f8cSDaniel Latypov kunit_resource_init_t init, 17161695f8cSDaniel Latypov kunit_resource_free_t free, 17261695f8cSDaniel Latypov struct kunit_resource *res, 173*ad69172eSDavid Gow void *data) 174*ad69172eSDavid Gow { 175*ad69172eSDavid Gow res->should_kfree = false; 176*ad69172eSDavid Gow return __kunit_add_resource(test, init, free, res, data); 177*ad69172eSDavid Gow } 178*ad69172eSDavid Gow 179*ad69172eSDavid Gow static inline struct kunit_resource * 180*ad69172eSDavid Gow kunit_find_named_resource(struct kunit *test, const char *name); 18161695f8cSDaniel Latypov 18261695f8cSDaniel Latypov /** 18361695f8cSDaniel Latypov * kunit_add_named_resource() - Add a named *test managed resource*. 18461695f8cSDaniel Latypov * @test: The test context object. 18561695f8cSDaniel Latypov * @init: a user-supplied function to initialize the resource data, if needed. 18661695f8cSDaniel Latypov * @free: a user-supplied function to free the resource data, if needed. 18761695f8cSDaniel Latypov * @res: The resource. 18861695f8cSDaniel Latypov * @name: name to be set for resource. 18961695f8cSDaniel Latypov * @data: value to pass to init function or set in resource data field. 19061695f8cSDaniel Latypov */ 191*ad69172eSDavid Gow static inline int kunit_add_named_resource(struct kunit *test, 19261695f8cSDaniel Latypov kunit_resource_init_t init, 19361695f8cSDaniel Latypov kunit_resource_free_t free, 19461695f8cSDaniel Latypov struct kunit_resource *res, 19561695f8cSDaniel Latypov const char *name, 196*ad69172eSDavid Gow void *data) 197*ad69172eSDavid Gow { 198*ad69172eSDavid Gow struct kunit_resource *existing; 199*ad69172eSDavid Gow 200*ad69172eSDavid Gow if (!name) 201*ad69172eSDavid Gow return -EINVAL; 202*ad69172eSDavid Gow 203*ad69172eSDavid Gow existing = kunit_find_named_resource(test, name); 204*ad69172eSDavid Gow if (existing) { 205*ad69172eSDavid Gow kunit_put_resource(existing); 206*ad69172eSDavid Gow return -EEXIST; 207*ad69172eSDavid Gow } 208*ad69172eSDavid Gow 209*ad69172eSDavid Gow res->name = name; 210*ad69172eSDavid Gow res->should_kfree = false; 211*ad69172eSDavid Gow 212*ad69172eSDavid Gow return __kunit_add_resource(test, init, free, res, data); 213*ad69172eSDavid Gow } 214*ad69172eSDavid Gow 215*ad69172eSDavid Gow /** 216*ad69172eSDavid Gow * kunit_alloc_and_get_resource() - Allocates and returns a *test managed resource*. 217*ad69172eSDavid Gow * @test: The test context object. 218*ad69172eSDavid Gow * @init: a user supplied function to initialize the resource. 219*ad69172eSDavid Gow * @free: a user supplied function to free the resource (if needed). 220*ad69172eSDavid Gow * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL 221*ad69172eSDavid Gow * @context: for the user to pass in arbitrary data to the init function. 222*ad69172eSDavid Gow * 223*ad69172eSDavid Gow * Allocates a *test managed resource*, a resource which will automatically be 224*ad69172eSDavid Gow * cleaned up at the end of a test case. See &struct kunit_resource for an 225*ad69172eSDavid Gow * example. 226*ad69172eSDavid Gow * 227*ad69172eSDavid Gow * This is effectively identical to kunit_alloc_resource, but returns the 228*ad69172eSDavid Gow * struct kunit_resource pointer, not just the 'data' pointer. It therefore 229*ad69172eSDavid Gow * also increments the resource's refcount, so kunit_put_resource() should be 230*ad69172eSDavid Gow * called when you've finished with it. 231*ad69172eSDavid Gow * 232*ad69172eSDavid Gow * Note: KUnit needs to allocate memory for a kunit_resource object. You must 233*ad69172eSDavid Gow * specify an @internal_gfp that is compatible with the use context of your 234*ad69172eSDavid Gow * resource. 235*ad69172eSDavid Gow */ 236*ad69172eSDavid Gow static inline struct kunit_resource * 237*ad69172eSDavid Gow kunit_alloc_and_get_resource(struct kunit *test, 238*ad69172eSDavid Gow kunit_resource_init_t init, 239*ad69172eSDavid Gow kunit_resource_free_t free, 240*ad69172eSDavid Gow gfp_t internal_gfp, 241*ad69172eSDavid Gow void *context) 242*ad69172eSDavid Gow { 243*ad69172eSDavid Gow struct kunit_resource *res; 244*ad69172eSDavid Gow int ret; 245*ad69172eSDavid Gow 246*ad69172eSDavid Gow res = kzalloc(sizeof(*res), internal_gfp); 247*ad69172eSDavid Gow if (!res) 248*ad69172eSDavid Gow return NULL; 249*ad69172eSDavid Gow 250*ad69172eSDavid Gow res->should_kfree = true; 251*ad69172eSDavid Gow 252*ad69172eSDavid Gow ret = __kunit_add_resource(test, init, free, res, context); 253*ad69172eSDavid Gow if (!ret) { 254*ad69172eSDavid Gow /* 255*ad69172eSDavid Gow * bump refcount for get; kunit_resource_put() should be called 256*ad69172eSDavid Gow * when done. 257*ad69172eSDavid Gow */ 258*ad69172eSDavid Gow kunit_get_resource(res); 259*ad69172eSDavid Gow return res; 260*ad69172eSDavid Gow } 261*ad69172eSDavid Gow return NULL; 262*ad69172eSDavid Gow } 26361695f8cSDaniel Latypov 26461695f8cSDaniel Latypov /** 26561695f8cSDaniel Latypov * kunit_alloc_resource() - Allocates a *test managed resource*. 26661695f8cSDaniel Latypov * @test: The test context object. 26761695f8cSDaniel Latypov * @init: a user supplied function to initialize the resource. 268*ad69172eSDavid Gow * @free: a user supplied function to free the resource (if needed). 26961695f8cSDaniel Latypov * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL 27061695f8cSDaniel Latypov * @context: for the user to pass in arbitrary data to the init function. 27161695f8cSDaniel Latypov * 27261695f8cSDaniel Latypov * Allocates a *test managed resource*, a resource which will automatically be 27361695f8cSDaniel Latypov * cleaned up at the end of a test case. See &struct kunit_resource for an 27461695f8cSDaniel Latypov * example. 27561695f8cSDaniel Latypov * 27661695f8cSDaniel Latypov * Note: KUnit needs to allocate memory for a kunit_resource object. You must 27761695f8cSDaniel Latypov * specify an @internal_gfp that is compatible with the use context of your 27861695f8cSDaniel Latypov * resource. 27961695f8cSDaniel Latypov */ 28061695f8cSDaniel Latypov static inline void *kunit_alloc_resource(struct kunit *test, 28161695f8cSDaniel Latypov kunit_resource_init_t init, 28261695f8cSDaniel Latypov kunit_resource_free_t free, 28361695f8cSDaniel Latypov gfp_t internal_gfp, 28461695f8cSDaniel Latypov void *context) 28561695f8cSDaniel Latypov { 28661695f8cSDaniel Latypov struct kunit_resource *res; 28761695f8cSDaniel Latypov 28861695f8cSDaniel Latypov res = kzalloc(sizeof(*res), internal_gfp); 28961695f8cSDaniel Latypov if (!res) 29061695f8cSDaniel Latypov return NULL; 29161695f8cSDaniel Latypov 292*ad69172eSDavid Gow res->should_kfree = true; 293*ad69172eSDavid Gow if (!__kunit_add_resource(test, init, free, res, context)) 29461695f8cSDaniel Latypov return res->data; 29561695f8cSDaniel Latypov 29661695f8cSDaniel Latypov return NULL; 29761695f8cSDaniel Latypov } 29861695f8cSDaniel Latypov 29961695f8cSDaniel Latypov typedef bool (*kunit_resource_match_t)(struct kunit *test, 30061695f8cSDaniel Latypov struct kunit_resource *res, 30161695f8cSDaniel Latypov void *match_data); 30261695f8cSDaniel Latypov 30361695f8cSDaniel Latypov /** 30461695f8cSDaniel Latypov * kunit_resource_instance_match() - Match a resource with the same instance. 30561695f8cSDaniel Latypov * @test: Test case to which the resource belongs. 30661695f8cSDaniel Latypov * @res: The resource. 30761695f8cSDaniel Latypov * @match_data: The resource pointer to match against. 30861695f8cSDaniel Latypov * 30961695f8cSDaniel Latypov * An instance of kunit_resource_match_t that matches a resource whose 31061695f8cSDaniel Latypov * allocation matches @match_data. 31161695f8cSDaniel Latypov */ 31261695f8cSDaniel Latypov static inline bool kunit_resource_instance_match(struct kunit *test, 31361695f8cSDaniel Latypov struct kunit_resource *res, 31461695f8cSDaniel Latypov void *match_data) 31561695f8cSDaniel Latypov { 31661695f8cSDaniel Latypov return res->data == match_data; 31761695f8cSDaniel Latypov } 31861695f8cSDaniel Latypov 31961695f8cSDaniel Latypov /** 32061695f8cSDaniel Latypov * kunit_resource_name_match() - Match a resource with the same name. 32161695f8cSDaniel Latypov * @test: Test case to which the resource belongs. 32261695f8cSDaniel Latypov * @res: The resource. 32361695f8cSDaniel Latypov * @match_name: The name to match against. 32461695f8cSDaniel Latypov */ 32561695f8cSDaniel Latypov static inline bool kunit_resource_name_match(struct kunit *test, 32661695f8cSDaniel Latypov struct kunit_resource *res, 32761695f8cSDaniel Latypov void *match_name) 32861695f8cSDaniel Latypov { 32961695f8cSDaniel Latypov return res->name && strcmp(res->name, match_name) == 0; 33061695f8cSDaniel Latypov } 33161695f8cSDaniel Latypov 33261695f8cSDaniel Latypov /** 33361695f8cSDaniel Latypov * kunit_find_resource() - Find a resource using match function/data. 33461695f8cSDaniel Latypov * @test: Test case to which the resource belongs. 33561695f8cSDaniel Latypov * @match: match function to be applied to resources/match data. 33661695f8cSDaniel Latypov * @match_data: data to be used in matching. 33761695f8cSDaniel Latypov */ 33861695f8cSDaniel Latypov static inline struct kunit_resource * 33961695f8cSDaniel Latypov kunit_find_resource(struct kunit *test, 34061695f8cSDaniel Latypov kunit_resource_match_t match, 34161695f8cSDaniel Latypov void *match_data) 34261695f8cSDaniel Latypov { 34361695f8cSDaniel Latypov struct kunit_resource *res, *found = NULL; 34461695f8cSDaniel Latypov unsigned long flags; 34561695f8cSDaniel Latypov 34661695f8cSDaniel Latypov spin_lock_irqsave(&test->lock, flags); 34761695f8cSDaniel Latypov 34861695f8cSDaniel Latypov list_for_each_entry_reverse(res, &test->resources, node) { 34961695f8cSDaniel Latypov if (match(test, res, (void *)match_data)) { 35061695f8cSDaniel Latypov found = res; 35161695f8cSDaniel Latypov kunit_get_resource(found); 35261695f8cSDaniel Latypov break; 35361695f8cSDaniel Latypov } 35461695f8cSDaniel Latypov } 35561695f8cSDaniel Latypov 35661695f8cSDaniel Latypov spin_unlock_irqrestore(&test->lock, flags); 35761695f8cSDaniel Latypov 35861695f8cSDaniel Latypov return found; 35961695f8cSDaniel Latypov } 36061695f8cSDaniel Latypov 36161695f8cSDaniel Latypov /** 36261695f8cSDaniel Latypov * kunit_find_named_resource() - Find a resource using match name. 36361695f8cSDaniel Latypov * @test: Test case to which the resource belongs. 36461695f8cSDaniel Latypov * @name: match name. 36561695f8cSDaniel Latypov */ 36661695f8cSDaniel Latypov static inline struct kunit_resource * 36761695f8cSDaniel Latypov kunit_find_named_resource(struct kunit *test, 36861695f8cSDaniel Latypov const char *name) 36961695f8cSDaniel Latypov { 37061695f8cSDaniel Latypov return kunit_find_resource(test, kunit_resource_name_match, 37161695f8cSDaniel Latypov (void *)name); 37261695f8cSDaniel Latypov } 37361695f8cSDaniel Latypov 37461695f8cSDaniel Latypov /** 37561695f8cSDaniel Latypov * kunit_destroy_resource() - Find a kunit_resource and destroy it. 37661695f8cSDaniel Latypov * @test: Test case to which the resource belongs. 37761695f8cSDaniel Latypov * @match: Match function. Returns whether a given resource matches @match_data. 37861695f8cSDaniel Latypov * @match_data: Data passed into @match. 37961695f8cSDaniel Latypov * 38061695f8cSDaniel Latypov * RETURNS: 38161695f8cSDaniel Latypov * 0 if kunit_resource is found and freed, -ENOENT if not found. 38261695f8cSDaniel Latypov */ 38361695f8cSDaniel Latypov int kunit_destroy_resource(struct kunit *test, 38461695f8cSDaniel Latypov kunit_resource_match_t match, 38561695f8cSDaniel Latypov void *match_data); 38661695f8cSDaniel Latypov 38761695f8cSDaniel Latypov static inline int kunit_destroy_named_resource(struct kunit *test, 38861695f8cSDaniel Latypov const char *name) 38961695f8cSDaniel Latypov { 39061695f8cSDaniel Latypov return kunit_destroy_resource(test, kunit_resource_name_match, 39161695f8cSDaniel Latypov (void *)name); 39261695f8cSDaniel Latypov } 39361695f8cSDaniel Latypov 39461695f8cSDaniel Latypov /** 39561695f8cSDaniel Latypov * kunit_remove_resource() - remove resource from resource list associated with 39661695f8cSDaniel Latypov * test. 39761695f8cSDaniel Latypov * @test: The test context object. 39861695f8cSDaniel Latypov * @res: The resource to be removed. 39961695f8cSDaniel Latypov * 40061695f8cSDaniel Latypov * Note that the resource will not be immediately freed since it is likely 40161695f8cSDaniel Latypov * the caller has a reference to it via alloc_and_get() or find(); 40261695f8cSDaniel Latypov * in this case a final call to kunit_put_resource() is required. 40361695f8cSDaniel Latypov */ 40461695f8cSDaniel Latypov void kunit_remove_resource(struct kunit *test, struct kunit_resource *res); 40561695f8cSDaniel Latypov 40661695f8cSDaniel Latypov #endif /* _KUNIT_RESOURCE_H */ 407