![]() |
|
|||
0001 /* SPDX-License-Identifier: GPL-2.0 */ 0002 /* 0003 * KUnit resource API for test managed resources (allocations, etc.). 0004 * 0005 * Copyright (C) 2022, Google LLC. 0006 * Author: Daniel Latypov <dlatypov@google.com> 0007 */ 0008 0009 #ifndef _KUNIT_RESOURCE_H 0010 #define _KUNIT_RESOURCE_H 0011 0012 #include <kunit/test.h> 0013 0014 #include <linux/kref.h> 0015 #include <linux/list.h> 0016 #include <linux/slab.h> 0017 #include <linux/spinlock.h> 0018 0019 struct kunit_resource; 0020 0021 typedef int (*kunit_resource_init_t)(struct kunit_resource *, void *); 0022 typedef void (*kunit_resource_free_t)(struct kunit_resource *); 0023 0024 /** 0025 * struct kunit_resource - represents a *test managed resource* 0026 * @data: for the user to store arbitrary data. 0027 * @name: optional name 0028 * @free: a user supplied function to free the resource. 0029 * 0030 * Represents a *test managed resource*, a resource which will automatically be 0031 * cleaned up at the end of a test case. This cleanup is performed by the 'free' 0032 * function. The struct kunit_resource itself is freed automatically with 0033 * kfree() if it was allocated by KUnit (e.g., by kunit_alloc_resource()), but 0034 * must be freed by the user otherwise. 0035 * 0036 * Resources are reference counted so if a resource is retrieved via 0037 * kunit_alloc_and_get_resource() or kunit_find_resource(), we need 0038 * to call kunit_put_resource() to reduce the resource reference count 0039 * when finished with it. Note that kunit_alloc_resource() does not require a 0040 * kunit_resource_put() because it does not retrieve the resource itself. 0041 * 0042 * Example: 0043 * 0044 * .. code-block:: c 0045 * 0046 * struct kunit_kmalloc_params { 0047 * size_t size; 0048 * gfp_t gfp; 0049 * }; 0050 * 0051 * static int kunit_kmalloc_init(struct kunit_resource *res, void *context) 0052 * { 0053 * struct kunit_kmalloc_params *params = context; 0054 * res->data = kmalloc(params->size, params->gfp); 0055 * 0056 * if (!res->data) 0057 * return -ENOMEM; 0058 * 0059 * return 0; 0060 * } 0061 * 0062 * static void kunit_kmalloc_free(struct kunit_resource *res) 0063 * { 0064 * kfree(res->data); 0065 * } 0066 * 0067 * void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp) 0068 * { 0069 * struct kunit_kmalloc_params params; 0070 * 0071 * params.size = size; 0072 * params.gfp = gfp; 0073 * 0074 * return kunit_alloc_resource(test, kunit_kmalloc_init, 0075 * kunit_kmalloc_free, ¶ms); 0076 * } 0077 * 0078 * Resources can also be named, with lookup/removal done on a name 0079 * basis also. kunit_add_named_resource(), kunit_find_named_resource() 0080 * and kunit_destroy_named_resource(). Resource names must be 0081 * unique within the test instance. 0082 */ 0083 struct kunit_resource { 0084 void *data; 0085 const char *name; 0086 kunit_resource_free_t free; 0087 0088 /* private: internal use only. */ 0089 struct kref refcount; 0090 struct list_head node; 0091 bool should_kfree; 0092 }; 0093 0094 /** 0095 * kunit_get_resource() - Hold resource for use. Should not need to be used 0096 * by most users as we automatically get resources 0097 * retrieved by kunit_find_resource*(). 0098 * @res: resource 0099 */ 0100 static inline void kunit_get_resource(struct kunit_resource *res) 0101 { 0102 kref_get(&res->refcount); 0103 } 0104 0105 /* 0106 * Called when refcount reaches zero via kunit_put_resource(); 0107 * should not be called directly. 0108 */ 0109 static inline void kunit_release_resource(struct kref *kref) 0110 { 0111 struct kunit_resource *res = container_of(kref, struct kunit_resource, 0112 refcount); 0113 0114 if (res->free) 0115 res->free(res); 0116 0117 /* 'res' is valid here, as if should_kfree is set, res->free may not free 0118 * 'res' itself, just res->data 0119 */ 0120 if (res->should_kfree) 0121 kfree(res); 0122 } 0123 0124 /** 0125 * kunit_put_resource() - When caller is done with retrieved resource, 0126 * kunit_put_resource() should be called to drop 0127 * reference count. The resource list maintains 0128 * a reference count on resources, so if no users 0129 * are utilizing a resource and it is removed from 0130 * the resource list, it will be freed via the 0131 * associated free function (if any). Only 0132 * needs to be used if we alloc_and_get() or 0133 * find() resource. 0134 * @res: resource 0135 */ 0136 static inline void kunit_put_resource(struct kunit_resource *res) 0137 { 0138 kref_put(&res->refcount, kunit_release_resource); 0139 } 0140 0141 /** 0142 * __kunit_add_resource() - Internal helper to add a resource. 0143 * 0144 * res->should_kfree is not initialised. 0145 * @test: The test context object. 0146 * @init: a user-supplied function to initialize the result (if needed). If 0147 * none is supplied, the resource data value is simply set to @data. 0148 * If an init function is supplied, @data is passed to it instead. 0149 * @free: a user-supplied function to free the resource (if needed). 0150 * @res: The resource. 0151 * @data: value to pass to init function or set in resource data field. 0152 */ 0153 int __kunit_add_resource(struct kunit *test, 0154 kunit_resource_init_t init, 0155 kunit_resource_free_t free, 0156 struct kunit_resource *res, 0157 void *data); 0158 0159 /** 0160 * kunit_add_resource() - Add a *test managed resource*. 0161 * @test: The test context object. 0162 * @init: a user-supplied function to initialize the result (if needed). If 0163 * none is supplied, the resource data value is simply set to @data. 0164 * If an init function is supplied, @data is passed to it instead. 0165 * @free: a user-supplied function to free the resource (if needed). 0166 * @res: The resource. 0167 * @data: value to pass to init function or set in resource data field. 0168 */ 0169 static inline int kunit_add_resource(struct kunit *test, 0170 kunit_resource_init_t init, 0171 kunit_resource_free_t free, 0172 struct kunit_resource *res, 0173 void *data) 0174 { 0175 res->should_kfree = false; 0176 return __kunit_add_resource(test, init, free, res, data); 0177 } 0178 0179 static inline struct kunit_resource * 0180 kunit_find_named_resource(struct kunit *test, const char *name); 0181 0182 /** 0183 * kunit_add_named_resource() - Add a named *test managed resource*. 0184 * @test: The test context object. 0185 * @init: a user-supplied function to initialize the resource data, if needed. 0186 * @free: a user-supplied function to free the resource data, if needed. 0187 * @res: The resource. 0188 * @name: name to be set for resource. 0189 * @data: value to pass to init function or set in resource data field. 0190 */ 0191 static inline int kunit_add_named_resource(struct kunit *test, 0192 kunit_resource_init_t init, 0193 kunit_resource_free_t free, 0194 struct kunit_resource *res, 0195 const char *name, 0196 void *data) 0197 { 0198 struct kunit_resource *existing; 0199 0200 if (!name) 0201 return -EINVAL; 0202 0203 existing = kunit_find_named_resource(test, name); 0204 if (existing) { 0205 kunit_put_resource(existing); 0206 return -EEXIST; 0207 } 0208 0209 res->name = name; 0210 res->should_kfree = false; 0211 0212 return __kunit_add_resource(test, init, free, res, data); 0213 } 0214 0215 /** 0216 * kunit_alloc_and_get_resource() - Allocates and returns a *test managed resource*. 0217 * @test: The test context object. 0218 * @init: a user supplied function to initialize the resource. 0219 * @free: a user supplied function to free the resource (if needed). 0220 * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL 0221 * @context: for the user to pass in arbitrary data to the init function. 0222 * 0223 * Allocates a *test managed resource*, a resource which will automatically be 0224 * cleaned up at the end of a test case. See &struct kunit_resource for an 0225 * example. 0226 * 0227 * This is effectively identical to kunit_alloc_resource, but returns the 0228 * struct kunit_resource pointer, not just the 'data' pointer. It therefore 0229 * also increments the resource's refcount, so kunit_put_resource() should be 0230 * called when you've finished with it. 0231 * 0232 * Note: KUnit needs to allocate memory for a kunit_resource object. You must 0233 * specify an @internal_gfp that is compatible with the use context of your 0234 * resource. 0235 */ 0236 static inline struct kunit_resource * 0237 kunit_alloc_and_get_resource(struct kunit *test, 0238 kunit_resource_init_t init, 0239 kunit_resource_free_t free, 0240 gfp_t internal_gfp, 0241 void *context) 0242 { 0243 struct kunit_resource *res; 0244 int ret; 0245 0246 res = kzalloc(sizeof(*res), internal_gfp); 0247 if (!res) 0248 return NULL; 0249 0250 res->should_kfree = true; 0251 0252 ret = __kunit_add_resource(test, init, free, res, context); 0253 if (!ret) { 0254 /* 0255 * bump refcount for get; kunit_resource_put() should be called 0256 * when done. 0257 */ 0258 kunit_get_resource(res); 0259 return res; 0260 } 0261 return NULL; 0262 } 0263 0264 /** 0265 * kunit_alloc_resource() - Allocates a *test managed resource*. 0266 * @test: The test context object. 0267 * @init: a user supplied function to initialize the resource. 0268 * @free: a user supplied function to free the resource (if needed). 0269 * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL 0270 * @context: for the user to pass in arbitrary data to the init function. 0271 * 0272 * Allocates a *test managed resource*, a resource which will automatically be 0273 * cleaned up at the end of a test case. See &struct kunit_resource for an 0274 * example. 0275 * 0276 * Note: KUnit needs to allocate memory for a kunit_resource object. You must 0277 * specify an @internal_gfp that is compatible with the use context of your 0278 * resource. 0279 */ 0280 static inline void *kunit_alloc_resource(struct kunit *test, 0281 kunit_resource_init_t init, 0282 kunit_resource_free_t free, 0283 gfp_t internal_gfp, 0284 void *context) 0285 { 0286 struct kunit_resource *res; 0287 0288 res = kzalloc(sizeof(*res), internal_gfp); 0289 if (!res) 0290 return NULL; 0291 0292 res->should_kfree = true; 0293 if (!__kunit_add_resource(test, init, free, res, context)) 0294 return res->data; 0295 0296 return NULL; 0297 } 0298 0299 typedef bool (*kunit_resource_match_t)(struct kunit *test, 0300 struct kunit_resource *res, 0301 void *match_data); 0302 0303 /** 0304 * kunit_resource_instance_match() - Match a resource with the same instance. 0305 * @test: Test case to which the resource belongs. 0306 * @res: The resource. 0307 * @match_data: The resource pointer to match against. 0308 * 0309 * An instance of kunit_resource_match_t that matches a resource whose 0310 * allocation matches @match_data. 0311 */ 0312 static inline bool kunit_resource_instance_match(struct kunit *test, 0313 struct kunit_resource *res, 0314 void *match_data) 0315 { 0316 return res->data == match_data; 0317 } 0318 0319 /** 0320 * kunit_resource_name_match() - Match a resource with the same name. 0321 * @test: Test case to which the resource belongs. 0322 * @res: The resource. 0323 * @match_name: The name to match against. 0324 */ 0325 static inline bool kunit_resource_name_match(struct kunit *test, 0326 struct kunit_resource *res, 0327 void *match_name) 0328 { 0329 return res->name && strcmp(res->name, match_name) == 0; 0330 } 0331 0332 /** 0333 * kunit_find_resource() - Find a resource using match function/data. 0334 * @test: Test case to which the resource belongs. 0335 * @match: match function to be applied to resources/match data. 0336 * @match_data: data to be used in matching. 0337 */ 0338 static inline struct kunit_resource * 0339 kunit_find_resource(struct kunit *test, 0340 kunit_resource_match_t match, 0341 void *match_data) 0342 { 0343 struct kunit_resource *res, *found = NULL; 0344 unsigned long flags; 0345 0346 spin_lock_irqsave(&test->lock, flags); 0347 0348 list_for_each_entry_reverse(res, &test->resources, node) { 0349 if (match(test, res, (void *)match_data)) { 0350 found = res; 0351 kunit_get_resource(found); 0352 break; 0353 } 0354 } 0355 0356 spin_unlock_irqrestore(&test->lock, flags); 0357 0358 return found; 0359 } 0360 0361 /** 0362 * kunit_find_named_resource() - Find a resource using match name. 0363 * @test: Test case to which the resource belongs. 0364 * @name: match name. 0365 */ 0366 static inline struct kunit_resource * 0367 kunit_find_named_resource(struct kunit *test, 0368 const char *name) 0369 { 0370 return kunit_find_resource(test, kunit_resource_name_match, 0371 (void *)name); 0372 } 0373 0374 /** 0375 * kunit_destroy_resource() - Find a kunit_resource and destroy it. 0376 * @test: Test case to which the resource belongs. 0377 * @match: Match function. Returns whether a given resource matches @match_data. 0378 * @match_data: Data passed into @match. 0379 * 0380 * RETURNS: 0381 * 0 if kunit_resource is found and freed, -ENOENT if not found. 0382 */ 0383 int kunit_destroy_resource(struct kunit *test, 0384 kunit_resource_match_t match, 0385 void *match_data); 0386 0387 static inline int kunit_destroy_named_resource(struct kunit *test, 0388 const char *name) 0389 { 0390 return kunit_destroy_resource(test, kunit_resource_name_match, 0391 (void *)name); 0392 } 0393 0394 /** 0395 * kunit_remove_resource() - remove resource from resource list associated with 0396 * test. 0397 * @test: The test context object. 0398 * @res: The resource to be removed. 0399 * 0400 * Note that the resource will not be immediately freed since it is likely 0401 * the caller has a reference to it via alloc_and_get() or find(); 0402 * in this case a final call to kunit_put_resource() is required. 0403 */ 0404 void kunit_remove_resource(struct kunit *test, struct kunit_resource *res); 0405 0406 #endif /* _KUNIT_RESOURCE_H */
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |