From patchwork Thu Feb 14 21:37:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brendan Higgins X-Patchwork-Id: 10813917 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8A1BE1390 for ; Thu, 14 Feb 2019 21:40:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7917E2EE76 for ; Thu, 14 Feb 2019 21:40:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7682B2F10E; Thu, 14 Feb 2019 21:40:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, USER_IN_DEF_DKIM_WL autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BF3AD2EE76 for ; Thu, 14 Feb 2019 21:40:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2437968AbfBNVih (ORCPT ); Thu, 14 Feb 2019 16:38:37 -0500 Received: from mail-vs1-f74.google.com ([209.85.217.74]:36178 "EHLO mail-vs1-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2392660AbfBNVif (ORCPT ); Thu, 14 Feb 2019 16:38:35 -0500 Received: by mail-vs1-f74.google.com with SMTP id r133so1838144vsc.3 for ; Thu, 14 Feb 2019 13:38:34 -0800 (PST) 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=Ck1SOUdJg93el6zD9LDGMFhnqwNSeCUtCQQCuQIbiP4=; b=VA/ItiSbuOaetkN+jfPRqnUJgkZI4hwto2HSV3Gm6FBLPmENe5bhxzdvmjivyTAXUA YGHMRN6+Gt1lgz3HoO71QyIMYU5ebg8o0nYUvippGkwnj7o7URfecbrLSLQ9NrlV7Eaa kvy+M956vkivnGNcbkpOA2J1BoonYm/S83c83yedwd0PqrLwaHlsocfSXaazmfsDPwvA DSp/CngfDuZdD3gY6HVWBeCDexd6/EO5FUVhjFORfGxmfH3Gco9US+O7qGEhMJ0WW7Ll VdXQFHD+zJ85tfVCwsUnJ4UBTkyFpyEyZqhtMmgSr3Kn+oiQn2B4wCOEegSm213D2oTj 8/Iw== 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=Ck1SOUdJg93el6zD9LDGMFhnqwNSeCUtCQQCuQIbiP4=; b=TH5ZAas7asTHQZ7m4+XtN0dGsCOLzkNDPt8dZOeDcSU/+lIXHi0u4ZdJIyuslkMu0+ tBvadBjprnsJTYvs0xNNEPcz3pm1ENQ0Gamf0B9p8+KnMn+hv+MhOZ9DmljbJPE/1Uo6 S2Zb63dqZSEtuTcdmpQaXJq0oP7SN5tIcnsOtmR/1J3fLCzxwhGcotXjIT3sgyq4L3H+ dR/HQoz9ladRmlpu439WIMf589O5M8BZdrsXqcvyAk+brIKPNW1Cg++q3tC2QekfK506 zYoOshGqA3rX28tuBRwAs9KB0UndU/Zvn6plWr5P28+GMw1LFEDAjMFXkMsX0c2CddsF yDQA== X-Gm-Message-State: AHQUAuZD617cDGLvVuRMCoGYRiuz9WLAYsvLzijneZlcGxHNOEvotZor sdaZ42CKTcGSnJR0RpBX4A6WRJ1qKuVJ5HGSjAKKQg== X-Google-Smtp-Source: AHgI3Iazr0Z1RDXNcLVul5hMYFZInF41qQKyauDrUV9IP5z9uQe9taO8vIqq0bN35etCoYbaQtjLR4faogM/WzqWwU3Nhg== X-Received: by 2002:a05:6102:18f:: with SMTP id r15mr3864278vsq.46.1550180313281; Thu, 14 Feb 2019 13:38:33 -0800 (PST) Date: Thu, 14 Feb 2019 13:37:14 -0800 In-Reply-To: <20190214213729.21702-1-brendanhiggins@google.com> Message-Id: <20190214213729.21702-3-brendanhiggins@google.com> Mime-Version: 1.0 References: <20190214213729.21702-1-brendanhiggins@google.com> X-Mailer: git-send-email 2.21.0.rc0.258.g878e2cd30e-goog Subject: [RFC v4 02/17] kunit: test: add test resource management API From: Brendan Higgins To: keescook@google.com, mcgrof@kernel.org, shuah@kernel.org, robh@kernel.org, kieran.bingham@ideasonboard.com, frowand.list@gmail.com Cc: gregkh@linuxfoundation.org, joel@jms.id.au, mpe@ellerman.id.au, joe@perches.com, brakmo@fb.com, rostedt@goodmis.org, Tim.Bird@sony.com, khilman@baylibre.com, julia.lawall@lip6.fr, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, linux-kernel@vger.kernel.org, jdike@addtoit.com, richard@nod.at, linux-um@lists.infradead.org, daniel@ffwll.ch, dri-devel@lists.freedesktop.org, dan.j.williams@intel.com, linux-nvdimm@lists.01.org, knut.omang@oracle.com, devicetree@vger.kernel.org, pmladek@suse.com, Alexander.Levin@microsoft.com, amir73il@gmail.com, dan.carpenter@oracle.com, wfg@linux.intel.com, Brendan Higgins Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 23c2ebedd6dd9..21abc9e953969 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -12,6 +12,69 @@ #include #include +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, ¶ms); + * 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, + ¶ms); + + 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, ...)