[PATCH 1/2] lib/string_helpers: Introduce strsplit_u32()
Péter Ujfalusi
peter.ujfalusi at linux.intel.com
Thu Jul 7 15:51:44 CEST 2022
On 07/07/2022 12:13, Cezary Rojewski wrote:
> Add strsplit_u32() and its __user variant to allow for splitting
> specified string into array of u32 tokens.
>
> Originally this functionality was added for the SOF sound driver. As
> more users are on the horizon, relocate it so it becomes a common good.
>
> Signed-off-by: Cezary Rojewski <cezary.rojewski at intel.com>
> ---
> include/linux/string_helpers.h | 3 +
> lib/string_helpers.c | 96 +++++++++++++++++++++++++++++++
> sound/soc/sof/sof-client-probes.c | 51 +---------------
> 3 files changed, 100 insertions(+), 50 deletions(-)
>
> diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h
> index 4d72258d42fd..a4630ddfca27 100644
> --- a/include/linux/string_helpers.h
> +++ b/include/linux/string_helpers.h
> @@ -126,4 +126,7 @@ static inline const char *str_enabled_disabled(bool v)
> return v ? "enabled" : "disabled";
> }
>
> +int strsplit_u32(const char *str, const char *delim, u32 **tkns, size_t *num_tkns);
> +int strsplit_u32_user(const char __user *from, size_t count, loff_t *ppos, const char *delim,
> + u32 **tkns, size_t *num_tkns);
> #endif
> diff --git a/lib/string_helpers.c b/lib/string_helpers.c
> index 5ed3beb066e6..bb24f0c62539 100644
> --- a/lib/string_helpers.c
> +++ b/lib/string_helpers.c
> @@ -984,3 +984,99 @@ void fortify_panic(const char *name)
> }
> EXPORT_SYMBOL(fortify_panic);
> #endif /* CONFIG_FORTIFY_SOURCE */
> +
> +/**
> + * strsplit_u32 - Split string into sequence of u32 tokens
> + * @str: The string to split into tokens.
> + * @delim: The string containing delimiter characters.
> + * @tkns: Returned u32 sequence pointer.
> + * @num_tkns: Returned number of tokens obtained.
> + *
> + * On success @num_tkns and @tkns are assigned the number of tokens extracted
> + * and the array itself respectively.
> + * Caller takes responsibility for freeing @tkns when no longer needed.
> + */
> +int strsplit_u32(const char *str, const char *delim, u32 **tkns, size_t *num_tkns)
> +{
> + size_t max_count = 32;
> + size_t count = 0;
> + char *s, **p;
> + u32 *buf, *tmp;
> + int ret = 0;
> +
> + p = (char **)&str;
> + *tkns = NULL;
> + *num_tkns = 0;
> +
> + buf = kcalloc(max_count, sizeof(*buf), GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + while ((s = strsep(p, delim)) != NULL) {
> + ret = kstrtouint(s, 0, buf + count);
> + if (ret)
> + goto free_buf;
> +
> + if (++count > max_count) {
I think this should be as it was originally:
if (++count >= max_count) {
Otherwise when we reach the max_count we would not realloc to get more
space and the data + max_count is pointing outside of the allocated area.
> + max_count *= 2;
> + tmp = krealloc(buf, max_count * sizeof(*buf), GFP_KERNEL);
> + if (!tmp) {
> + ret = -ENOMEM;
> + goto free_buf;
> + }
> + buf = tmp;
> + }
> + }
> +
> + if (!count)
> + goto free_buf;
> + *tkns = kmemdup(buf, count * sizeof(*buf), GFP_KERNEL);
> + if (*tkns == NULL) {
> + ret = -ENOMEM;
> + goto free_buf;
> + }
> + *num_tkns = count;
> +
> +free_buf:
> + kfree(buf);
> + return ret;
> +}
> +EXPORT_SYMBOL(strsplit_u32);
> +
> +/**
> + * strsplit_u32_user - Split string into sequence of u32 tokens
> + * @from: The user space buffer to read from
> + * @ppos: The current position in the buffer
> + * @count: The maximum number of bytes to read
> + * @delim: The string containing delimiter characters.
> + * @tkns: Returned u32 sequence pointer.
> + * @num_tkns: Returned number of tokens obtained.
> + *
> + * On success @num_tkns and @tkns are assigned the number of tokens extracted
> + * and the array itself respectively.
> + * Caller takes responsibility for freeing @tkns when no longer needed.
> + */
> +int strsplit_u32_user(const char __user *from, size_t count, loff_t *ppos, const char *delim,
> + u32 **tkns, size_t *num_tkns)
> +{
> + char *buf;
> + int ret;
> +
> + buf = kmalloc(count + 1, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + ret = simple_write_to_buffer(buf, count, ppos, from, count);
> + if (ret != count) {
> + ret = (ret < 0) ? ret : -EIO;
> + goto free_buf;
> + }
> +
> + buf[count] = '\0';
> + ret = strsplit_u32(buf, delim, tkns, num_tkns);
> +
> +free_buf:
> + kfree(buf);
> + return ret;
> +}
> +EXPORT_SYMBOL(strsplit_u32_user);
> diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c
> index 1f1ea93a7fbf..48ebbe58e2b9 100644
> --- a/sound/soc/sof/sof-client-probes.c
> +++ b/sound/soc/sof/sof-client-probes.c
> @@ -12,6 +12,7 @@
> #include <linux/debugfs.h>
> #include <linux/module.h>
> #include <linux/pm_runtime.h>
> +#include <linux/string_helpers.h>
> #include <sound/soc.h>
> #include <sound/sof/header.h>
> #include "sof-client.h"
> @@ -410,56 +411,6 @@ static const struct snd_compress_ops sof_probes_compressed_ops = {
> .copy = sof_probes_compr_copy,
> };
>
> -/**
> - * strsplit_u32 - Split string into sequence of u32 tokens
> - * @buf: String to split into tokens.
> - * @delim: String containing delimiter characters.
> - * @tkns: Returned u32 sequence pointer.
> - * @num_tkns: Returned number of tokens obtained.
> - */
> -static int strsplit_u32(char *buf, const char *delim, u32 **tkns, size_t *num_tkns)
> -{
> - char *s;
> - u32 *data, *tmp;
> - size_t count = 0;
> - size_t cap = 32;
> - int ret = 0;
> -
> - *tkns = NULL;
> - *num_tkns = 0;
> - data = kcalloc(cap, sizeof(*data), GFP_KERNEL);
> - if (!data)
> - return -ENOMEM;
> -
> - while ((s = strsep(&buf, delim)) != NULL) {
> - ret = kstrtouint(s, 0, data + count);
> - if (ret)
> - goto exit;
> - if (++count >= cap) {
> - cap *= 2;
> - tmp = krealloc(data, cap * sizeof(*data), GFP_KERNEL);
> - if (!tmp) {
> - ret = -ENOMEM;
> - goto exit;
> - }
> - data = tmp;
> - }
> - }
> -
> - if (!count)
> - goto exit;
> - *tkns = kmemdup(data, count * sizeof(*data), GFP_KERNEL);
> - if (!(*tkns)) {
> - ret = -ENOMEM;
> - goto exit;
> - }
> - *num_tkns = count;
> -
> -exit:
> - kfree(data);
> - return ret;
> -}
> -
> static int tokenize_input(const char __user *from, size_t count,
> loff_t *ppos, u32 **tkns, size_t *num_tkns)
> {
--
Péter
More information about the Alsa-devel
mailing list