Provide a resource managed version of kstrdup_const(). This variant
internally calls devm_kstrdup() on pointers that are outside of
.rodata section. Also provide a corresponding version of devm_kfree().
Signed-off-by: Bartosz Golaszewski <[email protected]>
---
include/linux/device.h | 2 ++
mm/util.c | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+)
diff --git a/include/linux/device.h b/include/linux/device.h
index 8f882549edee..f8f5982d26b2 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -693,7 +693,9 @@ static inline void *devm_kcalloc(struct device *dev,
return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
}
extern void devm_kfree(struct device *dev, void *p);
+extern void devm_kfree_const(struct device *dev, void *p);
extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
+extern char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp);
extern void *devm_kmemdup(struct device *dev, const void *src, size_t len,
gfp_t gfp);
diff --git a/mm/util.c b/mm/util.c
index d2890a407332..6d1f41b5775e 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -39,6 +39,20 @@ void kfree_const(const void *x)
}
EXPORT_SYMBOL(kfree_const);
+/**
+ * devm_kfree_const - Resource managed conditional kfree
+ * @dev: device this memory belongs to
+ * @p: memory to free
+ *
+ * Function calls devm_kfree only if @p is not in .rodata section.
+ */
+void devm_kfree_const(struct device *dev, void *p)
+{
+ if (!is_kernel_rodata((unsigned long)p))
+ devm_kfree(dev, p);
+}
+EXPORT_SYMBOL(devm_kfree_const);
+
/**
* kstrdup - allocate space for and copy an existing string
* @s: the string to duplicate
@@ -78,6 +92,27 @@ const char *kstrdup_const(const char *s, gfp_t gfp)
}
EXPORT_SYMBOL(kstrdup_const);
+/**
+ * devm_kstrdup_const - resource managed conditional string duplication
+ * @dev: device for which to duplicate the string
+ * @s: the string to duplicate
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Function returns source string if it is in .rodata section otherwise it
+ * fallbacks to devm_kstrdup.
+ *
+ * Strings allocated by devm_kstrdup_const will be automatically freed when
+ * the associated device is detached.
+ */
+char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp)
+{
+ if (is_kernel_rodata((unsigned long)s))
+ return s;
+
+ return devm_kstrdup(dev, s, gfp);
+}
+EXPORT_SYMBOL(devm_kstrdup_const);
+
/**
* kstrndup - allocate space for and copy an existing string
* @s: the string to duplicate
--
2.18.0
Use devm_kstrdup_const() in the pmc-atom driver. This mostly serves as
an example of how to use this new routine to shrink driver code.
While we're at it: replace a call to kcalloc() with devm_kcalloc().
Signed-off-by: Bartosz Golaszewski <[email protected]>
---
drivers/clk/x86/clk-pmc-atom.c | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c
index 08ef69945ffb..daa2192e6568 100644
--- a/drivers/clk/x86/clk-pmc-atom.c
+++ b/drivers/clk/x86/clk-pmc-atom.c
@@ -253,14 +253,6 @@ static void plt_clk_unregister_fixed_rate_loop(struct clk_plt_data *data,
plt_clk_unregister_fixed_rate(data->parents[i]);
}
-static void plt_clk_free_parent_names_loop(const char **parent_names,
- unsigned int i)
-{
- while (i--)
- kfree_const(parent_names[i]);
- kfree(parent_names);
-}
-
static void plt_clk_unregister_loop(struct clk_plt_data *data,
unsigned int i)
{
@@ -286,8 +278,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
if (!data->parents)
return ERR_PTR(-ENOMEM);
- parent_names = kcalloc(nparents, sizeof(*parent_names),
- GFP_KERNEL);
+ parent_names = devm_kcalloc(&pdev->dev, nparents,
+ sizeof(*parent_names), GFP_KERNEL);
if (!parent_names)
return ERR_PTR(-ENOMEM);
@@ -300,7 +292,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
err = PTR_ERR(data->parents[i]);
goto err_unreg;
}
- parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL);
+ parent_names[i] = devm_kstrdup_const(&pdev->dev,
+ clks[i].name, GFP_KERNEL);
}
data->nparents = nparents;
@@ -308,7 +301,6 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
err_unreg:
plt_clk_unregister_fixed_rate_loop(data, i);
- plt_clk_free_parent_names_loop(parent_names, i);
return ERR_PTR(err);
}
@@ -351,15 +343,12 @@ static int plt_clk_probe(struct platform_device *pdev)
goto err_unreg_clk_plt;
}
- plt_clk_free_parent_names_loop(parent_names, data->nparents);
-
platform_set_drvdata(pdev, data);
return 0;
err_unreg_clk_plt:
plt_clk_unregister_loop(data, i);
plt_clk_unregister_parents(data);
- plt_clk_free_parent_names_loop(parent_names, data->nparents);
return err;
}
--
2.18.0
On Mon, 2018-08-27 at 10:21 +0200, Bartosz Golaszewski wrote:
> Provide a resource managed version of kstrdup_const(). This variant
> internally calls devm_kstrdup() on pointers that are outside of
> .rodata section. Also provide a corresponding version of devm_kfree().
[]
> diff --git a/mm/util.c b/mm/util.c
[]
> /**
> * kstrdup - allocate space for and copy an existing string
> * @s: the string to duplicate
> @@ -78,6 +92,27 @@ const char *kstrdup_const(const char *s, gfp_t gfp)
> }
> EXPORT_SYMBOL(kstrdup_const);
>
> +/**
> + * devm_kstrdup_const - resource managed conditional string duplication
> + * @dev: device for which to duplicate the string
> + * @s: the string to duplicate
> + * @gfp: the GFP mask used in the kmalloc() call when allocating memory
> + *
> + * Function returns source string if it is in .rodata section otherwise it
> + * fallbacks to devm_kstrdup.
> + *
> + * Strings allocated by devm_kstrdup_const will be automatically freed when
> + * the associated device is detached.
> + */
> +char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp)
> +{
> + if (is_kernel_rodata((unsigned long)s))
> + return s;
> +
> + return devm_kstrdup(dev, s, gfp);
> +}
> +EXPORT_SYMBOL(devm_kstrdup_const);
Doesn't this lose constness and don't you get
a compiler warning here?
The kstrdup_const function returns a const char *,
why shouldn't this?
2018-08-27 10:42 GMT+02:00 Joe Perches <[email protected]>:
> On Mon, 2018-08-27 at 10:21 +0200, Bartosz Golaszewski wrote:
>> Provide a resource managed version of kstrdup_const(). This variant
>> internally calls devm_kstrdup() on pointers that are outside of
>> .rodata section. Also provide a corresponding version of devm_kfree().
> []
>> diff --git a/mm/util.c b/mm/util.c
> []
>> /**
>> * kstrdup - allocate space for and copy an existing string
>> * @s: the string to duplicate
>> @@ -78,6 +92,27 @@ const char *kstrdup_const(const char *s, gfp_t gfp)
>> }
>> EXPORT_SYMBOL(kstrdup_const);
>>
>> +/**
>> + * devm_kstrdup_const - resource managed conditional string duplication
>> + * @dev: device for which to duplicate the string
>> + * @s: the string to duplicate
>> + * @gfp: the GFP mask used in the kmalloc() call when allocating memory
>> + *
>> + * Function returns source string if it is in .rodata section otherwise it
>> + * fallbacks to devm_kstrdup.
>> + *
>> + * Strings allocated by devm_kstrdup_const will be automatically freed when
>> + * the associated device is detached.
>> + */
>> +char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp)
>> +{
>> + if (is_kernel_rodata((unsigned long)s))
>> + return s;
>> +
>> + return devm_kstrdup(dev, s, gfp);
>> +}
>> +EXPORT_SYMBOL(devm_kstrdup_const);
>
> Doesn't this lose constness and don't you get
> a compiler warning here?
>
Yes it does but for some reason gcc 6.3 didn't complain...
> The kstrdup_const function returns a const char *,
> why shouldn't this?
>
It probably should, I'll fix it for v2.
Bart
On Mon, Aug 27, 2018 at 10:21:00AM +0200, Bartosz Golaszewski wrote:
> Provide a resource managed version of kstrdup_const(). This variant
> internally calls devm_kstrdup() on pointers that are outside of
> .rodata section. Also provide a corresponding version of devm_kfree().
>
> Signed-off-by: Bartosz Golaszewski <[email protected]>
> ---
> include/linux/device.h | 2 ++
> mm/util.c | 35 +++++++++++++++++++++++++++++++++++
> 2 files changed, 37 insertions(+)
>
> diff --git a/include/linux/device.h b/include/linux/device.h
> index 8f882549edee..f8f5982d26b2 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -693,7 +693,9 @@ static inline void *devm_kcalloc(struct device *dev,
> return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
> }
> extern void devm_kfree(struct device *dev, void *p);
> +extern void devm_kfree_const(struct device *dev, void *p);
> extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
> +extern char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp);
> extern void *devm_kmemdup(struct device *dev, const void *src, size_t len,
> gfp_t gfp);
>
> diff --git a/mm/util.c b/mm/util.c
> index d2890a407332..6d1f41b5775e 100644
> --- a/mm/util.c
> +++ b/mm/util.c
> @@ -39,6 +39,20 @@ void kfree_const(const void *x)
> }
> EXPORT_SYMBOL(kfree_const);
>
> +/**
> + * devm_kfree_const - Resource managed conditional kfree
> + * @dev: device this memory belongs to
> + * @p: memory to free
> + *
> + * Function calls devm_kfree only if @p is not in .rodata section.
> + */
> +void devm_kfree_const(struct device *dev, void *p)
> +{
> + if (!is_kernel_rodata((unsigned long)p))
> + devm_kfree(dev, p);
> +}
> +EXPORT_SYMBOL(devm_kfree_const);
> +
> /**
> * kstrdup - allocate space for and copy an existing string
> * @s: the string to duplicate
> @@ -78,6 +92,27 @@ const char *kstrdup_const(const char *s, gfp_t gfp)
> }
> EXPORT_SYMBOL(kstrdup_const);
>
> +/**
> + * devm_kstrdup_const - resource managed conditional string duplication
> + * @dev: device for which to duplicate the string
> + * @s: the string to duplicate
> + * @gfp: the GFP mask used in the kmalloc() call when allocating memory
> + *
> + * Function returns source string if it is in .rodata section otherwise it
> + * fallbacks to devm_kstrdup.
Please make it proper "Returns:" description and move to the end of the
comment. See Documentation/doc-guide/kernel-doc.rst.
> + * Strings allocated by devm_kstrdup_const will be automatically freed when
> + * the associated device is detached.
> + */
> +char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp)
> +{
> + if (is_kernel_rodata((unsigned long)s))
> + return s;
> +
> + return devm_kstrdup(dev, s, gfp);
> +}
> +EXPORT_SYMBOL(devm_kstrdup_const);
> +
The devm_ variants seem to belong to drivers/base/devres.c rather than
mm/util.c
> /**
> * kstrndup - allocate space for and copy an existing string
> * @s: the string to duplicate
> --
> 2.18.0
>
--
Sincerely yours,
Mike.
On Mon, Aug 27, 2018 at 10:21:01AM +0200, Bartosz Golaszewski wrote:
> Use devm_kstrdup_const() in the pmc-atom driver. This mostly serves as
> an example of how to use this new routine to shrink driver code.
>
> While we're at it: replace a call to kcalloc() with devm_kcalloc().
>
> Signed-off-by: Bartosz Golaszewski <[email protected]>
> ---
> drivers/clk/x86/clk-pmc-atom.c | 19 ++++---------------
> 1 file changed, 4 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c
> index 08ef69945ffb..daa2192e6568 100644
> --- a/drivers/clk/x86/clk-pmc-atom.c
> +++ b/drivers/clk/x86/clk-pmc-atom.c
> @@ -253,14 +253,6 @@ static void plt_clk_unregister_fixed_rate_loop(struct clk_plt_data *data,
> plt_clk_unregister_fixed_rate(data->parents[i]);
> }
>
> -static void plt_clk_free_parent_names_loop(const char **parent_names,
> - unsigned int i)
> -{
> - while (i--)
> - kfree_const(parent_names[i]);
> - kfree(parent_names);
> -}
> -
> static void plt_clk_unregister_loop(struct clk_plt_data *data,
> unsigned int i)
> {
> @@ -286,8 +278,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
> if (!data->parents)
> return ERR_PTR(-ENOMEM);
>
> - parent_names = kcalloc(nparents, sizeof(*parent_names),
> - GFP_KERNEL);
> + parent_names = devm_kcalloc(&pdev->dev, nparents,
> + sizeof(*parent_names), GFP_KERNEL);
> if (!parent_names)
> return ERR_PTR(-ENOMEM);
>
> @@ -300,7 +292,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
> err = PTR_ERR(data->parents[i]);
> goto err_unreg;
> }
> - parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL);
> + parent_names[i] = devm_kstrdup_const(&pdev->dev,
> + clks[i].name, GFP_KERNEL);
> }
>
> data->nparents = nparents;
> @@ -308,7 +301,6 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
>
> err_unreg:
> plt_clk_unregister_fixed_rate_loop(data, i);
> - plt_clk_free_parent_names_loop(parent_names, i);
What happens if clks[i].name is not a part of RO data? The devm_kstrdup_const
will allocate memory and nothing will ever free it...
And, please don't drop kfree(parent_names) here.
> return ERR_PTR(err);
> }
>
> @@ -351,15 +343,12 @@ static int plt_clk_probe(struct platform_device *pdev)
> goto err_unreg_clk_plt;
> }
>
> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
> -
> platform_set_drvdata(pdev, data);
> return 0;
>
> err_unreg_clk_plt:
> plt_clk_unregister_loop(data, i);
> plt_clk_unregister_parents(data);
> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
Ditto.
> return err;
> }
>
> --
> 2.18.0
>
--
Sincerely yours,
Mike.
2018-08-27 12:39 GMT+02:00 Mike Rapoport <[email protected]>:
> On Mon, Aug 27, 2018 at 10:21:01AM +0200, Bartosz Golaszewski wrote:
>> Use devm_kstrdup_const() in the pmc-atom driver. This mostly serves as
>> an example of how to use this new routine to shrink driver code.
>>
>> While we're at it: replace a call to kcalloc() with devm_kcalloc().
>>
>> Signed-off-by: Bartosz Golaszewski <[email protected]>
>> ---
>> drivers/clk/x86/clk-pmc-atom.c | 19 ++++---------------
>> 1 file changed, 4 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c
>> index 08ef69945ffb..daa2192e6568 100644
>> --- a/drivers/clk/x86/clk-pmc-atom.c
>> +++ b/drivers/clk/x86/clk-pmc-atom.c
>> @@ -253,14 +253,6 @@ static void plt_clk_unregister_fixed_rate_loop(struct clk_plt_data *data,
>> plt_clk_unregister_fixed_rate(data->parents[i]);
>> }
>>
>> -static void plt_clk_free_parent_names_loop(const char **parent_names,
>> - unsigned int i)
>> -{
>> - while (i--)
>> - kfree_const(parent_names[i]);
>> - kfree(parent_names);
>> -}
>> -
>> static void plt_clk_unregister_loop(struct clk_plt_data *data,
>> unsigned int i)
>> {
>> @@ -286,8 +278,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
>> if (!data->parents)
>> return ERR_PTR(-ENOMEM);
>>
>> - parent_names = kcalloc(nparents, sizeof(*parent_names),
>> - GFP_KERNEL);
>> + parent_names = devm_kcalloc(&pdev->dev, nparents,
>> + sizeof(*parent_names), GFP_KERNEL);
>> if (!parent_names)
>> return ERR_PTR(-ENOMEM);
>>
>> @@ -300,7 +292,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
>> err = PTR_ERR(data->parents[i]);
>> goto err_unreg;
>> }
>> - parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL);
>> + parent_names[i] = devm_kstrdup_const(&pdev->dev,
>> + clks[i].name, GFP_KERNEL);
>> }
>>
>> data->nparents = nparents;
>> @@ -308,7 +301,6 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
>>
>> err_unreg:
>> plt_clk_unregister_fixed_rate_loop(data, i);
>> - plt_clk_free_parent_names_loop(parent_names, i);
>
> What happens if clks[i].name is not a part of RO data? The devm_kstrdup_const
> will allocate memory and nothing will ever free it...
>
I'm looking at it and trying to see if I'm missing something, but
AFAIK the whole concept of devm_* is to leave out the resource
management part.
devm_kstrdup_const() will internally call devm_kstrdup() for strings
that are not in .rodata and once the device is detached, the string
will be freed (or not if it's in .rodata).
BR
Bart
> And, please don't drop kfree(parent_names) here.
>
>> return ERR_PTR(err);
>> }
>>
>> @@ -351,15 +343,12 @@ static int plt_clk_probe(struct platform_device *pdev)
>> goto err_unreg_clk_plt;
>> }
>>
>> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
>> -
>> platform_set_drvdata(pdev, data);
>> return 0;
>>
>> err_unreg_clk_plt:
>> plt_clk_unregister_loop(data, i);
>> plt_clk_unregister_parents(data);
>> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
>
> Ditto.
>
>> return err;
>> }
>>
>> --
>> 2.18.0
>>
>
> --
> Sincerely yours,
> Mike.
>
Hi Bartosz,
I love your patch! Perhaps something to improve:
[auto build test WARNING on clk/clk-next]
[also build test WARNING on v4.19-rc1 next-20180827]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Bartosz-Golaszewski/devres-provide-devm_kstrdup_const/20180827-162336
base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: powerpc-mpc836x_mds_defconfig (attached as .config)
compiler: powerpc-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.2.0 make.cross ARCH=powerpc
All warnings (new ones prefixed by >>):
mm/util.c: In function 'devm_kstrdup_const':
>> mm/util.c:110:10: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
return s;
^
vim +/const +110 mm/util.c
94
95 /**
96 * devm_kstrdup_const - resource managed conditional string duplication
97 * @dev: device for which to duplicate the string
98 * @s: the string to duplicate
99 * @gfp: the GFP mask used in the kmalloc() call when allocating memory
100 *
101 * Function returns source string if it is in .rodata section otherwise it
102 * fallbacks to devm_kstrdup.
103 *
104 * Strings allocated by devm_kstrdup_const will be automatically freed when
105 * the associated device is detached.
106 */
107 char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp)
108 {
109 if (is_kernel_rodata((unsigned long)s))
> 110 return s;
111
112 return devm_kstrdup(dev, s, gfp);
113 }
114 EXPORT_SYMBOL(devm_kstrdup_const);
115
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
On Mon, Aug 27, 2018 at 02:28:45PM +0200, Bartosz Golaszewski wrote:
> 2018-08-27 12:39 GMT+02:00 Mike Rapoport <[email protected]>:
> > On Mon, Aug 27, 2018 at 10:21:01AM +0200, Bartosz Golaszewski wrote:
> >> Use devm_kstrdup_const() in the pmc-atom driver. This mostly serves as
> >> an example of how to use this new routine to shrink driver code.
> >>
> >> While we're at it: replace a call to kcalloc() with devm_kcalloc().
> >>
> >> Signed-off-by: Bartosz Golaszewski <[email protected]>
> >> ---
> >> drivers/clk/x86/clk-pmc-atom.c | 19 ++++---------------
> >> 1 file changed, 4 insertions(+), 15 deletions(-)
> >>
> >> diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c
> >> index 08ef69945ffb..daa2192e6568 100644
> >> --- a/drivers/clk/x86/clk-pmc-atom.c
> >> +++ b/drivers/clk/x86/clk-pmc-atom.c
> >> @@ -253,14 +253,6 @@ static void plt_clk_unregister_fixed_rate_loop(struct clk_plt_data *data,
> >> plt_clk_unregister_fixed_rate(data->parents[i]);
> >> }
> >>
> >> -static void plt_clk_free_parent_names_loop(const char **parent_names,
> >> - unsigned int i)
> >> -{
> >> - while (i--)
> >> - kfree_const(parent_names[i]);
> >> - kfree(parent_names);
> >> -}
> >> -
> >> static void plt_clk_unregister_loop(struct clk_plt_data *data,
> >> unsigned int i)
> >> {
> >> @@ -286,8 +278,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
> >> if (!data->parents)
> >> return ERR_PTR(-ENOMEM);
> >>
> >> - parent_names = kcalloc(nparents, sizeof(*parent_names),
> >> - GFP_KERNEL);
> >> + parent_names = devm_kcalloc(&pdev->dev, nparents,
> >> + sizeof(*parent_names), GFP_KERNEL);
> >> if (!parent_names)
> >> return ERR_PTR(-ENOMEM);
> >>
> >> @@ -300,7 +292,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
> >> err = PTR_ERR(data->parents[i]);
> >> goto err_unreg;
> >> }
> >> - parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL);
> >> + parent_names[i] = devm_kstrdup_const(&pdev->dev,
> >> + clks[i].name, GFP_KERNEL);
> >> }
> >>
> >> data->nparents = nparents;
> >> @@ -308,7 +301,6 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
> >>
> >> err_unreg:
> >> plt_clk_unregister_fixed_rate_loop(data, i);
> >> - plt_clk_free_parent_names_loop(parent_names, i);
> >
> > What happens if clks[i].name is not a part of RO data? The devm_kstrdup_const
> > will allocate memory and nothing will ever free it...
> >
>
> I'm looking at it and trying to see if I'm missing something, but
> AFAIK the whole concept of devm_* is to leave out the resource
> management part.
>
> devm_kstrdup_const() will internally call devm_kstrdup() for strings
> that are not in .rodata and once the device is detached, the string
> will be freed (or not if it's in .rodata).
And when it's going to be freed, how the resource management will know
whether it's .rodata or not?
> BR
> Bart
>
> > And, please don't drop kfree(parent_names) here.
> >
> >> return ERR_PTR(err);
> >> }
> >>
> >> @@ -351,15 +343,12 @@ static int plt_clk_probe(struct platform_device *pdev)
> >> goto err_unreg_clk_plt;
> >> }
> >>
> >> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
> >> -
> >> platform_set_drvdata(pdev, data);
> >> return 0;
> >>
> >> err_unreg_clk_plt:
> >> plt_clk_unregister_loop(data, i);
> >> plt_clk_unregister_parents(data);
> >> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
> >
> > Ditto.
> >
> >> return err;
> >> }
> >>
> >> --
> >> 2.18.0
> >>
> >
> > --
> > Sincerely yours,
> > Mike.
> >
>
--
Sincerely yours,
Mike.
2018-08-27 14:52 GMT+02:00 Mike Rapoport <[email protected]>:
> On Mon, Aug 27, 2018 at 02:28:45PM +0200, Bartosz Golaszewski wrote:
>> 2018-08-27 12:39 GMT+02:00 Mike Rapoport <[email protected]>:
>> > On Mon, Aug 27, 2018 at 10:21:01AM +0200, Bartosz Golaszewski wrote:
>> >> Use devm_kstrdup_const() in the pmc-atom driver. This mostly serves as
>> >> an example of how to use this new routine to shrink driver code.
>> >>
>> >> While we're at it: replace a call to kcalloc() with devm_kcalloc().
>> >>
>> >> Signed-off-by: Bartosz Golaszewski <[email protected]>
>> >> ---
>> >> drivers/clk/x86/clk-pmc-atom.c | 19 ++++---------------
>> >> 1 file changed, 4 insertions(+), 15 deletions(-)
>> >>
>> >> diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c
>> >> index 08ef69945ffb..daa2192e6568 100644
>> >> --- a/drivers/clk/x86/clk-pmc-atom.c
>> >> +++ b/drivers/clk/x86/clk-pmc-atom.c
>> >> @@ -253,14 +253,6 @@ static void plt_clk_unregister_fixed_rate_loop(struct clk_plt_data *data,
>> >> plt_clk_unregister_fixed_rate(data->parents[i]);
>> >> }
>> >>
>> >> -static void plt_clk_free_parent_names_loop(const char **parent_names,
>> >> - unsigned int i)
>> >> -{
>> >> - while (i--)
>> >> - kfree_const(parent_names[i]);
>> >> - kfree(parent_names);
>> >> -}
>> >> -
>> >> static void plt_clk_unregister_loop(struct clk_plt_data *data,
>> >> unsigned int i)
>> >> {
>> >> @@ -286,8 +278,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
>> >> if (!data->parents)
>> >> return ERR_PTR(-ENOMEM);
>> >>
>> >> - parent_names = kcalloc(nparents, sizeof(*parent_names),
>> >> - GFP_KERNEL);
>> >> + parent_names = devm_kcalloc(&pdev->dev, nparents,
>> >> + sizeof(*parent_names), GFP_KERNEL);
>> >> if (!parent_names)
>> >> return ERR_PTR(-ENOMEM);
>> >>
>> >> @@ -300,7 +292,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
>> >> err = PTR_ERR(data->parents[i]);
>> >> goto err_unreg;
>> >> }
>> >> - parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL);
>> >> + parent_names[i] = devm_kstrdup_const(&pdev->dev,
>> >> + clks[i].name, GFP_KERNEL);
>> >> }
>> >>
>> >> data->nparents = nparents;
>> >> @@ -308,7 +301,6 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
>> >>
>> >> err_unreg:
>> >> plt_clk_unregister_fixed_rate_loop(data, i);
>> >> - plt_clk_free_parent_names_loop(parent_names, i);
>> >
>> > What happens if clks[i].name is not a part of RO data? The devm_kstrdup_const
>> > will allocate memory and nothing will ever free it...
>> >
>>
>> I'm looking at it and trying to see if I'm missing something, but
>> AFAIK the whole concept of devm_* is to leave out the resource
>> management part.
>>
>> devm_kstrdup_const() will internally call devm_kstrdup() for strings
>> that are not in .rodata and once the device is detached, the string
>> will be freed (or not if it's in .rodata).
>
> And when it's going to be freed, how the resource management will know
> whether it's .rodata or not?
>
If the string to be duplicated is in .rodata, it's returned as is from
devm_kstrdup_const(). Never gets added to the devres list, never get's
freed. When the string to be duplicated is not in .rodata,
devm_kstrdup() is called from devm_kstrdup_const(). Now the string is
in the devres list of this device and it will get freed on driver
detach. I really don't see what else could be a problem here.
BR
Bart
>> BR
>> Bart
>>
>> > And, please don't drop kfree(parent_names) here.
>> >
>> >> return ERR_PTR(err);
>> >> }
>> >>
>> >> @@ -351,15 +343,12 @@ static int plt_clk_probe(struct platform_device *pdev)
>> >> goto err_unreg_clk_plt;
>> >> }
>> >>
>> >> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
>> >> -
>> >> platform_set_drvdata(pdev, data);
>> >> return 0;
>> >>
>> >> err_unreg_clk_plt:
>> >> plt_clk_unregister_loop(data, i);
>> >> plt_clk_unregister_parents(data);
>> >> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
>> >
>> > Ditto.
>> >
>> >> return err;
>> >> }
>> >>
>> >> --
>> >> 2.18.0
>> >>
>> >
>> > --
>> > Sincerely yours,
>> > Mike.
>> >
>>
>
> --
> Sincerely yours,
> Mike.
>
On Mon, Aug 27, 2018 at 02:58:46PM +0200, Bartosz Golaszewski wrote:
> 2018-08-27 14:52 GMT+02:00 Mike Rapoport <[email protected]>:
> > On Mon, Aug 27, 2018 at 02:28:45PM +0200, Bartosz Golaszewski wrote:
> >> 2018-08-27 12:39 GMT+02:00 Mike Rapoport <[email protected]>:
> >> > On Mon, Aug 27, 2018 at 10:21:01AM +0200, Bartosz Golaszewski wrote:
> >> >> Use devm_kstrdup_const() in the pmc-atom driver. This mostly serves as
> >> >> an example of how to use this new routine to shrink driver code.
> >> >>
> >> >> While we're at it: replace a call to kcalloc() with devm_kcalloc().
> >> >>
> >> >> Signed-off-by: Bartosz Golaszewski <[email protected]>
> >> >> ---
> >> >> drivers/clk/x86/clk-pmc-atom.c | 19 ++++---------------
> >> >> 1 file changed, 4 insertions(+), 15 deletions(-)
> >> >>
> >> >> diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c
> >> >> index 08ef69945ffb..daa2192e6568 100644
> >> >> --- a/drivers/clk/x86/clk-pmc-atom.c
> >> >> +++ b/drivers/clk/x86/clk-pmc-atom.c
> >> >> @@ -253,14 +253,6 @@ static void plt_clk_unregister_fixed_rate_loop(struct clk_plt_data *data,
> >> >> plt_clk_unregister_fixed_rate(data->parents[i]);
> >> >> }
> >> >>
> >> >> -static void plt_clk_free_parent_names_loop(const char **parent_names,
> >> >> - unsigned int i)
> >> >> -{
> >> >> - while (i--)
> >> >> - kfree_const(parent_names[i]);
> >> >> - kfree(parent_names);
> >> >> -}
> >> >> -
> >> >> static void plt_clk_unregister_loop(struct clk_plt_data *data,
> >> >> unsigned int i)
> >> >> {
> >> >> @@ -286,8 +278,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
> >> >> if (!data->parents)
> >> >> return ERR_PTR(-ENOMEM);
> >> >>
> >> >> - parent_names = kcalloc(nparents, sizeof(*parent_names),
> >> >> - GFP_KERNEL);
> >> >> + parent_names = devm_kcalloc(&pdev->dev, nparents,
> >> >> + sizeof(*parent_names), GFP_KERNEL);
> >> >> if (!parent_names)
> >> >> return ERR_PTR(-ENOMEM);
> >> >>
> >> >> @@ -300,7 +292,8 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
> >> >> err = PTR_ERR(data->parents[i]);
> >> >> goto err_unreg;
> >> >> }
> >> >> - parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL);
> >> >> + parent_names[i] = devm_kstrdup_const(&pdev->dev,
> >> >> + clks[i].name, GFP_KERNEL);
> >> >> }
> >> >>
> >> >> data->nparents = nparents;
> >> >> @@ -308,7 +301,6 @@ static const char **plt_clk_register_parents(struct platform_device *pdev,
> >> >>
> >> >> err_unreg:
> >> >> plt_clk_unregister_fixed_rate_loop(data, i);
> >> >> - plt_clk_free_parent_names_loop(parent_names, i);
> >> >
> >> > What happens if clks[i].name is not a part of RO data? The devm_kstrdup_const
> >> > will allocate memory and nothing will ever free it...
> >> >
> >>
> >> I'm looking at it and trying to see if I'm missing something, but
> >> AFAIK the whole concept of devm_* is to leave out the resource
> >> management part.
> >>
> >> devm_kstrdup_const() will internally call devm_kstrdup() for strings
> >> that are not in .rodata and once the device is detached, the string
> >> will be freed (or not if it's in .rodata).
> >
> > And when it's going to be freed, how the resource management will know
> > whether it's .rodata or not?
> >
>
> If the string to be duplicated is in .rodata, it's returned as is from
> devm_kstrdup_const(). Never gets added to the devres list, never get's
> freed. When the string to be duplicated is not in .rodata,
> devm_kstrdup() is called from devm_kstrdup_const(). Now the string is
> in the devres list of this device and it will get freed on driver
> detach. I really don't see what else could be a problem here.
Thanks for the clarification.
I think that it's worth adding a similar explanation to the changelog of
the first patch.
> BR
> Bart
>
> >> BR
> >> Bart
> >>
> >> > And, please don't drop kfree(parent_names) here.
> >> >
> >> >> return ERR_PTR(err);
> >> >> }
> >> >>
> >> >> @@ -351,15 +343,12 @@ static int plt_clk_probe(struct platform_device *pdev)
> >> >> goto err_unreg_clk_plt;
> >> >> }
> >> >>
> >> >> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
> >> >> -
> >> >> platform_set_drvdata(pdev, data);
> >> >> return 0;
> >> >>
> >> >> err_unreg_clk_plt:
> >> >> plt_clk_unregister_loop(data, i);
> >> >> plt_clk_unregister_parents(data);
> >> >> - plt_clk_free_parent_names_loop(parent_names, data->nparents);
> >> >
> >> > Ditto.
> >> >
> >> >> return err;
> >> >> }
> >> >>
> >> >> --
> >> >> 2.18.0
> >> >>
> >> >
> >> > --
> >> > Sincerely yours,
> >> > Mike.
> >> >
> >>
> >
> > --
> > Sincerely yours,
> > Mike.
> >
>
--
Sincerely yours,
Mike.
2018-08-27 12:33 GMT+02:00 Mike Rapoport <[email protected]>:
> On Mon, Aug 27, 2018 at 10:21:00AM +0200, Bartosz Golaszewski wrote:
>> Provide a resource managed version of kstrdup_const(). This variant
>> internally calls devm_kstrdup() on pointers that are outside of
>> .rodata section. Also provide a corresponding version of devm_kfree().
>>
>> Signed-off-by: Bartosz Golaszewski <[email protected]>
>> ---
>> include/linux/device.h | 2 ++
>> mm/util.c | 35 +++++++++++++++++++++++++++++++++++
>> 2 files changed, 37 insertions(+)
>>
>> diff --git a/include/linux/device.h b/include/linux/device.h
>> index 8f882549edee..f8f5982d26b2 100644
>> --- a/include/linux/device.h
>> +++ b/include/linux/device.h
>> @@ -693,7 +693,9 @@ static inline void *devm_kcalloc(struct device *dev,
>> return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
>> }
>> extern void devm_kfree(struct device *dev, void *p);
>> +extern void devm_kfree_const(struct device *dev, void *p);
>> extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
>> +extern char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp);
>> extern void *devm_kmemdup(struct device *dev, const void *src, size_t len,
>> gfp_t gfp);
>>
>> diff --git a/mm/util.c b/mm/util.c
>> index d2890a407332..6d1f41b5775e 100644
>> --- a/mm/util.c
>> +++ b/mm/util.c
>> @@ -39,6 +39,20 @@ void kfree_const(const void *x)
>> }
>> EXPORT_SYMBOL(kfree_const);
>>
>> +/**
>> + * devm_kfree_const - Resource managed conditional kfree
>> + * @dev: device this memory belongs to
>> + * @p: memory to free
>> + *
>> + * Function calls devm_kfree only if @p is not in .rodata section.
>> + */
>> +void devm_kfree_const(struct device *dev, void *p)
>> +{
>> + if (!is_kernel_rodata((unsigned long)p))
>> + devm_kfree(dev, p);
>> +}
>> +EXPORT_SYMBOL(devm_kfree_const);
>> +
>> /**
>> * kstrdup - allocate space for and copy an existing string
>> * @s: the string to duplicate
>> @@ -78,6 +92,27 @@ const char *kstrdup_const(const char *s, gfp_t gfp)
>> }
>> EXPORT_SYMBOL(kstrdup_const);
>>
>> +/**
>> + * devm_kstrdup_const - resource managed conditional string duplication
>> + * @dev: device for which to duplicate the string
>> + * @s: the string to duplicate
>> + * @gfp: the GFP mask used in the kmalloc() call when allocating memory
>> + *
>> + * Function returns source string if it is in .rodata section otherwise it
>> + * fallbacks to devm_kstrdup.
>
> Please make it proper "Returns:" description and move to the end of the
> comment. See Documentation/doc-guide/kernel-doc.rst.
>
Sure.
>> + * Strings allocated by devm_kstrdup_const will be automatically freed when
>> + * the associated device is detached.
>> + */
>> +char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp)
>> +{
>> + if (is_kernel_rodata((unsigned long)s))
>> + return s;
>> +
>> + return devm_kstrdup(dev, s, gfp);
>> +}
>> +EXPORT_SYMBOL(devm_kstrdup_const);
>> +
>
> The devm_ variants seem to belong to drivers/base/devres.c rather than
> mm/util.c
>
Not all devm_ variants live in drivers/base/devres.c, many subsystems
implement them locally. In this case we need to choose between
exporting is_kernel_rodata() and putting devm_kstrdup_const() in
mm/util.c. I chose the latter, since it's cleaner.
Bart
>> /**
>> * kstrndup - allocate space for and copy an existing string
>> * @s: the string to duplicate
>> --
>> 2.18.0
>>
>
> --
> Sincerely yours,
> Mike.
>
On Mon, Aug 27, 2018 at 04:28:55PM +0200, Bartosz Golaszewski wrote:
> 2018-08-27 12:33 GMT+02:00 Mike Rapoport <[email protected]>:
> > On Mon, Aug 27, 2018 at 10:21:00AM +0200, Bartosz Golaszewski wrote:
> >> Provide a resource managed version of kstrdup_const(). This variant
> >> internally calls devm_kstrdup() on pointers that are outside of
> >> .rodata section. Also provide a corresponding version of devm_kfree().
> >>
> >> Signed-off-by: Bartosz Golaszewski <[email protected]>
> >> ---
> >> include/linux/device.h | 2 ++
> >> mm/util.c | 35 +++++++++++++++++++++++++++++++++++
> >> 2 files changed, 37 insertions(+)
> >>
> >> diff --git a/include/linux/device.h b/include/linux/device.h
> >> index 8f882549edee..f8f5982d26b2 100644
> >> --- a/include/linux/device.h
> >> +++ b/include/linux/device.h
> >> @@ -693,7 +693,9 @@ static inline void *devm_kcalloc(struct device *dev,
> >> return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
> >> }
> >> extern void devm_kfree(struct device *dev, void *p);
> >> +extern void devm_kfree_const(struct device *dev, void *p);
> >> extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
> >> +extern char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp);
> >> extern void *devm_kmemdup(struct device *dev, const void *src, size_t len,
> >> gfp_t gfp);
> >>
> >> diff --git a/mm/util.c b/mm/util.c
> >> index d2890a407332..6d1f41b5775e 100644
> >> --- a/mm/util.c
> >> +++ b/mm/util.c
[ ... ]
> >> + * Strings allocated by devm_kstrdup_const will be automatically freed when
> >> + * the associated device is detached.
> >> + */
> >> +char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp)
> >> +{
> >> + if (is_kernel_rodata((unsigned long)s))
> >> + return s;
> >> +
> >> + return devm_kstrdup(dev, s, gfp);
> >> +}
> >> +EXPORT_SYMBOL(devm_kstrdup_const);
> >> +
> >
> > The devm_ variants seem to belong to drivers/base/devres.c rather than
> > mm/util.c
> >
>
> Not all devm_ variants live in drivers/base/devres.c, many subsystems
> implement them locally. In this case we need to choose between
> exporting is_kernel_rodata() and putting devm_kstrdup_const() in
> mm/util.c. I chose the latter, since it's cleaner.
I rather think that moving is_kernel_rodata() to
include/asm-generic/sections.h and having devm_kstrdup_const() next to
devm_kstrdup() would be cleaner.
> Bart
>
--
Sincerely yours,
Mike.