Commit f773f32d authored by Rasmus Villemoes's avatar Rasmus Villemoes Committed by Linus Torvalds

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: default avatarRasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0a9df786
...@@ -257,18 +257,32 @@ static int kobject_add_internal(struct kobject *kobj) ...@@ -257,18 +257,32 @@ static int kobject_add_internal(struct kobject *kobj)
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
va_list vargs) va_list vargs)
{ {
char *s; const char *s;
if (kobj->name && !fmt) if (kobj->name && !fmt)
return 0; return 0;
s = kvasprintf(GFP_KERNEL, fmt, vargs); s = kvasprintf_const(GFP_KERNEL, fmt, vargs);
if (!s) if (!s)
return -ENOMEM; return -ENOMEM;
/* ewww... some of these buggers have '/' in the name ... */ /*
strreplace(s, '/', '!'); * ewww... some of these buggers have '/' in the name ... If
kfree(kobj->name); * that's the case, we need to make sure we have an actual
* allocated copy to modify, since kvasprintf_const may have
* returned something from .rodata.
*/
if (strchr(s, '/')) {
char *t;
t = kstrdup(s, GFP_KERNEL);
kfree_const(s);
if (!t)
return -ENOMEM;
strreplace(t, '/', '!');
s = t;
}
kfree_const(kobj->name);
kobj->name = s; kobj->name = s;
return 0; return 0;
...@@ -466,7 +480,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name) ...@@ -466,7 +480,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name)
envp[0] = devpath_string; envp[0] = devpath_string;
envp[1] = NULL; envp[1] = NULL;
name = dup_name = kstrdup(new_name, GFP_KERNEL); name = dup_name = kstrdup_const(new_name, GFP_KERNEL);
if (!name) { if (!name) {
error = -ENOMEM; error = -ENOMEM;
goto out; goto out;
...@@ -486,7 +500,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name) ...@@ -486,7 +500,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name)
kobject_uevent_env(kobj, KOBJ_MOVE, envp); kobject_uevent_env(kobj, KOBJ_MOVE, envp);
out: out:
kfree(dup_name); kfree_const(dup_name);
kfree(devpath_string); kfree(devpath_string);
kfree(devpath); kfree(devpath);
kobject_put(kobj); kobject_put(kobj);
...@@ -634,7 +648,7 @@ static void kobject_cleanup(struct kobject *kobj) ...@@ -634,7 +648,7 @@ static void kobject_cleanup(struct kobject *kobj)
/* free name if we allocated it */ /* free name if we allocated it */
if (name) { if (name) {
pr_debug("kobject: '%s': free name\n", name); pr_debug("kobject: '%s': free name\n", name);
kfree(name); kfree_const(name);
} }
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment