From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.5 required=3.0 tests=DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 32A57C3A5A2 for ; Sat, 21 Sep 2019 00:58:37 +0000 (UTC) Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 02C0420C01 for ; Sat, 21 Sep 2019 00:58:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="cGgtdOzz" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 02C0420C01 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-nvdimm-bounces@lists.01.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 4FCFC202EF262; Fri, 20 Sep 2019 18:01:26 -0700 (PDT) Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2607:f8b0:4864:20::749; helo=mail-qk1-x749.google.com; envelope-from=3kf6fxq4kdfuye1a0xa45335af3bb381.zb985ahk-ai059985fgf.no.be3@flex--brendanhiggins.bounces.google.com; receiver=linux-nvdimm@lists.01.org Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id C026D202ECFBB for ; Fri, 20 Sep 2019 18:01:25 -0700 (PDT) Received: by mail-qk1-x749.google.com with SMTP id o133so10272846qke.4 for ; Fri, 20 Sep 2019 17:58:35 -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=Y0xYR4PS86ooH7AKhBWD3EqeH7toUpR236CnccW5V4s=; b=cGgtdOzzxccHP4HO2P0fyy/IBVjc/aM/KrWoEEG2kM2X/HfOu0oKt1ZjOwVueH9svC 7CBUaUqTLbSd2flZaUvvZ0xlv/MUJV9Ax9MNzwrbAZEealchV6ybPkd39NJh1ol2ShMw gNcLl5u1rS/tzbIA08ASCiaYAL+xGJgPY1hh//IzJkhfIjEk7yyge9MbussmWM4gs/C6 xM/5b4VpevMVUxWfBjWrV34TKEdEBrmojl/xzbbZJ2fVgUKgpYZfYktAUzGGPSdC+/S/ OBXFa7SZF0R2Dkf0ONxTVig8DSAXX6y5l2tbGwn3wBExzk7zHftrswHl4MfdgKLo+O2g +Eaw== 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=Y0xYR4PS86ooH7AKhBWD3EqeH7toUpR236CnccW5V4s=; b=U2HXU0woGoOO1M3xHiwACJcdwGdOL0SzgZhzOYjeX09w/I6pEjsrxLZgy9T4U6uiuG u+GfdI+EZB7KuGSOkxB6Bg8kbV82IFigxZyUm+Heezaqeb/MQ2u2+a7JHS5nFD7a2s/p trMTjCWtcNzQA8JiINhms6ehFoFH+DIJH2GEMhJ7nlcWLy0k+aRQhWSVovIxSB8dcsD0 8ex6amsT67zrGNevH7qAL0bPekw/qTkDHGnvDB7CWnWlrSNPSTgcHAMzcvm0X6lyVEOr 5vTpjGdQoaboym9sXPE1j5Ggp040tgS3YWBVTXRtYY1rVnqn31CsaddF63QT9h1PO8Is qULw== X-Gm-Message-State: APjAAAVCkjk8TfqK0KjiHtt/YLGW1fg+0GcgiC/zGYn458Pijjoa/vrA 3Ej8sGMW29Cv9rWte7YtmSqtWdF85y3iYt94iGL8+g== X-Google-Smtp-Source: APXvYqzk9PPAlQcfR7BQ5fHtHQPcShYKNOzmMDVDjY1njMOiG1Qe3n+8nYrgE8+PpZuwhdiW+2ENFCaGkhJyqZCiD/CZHw== X-Received: by 2002:a65:4786:: with SMTP id e6mr17354202pgs.448.1569021584212; Fri, 20 Sep 2019 16:19:44 -0700 (PDT) Date: Fri, 20 Sep 2019 16:19:06 -0700 In-Reply-To: <20190920231923.141900-1-brendanhiggins@google.com> Message-Id: <20190920231923.141900-3-brendanhiggins@google.com> Mime-Version: 1.0 References: <20190920231923.141900-1-brendanhiggins@google.com> X-Mailer: git-send-email 2.23.0.351.gc4317032e6-goog Subject: [PATCH v16 02/19] kunit: test: add test resource management API From: Brendan Higgins To: frowand.list@gmail.com, gregkh@linuxfoundation.org, jpoimboe@redhat.com, keescook@google.com, kieran.bingham@ideasonboard.com, mcgrof@kernel.org, peterz@infradead.org, robh@kernel.org, sboyd@kernel.org, shuah@kernel.org, tytso@mit.edu, yamada.masahiro@socionext.com X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: pmladek@suse.com, linux-doc@vger.kernel.org, amir73il@gmail.com, Brendan Higgins , dri-devel@lists.freedesktop.org, Alexander.Levin@microsoft.com, linux-kselftest@vger.kernel.org, linux-nvdimm@lists.01.org, khilman@baylibre.com, knut.omang@oracle.com, wfg@linux.intel.com, joel@jms.id.au, rientjes@google.com, jdike@addtoit.com, dan.carpenter@oracle.com, devicetree@vger.kernel.org, linux-kbuild@vger.kernel.org, Tim.Bird@sony.com, linux-um@lists.infradead.org, rostedt@goodmis.org, julia.lawall@lip6.fr, kunit-dev@googlegroups.com, richard@nod.at, torvalds@linux-foundation.org, rdunlap@infradead.org, linux-kernel@vger.kernel.org, daniel@ffwll.ch, mpe@ellerman.id.au, linux-fsdevel@vger.kernel.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" 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 Reviewed-by: Greg Kroah-Hartman Reviewed-by: Logan Gunthorpe Reviewed-by: Stephen Boyd --- include/kunit/test.h | 187 +++++++++++++++++++++++++++++++++++++++++++ lib/kunit/test.c | 163 +++++++++++++++++++++++++++++++++++++ 2 files changed, 350 insertions(+) diff --git a/include/kunit/test.h b/include/kunit/test.h index e30d1bf2fb68..6781c756f11b 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -9,8 +9,72 @@ #ifndef _KUNIT_TEST_H #define _KUNIT_TEST_H +#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; + * + * return NULL; + * } + */ +struct kunit_resource { + void *allocation; + kunit_resource_free_t free; + + /* private: internal use only. */ + struct list_head node; +}; + struct kunit; /** @@ -114,6 +178,13 @@ struct kunit { * with the test case have terminated. */ bool success; /* Read only after test_case finishes! */ + spinlock_t lock; /* Guards all mutable test state. */ + /* + * Because resources is a list that may be updated multiple times (with + * new resources) from any thread associated with a test case, we must + * protect it with some type of lock. + */ + struct list_head resources; /* Protected by lock. */ }; void kunit_init_test(struct kunit *test, const char *name); @@ -147,6 +218,122 @@ int kunit_run_tests(struct kunit_suite *suite); } \ late_initcall(kunit_suite_init##suite) +/* + * Like kunit_alloc_resource() below, but returns the struct kunit_resource + * object that contains the allocation. This is mostly for testing purposes. + */ +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); + +/** + * 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. + * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL + * @context: for the user to pass in arbitrary data to the init function. + * + * 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. + * + * NOTE: KUnit needs to allocate memory for each kunit_resource object. You must + * specify an @internal_gfp that is compatible with the use context of your + * resource. + */ +static inline void *kunit_alloc_resource(struct kunit *test, + kunit_resource_init_t init, + kunit_resource_free_t free, + gfp_t internal_gfp, + void *context) +{ + struct kunit_resource *res; + + res = kunit_alloc_and_get_resource(test, init, free, internal_gfp, + context); + + if (res) + return res->allocation; + + return NULL; +} + +typedef bool (*kunit_resource_match_t)(struct kunit *test, + const void *res, + void *match_data); + +/** + * kunit_resource_instance_match() - Match a resource with the same instance. + * @test: Test case to which the resource belongs. + * @res: The data stored in kunit_resource->allocation. + * @match_data: The resource pointer to match against. + * + * An instance of kunit_resource_match_t that matches a resource whose + * allocation matches @match_data. + */ +static inline bool kunit_resource_instance_match(struct kunit *test, + const void *res, + void *match_data) +{ + return res == match_data; +} + +/** + * kunit_resource_destroy() - Find a kunit_resource and destroy it. + * @test: Test case to which the resource belongs. + * @match: Match function. Returns whether a given resource matches @match_data. + * @free: Must match free on the kunit_resource to free. + * @match_data: Data passed into @match. + * + * Free the latest kunit_resource of @test for which @free matches the + * kunit_resource_free_t associated with the resource and for which @match + * returns true. + * + * RETURNS: + * 0 if kunit_resource is found and freed, -ENOENT if not found. + */ +int kunit_resource_destroy(struct kunit *test, + kunit_resource_match_t match, + kunit_resource_free_t free, + void *match_data); + +/** + * 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_kfree() - Like kfree except for allocations managed by KUnit. + * @test: The test case to which the resource belongs. + * @ptr: The memory allocation to free. + */ +void kunit_kfree(struct kunit *test, const void *ptr); + +/** + * 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/lib/kunit/test.c b/lib/kunit/test.c index d3dda359f99b..68b1037ab74d 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -122,6 +122,8 @@ static void kunit_print_test_case_ok_not_ok(struct kunit_case *test_case, void kunit_init_test(struct kunit *test, const char *name) { + spin_lock_init(&test->lock); + INIT_LIST_HEAD(&test->resources); test->name = name; test->success = true; } @@ -153,6 +155,8 @@ static void kunit_run_case(struct kunit_suite *suite, if (suite->exit) suite->exit(&test); + kunit_cleanup(&test); + test_case->success = test.success; } @@ -173,6 +177,165 @@ int kunit_run_tests(struct kunit_suite *suite) return 0; } +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) +{ + struct kunit_resource *res; + int ret; + + res = kzalloc(sizeof(*res), internal_gfp); + if (!res) + return NULL; + + ret = init(res, context); + if (ret) + return NULL; + + res->free = free; + spin_lock(&test->lock); + list_add_tail(&res->node, &test->resources); + spin_unlock(&test->lock); + + return res; +} + +static void kunit_resource_free(struct kunit *test, struct kunit_resource *res) +{ + res->free(res); + kfree(res); +} + +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 *resource; + + lockdep_assert_held(&test->lock); + + list_for_each_entry_reverse(resource, &test->resources, node) { + if (resource->free != free) + continue; + if (match(test, resource->allocation, match_data)) + return resource; + } + + return NULL; +} + +static struct kunit_resource *kunit_resource_remove( + struct kunit *test, + kunit_resource_match_t match, + kunit_resource_free_t free, + void *match_data) +{ + struct kunit_resource *resource; + + spin_lock(&test->lock); + resource = kunit_resource_find(test, match, free, match_data); + if (resource) + list_del(&resource->node); + spin_unlock(&test->lock); + + return resource; +} + +int kunit_resource_destroy(struct kunit *test, + kunit_resource_match_t match, + kunit_resource_free_t free, + void *match_data) +{ + struct kunit_resource *resource; + + resource = kunit_resource_remove(test, match, free, match_data); + + if (!resource) + return -ENOENT; + + kunit_resource_free(test, resource); + return 0; +} + +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 = { + .size = size, + .gfp = gfp + }; + + return kunit_alloc_resource(test, + kunit_kmalloc_init, + kunit_kmalloc_free, + gfp, + ¶ms); +} + +void kunit_kfree(struct kunit *test, const void *ptr) +{ + int rc; + + rc = kunit_resource_destroy(test, + kunit_resource_instance_match, + kunit_kmalloc_free, + (void *)ptr); + + WARN_ON(rc); +} + +void kunit_cleanup(struct kunit *test) +{ + struct kunit_resource *resource; + + /* + * test->resources is a stack - each allocation must be freed in the + * reverse order from which it was added since one resource may depend + * on another for its entire lifetime. + * Also, we cannot use the normal list_for_each constructs, even the + * safe ones because *arbitrary* nodes may be deleted when + * kunit_resource_free is called; the list_for_each_safe variants only + * protect against the current node being deleted, not the next. + */ + while (true) { + spin_lock(&test->lock); + if (list_empty(&test->resources)) { + spin_unlock(&test->lock); + break; + } + resource = list_last_entry(&test->resources, + struct kunit_resource, + node); + list_del(&resource->node); + spin_unlock(&test->lock); + + kunit_resource_free(test, resource); + } +} + void kunit_printk(const char *level, const struct kunit *test, const char *fmt, ...) -- 2.23.0.351.gc4317032e6-goog _______________________________________________ Linux-nvdimm mailing list Linux-nvdimm@lists.01.org https://lists.01.org/mailman/listinfo/linux-nvdimm From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.4 required=3.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8DA09C49ED7 for ; Fri, 20 Sep 2019 23:21:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 56ED121A4A for ; Fri, 20 Sep 2019 23:21:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="cGgtdOzz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2436975AbfITXTs (ORCPT ); Fri, 20 Sep 2019 19:19:48 -0400 Received: from mail-pf1-f202.google.com ([209.85.210.202]:50149 "EHLO mail-pf1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2394067AbfITXTp (ORCPT ); Fri, 20 Sep 2019 19:19:45 -0400 Received: by mail-pf1-f202.google.com with SMTP id i28so5740237pfq.16 for ; Fri, 20 Sep 2019 16:19:45 -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=Y0xYR4PS86ooH7AKhBWD3EqeH7toUpR236CnccW5V4s=; b=cGgtdOzzxccHP4HO2P0fyy/IBVjc/aM/KrWoEEG2kM2X/HfOu0oKt1ZjOwVueH9svC 7CBUaUqTLbSd2flZaUvvZ0xlv/MUJV9Ax9MNzwrbAZEealchV6ybPkd39NJh1ol2ShMw gNcLl5u1rS/tzbIA08ASCiaYAL+xGJgPY1hh//IzJkhfIjEk7yyge9MbussmWM4gs/C6 xM/5b4VpevMVUxWfBjWrV34TKEdEBrmojl/xzbbZJ2fVgUKgpYZfYktAUzGGPSdC+/S/ OBXFa7SZF0R2Dkf0ONxTVig8DSAXX6y5l2tbGwn3wBExzk7zHftrswHl4MfdgKLo+O2g +Eaw== 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=Y0xYR4PS86ooH7AKhBWD3EqeH7toUpR236CnccW5V4s=; b=PpkDzOW3Ja2MZrsVnyEC8HMP6zJ5Yj2VSY0sRemjM3JLjfxkdxF94S7lTjvtgEuG7d 7f9uXUQ4MqAB0CPGlKcrk6G9QgUELsXurr/9aCepYemWd6FdXy0I2PDSWPALmR/sopIG fze+cepwh2Hl5d4ObuzZH41+mu53Zd1B2RuhVOtnkGJZMddJx/YjLNNFwAWS5xYzAqUD 6DFZcYnESSrC4VJYHdrokUiekKUKu+Ja2aMa3g8IyA9cZnSrixNdlzihN+1EU1G2idBE Bl+3dF43jTSfbWQb3Mr2KjMUvgtXwK1w00QF05Gf4zyew/DW+/B0qXBuQ0oSvQzlVTWr ZA7g== X-Gm-Message-State: APjAAAXbTv3IQJ+VBvrS54vzeGUu4VLkLPPqBRztgFLZzx7PLRya/aE5 pTAb1qnjw8Kbv35XxdJjYQpmQHuL0kV45N3wnaSA6w== X-Google-Smtp-Source: APXvYqzk9PPAlQcfR7BQ5fHtHQPcShYKNOzmMDVDjY1njMOiG1Qe3n+8nYrgE8+PpZuwhdiW+2ENFCaGkhJyqZCiD/CZHw== X-Received: by 2002:a65:4786:: with SMTP id e6mr17354202pgs.448.1569021584212; Fri, 20 Sep 2019 16:19:44 -0700 (PDT) Date: Fri, 20 Sep 2019 16:19:06 -0700 In-Reply-To: <20190920231923.141900-1-brendanhiggins@google.com> Message-Id: <20190920231923.141900-3-brendanhiggins@google.com> Mime-Version: 1.0 References: <20190920231923.141900-1-brendanhiggins@google.com> X-Mailer: git-send-email 2.23.0.351.gc4317032e6-goog Subject: [PATCH v16 02/19] kunit: test: add test resource management API From: Brendan Higgins To: frowand.list@gmail.com, gregkh@linuxfoundation.org, jpoimboe@redhat.com, keescook@google.com, kieran.bingham@ideasonboard.com, mcgrof@kernel.org, peterz@infradead.org, robh@kernel.org, sboyd@kernel.org, shuah@kernel.org, tytso@mit.edu, yamada.masahiro@socionext.com Cc: devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, kunit-dev@googlegroups.com, linux-doc@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-nvdimm@lists.01.org, linux-um@lists.infradead.org, Alexander.Levin@microsoft.com, Tim.Bird@sony.com, amir73il@gmail.com, dan.carpenter@oracle.com, daniel@ffwll.ch, jdike@addtoit.com, joel@jms.id.au, julia.lawall@lip6.fr, khilman@baylibre.com, knut.omang@oracle.com, logang@deltatee.com, mpe@ellerman.id.au, pmladek@suse.com, rdunlap@infradead.org, richard@nod.at, rientjes@google.com, rostedt@goodmis.org, wfg@linux.intel.com, torvalds@linux-foundation.org, Brendan Higgins Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.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 Reviewed-by: Greg Kroah-Hartman Reviewed-by: Logan Gunthorpe Reviewed-by: Stephen Boyd --- include/kunit/test.h | 187 +++++++++++++++++++++++++++++++++++++++++++ lib/kunit/test.c | 163 +++++++++++++++++++++++++++++++++++++ 2 files changed, 350 insertions(+) diff --git a/include/kunit/test.h b/include/kunit/test.h index e30d1bf2fb68..6781c756f11b 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -9,8 +9,72 @@ #ifndef _KUNIT_TEST_H #define _KUNIT_TEST_H +#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; + * + * return NULL; + * } + */ +struct kunit_resource { + void *allocation; + kunit_resource_free_t free; + + /* private: internal use only. */ + struct list_head node; +}; + struct kunit; /** @@ -114,6 +178,13 @@ struct kunit { * with the test case have terminated. */ bool success; /* Read only after test_case finishes! */ + spinlock_t lock; /* Guards all mutable test state. */ + /* + * Because resources is a list that may be updated multiple times (with + * new resources) from any thread associated with a test case, we must + * protect it with some type of lock. + */ + struct list_head resources; /* Protected by lock. */ }; void kunit_init_test(struct kunit *test, const char *name); @@ -147,6 +218,122 @@ int kunit_run_tests(struct kunit_suite *suite); } \ late_initcall(kunit_suite_init##suite) +/* + * Like kunit_alloc_resource() below, but returns the struct kunit_resource + * object that contains the allocation. This is mostly for testing purposes. + */ +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); + +/** + * 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. + * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL + * @context: for the user to pass in arbitrary data to the init function. + * + * 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. + * + * NOTE: KUnit needs to allocate memory for each kunit_resource object. You must + * specify an @internal_gfp that is compatible with the use context of your + * resource. + */ +static inline void *kunit_alloc_resource(struct kunit *test, + kunit_resource_init_t init, + kunit_resource_free_t free, + gfp_t internal_gfp, + void *context) +{ + struct kunit_resource *res; + + res = kunit_alloc_and_get_resource(test, init, free, internal_gfp, + context); + + if (res) + return res->allocation; + + return NULL; +} + +typedef bool (*kunit_resource_match_t)(struct kunit *test, + const void *res, + void *match_data); + +/** + * kunit_resource_instance_match() - Match a resource with the same instance. + * @test: Test case to which the resource belongs. + * @res: The data stored in kunit_resource->allocation. + * @match_data: The resource pointer to match against. + * + * An instance of kunit_resource_match_t that matches a resource whose + * allocation matches @match_data. + */ +static inline bool kunit_resource_instance_match(struct kunit *test, + const void *res, + void *match_data) +{ + return res == match_data; +} + +/** + * kunit_resource_destroy() - Find a kunit_resource and destroy it. + * @test: Test case to which the resource belongs. + * @match: Match function. Returns whether a given resource matches @match_data. + * @free: Must match free on the kunit_resource to free. + * @match_data: Data passed into @match. + * + * Free the latest kunit_resource of @test for which @free matches the + * kunit_resource_free_t associated with the resource and for which @match + * returns true. + * + * RETURNS: + * 0 if kunit_resource is found and freed, -ENOENT if not found. + */ +int kunit_resource_destroy(struct kunit *test, + kunit_resource_match_t match, + kunit_resource_free_t free, + void *match_data); + +/** + * 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_kfree() - Like kfree except for allocations managed by KUnit. + * @test: The test case to which the resource belongs. + * @ptr: The memory allocation to free. + */ +void kunit_kfree(struct kunit *test, const void *ptr); + +/** + * 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/lib/kunit/test.c b/lib/kunit/test.c index d3dda359f99b..68b1037ab74d 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -122,6 +122,8 @@ static void kunit_print_test_case_ok_not_ok(struct kunit_case *test_case, void kunit_init_test(struct kunit *test, const char *name) { + spin_lock_init(&test->lock); + INIT_LIST_HEAD(&test->resources); test->name = name; test->success = true; } @@ -153,6 +155,8 @@ static void kunit_run_case(struct kunit_suite *suite, if (suite->exit) suite->exit(&test); + kunit_cleanup(&test); + test_case->success = test.success; } @@ -173,6 +177,165 @@ int kunit_run_tests(struct kunit_suite *suite) return 0; } +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) +{ + struct kunit_resource *res; + int ret; + + res = kzalloc(sizeof(*res), internal_gfp); + if (!res) + return NULL; + + ret = init(res, context); + if (ret) + return NULL; + + res->free = free; + spin_lock(&test->lock); + list_add_tail(&res->node, &test->resources); + spin_unlock(&test->lock); + + return res; +} + +static void kunit_resource_free(struct kunit *test, struct kunit_resource *res) +{ + res->free(res); + kfree(res); +} + +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 *resource; + + lockdep_assert_held(&test->lock); + + list_for_each_entry_reverse(resource, &test->resources, node) { + if (resource->free != free) + continue; + if (match(test, resource->allocation, match_data)) + return resource; + } + + return NULL; +} + +static struct kunit_resource *kunit_resource_remove( + struct kunit *test, + kunit_resource_match_t match, + kunit_resource_free_t free, + void *match_data) +{ + struct kunit_resource *resource; + + spin_lock(&test->lock); + resource = kunit_resource_find(test, match, free, match_data); + if (resource) + list_del(&resource->node); + spin_unlock(&test->lock); + + return resource; +} + +int kunit_resource_destroy(struct kunit *test, + kunit_resource_match_t match, + kunit_resource_free_t free, + void *match_data) +{ + struct kunit_resource *resource; + + resource = kunit_resource_remove(test, match, free, match_data); + + if (!resource) + return -ENOENT; + + kunit_resource_free(test, resource); + return 0; +} + +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 = { + .size = size, + .gfp = gfp + }; + + return kunit_alloc_resource(test, + kunit_kmalloc_init, + kunit_kmalloc_free, + gfp, + ¶ms); +} + +void kunit_kfree(struct kunit *test, const void *ptr) +{ + int rc; + + rc = kunit_resource_destroy(test, + kunit_resource_instance_match, + kunit_kmalloc_free, + (void *)ptr); + + WARN_ON(rc); +} + +void kunit_cleanup(struct kunit *test) +{ + struct kunit_resource *resource; + + /* + * test->resources is a stack - each allocation must be freed in the + * reverse order from which it was added since one resource may depend + * on another for its entire lifetime. + * Also, we cannot use the normal list_for_each constructs, even the + * safe ones because *arbitrary* nodes may be deleted when + * kunit_resource_free is called; the list_for_each_safe variants only + * protect against the current node being deleted, not the next. + */ + while (true) { + spin_lock(&test->lock); + if (list_empty(&test->resources)) { + spin_unlock(&test->lock); + break; + } + resource = list_last_entry(&test->resources, + struct kunit_resource, + node); + list_del(&resource->node); + spin_unlock(&test->lock); + + kunit_resource_free(test, resource); + } +} + void kunit_printk(const char *level, const struct kunit *test, const char *fmt, ...) -- 2.23.0.351.gc4317032e6-goog From mboxrd@z Thu Jan 1 00:00:00 1970 From: Brendan Higgins Subject: [PATCH v16 02/19] kunit: test: add test resource management API Date: Fri, 20 Sep 2019 16:19:06 -0700 Message-ID: <20190920231923.141900-3-brendanhiggins@google.com> References: <20190920231923.141900-1-brendanhiggins@google.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: <20190920231923.141900-1-brendanhiggins@google.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: frowand.list@gmail.com, gregkh@linuxfoundation.org, jpoimboe@redhat.com, keescook@google.com, kieran.bingham@ideasonboard.com, mcgrof@kernel.org, peterz@infradead.org, robh@kernel.org, sboyd@kernel.org, shuah@kernel.org, tytso@mit.edu, yamada.masahiro@socionext.com Cc: pmladek@suse.com, linux-doc@vger.kernel.org, amir73il@gmail.com, Brendan Higgins , dri-devel@lists.freedesktop.org, Alexander.Levin@microsoft.com, linux-kselftest@vger.kernel.org, linux-nvdimm@lists.01.org, khilman@baylibre.com, knut.omang@oracle.com, wfg@linux.intel.com, joel@jms.id.au, rientjes@google.com, jdike@addtoit.com, dan.carpenter@oracle.com, devicetree@vger.kernel.org, linux-kbuild@vger.kernel.org, Tim.Bird@sony.com, linux-um@lists.infradead.org, rostedt@goodmis.org, julia.lawall@lip6.fr, kunit-dev@googlegroups.com, richard@nod.at, torvalds@linux-foundation.org, rdunlap@infradead.org, linux-kernel@vger.kernel.org, mpe@ellerman.id.au, linux-fsdevel@vger.kernel.org, logang@deltatee.com List-Id: devicetree@vger.kernel.org Q3JlYXRlIGEgY29tbW9uIEFQSSBmb3IgdGVzdCBtYW5hZ2VkIHJlc291cmNlcyBsaWtlIG1lbW9y eSBhbmQgdGVzdApvYmplY3RzLiBBIGxvdCBvZiB0aW1lcyBhIHRlc3Qgd2lsbCB3YW50IHRvIHNl dCB1cCBpbmZyYXN0cnVjdHVyZSB0byBiZQp1c2VkIGluIHRlc3QgY2FzZXM7IHRoaXMgY291bGQg YmUgYW55dGhpbmcgZnJvbSBqdXN0IHdhbnRpbmcgdG8gYWxsb2NhdGUKc29tZSBtZW1vcnkgdG8g c2V0dGluZyB1cCBhIGRyaXZlciBzdGFjazsgdGhpcyBkZWZpbmVzIGZhY2lsaXRpZXMgZm9yCmNy ZWF0aW5nICJ0ZXN0IHJlc291cmNlcyIgd2hpY2ggYXJlIG1hbmFnZWQgYnkgdGhlIHRlc3QgaW5m cmFzdHJ1Y3R1cmUKYW5kIGFyZSBhdXRvbWF0aWNhbGx5IGNsZWFuZWQgdXAgYXQgdGhlIGNvbmNs dXNpb24gb2YgdGhlIHRlc3QuCgpTaWduZWQtb2ZmLWJ5OiBCcmVuZGFuIEhpZ2dpbnMgPGJyZW5k YW5oaWdnaW5zQGdvb2dsZS5jb20+ClJldmlld2VkLWJ5OiBHcmVnIEtyb2FoLUhhcnRtYW4gPGdy ZWdraEBsaW51eGZvdW5kYXRpb24ub3JnPgpSZXZpZXdlZC1ieTogTG9nYW4gR3VudGhvcnBlIDxs b2dhbmdAZGVsdGF0ZWUuY29tPgpSZXZpZXdlZC1ieTogU3RlcGhlbiBCb3lkIDxzYm95ZEBrZXJu ZWwub3JnPgotLS0KIGluY2x1ZGUva3VuaXQvdGVzdC5oIHwgMTg3ICsrKysrKysrKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKysKIGxpYi9rdW5pdC90ZXN0LmMgICAgIHwgMTYzICsr KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIDIgZmlsZXMgY2hhbmdlZCwgMzUw IGluc2VydGlvbnMoKykKCmRpZmYgLS1naXQgYS9pbmNsdWRlL2t1bml0L3Rlc3QuaCBiL2luY2x1 ZGUva3VuaXQvdGVzdC5oCmluZGV4IGUzMGQxYmYyZmI2OC4uNjc4MWM3NTZmMTFiIDEwMDY0NAot LS0gYS9pbmNsdWRlL2t1bml0L3Rlc3QuaAorKysgYi9pbmNsdWRlL2t1bml0L3Rlc3QuaApAQCAt OSw4ICs5LDcyIEBACiAjaWZuZGVmIF9LVU5JVF9URVNUX0gKICNkZWZpbmUgX0tVTklUX1RFU1Rf SAogCisjaW5jbHVkZSA8bGludXgvc2xhYi5oPgogI2luY2x1ZGUgPGxpbnV4L3R5cGVzLmg+CiAK K3N0cnVjdCBrdW5pdF9yZXNvdXJjZTsKKwordHlwZWRlZiBpbnQgKCprdW5pdF9yZXNvdXJjZV9p bml0X3QpKHN0cnVjdCBrdW5pdF9yZXNvdXJjZSAqLCB2b2lkICopOwordHlwZWRlZiB2b2lkICgq a3VuaXRfcmVzb3VyY2VfZnJlZV90KShzdHJ1Y3Qga3VuaXRfcmVzb3VyY2UgKik7CisKKy8qKgor ICogc3RydWN0IGt1bml0X3Jlc291cmNlIC0gcmVwcmVzZW50cyBhICp0ZXN0IG1hbmFnZWQgcmVz b3VyY2UqCisgKiBAYWxsb2NhdGlvbjogZm9yIHRoZSB1c2VyIHRvIHN0b3JlIGFyYml0cmFyeSBk YXRhLgorICogQGZyZWU6IGEgdXNlciBzdXBwbGllZCBmdW5jdGlvbiB0byBmcmVlIHRoZSByZXNv dXJjZS4gUG9wdWxhdGVkIGJ5CisgKiBrdW5pdF9hbGxvY19yZXNvdXJjZSgpLgorICoKKyAqIFJl cHJlc2VudHMgYSAqdGVzdCBtYW5hZ2VkIHJlc291cmNlKiwgYSByZXNvdXJjZSB3aGljaCB3aWxs IGF1dG9tYXRpY2FsbHkgYmUKKyAqIGNsZWFuZWQgdXAgYXQgdGhlIGVuZCBvZiBhIHRlc3QgY2Fz ZS4KKyAqCisgKiBFeGFtcGxlOgorICoKKyAqIC4uIGNvZGUtYmxvY2s6OiBjCisgKgorICoJc3Ry dWN0IGt1bml0X2ttYWxsb2NfcGFyYW1zIHsKKyAqCQlzaXplX3Qgc2l6ZTsKKyAqCQlnZnBfdCBn ZnA7CisgKgl9OworICoKKyAqCXN0YXRpYyBpbnQga3VuaXRfa21hbGxvY19pbml0KHN0cnVjdCBr dW5pdF9yZXNvdXJjZSAqcmVzLCB2b2lkICpjb250ZXh0KQorICoJeworICoJCXN0cnVjdCBrdW5p dF9rbWFsbG9jX3BhcmFtcyAqcGFyYW1zID0gY29udGV4dDsKKyAqCQlyZXMtPmFsbG9jYXRpb24g PSBrbWFsbG9jKHBhcmFtcy0+c2l6ZSwgcGFyYW1zLT5nZnApOworICoKKyAqCQlpZiAoIXJlcy0+ YWxsb2NhdGlvbikKKyAqCQkJcmV0dXJuIC1FTk9NRU07CisgKgorICoJCXJldHVybiAwOworICoJ fQorICoKKyAqCXN0YXRpYyB2b2lkIGt1bml0X2ttYWxsb2NfZnJlZShzdHJ1Y3Qga3VuaXRfcmVz b3VyY2UgKnJlcykKKyAqCXsKKyAqCQlrZnJlZShyZXMtPmFsbG9jYXRpb24pOworICoJfQorICoK KyAqCXZvaWQgKmt1bml0X2ttYWxsb2Moc3RydWN0IGt1bml0ICp0ZXN0LCBzaXplX3Qgc2l6ZSwg Z2ZwX3QgZ2ZwKQorICoJeworICoJCXN0cnVjdCBrdW5pdF9rbWFsbG9jX3BhcmFtcyBwYXJhbXM7 CisgKgkJc3RydWN0IGt1bml0X3Jlc291cmNlICpyZXM7CisgKgorICoJCXBhcmFtcy5zaXplID0g c2l6ZTsKKyAqCQlwYXJhbXMuZ2ZwID0gZ2ZwOworICoKKyAqCQlyZXMgPSBrdW5pdF9hbGxvY19y ZXNvdXJjZSh0ZXN0LCBrdW5pdF9rbWFsbG9jX2luaXQsCisgKgkJCWt1bml0X2ttYWxsb2NfZnJl ZSwgJnBhcmFtcyk7CisgKgkJaWYgKHJlcykKKyAqCQkJcmV0dXJuIHJlcy0+YWxsb2NhdGlvbjsK KyAqCisgKgkJcmV0dXJuIE5VTEw7CisgKgl9CisgKi8KK3N0cnVjdCBrdW5pdF9yZXNvdXJjZSB7 CisJdm9pZCAqYWxsb2NhdGlvbjsKKwlrdW5pdF9yZXNvdXJjZV9mcmVlX3QgZnJlZTsKKworCS8q IHByaXZhdGU6IGludGVybmFsIHVzZSBvbmx5LiAqLworCXN0cnVjdCBsaXN0X2hlYWQgbm9kZTsK K307CisKIHN0cnVjdCBrdW5pdDsKIAogLyoqCkBAIC0xMTQsNiArMTc4LDEzIEBAIHN0cnVjdCBr dW5pdCB7CiAJICogd2l0aCB0aGUgdGVzdCBjYXNlIGhhdmUgdGVybWluYXRlZC4KIAkgKi8KIAli b29sIHN1Y2Nlc3M7IC8qIFJlYWQgb25seSBhZnRlciB0ZXN0X2Nhc2UgZmluaXNoZXMhICovCisJ c3BpbmxvY2tfdCBsb2NrOyAvKiBHdWFyZHMgYWxsIG11dGFibGUgdGVzdCBzdGF0ZS4gKi8KKwkv KgorCSAqIEJlY2F1c2UgcmVzb3VyY2VzIGlzIGEgbGlzdCB0aGF0IG1heSBiZSB1cGRhdGVkIG11 bHRpcGxlIHRpbWVzICh3aXRoCisJICogbmV3IHJlc291cmNlcykgZnJvbSBhbnkgdGhyZWFkIGFz c29jaWF0ZWQgd2l0aCBhIHRlc3QgY2FzZSwgd2UgbXVzdAorCSAqIHByb3RlY3QgaXQgd2l0aCBz b21lIHR5cGUgb2YgbG9jay4KKwkgKi8KKwlzdHJ1Y3QgbGlzdF9oZWFkIHJlc291cmNlczsgLyog UHJvdGVjdGVkIGJ5IGxvY2suICovCiB9OwogCiB2b2lkIGt1bml0X2luaXRfdGVzdChzdHJ1Y3Qg a3VuaXQgKnRlc3QsIGNvbnN0IGNoYXIgKm5hbWUpOwpAQCAtMTQ3LDYgKzIxOCwxMjIgQEAgaW50 IGt1bml0X3J1bl90ZXN0cyhzdHJ1Y3Qga3VuaXRfc3VpdGUgKnN1aXRlKTsKIAl9CQkJCQkJCQkg ICAgICAgXAogCWxhdGVfaW5pdGNhbGwoa3VuaXRfc3VpdGVfaW5pdCMjc3VpdGUpCiAKKy8qCisg KiBMaWtlIGt1bml0X2FsbG9jX3Jlc291cmNlKCkgYmVsb3csIGJ1dCByZXR1cm5zIHRoZSBzdHJ1 Y3Qga3VuaXRfcmVzb3VyY2UKKyAqIG9iamVjdCB0aGF0IGNvbnRhaW5zIHRoZSBhbGxvY2F0aW9u LiBUaGlzIGlzIG1vc3RseSBmb3IgdGVzdGluZyBwdXJwb3Nlcy4KKyAqLworc3RydWN0IGt1bml0 X3Jlc291cmNlICprdW5pdF9hbGxvY19hbmRfZ2V0X3Jlc291cmNlKHN0cnVjdCBrdW5pdCAqdGVz dCwKKwkJCQkJCSAgICBrdW5pdF9yZXNvdXJjZV9pbml0X3QgaW5pdCwKKwkJCQkJCSAgICBrdW5p dF9yZXNvdXJjZV9mcmVlX3QgZnJlZSwKKwkJCQkJCSAgICBnZnBfdCBpbnRlcm5hbF9nZnAsCisJ CQkJCQkgICAgdm9pZCAqY29udGV4dCk7CisKKy8qKgorICoga3VuaXRfYWxsb2NfcmVzb3VyY2Uo KSAtIEFsbG9jYXRlcyBhICp0ZXN0IG1hbmFnZWQgcmVzb3VyY2UqLgorICogQHRlc3Q6IFRoZSB0 ZXN0IGNvbnRleHQgb2JqZWN0LgorICogQGluaXQ6IGEgdXNlciBzdXBwbGllZCBmdW5jdGlvbiB0 byBpbml0aWFsaXplIHRoZSByZXNvdXJjZS4KKyAqIEBmcmVlOiBhIHVzZXIgc3VwcGxpZWQgZnVu Y3Rpb24gdG8gZnJlZSB0aGUgcmVzb3VyY2UuCisgKiBAaW50ZXJuYWxfZ2ZwOiBnZnAgdG8gdXNl IGZvciBpbnRlcm5hbCBhbGxvY2F0aW9ucywgaWYgdW5zdXJlLCB1c2UgR0ZQX0tFUk5FTAorICog QGNvbnRleHQ6IGZvciB0aGUgdXNlciB0byBwYXNzIGluIGFyYml0cmFyeSBkYXRhIHRvIHRoZSBp bml0IGZ1bmN0aW9uLgorICoKKyAqIEFsbG9jYXRlcyBhICp0ZXN0IG1hbmFnZWQgcmVzb3VyY2Uq LCBhIHJlc291cmNlIHdoaWNoIHdpbGwgYXV0b21hdGljYWxseSBiZQorICogY2xlYW5lZCB1cCBh dCB0aGUgZW5kIG9mIGEgdGVzdCBjYXNlLiBTZWUgJnN0cnVjdCBrdW5pdF9yZXNvdXJjZSBmb3Ig YW4KKyAqIGV4YW1wbGUuCisgKgorICogTk9URTogS1VuaXQgbmVlZHMgdG8gYWxsb2NhdGUgbWVt b3J5IGZvciBlYWNoIGt1bml0X3Jlc291cmNlIG9iamVjdC4gWW91IG11c3QKKyAqIHNwZWNpZnkg YW4gQGludGVybmFsX2dmcCB0aGF0IGlzIGNvbXBhdGlibGUgd2l0aCB0aGUgdXNlIGNvbnRleHQg b2YgeW91cgorICogcmVzb3VyY2UuCisgKi8KK3N0YXRpYyBpbmxpbmUgdm9pZCAqa3VuaXRfYWxs b2NfcmVzb3VyY2Uoc3RydWN0IGt1bml0ICp0ZXN0LAorCQkJCQkga3VuaXRfcmVzb3VyY2VfaW5p dF90IGluaXQsCisJCQkJCSBrdW5pdF9yZXNvdXJjZV9mcmVlX3QgZnJlZSwKKwkJCQkJIGdmcF90 IGludGVybmFsX2dmcCwKKwkJCQkJIHZvaWQgKmNvbnRleHQpCit7CisJc3RydWN0IGt1bml0X3Jl c291cmNlICpyZXM7CisKKwlyZXMgPSBrdW5pdF9hbGxvY19hbmRfZ2V0X3Jlc291cmNlKHRlc3Qs IGluaXQsIGZyZWUsIGludGVybmFsX2dmcCwKKwkJCQkJICAgY29udGV4dCk7CisKKwlpZiAocmVz KQorCQlyZXR1cm4gcmVzLT5hbGxvY2F0aW9uOworCisJcmV0dXJuIE5VTEw7Cit9CisKK3R5cGVk ZWYgYm9vbCAoKmt1bml0X3Jlc291cmNlX21hdGNoX3QpKHN0cnVjdCBrdW5pdCAqdGVzdCwKKwkJ CQkgICAgICAgY29uc3Qgdm9pZCAqcmVzLAorCQkJCSAgICAgICB2b2lkICptYXRjaF9kYXRhKTsK KworLyoqCisgKiBrdW5pdF9yZXNvdXJjZV9pbnN0YW5jZV9tYXRjaCgpIC0gTWF0Y2ggYSByZXNv dXJjZSB3aXRoIHRoZSBzYW1lIGluc3RhbmNlLgorICogQHRlc3Q6IFRlc3QgY2FzZSB0byB3aGlj aCB0aGUgcmVzb3VyY2UgYmVsb25ncy4KKyAqIEByZXM6IFRoZSBkYXRhIHN0b3JlZCBpbiBrdW5p dF9yZXNvdXJjZS0+YWxsb2NhdGlvbi4KKyAqIEBtYXRjaF9kYXRhOiBUaGUgcmVzb3VyY2UgcG9p bnRlciB0byBtYXRjaCBhZ2FpbnN0LgorICoKKyAqIEFuIGluc3RhbmNlIG9mIGt1bml0X3Jlc291 cmNlX21hdGNoX3QgdGhhdCBtYXRjaGVzIGEgcmVzb3VyY2Ugd2hvc2UKKyAqIGFsbG9jYXRpb24g bWF0Y2hlcyBAbWF0Y2hfZGF0YS4KKyAqLworc3RhdGljIGlubGluZSBib29sIGt1bml0X3Jlc291 cmNlX2luc3RhbmNlX21hdGNoKHN0cnVjdCBrdW5pdCAqdGVzdCwKKwkJCQkJCSBjb25zdCB2b2lk ICpyZXMsCisJCQkJCQkgdm9pZCAqbWF0Y2hfZGF0YSkKK3sKKwlyZXR1cm4gcmVzID09IG1hdGNo X2RhdGE7Cit9CisKKy8qKgorICoga3VuaXRfcmVzb3VyY2VfZGVzdHJveSgpIC0gRmluZCBhIGt1 bml0X3Jlc291cmNlIGFuZCBkZXN0cm95IGl0LgorICogQHRlc3Q6IFRlc3QgY2FzZSB0byB3aGlj aCB0aGUgcmVzb3VyY2UgYmVsb25ncy4KKyAqIEBtYXRjaDogTWF0Y2ggZnVuY3Rpb24uIFJldHVy bnMgd2hldGhlciBhIGdpdmVuIHJlc291cmNlIG1hdGNoZXMgQG1hdGNoX2RhdGEuCisgKiBAZnJl ZTogTXVzdCBtYXRjaCBmcmVlIG9uIHRoZSBrdW5pdF9yZXNvdXJjZSB0byBmcmVlLgorICogQG1h dGNoX2RhdGE6IERhdGEgcGFzc2VkIGludG8gQG1hdGNoLgorICoKKyAqIEZyZWUgdGhlIGxhdGVz dCBrdW5pdF9yZXNvdXJjZSBvZiBAdGVzdCBmb3Igd2hpY2ggQGZyZWUgbWF0Y2hlcyB0aGUKKyAq IGt1bml0X3Jlc291cmNlX2ZyZWVfdCBhc3NvY2lhdGVkIHdpdGggdGhlIHJlc291cmNlIGFuZCBm b3Igd2hpY2ggQG1hdGNoCisgKiByZXR1cm5zIHRydWUuCisgKgorICogUkVUVVJOUzoKKyAqIDAg aWYga3VuaXRfcmVzb3VyY2UgaXMgZm91bmQgYW5kIGZyZWVkLCAtRU5PRU5UIGlmIG5vdCBmb3Vu ZC4KKyAqLworaW50IGt1bml0X3Jlc291cmNlX2Rlc3Ryb3koc3RydWN0IGt1bml0ICp0ZXN0LAor CQkJICAga3VuaXRfcmVzb3VyY2VfbWF0Y2hfdCBtYXRjaCwKKwkJCSAgIGt1bml0X3Jlc291cmNl X2ZyZWVfdCBmcmVlLAorCQkJICAgdm9pZCAqbWF0Y2hfZGF0YSk7CisKKy8qKgorICoga3VuaXRf a21hbGxvYygpIC0gTGlrZSBrbWFsbG9jKCkgZXhjZXB0IHRoZSBhbGxvY2F0aW9uIGlzICp0ZXN0 IG1hbmFnZWQqLgorICogQHRlc3Q6IFRoZSB0ZXN0IGNvbnRleHQgb2JqZWN0LgorICogQHNpemU6 IFRoZSBzaXplIGluIGJ5dGVzIG9mIHRoZSBkZXNpcmVkIG1lbW9yeS4KKyAqIEBnZnA6IGZsYWdz IHBhc3NlZCB0byB1bmRlcmx5aW5nIGttYWxsb2MoKS4KKyAqCisgKiBKdXN0IGxpa2UgYGttYWxs b2MoLi4uKWAsIGV4Y2VwdCB0aGUgYWxsb2NhdGlvbiBpcyBtYW5hZ2VkIGJ5IHRoZSB0ZXN0IGNh c2UKKyAqIGFuZCBpcyBhdXRvbWF0aWNhbGx5IGNsZWFuZWQgdXAgYWZ0ZXIgdGhlIHRlc3QgY2Fz ZSBjb25jbHVkZXMuIFNlZSAmc3RydWN0CisgKiBrdW5pdF9yZXNvdXJjZSBmb3IgbW9yZSBpbmZv cm1hdGlvbi4KKyAqLwordm9pZCAqa3VuaXRfa21hbGxvYyhzdHJ1Y3Qga3VuaXQgKnRlc3QsIHNp emVfdCBzaXplLCBnZnBfdCBnZnApOworCisvKioKKyAqIGt1bml0X2tmcmVlKCkgLSBMaWtlIGtm cmVlIGV4Y2VwdCBmb3IgYWxsb2NhdGlvbnMgbWFuYWdlZCBieSBLVW5pdC4KKyAqIEB0ZXN0OiBU aGUgdGVzdCBjYXNlIHRvIHdoaWNoIHRoZSByZXNvdXJjZSBiZWxvbmdzLgorICogQHB0cjogVGhl IG1lbW9yeSBhbGxvY2F0aW9uIHRvIGZyZWUuCisgKi8KK3ZvaWQga3VuaXRfa2ZyZWUoc3RydWN0 IGt1bml0ICp0ZXN0LCBjb25zdCB2b2lkICpwdHIpOworCisvKioKKyAqIGt1bml0X2t6YWxsb2Mo KSAtIEp1c3QgbGlrZSBrdW5pdF9rbWFsbG9jKCksIGJ1dCB6ZXJvZXMgdGhlIGFsbG9jYXRpb24u CisgKiBAdGVzdDogVGhlIHRlc3QgY29udGV4dCBvYmplY3QuCisgKiBAc2l6ZTogVGhlIHNpemUg aW4gYnl0ZXMgb2YgdGhlIGRlc2lyZWQgbWVtb3J5LgorICogQGdmcDogZmxhZ3MgcGFzc2VkIHRv IHVuZGVybHlpbmcga21hbGxvYygpLgorICoKKyAqIFNlZSBremFsbG9jKCkgYW5kIGt1bml0X2tt YWxsb2MoKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4KKyAqLworc3RhdGljIGlubGluZSB2b2lkICpr dW5pdF9remFsbG9jKHN0cnVjdCBrdW5pdCAqdGVzdCwgc2l6ZV90IHNpemUsIGdmcF90IGdmcCkK K3sKKwlyZXR1cm4ga3VuaXRfa21hbGxvYyh0ZXN0LCBzaXplLCBnZnAgfCBfX0dGUF9aRVJPKTsK K30KKwordm9pZCBrdW5pdF9jbGVhbnVwKHN0cnVjdCBrdW5pdCAqdGVzdCk7CisKIHZvaWQgX19w cmludGYoMywgNCkga3VuaXRfcHJpbnRrKGNvbnN0IGNoYXIgKmxldmVsLAogCQkJCSBjb25zdCBz dHJ1Y3Qga3VuaXQgKnRlc3QsCiAJCQkJIGNvbnN0IGNoYXIgKmZtdCwgLi4uKTsKZGlmZiAtLWdp dCBhL2xpYi9rdW5pdC90ZXN0LmMgYi9saWIva3VuaXQvdGVzdC5jCmluZGV4IGQzZGRhMzU5Zjk5 Yi4uNjhiMTAzN2FiNzRkIDEwMDY0NAotLS0gYS9saWIva3VuaXQvdGVzdC5jCisrKyBiL2xpYi9r dW5pdC90ZXN0LmMKQEAgLTEyMiw2ICsxMjIsOCBAQCBzdGF0aWMgdm9pZCBrdW5pdF9wcmludF90 ZXN0X2Nhc2Vfb2tfbm90X29rKHN0cnVjdCBrdW5pdF9jYXNlICp0ZXN0X2Nhc2UsCiAKIHZvaWQg a3VuaXRfaW5pdF90ZXN0KHN0cnVjdCBrdW5pdCAqdGVzdCwgY29uc3QgY2hhciAqbmFtZSkKIHsK KwlzcGluX2xvY2tfaW5pdCgmdGVzdC0+bG9jayk7CisJSU5JVF9MSVNUX0hFQUQoJnRlc3QtPnJl c291cmNlcyk7CiAJdGVzdC0+bmFtZSA9IG5hbWU7CiAJdGVzdC0+c3VjY2VzcyA9IHRydWU7CiB9 CkBAIC0xNTMsNiArMTU1LDggQEAgc3RhdGljIHZvaWQga3VuaXRfcnVuX2Nhc2Uoc3RydWN0IGt1 bml0X3N1aXRlICpzdWl0ZSwKIAlpZiAoc3VpdGUtPmV4aXQpCiAJCXN1aXRlLT5leGl0KCZ0ZXN0 KTsKIAorCWt1bml0X2NsZWFudXAoJnRlc3QpOworCiAJdGVzdF9jYXNlLT5zdWNjZXNzID0gdGVz dC5zdWNjZXNzOwogfQogCkBAIC0xNzMsNiArMTc3LDE2NSBAQCBpbnQga3VuaXRfcnVuX3Rlc3Rz KHN0cnVjdCBrdW5pdF9zdWl0ZSAqc3VpdGUpCiAJcmV0dXJuIDA7CiB9CiAKK3N0cnVjdCBrdW5p dF9yZXNvdXJjZSAqa3VuaXRfYWxsb2NfYW5kX2dldF9yZXNvdXJjZShzdHJ1Y3Qga3VuaXQgKnRl c3QsCisJCQkJCQkgICAga3VuaXRfcmVzb3VyY2VfaW5pdF90IGluaXQsCisJCQkJCQkgICAga3Vu aXRfcmVzb3VyY2VfZnJlZV90IGZyZWUsCisJCQkJCQkgICAgZ2ZwX3QgaW50ZXJuYWxfZ2ZwLAor CQkJCQkJICAgIHZvaWQgKmNvbnRleHQpCit7CisJc3RydWN0IGt1bml0X3Jlc291cmNlICpyZXM7 CisJaW50IHJldDsKKworCXJlcyA9IGt6YWxsb2Moc2l6ZW9mKCpyZXMpLCBpbnRlcm5hbF9nZnAp OworCWlmICghcmVzKQorCQlyZXR1cm4gTlVMTDsKKworCXJldCA9IGluaXQocmVzLCBjb250ZXh0 KTsKKwlpZiAocmV0KQorCQlyZXR1cm4gTlVMTDsKKworCXJlcy0+ZnJlZSA9IGZyZWU7CisJc3Bp bl9sb2NrKCZ0ZXN0LT5sb2NrKTsKKwlsaXN0X2FkZF90YWlsKCZyZXMtPm5vZGUsICZ0ZXN0LT5y ZXNvdXJjZXMpOworCXNwaW5fdW5sb2NrKCZ0ZXN0LT5sb2NrKTsKKworCXJldHVybiByZXM7Cit9 CisKK3N0YXRpYyB2b2lkIGt1bml0X3Jlc291cmNlX2ZyZWUoc3RydWN0IGt1bml0ICp0ZXN0LCBz dHJ1Y3Qga3VuaXRfcmVzb3VyY2UgKnJlcykKK3sKKwlyZXMtPmZyZWUocmVzKTsKKwlrZnJlZShy ZXMpOworfQorCitzdGF0aWMgc3RydWN0IGt1bml0X3Jlc291cmNlICprdW5pdF9yZXNvdXJjZV9m aW5kKHN0cnVjdCBrdW5pdCAqdGVzdCwKKwkJCQkJCSAga3VuaXRfcmVzb3VyY2VfbWF0Y2hfdCBt YXRjaCwKKwkJCQkJCSAga3VuaXRfcmVzb3VyY2VfZnJlZV90IGZyZWUsCisJCQkJCQkgIHZvaWQg Km1hdGNoX2RhdGEpCit7CisJc3RydWN0IGt1bml0X3Jlc291cmNlICpyZXNvdXJjZTsKKworCWxv Y2tkZXBfYXNzZXJ0X2hlbGQoJnRlc3QtPmxvY2spOworCisJbGlzdF9mb3JfZWFjaF9lbnRyeV9y ZXZlcnNlKHJlc291cmNlLCAmdGVzdC0+cmVzb3VyY2VzLCBub2RlKSB7CisJCWlmIChyZXNvdXJj ZS0+ZnJlZSAhPSBmcmVlKQorCQkJY29udGludWU7CisJCWlmIChtYXRjaCh0ZXN0LCByZXNvdXJj ZS0+YWxsb2NhdGlvbiwgbWF0Y2hfZGF0YSkpCisJCQlyZXR1cm4gcmVzb3VyY2U7CisJfQorCisJ cmV0dXJuIE5VTEw7Cit9CisKK3N0YXRpYyBzdHJ1Y3Qga3VuaXRfcmVzb3VyY2UgKmt1bml0X3Jl c291cmNlX3JlbW92ZSgKKwkJc3RydWN0IGt1bml0ICp0ZXN0LAorCQlrdW5pdF9yZXNvdXJjZV9t YXRjaF90IG1hdGNoLAorCQlrdW5pdF9yZXNvdXJjZV9mcmVlX3QgZnJlZSwKKwkJdm9pZCAqbWF0 Y2hfZGF0YSkKK3sKKwlzdHJ1Y3Qga3VuaXRfcmVzb3VyY2UgKnJlc291cmNlOworCisJc3Bpbl9s b2NrKCZ0ZXN0LT5sb2NrKTsKKwlyZXNvdXJjZSA9IGt1bml0X3Jlc291cmNlX2ZpbmQodGVzdCwg bWF0Y2gsIGZyZWUsIG1hdGNoX2RhdGEpOworCWlmIChyZXNvdXJjZSkKKwkJbGlzdF9kZWwoJnJl c291cmNlLT5ub2RlKTsKKwlzcGluX3VubG9jaygmdGVzdC0+bG9jayk7CisKKwlyZXR1cm4gcmVz b3VyY2U7Cit9CisKK2ludCBrdW5pdF9yZXNvdXJjZV9kZXN0cm95KHN0cnVjdCBrdW5pdCAqdGVz dCwKKwkJCSAgIGt1bml0X3Jlc291cmNlX21hdGNoX3QgbWF0Y2gsCisJCQkgICBrdW5pdF9yZXNv dXJjZV9mcmVlX3QgZnJlZSwKKwkJCSAgIHZvaWQgKm1hdGNoX2RhdGEpCit7CisJc3RydWN0IGt1 bml0X3Jlc291cmNlICpyZXNvdXJjZTsKKworCXJlc291cmNlID0ga3VuaXRfcmVzb3VyY2VfcmVt b3ZlKHRlc3QsIG1hdGNoLCBmcmVlLCBtYXRjaF9kYXRhKTsKKworCWlmICghcmVzb3VyY2UpCisJ CXJldHVybiAtRU5PRU5UOworCisJa3VuaXRfcmVzb3VyY2VfZnJlZSh0ZXN0LCByZXNvdXJjZSk7 CisJcmV0dXJuIDA7Cit9CisKK3N0cnVjdCBrdW5pdF9rbWFsbG9jX3BhcmFtcyB7CisJc2l6ZV90 IHNpemU7CisJZ2ZwX3QgZ2ZwOworfTsKKworc3RhdGljIGludCBrdW5pdF9rbWFsbG9jX2luaXQo c3RydWN0IGt1bml0X3Jlc291cmNlICpyZXMsIHZvaWQgKmNvbnRleHQpCit7CisJc3RydWN0IGt1 bml0X2ttYWxsb2NfcGFyYW1zICpwYXJhbXMgPSBjb250ZXh0OworCisJcmVzLT5hbGxvY2F0aW9u ID0ga21hbGxvYyhwYXJhbXMtPnNpemUsIHBhcmFtcy0+Z2ZwKTsKKwlpZiAoIXJlcy0+YWxsb2Nh dGlvbikKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHZvaWQg a3VuaXRfa21hbGxvY19mcmVlKHN0cnVjdCBrdW5pdF9yZXNvdXJjZSAqcmVzKQoreworCWtmcmVl KHJlcy0+YWxsb2NhdGlvbik7Cit9CisKK3ZvaWQgKmt1bml0X2ttYWxsb2Moc3RydWN0IGt1bml0 ICp0ZXN0LCBzaXplX3Qgc2l6ZSwgZ2ZwX3QgZ2ZwKQoreworCXN0cnVjdCBrdW5pdF9rbWFsbG9j X3BhcmFtcyBwYXJhbXMgPSB7CisJCS5zaXplID0gc2l6ZSwKKwkJLmdmcCA9IGdmcAorCX07CisK KwlyZXR1cm4ga3VuaXRfYWxsb2NfcmVzb3VyY2UodGVzdCwKKwkJCQkgICAga3VuaXRfa21hbGxv Y19pbml0LAorCQkJCSAgICBrdW5pdF9rbWFsbG9jX2ZyZWUsCisJCQkJICAgIGdmcCwKKwkJCQkg ICAgJnBhcmFtcyk7Cit9CisKK3ZvaWQga3VuaXRfa2ZyZWUoc3RydWN0IGt1bml0ICp0ZXN0LCBj b25zdCB2b2lkICpwdHIpCit7CisJaW50IHJjOworCisJcmMgPSBrdW5pdF9yZXNvdXJjZV9kZXN0 cm95KHRlc3QsCisJCQkJICAgIGt1bml0X3Jlc291cmNlX2luc3RhbmNlX21hdGNoLAorCQkJCSAg ICBrdW5pdF9rbWFsbG9jX2ZyZWUsCisJCQkJICAgICh2b2lkICopcHRyKTsKKworCVdBUk5fT04o cmMpOworfQorCit2b2lkIGt1bml0X2NsZWFudXAoc3RydWN0IGt1bml0ICp0ZXN0KQoreworCXN0 cnVjdCBrdW5pdF9yZXNvdXJjZSAqcmVzb3VyY2U7CisKKwkvKgorCSAqIHRlc3QtPnJlc291cmNl cyBpcyBhIHN0YWNrIC0gZWFjaCBhbGxvY2F0aW9uIG11c3QgYmUgZnJlZWQgaW4gdGhlCisJICog cmV2ZXJzZSBvcmRlciBmcm9tIHdoaWNoIGl0IHdhcyBhZGRlZCBzaW5jZSBvbmUgcmVzb3VyY2Ug bWF5IGRlcGVuZAorCSAqIG9uIGFub3RoZXIgZm9yIGl0cyBlbnRpcmUgbGlmZXRpbWUuCisJICog QWxzbywgd2UgY2Fubm90IHVzZSB0aGUgbm9ybWFsIGxpc3RfZm9yX2VhY2ggY29uc3RydWN0cywg ZXZlbiB0aGUKKwkgKiBzYWZlIG9uZXMgYmVjYXVzZSAqYXJiaXRyYXJ5KiBub2RlcyBtYXkgYmUg ZGVsZXRlZCB3aGVuCisJICoga3VuaXRfcmVzb3VyY2VfZnJlZSBpcyBjYWxsZWQ7IHRoZSBsaXN0 X2Zvcl9lYWNoX3NhZmUgdmFyaWFudHMgb25seQorCSAqIHByb3RlY3QgYWdhaW5zdCB0aGUgY3Vy cmVudCBub2RlIGJlaW5nIGRlbGV0ZWQsIG5vdCB0aGUgbmV4dC4KKwkgKi8KKwl3aGlsZSAodHJ1 ZSkgeworCQlzcGluX2xvY2soJnRlc3QtPmxvY2spOworCQlpZiAobGlzdF9lbXB0eSgmdGVzdC0+ cmVzb3VyY2VzKSkgeworCQkJc3Bpbl91bmxvY2soJnRlc3QtPmxvY2spOworCQkJYnJlYWs7CisJ CX0KKwkJcmVzb3VyY2UgPSBsaXN0X2xhc3RfZW50cnkoJnRlc3QtPnJlc291cmNlcywKKwkJCQkJ ICAgc3RydWN0IGt1bml0X3Jlc291cmNlLAorCQkJCQkgICBub2RlKTsKKwkJbGlzdF9kZWwoJnJl c291cmNlLT5ub2RlKTsKKwkJc3Bpbl91bmxvY2soJnRlc3QtPmxvY2spOworCisJCWt1bml0X3Jl c291cmNlX2ZyZWUodGVzdCwgcmVzb3VyY2UpOworCX0KK30KKwogdm9pZCBrdW5pdF9wcmludGso Y29uc3QgY2hhciAqbGV2ZWwsCiAJCSAgY29uc3Qgc3RydWN0IGt1bml0ICp0ZXN0LAogCQkgIGNv bnN0IGNoYXIgKmZtdCwgLi4uKQotLSAKMi4yMy4wLjM1MS5nYzQzMTcwMzJlNi1nb29nCgpfX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpkcmktZGV2ZWwgbWFp bGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5m cmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9kcmktZGV2ZWw= From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pf1-x44a.google.com ([2607:f8b0:4864:20::44a]) by bombadil.infradead.org with esmtps (Exim 4.92.2 #3 (Red Hat Linux)) id 1iBSBo-0003CR-GM for linux-um@lists.infradead.org; Fri, 20 Sep 2019 23:19:50 +0000 Received: by mail-pf1-x44a.google.com with SMTP id f2so5761600pfk.13 for ; Fri, 20 Sep 2019 16:19:45 -0700 (PDT) Date: Fri, 20 Sep 2019 16:19:06 -0700 In-Reply-To: <20190920231923.141900-1-brendanhiggins@google.com> Message-Id: <20190920231923.141900-3-brendanhiggins@google.com> Mime-Version: 1.0 References: <20190920231923.141900-1-brendanhiggins@google.com> Subject: [PATCH v16 02/19] kunit: test: add test resource management API From: Brendan Higgins List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-um" Errors-To: linux-um-bounces+geert=linux-m68k.org@lists.infradead.org To: frowand.list@gmail.com, gregkh@linuxfoundation.org, jpoimboe@redhat.com, keescook@google.com, kieran.bingham@ideasonboard.com, mcgrof@kernel.org, peterz@infradead.org, robh@kernel.org, sboyd@kernel.org, shuah@kernel.org, tytso@mit.edu, yamada.masahiro@socionext.com Cc: pmladek@suse.com, linux-doc@vger.kernel.org, amir73il@gmail.com, Brendan Higgins , dri-devel@lists.freedesktop.org, Alexander.Levin@microsoft.com, linux-kselftest@vger.kernel.org, linux-nvdimm@lists.01.org, khilman@baylibre.com, knut.omang@oracle.com, wfg@linux.intel.com, joel@jms.id.au, rientjes@google.com, jdike@addtoit.com, dan.carpenter@oracle.com, devicetree@vger.kernel.org, linux-kbuild@vger.kernel.org, Tim.Bird@sony.com, linux-um@lists.infradead.org, rostedt@goodmis.org, julia.lawall@lip6.fr, kunit-dev@googlegroups.com, richard@nod.at, torvalds@linux-foundation.org, rdunlap@infradead.org, linux-kernel@vger.kernel.org, daniel@ffwll.ch, mpe@ellerman.id.au, linux-fsdevel@vger.kernel.org, logang@deltatee.com 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 Reviewed-by: Greg Kroah-Hartman Reviewed-by: Logan Gunthorpe Reviewed-by: Stephen Boyd --- include/kunit/test.h | 187 +++++++++++++++++++++++++++++++++++++++++++ lib/kunit/test.c | 163 +++++++++++++++++++++++++++++++++++++ 2 files changed, 350 insertions(+) diff --git a/include/kunit/test.h b/include/kunit/test.h index e30d1bf2fb68..6781c756f11b 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -9,8 +9,72 @@ #ifndef _KUNIT_TEST_H #define _KUNIT_TEST_H +#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; + * + * return NULL; + * } + */ +struct kunit_resource { + void *allocation; + kunit_resource_free_t free; + + /* private: internal use only. */ + struct list_head node; +}; + struct kunit; /** @@ -114,6 +178,13 @@ struct kunit { * with the test case have terminated. */ bool success; /* Read only after test_case finishes! */ + spinlock_t lock; /* Guards all mutable test state. */ + /* + * Because resources is a list that may be updated multiple times (with + * new resources) from any thread associated with a test case, we must + * protect it with some type of lock. + */ + struct list_head resources; /* Protected by lock. */ }; void kunit_init_test(struct kunit *test, const char *name); @@ -147,6 +218,122 @@ int kunit_run_tests(struct kunit_suite *suite); } \ late_initcall(kunit_suite_init##suite) +/* + * Like kunit_alloc_resource() below, but returns the struct kunit_resource + * object that contains the allocation. This is mostly for testing purposes. + */ +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); + +/** + * 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. + * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL + * @context: for the user to pass in arbitrary data to the init function. + * + * 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. + * + * NOTE: KUnit needs to allocate memory for each kunit_resource object. You must + * specify an @internal_gfp that is compatible with the use context of your + * resource. + */ +static inline void *kunit_alloc_resource(struct kunit *test, + kunit_resource_init_t init, + kunit_resource_free_t free, + gfp_t internal_gfp, + void *context) +{ + struct kunit_resource *res; + + res = kunit_alloc_and_get_resource(test, init, free, internal_gfp, + context); + + if (res) + return res->allocation; + + return NULL; +} + +typedef bool (*kunit_resource_match_t)(struct kunit *test, + const void *res, + void *match_data); + +/** + * kunit_resource_instance_match() - Match a resource with the same instance. + * @test: Test case to which the resource belongs. + * @res: The data stored in kunit_resource->allocation. + * @match_data: The resource pointer to match against. + * + * An instance of kunit_resource_match_t that matches a resource whose + * allocation matches @match_data. + */ +static inline bool kunit_resource_instance_match(struct kunit *test, + const void *res, + void *match_data) +{ + return res == match_data; +} + +/** + * kunit_resource_destroy() - Find a kunit_resource and destroy it. + * @test: Test case to which the resource belongs. + * @match: Match function. Returns whether a given resource matches @match_data. + * @free: Must match free on the kunit_resource to free. + * @match_data: Data passed into @match. + * + * Free the latest kunit_resource of @test for which @free matches the + * kunit_resource_free_t associated with the resource and for which @match + * returns true. + * + * RETURNS: + * 0 if kunit_resource is found and freed, -ENOENT if not found. + */ +int kunit_resource_destroy(struct kunit *test, + kunit_resource_match_t match, + kunit_resource_free_t free, + void *match_data); + +/** + * 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_kfree() - Like kfree except for allocations managed by KUnit. + * @test: The test case to which the resource belongs. + * @ptr: The memory allocation to free. + */ +void kunit_kfree(struct kunit *test, const void *ptr); + +/** + * 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/lib/kunit/test.c b/lib/kunit/test.c index d3dda359f99b..68b1037ab74d 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -122,6 +122,8 @@ static void kunit_print_test_case_ok_not_ok(struct kunit_case *test_case, void kunit_init_test(struct kunit *test, const char *name) { + spin_lock_init(&test->lock); + INIT_LIST_HEAD(&test->resources); test->name = name; test->success = true; } @@ -153,6 +155,8 @@ static void kunit_run_case(struct kunit_suite *suite, if (suite->exit) suite->exit(&test); + kunit_cleanup(&test); + test_case->success = test.success; } @@ -173,6 +177,165 @@ int kunit_run_tests(struct kunit_suite *suite) return 0; } +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) +{ + struct kunit_resource *res; + int ret; + + res = kzalloc(sizeof(*res), internal_gfp); + if (!res) + return NULL; + + ret = init(res, context); + if (ret) + return NULL; + + res->free = free; + spin_lock(&test->lock); + list_add_tail(&res->node, &test->resources); + spin_unlock(&test->lock); + + return res; +} + +static void kunit_resource_free(struct kunit *test, struct kunit_resource *res) +{ + res->free(res); + kfree(res); +} + +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 *resource; + + lockdep_assert_held(&test->lock); + + list_for_each_entry_reverse(resource, &test->resources, node) { + if (resource->free != free) + continue; + if (match(test, resource->allocation, match_data)) + return resource; + } + + return NULL; +} + +static struct kunit_resource *kunit_resource_remove( + struct kunit *test, + kunit_resource_match_t match, + kunit_resource_free_t free, + void *match_data) +{ + struct kunit_resource *resource; + + spin_lock(&test->lock); + resource = kunit_resource_find(test, match, free, match_data); + if (resource) + list_del(&resource->node); + spin_unlock(&test->lock); + + return resource; +} + +int kunit_resource_destroy(struct kunit *test, + kunit_resource_match_t match, + kunit_resource_free_t free, + void *match_data) +{ + struct kunit_resource *resource; + + resource = kunit_resource_remove(test, match, free, match_data); + + if (!resource) + return -ENOENT; + + kunit_resource_free(test, resource); + return 0; +} + +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 = { + .size = size, + .gfp = gfp + }; + + return kunit_alloc_resource(test, + kunit_kmalloc_init, + kunit_kmalloc_free, + gfp, + ¶ms); +} + +void kunit_kfree(struct kunit *test, const void *ptr) +{ + int rc; + + rc = kunit_resource_destroy(test, + kunit_resource_instance_match, + kunit_kmalloc_free, + (void *)ptr); + + WARN_ON(rc); +} + +void kunit_cleanup(struct kunit *test) +{ + struct kunit_resource *resource; + + /* + * test->resources is a stack - each allocation must be freed in the + * reverse order from which it was added since one resource may depend + * on another for its entire lifetime. + * Also, we cannot use the normal list_for_each constructs, even the + * safe ones because *arbitrary* nodes may be deleted when + * kunit_resource_free is called; the list_for_each_safe variants only + * protect against the current node being deleted, not the next. + */ + while (true) { + spin_lock(&test->lock); + if (list_empty(&test->resources)) { + spin_unlock(&test->lock); + break; + } + resource = list_last_entry(&test->resources, + struct kunit_resource, + node); + list_del(&resource->node); + spin_unlock(&test->lock); + + kunit_resource_free(test, resource); + } +} + void kunit_printk(const char *level, const struct kunit *test, const char *fmt, ...) -- 2.23.0.351.gc4317032e6-goog _______________________________________________ linux-um mailing list linux-um@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-um