summaryrefslogtreecommitdiff
path: root/lib/kunit
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kunit')
-rw-r--r--lib/kunit/kunit-test.c111
-rw-r--r--lib/kunit/string-stream.c14
-rw-r--r--lib/kunit/test.c171
3 files changed, 200 insertions, 96 deletions
diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
index 4f3d36a72f8f..69f902440a0e 100644
--- a/lib/kunit/kunit-test.c
+++ b/lib/kunit/kunit-test.c
@@ -118,14 +118,14 @@ static int fake_resource_init(struct kunit_resource *res, void *context)
{
struct kunit_test_resource_context *ctx = context;
- res->allocation = &ctx->is_resource_initialized;
+ res->data = &ctx->is_resource_initialized;
ctx->is_resource_initialized = true;
return 0;
}
static void fake_resource_free(struct kunit_resource *res)
{
- bool *is_resource_initialized = res->allocation;
+ bool *is_resource_initialized = res->data;
*is_resource_initialized = false;
}
@@ -154,11 +154,21 @@ static void kunit_resource_test_alloc_resource(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res);
KUNIT_EXPECT_PTR_EQ(test,
&ctx->is_resource_initialized,
- (bool *) res->allocation);
+ (bool *)res->data);
KUNIT_EXPECT_TRUE(test, list_is_last(&res->node, &ctx->test.resources));
KUNIT_EXPECT_PTR_EQ(test, free, res->free);
+
+ kunit_put_resource(res);
}
+/*
+ * Note: tests below use kunit_alloc_and_get_resource(), so as a consequence
+ * they have a reference to the associated resource that they must release
+ * via kunit_put_resource(). In normal operation, users will only
+ * have to do this for cases where they use kunit_find_resource(), and the
+ * kunit_alloc_resource() function will be used (which does not take a
+ * resource reference).
+ */
static void kunit_resource_test_destroy_resource(struct kunit *test)
{
struct kunit_test_resource_context *ctx = test->priv;
@@ -169,11 +179,12 @@ static void kunit_resource_test_destroy_resource(struct kunit *test)
GFP_KERNEL,
ctx);
+ kunit_put_resource(res);
+
KUNIT_ASSERT_FALSE(test,
- kunit_resource_destroy(&ctx->test,
+ kunit_destroy_resource(&ctx->test,
kunit_resource_instance_match,
- res->free,
- res->allocation));
+ res->data));
KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized);
KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
@@ -191,6 +202,7 @@ static void kunit_resource_test_cleanup_resources(struct kunit *test)
fake_resource_free,
GFP_KERNEL,
ctx);
+ kunit_put_resource(resources[i]);
}
kunit_cleanup(&ctx->test);
@@ -221,14 +233,14 @@ static int fake_resource_2_init(struct kunit_resource *res, void *context)
KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 2);
- res->allocation = ctx;
+ res->data = ctx;
return 0;
}
static void fake_resource_2_free(struct kunit_resource *res)
{
- struct kunit_test_resource_context *ctx = res->allocation;
+ struct kunit_test_resource_context *ctx = res->data;
KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 2);
}
@@ -236,23 +248,26 @@ static void fake_resource_2_free(struct kunit_resource *res)
static int fake_resource_1_init(struct kunit_resource *res, void *context)
{
struct kunit_test_resource_context *ctx = context;
+ struct kunit_resource *res2;
- kunit_alloc_and_get_resource(&ctx->test,
- fake_resource_2_init,
- fake_resource_2_free,
- GFP_KERNEL,
- ctx);
+ res2 = kunit_alloc_and_get_resource(&ctx->test,
+ fake_resource_2_init,
+ fake_resource_2_free,
+ GFP_KERNEL,
+ ctx);
KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 1);
- res->allocation = ctx;
+ res->data = ctx;
+
+ kunit_put_resource(res2);
return 0;
}
static void fake_resource_1_free(struct kunit_resource *res)
{
- struct kunit_test_resource_context *ctx = res->allocation;
+ struct kunit_test_resource_context *ctx = res->data;
KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 1);
}
@@ -265,13 +280,14 @@ static void fake_resource_1_free(struct kunit_resource *res)
static void kunit_resource_test_proper_free_ordering(struct kunit *test)
{
struct kunit_test_resource_context *ctx = test->priv;
+ struct kunit_resource *res;
/* fake_resource_1 allocates a fake_resource_2 in its init. */
- kunit_alloc_and_get_resource(&ctx->test,
- fake_resource_1_init,
- fake_resource_1_free,
- GFP_KERNEL,
- ctx);
+ res = kunit_alloc_and_get_resource(&ctx->test,
+ fake_resource_1_init,
+ fake_resource_1_free,
+ GFP_KERNEL,
+ ctx);
/*
* Since fake_resource_2_init calls KUNIT_RESOURCE_TEST_MARK_ORDER
@@ -281,6 +297,8 @@ static void kunit_resource_test_proper_free_ordering(struct kunit *test)
KUNIT_EXPECT_EQ(test, ctx->allocate_order[0], 2);
KUNIT_EXPECT_EQ(test, ctx->allocate_order[1], 1);
+ kunit_put_resource(res);
+
kunit_cleanup(&ctx->test);
/*
@@ -292,6 +310,57 @@ static void kunit_resource_test_proper_free_ordering(struct kunit *test)
KUNIT_EXPECT_EQ(test, ctx->free_order[1], 2);
}
+static void kunit_resource_test_static(struct kunit *test)
+{
+ struct kunit_test_resource_context ctx;
+ struct kunit_resource res;
+
+ KUNIT_EXPECT_EQ(test, kunit_add_resource(test, NULL, NULL, &res, &ctx),
+ 0);
+
+ KUNIT_EXPECT_PTR_EQ(test, res.data, (void *)&ctx);
+
+ kunit_cleanup(test);
+
+ KUNIT_EXPECT_TRUE(test, list_empty(&test->resources));
+}
+
+static void kunit_resource_test_named(struct kunit *test)
+{
+ struct kunit_resource res1, res2, *found = NULL;
+ struct kunit_test_resource_context ctx;
+
+ KUNIT_EXPECT_EQ(test,
+ kunit_add_named_resource(test, NULL, NULL, &res1,
+ "resource_1", &ctx),
+ 0);
+ KUNIT_EXPECT_PTR_EQ(test, res1.data, (void *)&ctx);
+
+ KUNIT_EXPECT_EQ(test,
+ kunit_add_named_resource(test, NULL, NULL, &res1,
+ "resource_1", &ctx),
+ -EEXIST);
+
+ KUNIT_EXPECT_EQ(test,
+ kunit_add_named_resource(test, NULL, NULL, &res2,
+ "resource_2", &ctx),
+ 0);
+
+ found = kunit_find_named_resource(test, "resource_1");
+
+ KUNIT_EXPECT_PTR_EQ(test, found, &res1);
+
+ if (found)
+ kunit_put_resource(&res1);
+
+ KUNIT_EXPECT_EQ(test, kunit_destroy_named_resource(test, "resource_2"),
+ 0);
+
+ kunit_cleanup(test);
+
+ KUNIT_EXPECT_TRUE(test, list_empty(&test->resources));
+}
+
static int kunit_resource_test_init(struct kunit *test)
{
struct kunit_test_resource_context *ctx =
@@ -320,6 +389,8 @@ static struct kunit_case kunit_resource_test_cases[] = {
KUNIT_CASE(kunit_resource_test_destroy_resource),
KUNIT_CASE(kunit_resource_test_cleanup_resources),
KUNIT_CASE(kunit_resource_test_proper_free_ordering),
+ KUNIT_CASE(kunit_resource_test_static),
+ KUNIT_CASE(kunit_resource_test_named),
{}
};
diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c
index 350392013c14..141789ca8949 100644
--- a/lib/kunit/string-stream.c
+++ b/lib/kunit/string-stream.c
@@ -33,14 +33,14 @@ static int string_stream_fragment_init(struct kunit_resource *res,
if (!frag->fragment)
return -ENOMEM;
- res->allocation = frag;
+ res->data = frag;
return 0;
}
static void string_stream_fragment_free(struct kunit_resource *res)
{
- struct string_stream_fragment *frag = res->allocation;
+ struct string_stream_fragment *frag = res->data;
list_del(&frag->node);
kunit_kfree(frag->test, frag->fragment);
@@ -65,9 +65,8 @@ static struct string_stream_fragment *alloc_string_stream_fragment(
static int string_stream_fragment_destroy(struct string_stream_fragment *frag)
{
- return kunit_resource_destroy(frag->test,
+ return kunit_destroy_resource(frag->test,
kunit_resource_instance_match,
- string_stream_fragment_free,
frag);
}
@@ -179,7 +178,7 @@ static int string_stream_init(struct kunit_resource *res, void *context)
if (!stream)
return -ENOMEM;
- res->allocation = stream;
+ res->data = stream;
stream->gfp = ctx->gfp;
stream->test = ctx->test;
INIT_LIST_HEAD(&stream->fragments);
@@ -190,7 +189,7 @@ static int string_stream_init(struct kunit_resource *res, void *context)
static void string_stream_free(struct kunit_resource *res)
{
- struct string_stream *stream = res->allocation;
+ struct string_stream *stream = res->data;
string_stream_clear(stream);
}
@@ -211,8 +210,7 @@ struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp)
int string_stream_destroy(struct string_stream *stream)
{
- return kunit_resource_destroy(stream->test,
+ return kunit_destroy_resource(stream->test,
kunit_resource_instance_match,
- string_stream_free,
stream);
}
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index ccb2ffad8dcf..c36037200310 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -8,6 +8,7 @@
#include <kunit/test.h>
#include <linux/kernel.h>
+#include <linux/kref.h>
#include <linux/sched/debug.h>
#include "debugfs.h"
@@ -406,90 +407,116 @@ void __kunit_test_suites_exit(struct kunit_suite **suites)
}
EXPORT_SYMBOL_GPL(__kunit_test_suites_exit);
-struct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test,
- kunit_resource_init_t init,
- kunit_resource_free_t free,
- gfp_t internal_gfp,
- void *context)
+/*
+ * Used for static resources and when a kunit_resource * has been created by
+ * kunit_alloc_resource(). When an init function is supplied, @data is passed
+ * into the init function; otherwise, we simply set the resource data field to
+ * the data value passed in.
+ */
+int kunit_add_resource(struct kunit *test,
+ kunit_resource_init_t init,
+ kunit_resource_free_t free,
+ struct kunit_resource *res,
+ void *data)
{
- struct kunit_resource *res;
- int ret;
+ int ret = 0;
- res = kzalloc(sizeof(*res), internal_gfp);
- if (!res)
- return NULL;
+ res->free = free;
+ kref_init(&res->refcount);
- ret = init(res, context);
- if (ret)
- return NULL;
+ if (init) {
+ ret = init(res, data);
+ if (ret)
+ return ret;
+ } else {
+ res->data = data;
+ }
- res->free = free;
spin_lock(&test->lock);
list_add_tail(&res->node, &test->resources);
+ /* refcount for list is established by kref_init() */
spin_unlock(&test->lock);
- return res;
+ return ret;
}
-EXPORT_SYMBOL_GPL(kunit_alloc_and_get_resource);
+EXPORT_SYMBOL_GPL(kunit_add_resource);
-static void kunit_resource_free(struct kunit *test, struct kunit_resource *res)
+int kunit_add_named_resource(struct kunit *test,
+ kunit_resource_init_t init,
+ kunit_resource_free_t free,
+ struct kunit_resource *res,
+ const char *name,
+ void *data)
{
- res->free(res);
- kfree(res);
+ struct kunit_resource *existing;
+
+ if (!name)
+ return -EINVAL;
+
+ existing = kunit_find_named_resource(test, name);
+ if (existing) {
+ kunit_put_resource(existing);
+ return -EEXIST;
+ }
+
+ res->name = name;
+
+ return kunit_add_resource(test, init, free, res, data);
}
+EXPORT_SYMBOL_GPL(kunit_add_named_resource);
-static struct kunit_resource *kunit_resource_find(struct kunit *test,
- kunit_resource_match_t match,
- kunit_resource_free_t free,
- void *match_data)
+struct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test,
+ kunit_resource_init_t init,
+ kunit_resource_free_t free,
+ gfp_t internal_gfp,
+ void *data)
{
- struct kunit_resource *resource;
+ struct kunit_resource *res;
+ int ret;
- lockdep_assert_held(&test->lock);
+ res = kzalloc(sizeof(*res), internal_gfp);
+ if (!res)
+ return NULL;
- list_for_each_entry_reverse(resource, &test->resources, node) {
- if (resource->free != free)
- continue;
- if (match(test, resource->allocation, match_data))
- return resource;
+ ret = kunit_add_resource(test, init, free, res, data);
+ if (!ret) {
+ /*
+ * bump refcount for get; kunit_resource_put() should be called
+ * when done.
+ */
+ kunit_get_resource(res);
+ return res;
}
-
return NULL;
}
+EXPORT_SYMBOL_GPL(kunit_alloc_and_get_resource);
-static struct kunit_resource *kunit_resource_remove(
- struct kunit *test,
- kunit_resource_match_t match,
- kunit_resource_free_t free,
- void *match_data)
+void kunit_remove_resource(struct kunit *test, struct kunit_resource *res)
{
- struct kunit_resource *resource;
-
spin_lock(&test->lock);
- resource = kunit_resource_find(test, match, free, match_data);
- if (resource)
- list_del(&resource->node);
+ list_del(&res->node);
spin_unlock(&test->lock);
-
- return resource;
+ kunit_put_resource(res);
}
+EXPORT_SYMBOL_GPL(kunit_remove_resource);
-int kunit_resource_destroy(struct kunit *test,
- kunit_resource_match_t match,
- kunit_resource_free_t free,
+int kunit_destroy_resource(struct kunit *test, kunit_resource_match_t match,
void *match_data)
{
- struct kunit_resource *resource;
-
- resource = kunit_resource_remove(test, match, free, match_data);
+ struct kunit_resource *res = kunit_find_resource(test, match,
+ match_data);
- if (!resource)
+ if (!res)
return -ENOENT;
- kunit_resource_free(test, resource);
+ kunit_remove_resource(test, res);
+
+ /* We have a reference also via _find(); drop it. */
+ kunit_put_resource(res);
+
return 0;
}
-EXPORT_SYMBOL_GPL(kunit_resource_destroy);
+EXPORT_SYMBOL_GPL(kunit_destroy_resource);
struct kunit_kmalloc_params {
size_t size;
@@ -500,8 +527,8 @@ 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)
+ res->data = kmalloc(params->size, params->gfp);
+ if (!res->data)
return -ENOMEM;
return 0;
@@ -509,7 +536,7 @@ static int kunit_kmalloc_init(struct kunit_resource *res, void *context)
static void kunit_kmalloc_free(struct kunit_resource *res)
{
- kfree(res->allocation);
+ kfree(res->data);
}
void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp)
@@ -529,20 +556,25 @@ EXPORT_SYMBOL_GPL(kunit_kmalloc);
void kunit_kfree(struct kunit *test, const void *ptr)
{
- int rc;
+ struct kunit_resource *res;
- rc = kunit_resource_destroy(test,
- kunit_resource_instance_match,
- kunit_kmalloc_free,
- (void *)ptr);
+ res = kunit_find_resource(test, kunit_resource_instance_match,
+ (void *)ptr);
+
+ /*
+ * Removing the resource from the list of resources drops the
+ * reference count to 1; the final put will trigger the free.
+ */
+ kunit_remove_resource(test, res);
+
+ kunit_put_resource(res);
- WARN_ON(rc);
}
EXPORT_SYMBOL_GPL(kunit_kfree);
void kunit_cleanup(struct kunit *test)
{
- struct kunit_resource *resource;
+ struct kunit_resource *res;
/*
* test->resources is a stack - each allocation must be freed in the
@@ -559,13 +591,16 @@ void kunit_cleanup(struct kunit *test)
spin_unlock(&test->lock);
break;
}
- resource = list_last_entry(&test->resources,
- struct kunit_resource,
- node);
- list_del(&resource->node);
+ res = list_last_entry(&test->resources,
+ struct kunit_resource,
+ node);
+ /*
+ * Need to unlock here as a resource may remove another
+ * resource, and this can't happen if the test->lock
+ * is held.
+ */
spin_unlock(&test->lock);
-
- kunit_resource_free(test, resource);
+ kunit_remove_resource(test, res);
}
}
EXPORT_SYMBOL_GPL(kunit_cleanup);