[PATCH 3/7] string: implement proper strdup_const/free_const

Ahmad Fatoum a.fatoum at pengutronix.de
Mon Nov 25 07:29:23 PST 2024


We currently implement strdup_const as strdup, which is correct, but
leaves the benefits of a proper implementation on the table:
Reducing allocations for .rodata strings, which have static storage
duration anyway.

Let's implement it properly using the newly added is_barebox_rodata
and add free_const, dma_free_const and kfree_const that go along with
it.

There will be a slight difference to Linux in our API though: In Linux
devm_kfree can be used with devm_kstrdup_const, but kfree can't be used
with kstrdup_const and instead kfree_const needs to be used.

In barebox, we kfree and kfree_const is identical. This is because Linux
gives kfree a const void * parameter and we have existing code that uses
const pointers to the heap and passes them to kfree and it's not worth
risking memory corruption in this case.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/dma.h          |  5 +++++
 include/linux/slab.h   |  7 ++++---
 include/linux/string.h |  5 +++++
 lib/string.c           | 28 ++++++++++++++++++++++++++++
 4 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/include/dma.h b/include/dma.h
index 1f650aecb950..5877f4b13c0d 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -46,6 +46,11 @@ static inline void dma_free(void *mem)
 	free(mem);
 }
 
+static inline void dma_free_const(const void *mem)
+{
+	free_const(mem);
+}
+
 static inline void dma_free_sensitive(void *mem)
 {
 	free_sensitive(mem);
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 5e08c7697daf..93ce25a58299 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -59,9 +59,11 @@ static inline void kmem_cache_destroy(struct kmem_cache *cache)
 
 static inline void kfree(const void *mem)
 {
-	dma_free((void *)mem);
+	dma_free_const(mem);
 }
 
+#define kfree_const(ptr) dma_free_const(ptr)
+
 static inline void kfree_sensitive(const void *objp)
 {
 	dma_free_sensitive((void *)objp);
@@ -112,7 +114,6 @@ static inline char *kstrdup(const char *str, gfp_t flags)
 	return strdup(str);
 }
 
-#define kstrdup_const(str, flags) strdup(str)
-#define kfree_const(ptr) kfree((void *)ptr)
+#define kstrdup_const(str, flags) strdup_const(str)
 
 #endif /* _LINUX_SLAB_H */
diff --git a/include/linux/string.h b/include/linux/string.h
index 5d5824b61bf0..0fa84f095e02 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -93,6 +93,11 @@ extern __kernel_size_t strnlen(const char *,__kernel_size_t);
 #ifndef __HAVE_ARCH_STRDUP
 extern char * strdup(const char *);
 #endif
+
+extern void free_const(const void *x);
+extern const char *strdup_const(const char *s);
+const char *xstrdup_const(const char *s);
+
 #ifndef __HAVE_ARCH_STRNDUP
 extern char *strndup(const char *, size_t);
 #endif
diff --git a/lib/string.c b/lib/string.c
index cab543baf38d..f2272be37e76 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -24,6 +24,7 @@
 #include <linux/ctype.h>
 #include <asm/word-at-a-time.h>
 #include <malloc.h>
+#include <asm-generic/sections.h>
 
 #ifndef __HAVE_ARCH_STRCASECMP
 int strcasecmp(const char *s1, const char *s2)
@@ -1055,6 +1056,33 @@ char *strjoin(const char *separator, char **arr, size_t arrlen)
 }
 EXPORT_SYMBOL(strjoin);
 
+const char *xstrdup_const(const char *str)
+{
+	if (is_barebox_rodata((ulong)str))
+		return str;
+
+	return xstrdup(str);
+}
+EXPORT_SYMBOL(xstrdup_const);
+
+const char *strdup_const(const char *str)
+{
+	if (is_barebox_rodata((ulong)str))
+		return str;
+
+	return strdup(str);
+}
+EXPORT_SYMBOL(strdup_const);
+
+void free_const(const void *str)
+{
+	if (is_barebox_rodata((ulong)str))
+		return;
+
+	free((void *)str);
+}
+EXPORT_SYMBOL(free_const);
+
 /**
  * strreplace - Replace all occurrences of character in string.
  * @str: The string to operate on.
-- 
2.39.5




More information about the barebox mailing list