summaryrefslogtreecommitdiff
path: root/lib/kunit/resource.c
diff options
context:
space:
mode:
authorDavid Gow <davidgow@google.com>2022-04-02 12:35:29 +0800
committerShuah Khan <skhan@linuxfoundation.org>2022-04-05 13:32:50 -0600
commit59729170afcd4900e08997a482467ffda8d88c7f (patch)
treebeff30b890129fc822ada22e2480f42c69cf84bf /lib/kunit/resource.c
parent1ff522b6ef4b40e7f46a9d8efe7554b2f3d36311 (diff)
kunit: Make kunit_remove_resource() idempotent
The kunit_remove_resource() function is used to unlink a resource from the list of resources in the test, making it no longer show up in kunit_find_resource(). However, this could lead to a race condition if two threads called kunit_remove_resource() on the same resource at the same time: the resource would be removed from the list twice (causing a crash at the second list_del()), and the refcount for the resource would be decremented twice (instead of once, for the reference held by the resource list). Fix both problems, the first by using list_del_init(), and the second by checking if the resource has already been removed using list_empty(), and only decrementing its refcount if it has not. Also add a KUnit test for the kunit_remove_resource() function which tests this behaviour. Reported-by: Daniel Latypov <dlatypov@google.com> Signed-off-by: David Gow <davidgow@google.com> Reviewed-by: Brendan Higgins <brendanhiggins@google.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Diffstat (limited to 'lib/kunit/resource.c')
-rw-r--r--lib/kunit/resource.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/lib/kunit/resource.c b/lib/kunit/resource.c
index 8f8057aad78f..b3ba0d98d89e 100644
--- a/lib/kunit/resource.c
+++ b/lib/kunit/resource.c
@@ -98,11 +98,15 @@ EXPORT_SYMBOL_GPL(kunit_alloc_and_get_resource);
void kunit_remove_resource(struct kunit *test, struct kunit_resource *res)
{
unsigned long flags;
+ bool was_linked;
spin_lock_irqsave(&test->lock, flags);
- list_del(&res->node);
+ was_linked = !list_empty(&res->node);
+ list_del_init(&res->node);
spin_unlock_irqrestore(&test->lock, flags);
- kunit_put_resource(res);
+
+ if (was_linked)
+ kunit_put_resource(res);
}
EXPORT_SYMBOL_GPL(kunit_remove_resource);