From patchwork Tue Oct 23 23:57:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brendan Higgins X-Patchwork-Id: 988423 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-um-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="SnAKEa3O"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b="vqTUqp8T"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42fr3r0sJ4z9sD4 for ; Wed, 24 Oct 2018 11:00:07 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:To:From:Subject:References:Mime-Version :Message-Id:In-Reply-To:Date:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=JlGhBjLtiEvoluw44X40+jJRjJbcah1qiBs3JAKDYdY=; b=SnAKEa3Og6M7u2 zXByddQE153H/lVFcDYIs0l19j7Hmp3S+WuuSeiRbWPiQcd4qDnTxACoYwVYELCmsQpljIVdTiuZP c4Ys2Wgzw5ley/Dbcw2JPbJEHuueHMMJgY49Exc4ip8geDXQao7BXuhOePkKSRkiuHkBBbB5ONKkK y75F8MoZ5YvkhLFKRMfB0Zzq3tqp5iag/eSTMSJRrPKvl+g8msLWy67CLABXVE5DfK+QecQ2GqZJj PJbUQyqdIVDUPjRvcUFMqZ6ZpnhOn5apJfcxv/W3Ad9u0GpM3Vxin26NFW/vs524zfPVBeUSaoVH/ kYbwqH3TULMeUjF73LBg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1gF6ad-0004EC-Ck; Tue, 23 Oct 2018 23:59:59 +0000 Received: from mail-io1-xd4a.google.com ([2607:f8b0:4864:20::d4a]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1gF6aZ-0004BG-Dm for linux-um@lists.infradead.org; Tue, 23 Oct 2018 23:59:57 +0000 Received: by mail-io1-xd4a.google.com with SMTP id o7-v6so2538902ioh.22 for ; Tue, 23 Oct 2018 16:59:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=i4liTM7DhPQkyMhWTx9SIOf7oCnvjh8LOHAI/o3dxM0=; b=vqTUqp8Tg6ilFvs6r7sRzs2MGC2n9yceVmD4gqlTxgWfh6Dz7MMBS4I7H6ZW9n6ntZ VCa3f4lwvst9ngY6Hd+H7jzKfzIA32kDxIAxbQRzEenV+eFC6BReOLIzSUF2akgrAsfk e9Fk3zUYuxU7+APyETXfgYo/s7t67mP0RL8BGR99svsodE2uBTbcgQwtGNiwDZVxjfQC W++SIFYEW+szMba3q8sBuqj5gnF2u8OVVJcYpum5nS+I77FskiLhPG/juf/KzAZc2CAN mDCyR64PKgX5HSLVS67YsnRVOM04jvuLFWQh9m+HhHLRo/wvXUQ+gA/Qx9CFTnwgnPVC HpnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=i4liTM7DhPQkyMhWTx9SIOf7oCnvjh8LOHAI/o3dxM0=; b=qPpJrrONUcNMGcVfivDLj2zKlwJHXwiAu+QuxtSfuO0TDSHt7fJHcm9yrdGl5atZyD IPfQAt1KBWUnd1wL9gqiWr2zAmBYy8CS3de/85br4/iRV+ZoVuWJ/vcvIf4EeST7j0le /bXVf5ze0G9+UL1rqxZ6ktJj/faDK2JjgH9tJY82CJfHCRZo3Jy/6lnjMhj2KWh2Sakb pLNAoDe/KZWLzkhQDcqrfhXcbJUxvOB5gseIJ4nXz1ldU1sK06cDdtXCYU3eapx6yddG 3ImWyiCAEOQAMFJv7S4U6YhE9K8ZjlQax8+w0iJdPYceAGQKQI8yPKyHIQDz9l2gyfk7 nqVg== X-Gm-Message-State: AGRZ1gJMqWUseLv/WnSOmQdzgk/hC9GW0pRJ8Rum59UDTrkl8O3EHkfm Qa6oNMvy/u3gGArWKC1/ZB9KRTkhiPtx6deQhcf9oQ== X-Google-Smtp-Source: AJdET5d7P8dRci7ukLx0FEvpHPKz1sJLYItNi2iv8ph7KOhrIkPTa82qKlIFTNKssRTKSW6z4VzGZIyf1HNaVOftl1DFlA== X-Received: by 2002:a24:7445:: with SMTP id o66-v6mr257273itc.20.1540339183059; Tue, 23 Oct 2018 16:59:43 -0700 (PDT) Date: Tue, 23 Oct 2018 16:57:38 -0700 In-Reply-To: <20181023235750.103146-1-brendanhiggins@google.com> Message-Id: <20181023235750.103146-3-brendanhiggins@google.com> Mime-Version: 1.0 References: <20181023235750.103146-1-brendanhiggins@google.com> X-Mailer: git-send-email 2.19.1.568.g152ad8e336-goog Subject: [RFC v2 02/14] kunit: test: add test resource management API From: Brendan Higgins To: gregkh@linuxfoundation.org, keescook@google.com, mcgrof@kernel.org, shuah@kernel.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20181023_165955_517366_C2171FC4 X-CRM114-Status: GOOD ( 14.43 ) X-Spam-Score: -7.6 (-------) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-7.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:d4a listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -7.5 USER_IN_DEF_DKIM_WL From: address is in the default DKIM white-list 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.0 DKIMWL_WL_MED DKIMwl.org - Whitelisted Medium sender X-BeenThere: linux-um@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: brakmo@fb.com, robh@kernel.org, richard@nod.at, dri-devel@lists.freedesktop.org, linux-nvdimm@lists.01.org, mpe@ellerman.id.au, Tim.Bird@sony.com, linux-um@lists.infradead.org, linux-kernel@vger.kernel.org, rostedt@goodmis.org, kieran.bingham@ideasonboard.com, julia.lawall@lip6.fr, joel@jms.id.au, linux-kselftest@vger.kernel.org, khilman@baylibre.com, joe@perches.com, daniel@ffwll.ch, dan.j.williams@intel.com, jdike@addtoit.com, Brendan Higgins , kunit-dev@googlegroups.com Sender: "linux-um" Errors-To: linux-um-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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 --- 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 e0b14b227ac44..1c116a20063da 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -12,6 +12,69 @@ #include #include +struct test_resource; + +typedef int (*test_resource_init_t)(struct test_resource *, void *); +typedef void (*test_resource_free_t)(struct test_resource *); + +/** + * struct test_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 + * test_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 test_kmalloc_params { + * size_t size; + * gfp_t gfp; + * }; + * + * static int test_kmalloc_init(struct test_resource *res, void *context) + * { + * struct test_kmalloc_params *params = context; + * res->allocation = kmalloc(params->size, params->gfp); + * + * if (!res->allocation) + * return -ENOMEM; + * + * return 0; + * } + * + * static void test_kmalloc_free(struct test_resource *res) + * { + * kfree(res->allocation); + * } + * + * void *test_kmalloc(struct test *test, size_t size, gfp_t gfp) + * { + * struct test_kmalloc_params params; + * struct test_resource *res; + * + * params.size = size; + * params.gfp = gfp; + * + * res = test_alloc_resource(test, test_kmalloc_init, + * test_kmalloc_free, ¶ms); + * if (res) + * return res->allocation; + * else + * return NULL; + * } + */ +struct test_resource { + void *allocation; + test_resource_free_t free; + + /* private: internal use only. */ + struct list_head node; +}; + struct test; /** @@ -104,6 +167,7 @@ struct test { 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 test *test, const char *level, struct va_format *vaf); @@ -127,6 +191,51 @@ int test_run_tests(struct test_module *module); } \ late_initcall(module_test_init##module) +/** + * test_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 test_resource for an + * example. + */ +struct test_resource *test_alloc_resource(struct test *test, + test_resource_init_t init, + test_resource_free_t free, + void *context); + +void test_free_resource(struct test *test, struct test_resource *res); + +/** + * test_kmalloc() - Just 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 + * test_resource for more information. + */ +void *test_kmalloc(struct test *test, size_t size, gfp_t gfp); + +/** + * test_kzalloc() - Just like test_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 test_kmalloc() for more information. + */ +static inline void *test_kzalloc(struct test *test, size_t size, gfp_t gfp) +{ + return test_kmalloc(test, size, gfp | __GFP_ZERO); +} + +void test_cleanup(struct test *test); + void __printf(3, 4) test_printk(const char *level, const struct test *test, const char *fmt, ...); diff --git a/kunit/test.c b/kunit/test.c index 4732e5f0d7575..fd0a51245215e 100644 --- a/kunit/test.c +++ b/kunit/test.c @@ -66,6 +66,7 @@ static void test_vprintk(const struct test *test, int test_init_test(struct test *test, const char *name) { spin_lock_init(&test->lock); + INIT_LIST_HEAD(&test->resources); test->name = name; test->vprintk = test_vprintk; @@ -93,6 +94,11 @@ static void test_run_case_internal(struct test *test, test_case->run_case(test); } +static void test_case_internal_cleanup(struct test *test) +{ + test_cleanup(test); +} + /* * Performs post validations and cleanup after a test case was run. * XXX: Should ONLY BE CALLED AFTER test_run_case_internal! @@ -103,6 +109,8 @@ static void test_run_case_cleanup(struct test *test, { if (module->exit) module->exit(test); + + test_case_internal_cleanup(test); } /* @@ -150,6 +158,93 @@ int test_run_tests(struct test_module *module) return 0; } +struct test_resource *test_alloc_resource(struct test *test, + test_resource_init_t init, + test_resource_free_t free, + void *context) +{ + struct test_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 test_free_resource(struct test *test, struct test_resource *res) +{ + res->free(res); + list_del(&res->node); + kfree(res); +} + +struct test_kmalloc_params { + size_t size; + gfp_t gfp; +}; + +static int test_kmalloc_init(struct test_resource *res, void *context) +{ + struct test_kmalloc_params *params = context; + + res->allocation = kmalloc(params->size, params->gfp); + if (!res->allocation) + return -ENOMEM; + + return 0; +} + +static void test_kmalloc_free(struct test_resource *res) +{ + kfree(res->allocation); +} + +void *test_kmalloc(struct test *test, size_t size, gfp_t gfp) +{ + struct test_kmalloc_params params; + struct test_resource *res; + + params.size = size; + params.gfp = gfp; + + res = test_alloc_resource(test, + test_kmalloc_init, + test_kmalloc_free, + ¶ms); + + if (res) + return res->allocation; + else + return NULL; +} + +void test_cleanup(struct test *test) +{ + struct test_resource *resource, *resource_safe; + unsigned long flags; + + spin_lock_irqsave(&test->lock, flags); + list_for_each_entry_safe(resource, + resource_safe, + &test->resources, + node) { + test_free_resource(test, resource); + } + spin_unlock_irqrestore(&test->lock, flags); +} + void test_printk(const char *level, const struct test *test, const char *fmt, ...)