Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm/util: add kstrdup_const

kstrdup() is often used to duplicate strings where neither source neither
destination will be ever modified. In such case we can just reuse the
source instead of duplicating it. The problem is that we must be sure
that the source is non-modifiable and its life-time is long enough.

I suspect the good candidates for such strings are strings located in
kernel .rodata section, they cannot be modifed because the section is
read-only and their life-time is equal to kernel life-time.

This small patchset proposes alternative version of kstrdup -
kstrdup_const, which returns source string if it is located in .rodata
otherwise it fallbacks to kstrdup. To verify if the source is in
.rodata function checks if the address is between sentinels
__start_rodata, __end_rodata. I guess it should work with all
architectures.

The main patch is accompanied by four patches constifying kstrdup for
cases where situtation described above happens frequently.

I have tested the patchset on mobile platform (exynos4210-trats) and it
saves 3272 string allocations. Since minimal allocation is 32 or 64
bytes depending on Kconfig options the patchset saves respectively about
100KB or 200KB of memory.

Stats from tested platform show that the main offender is sysfs:

By caller:
2260 __kernfs_new_node
631 clk_register+0xc8/0x1b8
318 clk_register+0x34/0x1b8
51 kmem_cache_create
12 alloc_vfsmnt

By string (with count >= 5):
883 power
876 subsystem
135 parameters
132 device
61 iommu_group
...

This patch (of 5):

Add an alternative version of kstrdup which returns pointer to constant
char array. The function checks if input string is in persistent and
read-only memory section, if yes it returns the input string, otherwise it
fallbacks to kstrdup.

kstrdup_const is accompanied by kfree_const performing conditional memory
deallocation of the string.

Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Greg KH <greg@kroah.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Andrzej Hajda and committed by
Linus Torvalds
a4bb1e43 f5e38b92

+41
+3
include/linux/string.h
··· 112 112 #endif 113 113 void *memchr_inv(const void *s, int c, size_t n); 114 114 115 + extern void kfree_const(const void *x); 116 + 115 117 extern char *kstrdup(const char *s, gfp_t gfp); 118 + extern const char *kstrdup_const(const char *s, gfp_t gfp); 116 119 extern char *kstrndup(const char *s, size_t len, gfp_t gfp); 117 120 extern void *kmemdup(const void *src, size_t len, gfp_t gfp); 118 121
+38
mm/util.c
··· 12 12 #include <linux/hugetlb.h> 13 13 #include <linux/vmalloc.h> 14 14 15 + #include <asm/sections.h> 15 16 #include <asm/uaccess.h> 16 17 17 18 #include "internal.h" 19 + 20 + static inline int is_kernel_rodata(unsigned long addr) 21 + { 22 + return addr >= (unsigned long)__start_rodata && 23 + addr < (unsigned long)__end_rodata; 24 + } 25 + 26 + /** 27 + * kfree_const - conditionally free memory 28 + * @x: pointer to the memory 29 + * 30 + * Function calls kfree only if @x is not in .rodata section. 31 + */ 32 + void kfree_const(const void *x) 33 + { 34 + if (!is_kernel_rodata((unsigned long)x)) 35 + kfree(x); 36 + } 37 + EXPORT_SYMBOL(kfree_const); 18 38 19 39 /** 20 40 * kstrdup - allocate space for and copy an existing string ··· 56 36 return buf; 57 37 } 58 38 EXPORT_SYMBOL(kstrdup); 39 + 40 + /** 41 + * kstrdup_const - conditionally duplicate an existing const string 42 + * @s: the string to duplicate 43 + * @gfp: the GFP mask used in the kmalloc() call when allocating memory 44 + * 45 + * Function returns source string if it is in .rodata section otherwise it 46 + * fallbacks to kstrdup. 47 + * Strings allocated by kstrdup_const should be freed by kfree_const. 48 + */ 49 + const char *kstrdup_const(const char *s, gfp_t gfp) 50 + { 51 + if (is_kernel_rodata((unsigned long)s)) 52 + return s; 53 + 54 + return kstrdup(s, gfp); 55 + } 56 + EXPORT_SYMBOL(kstrdup_const); 59 57 60 58 /** 61 59 * kstrndup - allocate space for and copy an existing string