Back to home page

OSCL-LXR

 
 

    


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, &params);
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 */