diff mbox series

[v3,3/4] devres: provide devm_kstrdup_const()

Message ID 20180924101150.23349-4-brgl@bgdev.pl (mailing list archive)
State Not Applicable, archived
Headers show
Series devres: provide and use devm_kstrdup_const() | expand

Commit Message

Bartosz Golaszewski Sept. 24, 2018, 10:11 a.m. UTC
Provide a resource managed version of kstrdup_const(). This variant
internally calls devm_kstrdup() on pointers that are outside of
.rodata section and returns the string as is otherwise.

Also provide a corresponding version of devm_kfree().

Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/base/devres.c  | 38 ++++++++++++++++++++++++++++++++++++++
 include/linux/device.h |  3 +++
 2 files changed, 41 insertions(+)

Comments

Mike Rapoport Sept. 24, 2018, 10:32 a.m. UTC | #1
On Mon, Sep 24, 2018 at 12:11:49PM +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 and returns the string as is otherwise.
> 
> Also provide a corresponding version of devm_kfree().
> 
> Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>

Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>

> ---
>  drivers/base/devres.c  | 38 ++++++++++++++++++++++++++++++++++++++
>  include/linux/device.h |  3 +++
>  2 files changed, 41 insertions(+)
> 
> diff --git a/drivers/base/devres.c b/drivers/base/devres.c
> index 438c91a43508..48185d57bc5b 100644
> --- a/drivers/base/devres.c
> +++ b/drivers/base/devres.c
> @@ -11,6 +11,8 @@
>  #include <linux/slab.h>
>  #include <linux/percpu.h>
> 
> +#include <asm/sections.h>
> +
>  #include "base.h"
> 
>  struct devres_node {
> @@ -822,6 +824,28 @@ char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
>  }
>  EXPORT_SYMBOL_GPL(devm_kstrdup);
> 
> +/**
> + * 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
> + *
> + * Strings allocated by devm_kstrdup_const will be automatically freed when
> + * the associated device is detached.
> + *
> + * RETURNS:
> + * Source string if it is in .rodata section otherwise it falls back to
> + * devm_kstrdup.
> + */
> +const 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);
> +
>  /**
>   * devm_kvasprintf - Allocate resource managed space and format a string
>   *		     into that.
> @@ -895,6 +919,20 @@ void devm_kfree(struct device *dev, const void *p)
>  }
>  EXPORT_SYMBOL_GPL(devm_kfree);
> 
> +/**
> + * 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, const void *p)
> +{
> +	if (!is_kernel_rodata((unsigned long)p))
> +		devm_kfree(dev, p);
> +}
> +EXPORT_SYMBOL(devm_kfree_const);
> +
>  /**
>   * devm_kmemdup - Resource-managed kmemdup
>   * @dev: Device this memory belongs to
> diff --git a/include/linux/device.h b/include/linux/device.h
> index 33f7cb271fbb..79ccc6eb0975 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -693,7 +693,10 @@ 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, const void *p);
> +extern void devm_kfree_const(struct device *dev, const void *p);
>  extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
> +extern const 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);
> 
> -- 
> 2.18.0
>
Kees Cook Sept. 26, 2018, 11:13 p.m. UTC | #2
On Mon, Sep 24, 2018 at 3:11 AM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> Provide a resource managed version of kstrdup_const(). This variant
> internally calls devm_kstrdup() on pointers that are outside of
> .rodata section and returns the string as is otherwise.
>
> Also provide a corresponding version of devm_kfree().
>
> Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>  drivers/base/devres.c  | 38 ++++++++++++++++++++++++++++++++++++++
>  include/linux/device.h |  3 +++
>  2 files changed, 41 insertions(+)
>
> diff --git a/drivers/base/devres.c b/drivers/base/devres.c
> index 438c91a43508..48185d57bc5b 100644
> --- a/drivers/base/devres.c
> +++ b/drivers/base/devres.c
> @@ -11,6 +11,8 @@
>  #include <linux/slab.h>
>  #include <linux/percpu.h>
>
> +#include <asm/sections.h>
> +
>  #include "base.h"
>
>  struct devres_node {
> @@ -822,6 +824,28 @@ char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
>  }
>  EXPORT_SYMBOL_GPL(devm_kstrdup);
>
> +/**
> + * 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
> + *
> + * Strings allocated by devm_kstrdup_const will be automatically freed when
> + * the associated device is detached.
> + *
> + * RETURNS:
> + * Source string if it is in .rodata section otherwise it falls back to
> + * devm_kstrdup.
> + */
> +const 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);
> +
>  /**
>   * devm_kvasprintf - Allocate resource managed space and format a string
>   *                  into that.
> @@ -895,6 +919,20 @@ void devm_kfree(struct device *dev, const void *p)
>  }
>  EXPORT_SYMBOL_GPL(devm_kfree);
>
> +/**
> + * 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, const void *p)
> +{
> +       if (!is_kernel_rodata((unsigned long)p))
> +               devm_kfree(dev, p);
> +}
> +EXPORT_SYMBOL(devm_kfree_const);
> +
>  /**
>   * devm_kmemdup - Resource-managed kmemdup
>   * @dev: Device this memory belongs to
> diff --git a/include/linux/device.h b/include/linux/device.h
> index 33f7cb271fbb..79ccc6eb0975 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -693,7 +693,10 @@ 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, const void *p);
> +extern void devm_kfree_const(struct device *dev, const void *p);

With devm_kfree and devm_kfree_const both taking "const", how are
devm_kstrdup_const() and devm_kfree_const() going to be correctly
paired at compile time? (i.e. I wasn't expecting the prototype change
to devm_kfree())

-Kees

>  extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
> +extern const 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);
>
> --
> 2.18.0
>
Bartosz Golaszewski Sept. 27, 2018, 8:53 a.m. UTC | #3
czw., 27 wrz 2018 o 01:20 Kees Cook <keescook@chromium.org> napisaƂ(a):
>
> On Mon, Sep 24, 2018 at 3:11 AM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > Provide a resource managed version of kstrdup_const(). This variant
> > internally calls devm_kstrdup() on pointers that are outside of
> > .rodata section and returns the string as is otherwise.
> >
> > Also provide a corresponding version of devm_kfree().
> >
> > Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
> > Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> > ---
> >  drivers/base/devres.c  | 38 ++++++++++++++++++++++++++++++++++++++
> >  include/linux/device.h |  3 +++
> >  2 files changed, 41 insertions(+)
> >
> > diff --git a/drivers/base/devres.c b/drivers/base/devres.c
> > index 438c91a43508..48185d57bc5b 100644
> > --- a/drivers/base/devres.c
> > +++ b/drivers/base/devres.c
> > @@ -11,6 +11,8 @@
> >  #include <linux/slab.h>
> >  #include <linux/percpu.h>
> >
> > +#include <asm/sections.h>
> > +
> >  #include "base.h"
> >
> >  struct devres_node {
> > @@ -822,6 +824,28 @@ char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
> >  }
> >  EXPORT_SYMBOL_GPL(devm_kstrdup);
> >
> > +/**
> > + * 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
> > + *
> > + * Strings allocated by devm_kstrdup_const will be automatically freed when
> > + * the associated device is detached.
> > + *
> > + * RETURNS:
> > + * Source string if it is in .rodata section otherwise it falls back to
> > + * devm_kstrdup.
> > + */
> > +const 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);
> > +
> >  /**
> >   * devm_kvasprintf - Allocate resource managed space and format a string
> >   *                  into that.
> > @@ -895,6 +919,20 @@ void devm_kfree(struct device *dev, const void *p)
> >  }
> >  EXPORT_SYMBOL_GPL(devm_kfree);
> >
> > +/**
> > + * 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, const void *p)
> > +{
> > +       if (!is_kernel_rodata((unsigned long)p))
> > +               devm_kfree(dev, p);
> > +}
> > +EXPORT_SYMBOL(devm_kfree_const);
> > +
> >  /**
> >   * devm_kmemdup - Resource-managed kmemdup
> >   * @dev: Device this memory belongs to
> > diff --git a/include/linux/device.h b/include/linux/device.h
> > index 33f7cb271fbb..79ccc6eb0975 100644
> > --- a/include/linux/device.h
> > +++ b/include/linux/device.h
> > @@ -693,7 +693,10 @@ 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, const void *p);
> > +extern void devm_kfree_const(struct device *dev, const void *p);
>
> With devm_kfree and devm_kfree_const both taking "const", how are
> devm_kstrdup_const() and devm_kfree_const() going to be correctly
> paired at compile time? (i.e. I wasn't expecting the prototype change
> to devm_kfree())
>

I guess the same as with kfree() and kfree_const() which both take
const void * as argument - it's up to users to only use
devm_kfree_const() on resources allocated with devm_kstrdup_const().

Bart

> -Kees
>
> >  extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
> > +extern const 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);
> >
> > --
> > 2.18.0
> >
>
>
>
> --
> Kees Cook
> Pixel Security
Rasmus Villemoes Sept. 27, 2018, 10:55 a.m. UTC | #4
On 2018-09-27 01:13, Kees Cook wrote:
> On Mon, Sep 24, 2018 at 3:11 AM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>> Provide a resource managed version of kstrdup_const(). This variant
>> internally calls devm_kstrdup() on pointers that are outside of
>> .rodata section and returns the string as is otherwise.
>>
>> Also provide a corresponding version of devm_kfree().
>>
>> +/**
>> + * 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, const void *p)
>> +{
>> +       if (!is_kernel_rodata((unsigned long)p))
>> +               devm_kfree(dev, p);
>> +}
>> +EXPORT_SYMBOL(devm_kfree_const);
>> +
>>  /**
>>   * devm_kmemdup - Resource-managed kmemdup
>>   * @dev: Device this memory belongs to
>> diff --git a/include/linux/device.h b/include/linux/device.h
>> index 33f7cb271fbb..79ccc6eb0975 100644
>> --- a/include/linux/device.h
>> +++ b/include/linux/device.h
>> @@ -693,7 +693,10 @@ 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, const void *p);
>> +extern void devm_kfree_const(struct device *dev, const void *p);
> 
> With devm_kfree and devm_kfree_const both taking "const", how are
> devm_kstrdup_const() and devm_kfree_const() going to be correctly
> paired at compile time? (i.e. I wasn't expecting the prototype change
> to devm_kfree())

Just drop devm_kfree_const and teach devm_kfree to ignore
is_kernel_rodata(). That avoids the 50-100 bytes of overhead for adding
yet another EXPORT_SYMBOL and makes it easier to port drivers to
devm_kstrdup_const (and avoids the bugs Kees is worried about). devm
managed resources are almost never freed explicitly, so that single
extra comparison in devm_kfree shouldn't matter for performance.

Rasmus
Geert Uytterhoeven Sept. 27, 2018, 11:01 a.m. UTC | #5
Hi Rasmus,

On Thu, Sep 27, 2018 at 12:55 PM Rasmus Villemoes
<linux@rasmusvillemoes.dk> wrote:
> On 2018-09-27 01:13, Kees Cook wrote:
> > On Mon, Sep 24, 2018 at 3:11 AM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >> Provide a resource managed version of kstrdup_const(). This variant
> >> internally calls devm_kstrdup() on pointers that are outside of
> >> .rodata section and returns the string as is otherwise.
> >>
> >> Also provide a corresponding version of devm_kfree().
> >>
> >> +/**
> >> + * 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, const void *p)
> >> +{
> >> +       if (!is_kernel_rodata((unsigned long)p))
> >> +               devm_kfree(dev, p);
> >> +}
> >> +EXPORT_SYMBOL(devm_kfree_const);
> >> +
> >>  /**
> >>   * devm_kmemdup - Resource-managed kmemdup
> >>   * @dev: Device this memory belongs to
> >> diff --git a/include/linux/device.h b/include/linux/device.h
> >> index 33f7cb271fbb..79ccc6eb0975 100644
> >> --- a/include/linux/device.h
> >> +++ b/include/linux/device.h
> >> @@ -693,7 +693,10 @@ 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, const void *p);
> >> +extern void devm_kfree_const(struct device *dev, const void *p);
> >
> > With devm_kfree and devm_kfree_const both taking "const", how are
> > devm_kstrdup_const() and devm_kfree_const() going to be correctly
> > paired at compile time? (i.e. I wasn't expecting the prototype change
> > to devm_kfree())
>
> Just drop devm_kfree_const and teach devm_kfree to ignore
> is_kernel_rodata(). That avoids the 50-100 bytes of overhead for adding
> yet another EXPORT_SYMBOL and makes it easier to port drivers to
> devm_kstrdup_const (and avoids the bugs Kees is worried about). devm
> managed resources are almost never freed explicitly, so that single
> extra comparison in devm_kfree shouldn't matter for performance.

I guess we can also teach kfree() to ignore is_kernel_rodata(), and
drop kfree_const()?

Gr{oetje,eeting}s,

                        Geert
Rasmus Villemoes Sept. 27, 2018, 11:30 a.m. UTC | #6
On 2018-09-27 13:01, Geert Uytterhoeven wrote:
> Hi Rasmus,
> 
> On Thu, Sep 27, 2018 at 12:55 PM Rasmus Villemoes
> <linux@rasmusvillemoes.dk> wrote:
>> On 2018-09-27 01:13, Kees Cook wrote:
>>
>> Just drop devm_kfree_const and teach devm_kfree to ignore
>> is_kernel_rodata(). That avoids the 50-100 bytes of overhead for adding
>> yet another EXPORT_SYMBOL and makes it easier to port drivers to
>> devm_kstrdup_const (and avoids the bugs Kees is worried about). devm
>> managed resources are almost never freed explicitly, so that single
>> extra comparison in devm_kfree shouldn't matter for performance.
> 
> I guess we can also teach kfree() to ignore is_kernel_rodata(), and
> drop kfree_const()?

In principle, yes, but the difference is that kfree() is called a lot
more frequently, and on normal code paths, whereas devm_kfree is more
often (though not always) called on error paths.

The goal of _const variants of strdup is to save some memory, so one
place to start is to reduce the .text overhead of that feature. And it
avoids introducing subtle bugs if some devm_kfree() call is missed
during conversion to devm_kstrdup_const().

Rasmus
diff mbox series

Patch

diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 438c91a43508..48185d57bc5b 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -11,6 +11,8 @@ 
 #include <linux/slab.h>
 #include <linux/percpu.h>
 
+#include <asm/sections.h>
+
 #include "base.h"
 
 struct devres_node {
@@ -822,6 +824,28 @@  char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
 }
 EXPORT_SYMBOL_GPL(devm_kstrdup);
 
+/**
+ * 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
+ *
+ * Strings allocated by devm_kstrdup_const will be automatically freed when
+ * the associated device is detached.
+ *
+ * RETURNS:
+ * Source string if it is in .rodata section otherwise it falls back to
+ * devm_kstrdup.
+ */
+const 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);
+
 /**
  * devm_kvasprintf - Allocate resource managed space and format a string
  *		     into that.
@@ -895,6 +919,20 @@  void devm_kfree(struct device *dev, const void *p)
 }
 EXPORT_SYMBOL_GPL(devm_kfree);
 
+/**
+ * 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, const void *p)
+{
+	if (!is_kernel_rodata((unsigned long)p))
+		devm_kfree(dev, p);
+}
+EXPORT_SYMBOL(devm_kfree_const);
+
 /**
  * devm_kmemdup - Resource-managed kmemdup
  * @dev: Device this memory belongs to
diff --git a/include/linux/device.h b/include/linux/device.h
index 33f7cb271fbb..79ccc6eb0975 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -693,7 +693,10 @@  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, const void *p);
+extern void devm_kfree_const(struct device *dev, const void *p);
 extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
+extern const 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);