/* SPDX-License-Identifier: GPL-2.0 */1/*2* KUnit resource API for test managed resources (allocations, etc.).3*4* Copyright (C) 2022, Google LLC.5* Author: Daniel Latypov <[email protected]>6*/78#ifndef _KUNIT_RESOURCE_H9#define _KUNIT_RESOURCE_H1011#include <kunit/test.h>1213#include <linux/kref.h>14#include <linux/list.h>15#include <linux/slab.h>16#include <linux/spinlock.h>1718struct kunit_resource;1920typedef int (*kunit_resource_init_t)(struct kunit_resource *, void *);21typedef void (*kunit_resource_free_t)(struct kunit_resource *);2223/**24* struct kunit_resource - represents a *test managed resource*25* @data: for the user to store arbitrary data.26* @name: optional name27* @free: a user supplied function to free the resource.28*29* Represents a *test managed resource*, a resource which will automatically be30* cleaned up at the end of a test case. This cleanup is performed by the 'free'31* function. The struct kunit_resource itself is freed automatically with32* kfree() if it was allocated by KUnit (e.g., by kunit_alloc_resource()), but33* must be freed by the user otherwise.34*35* Resources are reference counted so if a resource is retrieved via36* kunit_alloc_and_get_resource() or kunit_find_resource(), we need37* to call kunit_put_resource() to reduce the resource reference count38* when finished with it. Note that kunit_alloc_resource() does not require a39* kunit_resource_put() because it does not retrieve the resource itself.40*41* Example:42*43* .. code-block:: c44*45* struct kunit_kmalloc_params {46* size_t size;47* gfp_t gfp;48* };49*50* static int kunit_kmalloc_init(struct kunit_resource *res, void *context)51* {52* struct kunit_kmalloc_params *params = context;53* res->data = kmalloc(params->size, params->gfp);54*55* if (!res->data)56* return -ENOMEM;57*58* return 0;59* }60*61* static void kunit_kmalloc_free(struct kunit_resource *res)62* {63* kfree(res->data);64* }65*66* void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp)67* {68* struct kunit_kmalloc_params params;69*70* params.size = size;71* params.gfp = gfp;72*73* return kunit_alloc_resource(test, kunit_kmalloc_init,74* kunit_kmalloc_free, gfp, ¶ms);75* }76*77* Resources can also be named, with lookup/removal done on a name78* basis also. kunit_add_named_resource(), kunit_find_named_resource()79* and kunit_destroy_named_resource(). Resource names must be80* unique within the test instance.81*/82struct kunit_resource {83void *data;84const char *name;85kunit_resource_free_t free;8687/* private: internal use only. */88struct kref refcount;89struct list_head node;90bool should_kfree;91};9293/**94* kunit_get_resource() - Hold resource for use. Should not need to be used95* by most users as we automatically get resources96* retrieved by kunit_find_resource*().97* @res: resource98*/99static inline void kunit_get_resource(struct kunit_resource *res)100{101kref_get(&res->refcount);102}103104/*105* Called when refcount reaches zero via kunit_put_resource();106* should not be called directly.107*/108static inline void kunit_release_resource(struct kref *kref)109{110struct kunit_resource *res = container_of(kref, struct kunit_resource,111refcount);112113if (res->free)114res->free(res);115116/* 'res' is valid here, as if should_kfree is set, res->free may not free117* 'res' itself, just res->data118*/119if (res->should_kfree)120kfree(res);121}122123/**124* kunit_put_resource() - When caller is done with retrieved resource,125* kunit_put_resource() should be called to drop126* reference count. The resource list maintains127* a reference count on resources, so if no users128* are utilizing a resource and it is removed from129* the resource list, it will be freed via the130* associated free function (if any). Only131* needs to be used if we alloc_and_get() or132* find() resource.133* @res: resource134*/135static inline void kunit_put_resource(struct kunit_resource *res)136{137kref_put(&res->refcount, kunit_release_resource);138}139140/**141* __kunit_add_resource() - Internal helper to add a resource.142*143* res->should_kfree is not initialised.144* @test: The test context object.145* @init: a user-supplied function to initialize the result (if needed). If146* none is supplied, the resource data value is simply set to @data.147* If an init function is supplied, @data is passed to it instead.148* @free: a user-supplied function to free the resource (if needed).149* @res: The resource.150* @data: value to pass to init function or set in resource data field.151*/152int __kunit_add_resource(struct kunit *test,153kunit_resource_init_t init,154kunit_resource_free_t free,155struct kunit_resource *res,156void *data);157158/**159* kunit_add_resource() - Add a *test managed resource*.160* @test: The test context object.161* @init: a user-supplied function to initialize the result (if needed). If162* none is supplied, the resource data value is simply set to @data.163* If an init function is supplied, @data is passed to it instead.164* @free: a user-supplied function to free the resource (if needed).165* @res: The resource.166* @data: value to pass to init function or set in resource data field.167*/168static inline int kunit_add_resource(struct kunit *test,169kunit_resource_init_t init,170kunit_resource_free_t free,171struct kunit_resource *res,172void *data)173{174res->should_kfree = false;175return __kunit_add_resource(test, init, free, res, data);176}177178static inline struct kunit_resource *179kunit_find_named_resource(struct kunit *test, const char *name);180181/**182* kunit_add_named_resource() - Add a named *test managed resource*.183* @test: The test context object.184* @init: a user-supplied function to initialize the resource data, if needed.185* @free: a user-supplied function to free the resource data, if needed.186* @res: The resource.187* @name: name to be set for resource.188* @data: value to pass to init function or set in resource data field.189*/190static inline int kunit_add_named_resource(struct kunit *test,191kunit_resource_init_t init,192kunit_resource_free_t free,193struct kunit_resource *res,194const char *name,195void *data)196{197struct kunit_resource *existing;198199if (!name)200return -EINVAL;201202existing = kunit_find_named_resource(test, name);203if (existing) {204kunit_put_resource(existing);205return -EEXIST;206}207208res->name = name;209res->should_kfree = false;210211return __kunit_add_resource(test, init, free, res, data);212}213214/**215* kunit_alloc_and_get_resource() - Allocates and returns a *test managed resource*.216* @test: The test context object.217* @init: a user supplied function to initialize the resource.218* @free: a user supplied function to free the resource (if needed).219* @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL220* @context: for the user to pass in arbitrary data to the init function.221*222* Allocates a *test managed resource*, a resource which will automatically be223* cleaned up at the end of a test case. See &struct kunit_resource for an224* example.225*226* This is effectively identical to kunit_alloc_resource, but returns the227* struct kunit_resource pointer, not just the 'data' pointer. It therefore228* also increments the resource's refcount, so kunit_put_resource() should be229* called when you've finished with it.230*231* Note: KUnit needs to allocate memory for a kunit_resource object. You must232* specify an @internal_gfp that is compatible with the use context of your233* resource.234*/235static inline struct kunit_resource *236kunit_alloc_and_get_resource(struct kunit *test,237kunit_resource_init_t init,238kunit_resource_free_t free,239gfp_t internal_gfp,240void *context)241{242struct kunit_resource *res;243int ret;244245res = kzalloc(sizeof(*res), internal_gfp);246if (!res)247return NULL;248249res->should_kfree = true;250251ret = __kunit_add_resource(test, init, free, res, context);252if (!ret) {253/*254* bump refcount for get; kunit_resource_put() should be called255* when done.256*/257kunit_get_resource(res);258return res;259}260return NULL;261}262263/**264* kunit_alloc_resource() - Allocates a *test managed resource*.265* @test: The test context object.266* @init: a user supplied function to initialize the resource.267* @free: a user supplied function to free the resource (if needed).268* @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL269* @context: for the user to pass in arbitrary data to the init function.270*271* Allocates a *test managed resource*, a resource which will automatically be272* cleaned up at the end of a test case. See &struct kunit_resource for an273* example.274*275* Note: KUnit needs to allocate memory for a kunit_resource object. You must276* specify an @internal_gfp that is compatible with the use context of your277* resource.278*/279static inline void *kunit_alloc_resource(struct kunit *test,280kunit_resource_init_t init,281kunit_resource_free_t free,282gfp_t internal_gfp,283void *context)284{285struct kunit_resource *res;286287res = kzalloc(sizeof(*res), internal_gfp);288if (!res)289return NULL;290291res->should_kfree = true;292if (!__kunit_add_resource(test, init, free, res, context))293return res->data;294295return NULL;296}297298typedef bool (*kunit_resource_match_t)(struct kunit *test,299struct kunit_resource *res,300void *match_data);301302/**303* kunit_resource_name_match() - Match a resource with the same name.304* @test: Test case to which the resource belongs.305* @res: The resource.306* @match_name: The name to match against.307*/308static inline bool kunit_resource_name_match(struct kunit *test,309struct kunit_resource *res,310void *match_name)311{312return res->name && strcmp(res->name, match_name) == 0;313}314315/**316* kunit_find_resource() - Find a resource using match function/data.317* @test: Test case to which the resource belongs.318* @match: match function to be applied to resources/match data.319* @match_data: data to be used in matching.320*/321static inline struct kunit_resource *322kunit_find_resource(struct kunit *test,323kunit_resource_match_t match,324void *match_data)325{326struct kunit_resource *res, *found = NULL;327unsigned long flags;328329spin_lock_irqsave(&test->lock, flags);330331list_for_each_entry_reverse(res, &test->resources, node) {332if (match(test, res, (void *)match_data)) {333found = res;334kunit_get_resource(found);335break;336}337}338339spin_unlock_irqrestore(&test->lock, flags);340341return found;342}343344/**345* kunit_find_named_resource() - Find a resource using match name.346* @test: Test case to which the resource belongs.347* @name: match name.348*/349static inline struct kunit_resource *350kunit_find_named_resource(struct kunit *test,351const char *name)352{353return kunit_find_resource(test, kunit_resource_name_match,354(void *)name);355}356357/**358* kunit_destroy_resource() - Find a kunit_resource and destroy it.359* @test: Test case to which the resource belongs.360* @match: Match function. Returns whether a given resource matches @match_data.361* @match_data: Data passed into @match.362*363* RETURNS:364* 0 if kunit_resource is found and freed, -ENOENT if not found.365*/366int kunit_destroy_resource(struct kunit *test,367kunit_resource_match_t match,368void *match_data);369370static inline int kunit_destroy_named_resource(struct kunit *test,371const char *name)372{373return kunit_destroy_resource(test, kunit_resource_name_match,374(void *)name);375}376377/**378* kunit_remove_resource() - remove resource from resource list associated with379* test.380* @test: The test context object.381* @res: The resource to be removed.382*383* Note that the resource will not be immediately freed since it is likely384* the caller has a reference to it via alloc_and_get() or find();385* in this case a final call to kunit_put_resource() is required.386*/387void kunit_remove_resource(struct kunit *test, struct kunit_resource *res);388389/* A 'deferred action' function to be used with kunit_add_action. */390typedef void (kunit_action_t)(void *);391392/**393* KUNIT_DEFINE_ACTION_WRAPPER() - Wrap a function for use as a deferred action.394*395* @wrapper: The name of the new wrapper function define.396* @orig: The original function to wrap.397* @arg_type: The type of the argument accepted by @orig.398*399* Defines a wrapper for a function which accepts a single, pointer-sized400* argument. This wrapper can then be passed to kunit_add_action() and401* similar. This should be used in preference to casting a function402* directly to kunit_action_t, as casting function pointers will break403* control flow integrity (CFI), leading to crashes.404*/405#define KUNIT_DEFINE_ACTION_WRAPPER(wrapper, orig, arg_type) \406static void wrapper(void *in) \407{ \408arg_type arg = (arg_type)in; \409orig(arg); \410}411412413/**414* kunit_add_action() - Call a function when the test ends.415* @test: Test case to associate the action with.416* @action: The function to run on test exit417* @ctx: Data passed into @func418*419* Defer the execution of a function until the test exits, either normally or420* due to a failure. @ctx is passed as additional context. All functions421* registered with kunit_add_action() will execute in the opposite order to that422* they were registered in.423*424* This is useful for cleaning up allocated memory and resources, as these425* functions are called even if the test aborts early due to, e.g., a failed426* assertion.427*428* See also: devm_add_action() for the devres equivalent.429*430* Returns:431* 0 on success, an error if the action could not be deferred.432*/433int kunit_add_action(struct kunit *test, kunit_action_t *action, void *ctx);434435/**436* kunit_add_action_or_reset() - Call a function when the test ends.437* @test: Test case to associate the action with.438* @action: The function to run on test exit439* @ctx: Data passed into @func440*441* Defer the execution of a function until the test exits, either normally or442* due to a failure. @ctx is passed as additional context. All functions443* registered with kunit_add_action() will execute in the opposite order to that444* they were registered in.445*446* This is useful for cleaning up allocated memory and resources, as these447* functions are called even if the test aborts early due to, e.g., a failed448* assertion.449*450* If the action cannot be created (e.g., due to the system being out of memory),451* then action(ctx) will be called immediately, and an error will be returned.452*453* See also: devm_add_action_or_reset() for the devres equivalent.454*455* Returns:456* 0 on success, an error if the action could not be deferred.457*/458int kunit_add_action_or_reset(struct kunit *test, kunit_action_t *action,459void *ctx);460461/**462* kunit_remove_action() - Cancel a matching deferred action.463* @test: Test case the action is associated with.464* @action: The deferred function to cancel.465* @ctx: The context passed to the deferred function to trigger.466*467* Prevent an action deferred via kunit_add_action() from executing when the468* test terminates.469*470* If the function/context pair was deferred multiple times, only the most471* recent one will be cancelled.472*473* See also: devm_remove_action() for the devres equivalent.474*/475void kunit_remove_action(struct kunit *test,476kunit_action_t *action,477void *ctx);478479/**480* kunit_release_action() - Run a matching action call immediately.481* @test: Test case the action is associated with.482* @action: The deferred function to trigger.483* @ctx: The context passed to the deferred function to trigger.484*485* Execute a function deferred via kunit_add_action()) immediately, rather than486* when the test ends.487*488* If the function/context pair was deferred multiple times, it will only be489* executed once here. The most recent deferral will no longer execute when490* the test ends.491*492* kunit_release_action(test, func, ctx);493* is equivalent to494* func(ctx);495* kunit_remove_action(test, func, ctx);496*497* See also: devm_release_action() for the devres equivalent.498*/499void kunit_release_action(struct kunit *test,500kunit_action_t *action,501void *ctx);502#endif /* _KUNIT_RESOURCE_H */503504505