From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
To: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Mathieu Poirier <mathieu.poirier@linaro.org>,
linux-kernel@vger.kernel.org
Subject: Re: [QUEUED v20180920 15/16] lib: Add memcat_p(): paste 2 pointer arrays together
Date: Fri, 21 Sep 2018 19:56:32 +0300 [thread overview]
Message-ID: <20180921165632.GA15943@smile.fi.intel.com> (raw)
In-Reply-To: <20180920124553.56978-16-alexander.shishkin@linux.intel.com>
On Thu, Sep 20, 2018 at 03:45:52PM +0300, Alexander Shishkin wrote:
> This adds a helper to paste 2 pointer arrays together, useful for merging
> various types of attribute arrays. There are a few places in the kernel
> tree where this is open coded, and I just added one more in the STM class.
>
> The naming is inspired by memset_p() and memcat(), and partial credit for
> it goes to Andy Shevchenko.
>
> This patch adds the function wrapped in a type-enforcing macro and a test
> module.
>
> Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> include/linux/string.h | 7 +++
> lib/Kconfig.debug | 8 +++
> lib/Makefile | 1 +
> lib/string.c | 31 +++++++++++
> lib/test_memcat_p.c | 115 +++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 162 insertions(+)
> create mode 100644 lib/test_memcat_p.c
>
> diff --git a/include/linux/string.h b/include/linux/string.h
> index 4a5a0eb7df51..27d0482e5e05 100644
> --- a/include/linux/string.h
> +++ b/include/linux/string.h
> @@ -131,6 +131,13 @@ static inline void *memset_p(void **p, void *v, __kernel_size_t n)
> return memset64((uint64_t *)p, (uintptr_t)v, n);
> }
>
> +extern void **__memcat_p(void **a, void **b);
> +#define memcat_p(a, b) ({ \
> + BUILD_BUG_ON_MSG(!__same_type(*(a), *(b)), \
> + "type mismatch in memcat_p()"); \
> + (typeof(*a) *)__memcat_p((void **)(a), (void **)(b)); \
> +})
> +
> #ifndef __HAVE_ARCH_MEMCPY
> extern void * memcpy(void *,const void *,__kernel_size_t);
> #endif
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 613316724c6a..177e21006359 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -1965,6 +1965,14 @@ config TEST_DEBUG_VIRTUAL
>
> If unsure, say N.
>
> +config TEST_MEMCAT_P
> + tristate "Test memcat_p() helper function"
> + help
> + Test the memcat_p() helper for correctly merging two
> + pointer arrays together.
> +
> + If unsure, say N.
> +
> endif # RUNTIME_TESTING_MENU
>
> config MEMTEST
> diff --git a/lib/Makefile b/lib/Makefile
> index ca3f7ebb900d..c2588a2d7b1e 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -71,6 +71,7 @@ obj-$(CONFIG_TEST_UUID) += test_uuid.o
> obj-$(CONFIG_TEST_PARMAN) += test_parman.o
> obj-$(CONFIG_TEST_KMOD) += test_kmod.o
> obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o
> +obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o
>
> ifeq ($(CONFIG_DEBUG_KOBJECT),y)
> CFLAGS_kobject.o += -DDEBUG
> diff --git a/lib/string.c b/lib/string.c
> index 2c0900a5d51a..453f35994eb6 100644
> --- a/lib/string.c
> +++ b/lib/string.c
> @@ -27,6 +27,7 @@
> #include <linux/export.h>
> #include <linux/bug.h>
> #include <linux/errno.h>
> +#include <linux/slab.h>
>
> #include <asm/byteorder.h>
> #include <asm/word-at-a-time.h>
> @@ -890,6 +891,36 @@ void *memscan(void *addr, int c, size_t size)
> EXPORT_SYMBOL(memscan);
> #endif
>
> +/*
> + * Merge two NULL-terminated pointer arrays into a newly allocated
> + * array, which is also NULL-terminated. Nomenclature is inspired by
> + * memset_p() and memcat() found elsewhere in the kernel source tree.
> + */
> +void **__memcat_p(void **a, void **b)
> +{
> + void **p = a, **new;
> + int nr;
> +
> + /* count the elements in both arrays */
> + for (nr = 0, p = a; *p; nr++, p++)
> + ;
> + for (p = b; *p; nr++, p++)
> + ;
> + /* one for the NULL-terminator */
> + nr++;
> +
> + new = kmalloc_array(nr, sizeof(void *), GFP_KERNEL);
> + if (!new)
> + return NULL;
> +
> + /* nr -> last index; p points to NULL in b[] */
> + for (nr--; nr >= 0; nr--, p = p == b ? &a[nr] : p - 1)
> + new[nr] = *p;
As far as I understand the logic behind this initially we have:
n elements + NULL + m elements + NULL,
nr equals n + m + NULL,
nr - 1 points to the last element in the new array at the beginning of the
loop. Since we are operating on arrays, p at some point becomes 'b' at which
time we switch to the 'a' array. It might be rewritten slightly more
straightforward (like in two loops, but on the other hand it would require to
track number of elements in each of the arrays separately).
So, I don't see any off-by-one issues here.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> +
> + return new;
> +}
> +EXPORT_SYMBOL_GPL(__memcat_p);
> +
> #ifndef __HAVE_ARCH_STRSTR
> /**
> * strstr - Find the first substring in a %NUL terminated string
> diff --git a/lib/test_memcat_p.c b/lib/test_memcat_p.c
> new file mode 100644
> index 000000000000..2b163a749ecb
> --- /dev/null
> +++ b/lib/test_memcat_p.c
> @@ -0,0 +1,115 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Test cases for memcat_p() in lib/string.c
> + */
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +
> +struct test_struct {
> + int num;
> + unsigned int magic;
> +};
> +
> +#define MAGIC 0xf00ff00f
> +/* Size of each of the NULL-terminated input arrays */
> +#define INPUT_MAX 128
> +/* Expected number of non-NULL elements in the output array */
> +#define EXPECT (INPUT_MAX * 2 - 2)
> +
> +static int __init test_memcat_p_init(void)
> +{
> + struct test_struct **in0, **in1, **out, **p;
> + int err = -ENOMEM, i, r, total = 0;
> +
> + in0 = kcalloc(INPUT_MAX, sizeof(*in0), GFP_KERNEL);
> + if (!in0)
> + return err;
> +
> + in1 = kcalloc(INPUT_MAX, sizeof(*in1), GFP_KERNEL);
> + if (!in1)
> + goto err_free_in0;
> +
> + for (i = 0, r = 1; i < INPUT_MAX - 1; i++) {
> + in0[i] = kmalloc(sizeof(**in0), GFP_KERNEL);
> + if (!in0[i])
> + goto err_free_elements;
> +
> + in1[i] = kmalloc(sizeof(**in1), GFP_KERNEL);
> + if (!in1[i]) {
> + kfree(in0[i]);
> + goto err_free_elements;
> + }
> +
> + /* lifted from test_sort.c */
> + r = (r * 725861) % 6599;
> + in0[i]->num = r;
> + in1[i]->num = -r;
> + in0[i]->magic = MAGIC;
> + in1[i]->magic = MAGIC;
> + }
> +
> + in0[i] = in1[i] = NULL;
> +
> + out = memcat_p(in0, in1);
> + if (!out)
> + goto err_free_all_elements;
> +
> + err = -EINVAL;
> + for (i = 0, p = out; *p && (i < INPUT_MAX * 2 - 1); p++, i++) {
> + total += (*p)->num;
> +
> + if ((*p)->magic != MAGIC) {
> + pr_err("test failed: wrong magic at %d: %u\n", i,
> + (*p)->magic);
> + goto err_free_out;
> + }
> + }
> +
> + if (total) {
> + pr_err("test failed: expected zero total, got %d\n", total);
> + goto err_free_out;
> + }
> +
> + if (i != EXPECT) {
> + pr_err("test failed: expected output size %d, got %d\n",
> + EXPECT, i);
> + goto err_free_out;
> + }
> +
> + for (i = 0; i < INPUT_MAX - 1; i++)
> + if (out[i] != in0[i] || out[i + INPUT_MAX - 1] != in1[i]) {
> + pr_err("test failed: wrong element order at %d\n", i);
> + goto err_free_out;
> + }
> +
> + err = 0;
> + pr_info("test passed\n");
> +
> +err_free_out:
> + kfree(out);
> +err_free_all_elements:
> + i = INPUT_MAX;
> +err_free_elements:
> + for (i--; i >= 0; i--) {
> + kfree(in1[i]);
> + kfree(in0[i]);
> + }
> +
> + kfree(in1);
> +err_free_in0:
> + kfree(in0);
> +
> + return err;
> +}
> +
> +static void __exit test_memcat_p_exit(void)
> +{
> +}
> +
> +module_init(test_memcat_p_init);
> +module_exit(test_memcat_p_exit);
> +
> +MODULE_LICENSE("GPL");
> --
> 2.18.0
>
--
With Best Regards,
Andy Shevchenko
next prev parent reply other threads:[~2018-09-21 16:57 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-09-20 12:45 [QUEUED v20180920 00/16] stm class/intel_th: Queued updates for v4.20 Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 01/16] stm class: Rework policy node fallback Alexander Shishkin
2018-09-27 16:31 ` Mathieu Poirier
2018-09-20 12:45 ` [QUEUED v20180920 02/16] stm class: Clarify configfs root type/operations names Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 03/16] stm class: Clean up stp_configfs_init Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 04/16] stm class: Introduce framing protocol drivers Alexander Shishkin
2018-09-27 16:46 ` Mathieu Poirier
2018-10-03 13:03 ` Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 05/16] stm class: Add a helper for writing data packets Alexander Shishkin
2018-09-27 17:07 ` Mathieu Poirier
2018-10-03 12:58 ` Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 06/16] stm class: Factor out default framing protocol Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 07/16] stm class: Switch over to the protocol driver Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 08/16] stm class: Add MIPI SyS-T protocol support Alexander Shishkin
2018-09-27 17:08 ` Mathieu Poirier
2018-09-20 12:45 ` [QUEUED v20180920 09/16] stm class: p_sys-t: Add support for CLOCKSYNC packets Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 10/16] stm class: p_sys-t: Document the configfs interface Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 11/16] stm class: Document the MIPI SyS-T protocol usage Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 12/16] intel_th: SPDX-ify the documentation Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 13/16] stm class: " Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 14/16] stm class: heartbeat: Fix whitespace Alexander Shishkin
2018-09-20 12:45 ` [QUEUED v20180920 15/16] lib: Add memcat_p(): paste 2 pointer arrays together Alexander Shishkin
2018-09-20 13:00 ` Greg Kroah-Hartman
2018-09-21 16:56 ` Andy Shevchenko [this message]
2018-09-20 12:45 ` [QUEUED v20180920 16/16] stm class: Use memcat_p() Alexander Shishkin
2018-09-27 17:18 ` [QUEUED v20180920 00/16] stm class/intel_th: Queued updates for v4.20 Mathieu Poirier
2018-10-03 12:52 ` Alexander Shishkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180921165632.GA15943@smile.fi.intel.com \
--to=andriy.shevchenko@linux.intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mathieu.poirier@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox