lkml.org 
[lkml]   [2019]   [Feb]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    Subject[RFC v4 02/17] kunit: test: add test resource management API
    From
    Create a common API for test managed resources like memory and test
    objects. A lot of times a test will want to set up infrastructure to be
    used in test cases; this could be anything from just wanting to allocate
    some memory to setting up a driver stack; this defines facilities for
    creating "test resources" which are managed by the test infrastructure
    and are automatically cleaned up at the conclusion of the test.

    Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
    ---
    include/kunit/test.h | 109 +++++++++++++++++++++++++++++++++++++++++++
    kunit/test.c | 95 +++++++++++++++++++++++++++++++++++++
    2 files changed, 204 insertions(+)

    diff --git a/include/kunit/test.h b/include/kunit/test.h
    index 23c2ebedd6dd9..21abc9e953969 100644
    --- a/include/kunit/test.h
    +++ b/include/kunit/test.h
    @@ -12,6 +12,69 @@
    #include <linux/types.h>
    #include <linux/slab.h>

    +struct kunit_resource;
    +
    +typedef int (*kunit_resource_init_t)(struct kunit_resource *, void *);
    +typedef void (*kunit_resource_free_t)(struct kunit_resource *);
    +
    +/**
    + * struct kunit_resource - represents a *test managed resource*
    + * @allocation: for the user to store arbitrary data.
    + * @free: a user supplied function to free the resource. Populated by
    + * kunit_alloc_resource().
    + *
    + * Represents a *test managed resource*, a resource which will automatically be
    + * cleaned up at the end of a test case.
    + *
    + * Example:
    + *
    + * .. code-block:: c
    + *
    + * struct kunit_kmalloc_params {
    + * size_t size;
    + * gfp_t gfp;
    + * };
    + *
    + * static int kunit_kmalloc_init(struct kunit_resource *res, void *context)
    + * {
    + * struct kunit_kmalloc_params *params = context;
    + * res->allocation = kmalloc(params->size, params->gfp);
    + *
    + * if (!res->allocation)
    + * return -ENOMEM;
    + *
    + * return 0;
    + * }
    + *
    + * static void kunit_kmalloc_free(struct kunit_resource *res)
    + * {
    + * kfree(res->allocation);
    + * }
    + *
    + * void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp)
    + * {
    + * struct kunit_kmalloc_params params;
    + * struct kunit_resource *res;
    + *
    + * params.size = size;
    + * params.gfp = gfp;
    + *
    + * res = kunit_alloc_resource(test, kunit_kmalloc_init,
    + * kunit_kmalloc_free, &params);
    + * if (res)
    + * return res->allocation;
    + * else
    + * return NULL;
    + * }
    + */
    +struct kunit_resource {
    + void *allocation;
    + kunit_resource_free_t free;
    +
    + /* private: internal use only. */
    + struct list_head node;
    +};
    +
    struct kunit;

    /**
    @@ -104,6 +167,7 @@ struct kunit {
    const char *name; /* Read only after initialization! */
    spinlock_t lock; /* Gaurds all mutable test state. */
    bool success; /* Protected by lock. */
    + struct list_head resources; /* Protected by lock. */
    void (*vprintk)(const struct kunit *test,
    const char *level,
    struct va_format *vaf);
    @@ -127,6 +191,51 @@ int kunit_run_tests(struct kunit_module *module);
    } \
    late_initcall(module_kunit_init##module)

    +/**
    + * kunit_alloc_resource() - Allocates a *test managed resource*.
    + * @test: The test context object.
    + * @init: a user supplied function to initialize the resource.
    + * @free: a user supplied function to free the resource.
    + * @context: for the user to pass in arbitrary data.
    + *
    + * Allocates a *test managed resource*, a resource which will automatically be
    + * cleaned up at the end of a test case. See &struct kunit_resource for an
    + * example.
    + */
    +struct kunit_resource *kunit_alloc_resource(struct kunit *test,
    + kunit_resource_init_t init,
    + kunit_resource_free_t free,
    + void *context);
    +
    +void kunit_free_resource(struct kunit *test, struct kunit_resource *res);
    +
    +/**
    + * kunit_kmalloc() - Like kmalloc() except the allocation is *test managed*.
    + * @test: The test context object.
    + * @size: The size in bytes of the desired memory.
    + * @gfp: flags passed to underlying kmalloc().
    + *
    + * Just like `kmalloc(...)`, except the allocation is managed by the test case
    + * and is automatically cleaned up after the test case concludes. See &struct
    + * kunit_resource for more information.
    + */
    +void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp);
    +
    +/**
    + * kunit_kzalloc() - Just like kunit_kmalloc(), but zeroes the allocation.
    + * @test: The test context object.
    + * @size: The size in bytes of the desired memory.
    + * @gfp: flags passed to underlying kmalloc().
    + *
    + * See kzalloc() and kunit_kmalloc() for more information.
    + */
    +static inline void *kunit_kzalloc(struct kunit *test, size_t size, gfp_t gfp)
    +{
    + return kunit_kmalloc(test, size, gfp | __GFP_ZERO);
    +}
    +
    +void kunit_cleanup(struct kunit *test);
    +
    void __printf(3, 4) kunit_printk(const char *level,
    const struct kunit *test,
    const char *fmt, ...);
    diff --git a/kunit/test.c b/kunit/test.c
    index 0b4396f92086e..84f2e1c040af3 100644
    --- a/kunit/test.c
    +++ b/kunit/test.c
    @@ -66,6 +66,7 @@ static void kunit_vprintk(const struct kunit *test,
    int kunit_init_test(struct kunit *test, const char *name)
    {
    spin_lock_init(&test->lock);
    + INIT_LIST_HEAD(&test->resources);
    test->name = name;
    test->vprintk = kunit_vprintk;

    @@ -93,6 +94,11 @@ static void kunit_run_case_internal(struct kunit *test,
    test_case->run_case(test);
    }

    +static void kunit_case_internal_cleanup(struct kunit *test)
    +{
    + kunit_cleanup(test);
    +}
    +
    /*
    * Performs post validations and cleanup after a test case was run.
    * XXX: Should ONLY BE CALLED AFTER kunit_run_case_internal!
    @@ -103,6 +109,8 @@ static void kunit_run_case_cleanup(struct kunit *test,
    {
    if (module->exit)
    module->exit(test);
    +
    + kunit_case_internal_cleanup(test);
    }

    /*
    @@ -150,6 +158,93 @@ int kunit_run_tests(struct kunit_module *module)
    return 0;
    }

    +struct kunit_resource *kunit_alloc_resource(struct kunit *test,
    + kunit_resource_init_t init,
    + kunit_resource_free_t free,
    + void *context)
    +{
    + struct kunit_resource *res;
    + unsigned long flags;
    + int ret;
    +
    + res = kzalloc(sizeof(*res), GFP_KERNEL);
    + if (!res)
    + return NULL;
    +
    + ret = init(res, context);
    + if (ret)
    + return NULL;
    +
    + res->free = free;
    + spin_lock_irqsave(&test->lock, flags);
    + list_add_tail(&res->node, &test->resources);
    + spin_unlock_irqrestore(&test->lock, flags);
    +
    + return res;
    +}
    +
    +void kunit_free_resource(struct kunit *test, struct kunit_resource *res)
    +{
    + res->free(res);
    + list_del(&res->node);
    + kfree(res);
    +}
    +
    +struct kunit_kmalloc_params {
    + size_t size;
    + gfp_t gfp;
    +};
    +
    +static int kunit_kmalloc_init(struct kunit_resource *res, void *context)
    +{
    + struct kunit_kmalloc_params *params = context;
    +
    + res->allocation = kmalloc(params->size, params->gfp);
    + if (!res->allocation)
    + return -ENOMEM;
    +
    + return 0;
    +}
    +
    +static void kunit_kmalloc_free(struct kunit_resource *res)
    +{
    + kfree(res->allocation);
    +}
    +
    +void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp)
    +{
    + struct kunit_kmalloc_params params;
    + struct kunit_resource *res;
    +
    + params.size = size;
    + params.gfp = gfp;
    +
    + res = kunit_alloc_resource(test,
    + kunit_kmalloc_init,
    + kunit_kmalloc_free,
    + &params);
    +
    + if (res)
    + return res->allocation;
    + else
    + return NULL;
    +}
    +
    +void kunit_cleanup(struct kunit *test)
    +{
    + struct kunit_resource *resource, *resource_safe;
    + unsigned long flags;
    +
    + spin_lock_irqsave(&test->lock, flags);
    + list_for_each_entry_safe(resource,
    + resource_safe,
    + &test->resources,
    + node) {
    + kunit_free_resource(test, resource);
    + }
    + spin_unlock_irqrestore(&test->lock, flags);
    +}
    +
    void kunit_printk(const char *level,
    const struct kunit *test,
    const char *fmt, ...)
    --
    2.21.0.rc0.258.g878e2cd30e-goog
    \
     
     \ /
      Last update: 2019-02-14 22:39    [W:7.827 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site