resource.h (12398B)
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#ifndef _KUNIT_RESOURCE_H 10#define _KUNIT_RESOURCE_H 11 12#include <kunit/test.h> 13 14#include <linux/kref.h> 15#include <linux/list.h> 16#include <linux/slab.h> 17#include <linux/spinlock.h> 18 19struct kunit_resource; 20 21typedef int (*kunit_resource_init_t)(struct kunit_resource *, void *); 22typedef void (*kunit_resource_free_t)(struct kunit_resource *); 23 24/** 25 * struct kunit_resource - represents a *test managed resource* 26 * @data: for the user to store arbitrary data. 27 * @name: optional name 28 * @free: a user supplied function to free the resource. 29 * 30 * Represents a *test managed resource*, a resource which will automatically be 31 * cleaned up at the end of a test case. This cleanup is performed by the 'free' 32 * function. The struct kunit_resource itself is freed automatically with 33 * kfree() if it was allocated by KUnit (e.g., by kunit_alloc_resource()), but 34 * must be freed by the user otherwise. 35 * 36 * Resources are reference counted so if a resource is retrieved via 37 * kunit_alloc_and_get_resource() or kunit_find_resource(), we need 38 * to call kunit_put_resource() to reduce the resource reference count 39 * when finished with it. Note that kunit_alloc_resource() does not require a 40 * kunit_resource_put() because it does not retrieve the resource itself. 41 * 42 * Example: 43 * 44 * .. code-block:: c 45 * 46 * struct kunit_kmalloc_params { 47 * size_t size; 48 * gfp_t gfp; 49 * }; 50 * 51 * static int kunit_kmalloc_init(struct kunit_resource *res, void *context) 52 * { 53 * struct kunit_kmalloc_params *params = context; 54 * res->data = kmalloc(params->size, params->gfp); 55 * 56 * if (!res->data) 57 * return -ENOMEM; 58 * 59 * return 0; 60 * } 61 * 62 * static void kunit_kmalloc_free(struct kunit_resource *res) 63 * { 64 * kfree(res->data); 65 * } 66 * 67 * void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp) 68 * { 69 * struct kunit_kmalloc_params params; 70 * 71 * params.size = size; 72 * params.gfp = gfp; 73 * 74 * return kunit_alloc_resource(test, kunit_kmalloc_init, 75 * kunit_kmalloc_free, ¶ms); 76 * } 77 * 78 * Resources can also be named, with lookup/removal done on a name 79 * basis also. kunit_add_named_resource(), kunit_find_named_resource() 80 * and kunit_destroy_named_resource(). Resource names must be 81 * unique within the test instance. 82 */ 83struct kunit_resource { 84 void *data; 85 const char *name; 86 kunit_resource_free_t free; 87 88 /* private: internal use only. */ 89 struct kref refcount; 90 struct list_head node; 91 bool should_kfree; 92}; 93 94/** 95 * kunit_get_resource() - Hold resource for use. Should not need to be used 96 * by most users as we automatically get resources 97 * retrieved by kunit_find_resource*(). 98 * @res: resource 99 */ 100static inline void kunit_get_resource(struct kunit_resource *res) 101{ 102 kref_get(&res->refcount); 103} 104 105/* 106 * Called when refcount reaches zero via kunit_put_resource(); 107 * should not be called directly. 108 */ 109static inline void kunit_release_resource(struct kref *kref) 110{ 111 struct kunit_resource *res = container_of(kref, struct kunit_resource, 112 refcount); 113 114 if (res->free) 115 res->free(res); 116 117 /* 'res' is valid here, as if should_kfree is set, res->free may not free 118 * 'res' itself, just res->data 119 */ 120 if (res->should_kfree) 121 kfree(res); 122} 123 124/** 125 * kunit_put_resource() - When caller is done with retrieved resource, 126 * kunit_put_resource() should be called to drop 127 * reference count. The resource list maintains 128 * a reference count on resources, so if no users 129 * are utilizing a resource and it is removed from 130 * the resource list, it will be freed via the 131 * associated free function (if any). Only 132 * needs to be used if we alloc_and_get() or 133 * find() resource. 134 * @res: resource 135 */ 136static inline void kunit_put_resource(struct kunit_resource *res) 137{ 138 kref_put(&res->refcount, kunit_release_resource); 139} 140 141/** 142 * __kunit_add_resource() - Internal helper to add a resource. 143 * 144 * res->should_kfree is not initialised. 145 * @test: The test context object. 146 * @init: a user-supplied function to initialize the result (if needed). If 147 * none is supplied, the resource data value is simply set to @data. 148 * If an init function is supplied, @data is passed to it instead. 149 * @free: a user-supplied function to free the resource (if needed). 150 * @res: The resource. 151 * @data: value to pass to init function or set in resource data field. 152 */ 153int __kunit_add_resource(struct kunit *test, 154 kunit_resource_init_t init, 155 kunit_resource_free_t free, 156 struct kunit_resource *res, 157 void *data); 158 159/** 160 * kunit_add_resource() - Add a *test managed resource*. 161 * @test: The test context object. 162 * @init: a user-supplied function to initialize the result (if needed). If 163 * none is supplied, the resource data value is simply set to @data. 164 * If an init function is supplied, @data is passed to it instead. 165 * @free: a user-supplied function to free the resource (if needed). 166 * @res: The resource. 167 * @data: value to pass to init function or set in resource data field. 168 */ 169static inline int kunit_add_resource(struct kunit *test, 170 kunit_resource_init_t init, 171 kunit_resource_free_t free, 172 struct kunit_resource *res, 173 void *data) 174{ 175 res->should_kfree = false; 176 return __kunit_add_resource(test, init, free, res, data); 177} 178 179static inline struct kunit_resource * 180kunit_find_named_resource(struct kunit *test, const char *name); 181 182/** 183 * kunit_add_named_resource() - Add a named *test managed resource*. 184 * @test: The test context object. 185 * @init: a user-supplied function to initialize the resource data, if needed. 186 * @free: a user-supplied function to free the resource data, if needed. 187 * @res: The resource. 188 * @name: name to be set for resource. 189 * @data: value to pass to init function or set in resource data field. 190 */ 191static inline int kunit_add_named_resource(struct kunit *test, 192 kunit_resource_init_t init, 193 kunit_resource_free_t free, 194 struct kunit_resource *res, 195 const char *name, 196 void *data) 197{ 198 struct kunit_resource *existing; 199 200 if (!name) 201 return -EINVAL; 202 203 existing = kunit_find_named_resource(test, name); 204 if (existing) { 205 kunit_put_resource(existing); 206 return -EEXIST; 207 } 208 209 res->name = name; 210 res->should_kfree = false; 211 212 return __kunit_add_resource(test, init, free, res, data); 213} 214 215/** 216 * kunit_alloc_and_get_resource() - Allocates and returns a *test managed resource*. 217 * @test: The test context object. 218 * @init: a user supplied function to initialize the resource. 219 * @free: a user supplied function to free the resource (if needed). 220 * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL 221 * @context: for the user to pass in arbitrary data to the init function. 222 * 223 * Allocates a *test managed resource*, a resource which will automatically be 224 * cleaned up at the end of a test case. See &struct kunit_resource for an 225 * example. 226 * 227 * This is effectively identical to kunit_alloc_resource, but returns the 228 * struct kunit_resource pointer, not just the 'data' pointer. It therefore 229 * also increments the resource's refcount, so kunit_put_resource() should be 230 * called when you've finished with it. 231 * 232 * Note: KUnit needs to allocate memory for a kunit_resource object. You must 233 * specify an @internal_gfp that is compatible with the use context of your 234 * resource. 235 */ 236static inline struct kunit_resource * 237kunit_alloc_and_get_resource(struct kunit *test, 238 kunit_resource_init_t init, 239 kunit_resource_free_t free, 240 gfp_t internal_gfp, 241 void *context) 242{ 243 struct kunit_resource *res; 244 int ret; 245 246 res = kzalloc(sizeof(*res), internal_gfp); 247 if (!res) 248 return NULL; 249 250 res->should_kfree = true; 251 252 ret = __kunit_add_resource(test, init, free, res, context); 253 if (!ret) { 254 /* 255 * bump refcount for get; kunit_resource_put() should be called 256 * when done. 257 */ 258 kunit_get_resource(res); 259 return res; 260 } 261 return NULL; 262} 263 264/** 265 * kunit_alloc_resource() - Allocates a *test managed resource*. 266 * @test: The test context object. 267 * @init: a user supplied function to initialize the resource. 268 * @free: a user supplied function to free the resource (if needed). 269 * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL 270 * @context: for the user to pass in arbitrary data to the init function. 271 * 272 * Allocates a *test managed resource*, a resource which will automatically be 273 * cleaned up at the end of a test case. See &struct kunit_resource for an 274 * example. 275 * 276 * Note: KUnit needs to allocate memory for a kunit_resource object. You must 277 * specify an @internal_gfp that is compatible with the use context of your 278 * resource. 279 */ 280static inline void *kunit_alloc_resource(struct kunit *test, 281 kunit_resource_init_t init, 282 kunit_resource_free_t free, 283 gfp_t internal_gfp, 284 void *context) 285{ 286 struct kunit_resource *res; 287 288 res = kzalloc(sizeof(*res), internal_gfp); 289 if (!res) 290 return NULL; 291 292 res->should_kfree = true; 293 if (!__kunit_add_resource(test, init, free, res, context)) 294 return res->data; 295 296 return NULL; 297} 298 299typedef bool (*kunit_resource_match_t)(struct kunit *test, 300 struct kunit_resource *res, 301 void *match_data); 302 303/** 304 * kunit_resource_instance_match() - Match a resource with the same instance. 305 * @test: Test case to which the resource belongs. 306 * @res: The resource. 307 * @match_data: The resource pointer to match against. 308 * 309 * An instance of kunit_resource_match_t that matches a resource whose 310 * allocation matches @match_data. 311 */ 312static inline bool kunit_resource_instance_match(struct kunit *test, 313 struct kunit_resource *res, 314 void *match_data) 315{ 316 return res->data == match_data; 317} 318 319/** 320 * kunit_resource_name_match() - Match a resource with the same name. 321 * @test: Test case to which the resource belongs. 322 * @res: The resource. 323 * @match_name: The name to match against. 324 */ 325static inline bool kunit_resource_name_match(struct kunit *test, 326 struct kunit_resource *res, 327 void *match_name) 328{ 329 return res->name && strcmp(res->name, match_name) == 0; 330} 331 332/** 333 * kunit_find_resource() - Find a resource using match function/data. 334 * @test: Test case to which the resource belongs. 335 * @match: match function to be applied to resources/match data. 336 * @match_data: data to be used in matching. 337 */ 338static inline struct kunit_resource * 339kunit_find_resource(struct kunit *test, 340 kunit_resource_match_t match, 341 void *match_data) 342{ 343 struct kunit_resource *res, *found = NULL; 344 unsigned long flags; 345 346 spin_lock_irqsave(&test->lock, flags); 347 348 list_for_each_entry_reverse(res, &test->resources, node) { 349 if (match(test, res, (void *)match_data)) { 350 found = res; 351 kunit_get_resource(found); 352 break; 353 } 354 } 355 356 spin_unlock_irqrestore(&test->lock, flags); 357 358 return found; 359} 360 361/** 362 * kunit_find_named_resource() - Find a resource using match name. 363 * @test: Test case to which the resource belongs. 364 * @name: match name. 365 */ 366static inline struct kunit_resource * 367kunit_find_named_resource(struct kunit *test, 368 const char *name) 369{ 370 return kunit_find_resource(test, kunit_resource_name_match, 371 (void *)name); 372} 373 374/** 375 * kunit_destroy_resource() - Find a kunit_resource and destroy it. 376 * @test: Test case to which the resource belongs. 377 * @match: Match function. Returns whether a given resource matches @match_data. 378 * @match_data: Data passed into @match. 379 * 380 * RETURNS: 381 * 0 if kunit_resource is found and freed, -ENOENT if not found. 382 */ 383int kunit_destroy_resource(struct kunit *test, 384 kunit_resource_match_t match, 385 void *match_data); 386 387static inline int kunit_destroy_named_resource(struct kunit *test, 388 const char *name) 389{ 390 return kunit_destroy_resource(test, kunit_resource_name_match, 391 (void *)name); 392} 393 394/** 395 * kunit_remove_resource() - remove resource from resource list associated with 396 * test. 397 * @test: The test context object. 398 * @res: The resource to be removed. 399 * 400 * Note that the resource will not be immediately freed since it is likely 401 * the caller has a reference to it via alloc_and_get() or find(); 402 * in this case a final call to kunit_put_resource() is required. 403 */ 404void kunit_remove_resource(struct kunit *test, struct kunit_resource *res); 405 406#endif /* _KUNIT_RESOURCE_H */