diff options
author | Rasmus Villemoes <linux@rasmusvillemoes.dk> | 2015-11-06 19:31:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-06 20:50:42 -0500 |
commit | f773f32d71a4ed9a645634da107cd249e09e1180 (patch) | |
tree | d121a233372164a2b9d75614c9b95cce923b5584 /lib/kobject.c | |
parent | 0a9df786a6ae2f898114bdd242b64920dedf53bd (diff) |
lib/kobject.c: use kvasprintf_const for formatting ->name
Sometimes kobject_set_name_vargs is called with a format string conaining
no %, or a format string of precisely "%s", where the single vararg
happens to point to .rodata. kvasprintf_const detects these cases for us
and returns a copy of that pointer instead of duplicating the string, thus
saving some run-time memory. Otherwise, it falls back to kvasprintf. We
just need to always deallocate ->name using kfree_const.
Unfortunately, the dance we need to do to perform the '/' -> '!'
sanitization makes the resulting code rather ugly.
I instrumented kstrdup_const to provide some statistics on the memory
saved, and for me this gave an additional ~14KB after boot (306KB was
already saved; this patch bumped that to 320KB). I have
KMALLOC_SHIFT_LOW==3, and since 80% of the kvasprintf_const hits were
satisfied by an 8-byte allocation, the 14K would roughly be quadrupled
when KMALLOC_SHIFT_LOW==5. Whether these numbers are sufficient to
justify the ugliness I'll leave to others to decide.
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib/kobject.c')
-rw-r--r-- | lib/kobject.c | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/lib/kobject.c b/lib/kobject.c index 055407746266..7cbccd2b4c72 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
@@ -257,18 +257,32 @@ static int kobject_add_internal(struct kobject *kobj) | |||
257 | int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, | 257 | int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, |
258 | va_list vargs) | 258 | va_list vargs) |
259 | { | 259 | { |
260 | char *s; | 260 | const char *s; |
261 | 261 | ||
262 | if (kobj->name && !fmt) | 262 | if (kobj->name && !fmt) |
263 | return 0; | 263 | return 0; |
264 | 264 | ||
265 | s = kvasprintf(GFP_KERNEL, fmt, vargs); | 265 | s = kvasprintf_const(GFP_KERNEL, fmt, vargs); |
266 | if (!s) | 266 | if (!s) |
267 | return -ENOMEM; | 267 | return -ENOMEM; |
268 | 268 | ||
269 | /* ewww... some of these buggers have '/' in the name ... */ | 269 | /* |
270 | strreplace(s, '/', '!'); | 270 | * ewww... some of these buggers have '/' in the name ... If |
271 | kfree(kobj->name); | 271 | * that's the case, we need to make sure we have an actual |
272 | * allocated copy to modify, since kvasprintf_const may have | ||
273 | * returned something from .rodata. | ||
274 | */ | ||
275 | if (strchr(s, '/')) { | ||
276 | char *t; | ||
277 | |||
278 | t = kstrdup(s, GFP_KERNEL); | ||
279 | kfree_const(s); | ||
280 | if (!t) | ||
281 | return -ENOMEM; | ||
282 | strreplace(t, '/', '!'); | ||
283 | s = t; | ||
284 | } | ||
285 | kfree_const(kobj->name); | ||
272 | kobj->name = s; | 286 | kobj->name = s; |
273 | 287 | ||
274 | return 0; | 288 | return 0; |
@@ -466,7 +480,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name) | |||
466 | envp[0] = devpath_string; | 480 | envp[0] = devpath_string; |
467 | envp[1] = NULL; | 481 | envp[1] = NULL; |
468 | 482 | ||
469 | name = dup_name = kstrdup(new_name, GFP_KERNEL); | 483 | name = dup_name = kstrdup_const(new_name, GFP_KERNEL); |
470 | if (!name) { | 484 | if (!name) { |
471 | error = -ENOMEM; | 485 | error = -ENOMEM; |
472 | goto out; | 486 | goto out; |
@@ -486,7 +500,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name) | |||
486 | kobject_uevent_env(kobj, KOBJ_MOVE, envp); | 500 | kobject_uevent_env(kobj, KOBJ_MOVE, envp); |
487 | 501 | ||
488 | out: | 502 | out: |
489 | kfree(dup_name); | 503 | kfree_const(dup_name); |
490 | kfree(devpath_string); | 504 | kfree(devpath_string); |
491 | kfree(devpath); | 505 | kfree(devpath); |
492 | kobject_put(kobj); | 506 | kobject_put(kobj); |
@@ -634,7 +648,7 @@ static void kobject_cleanup(struct kobject *kobj) | |||
634 | /* free name if we allocated it */ | 648 | /* free name if we allocated it */ |
635 | if (name) { | 649 | if (name) { |
636 | pr_debug("kobject: '%s': free name\n", name); | 650 | pr_debug("kobject: '%s': free name\n", name); |
637 | kfree(name); | 651 | kfree_const(name); |
638 | } | 652 | } |
639 | } | 653 | } |
640 | 654 | ||