lib/kasprintf.c: introduce kvasprintf_const

This adds kvasprintf_const which tries to use kstrdup_const if possible:
If the format string contains no % characters, or if the format string is
exactly "%s", we delegate to kstrdup_const.  Otherwise, we fall back to
kvasprintf.

Just as for kstrdup_const, the main motivation is to save memory by
reusing .rodata when possible.

The return value should be freed by kfree_const, just like for
kstrdup_const.

There is deliberately no kasprintf_const: In the vast majority of cases,
the format string argument is a literal, so one can determine statically
whether one could instead use kstrdup_const directly (which would also
require one to change all corresponding kfree calls to kfree_const).

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>
This commit is contained in:
Rasmus Villemoes 2015-11-06 16:31:20 -08:00 committed by Linus Torvalds
parent 2cf12f821c
commit 0a9df786a6
2 changed files with 18 additions and 0 deletions

View File

@ -413,6 +413,8 @@ extern __printf(2, 3)
char *kasprintf(gfp_t gfp, const char *fmt, ...); char *kasprintf(gfp_t gfp, const char *fmt, ...);
extern __printf(2, 0) extern __printf(2, 0)
char *kvasprintf(gfp_t gfp, const char *fmt, va_list args); char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
extern __printf(2, 0)
const char *kvasprintf_const(gfp_t gfp, const char *fmt, va_list args);
extern __scanf(2, 3) extern __scanf(2, 3)
int sscanf(const char *, const char *, ...); int sscanf(const char *, const char *, ...);

View File

@ -31,6 +31,22 @@ char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
} }
EXPORT_SYMBOL(kvasprintf); EXPORT_SYMBOL(kvasprintf);
/*
* If fmt contains no % (or is exactly %s), use kstrdup_const. If fmt
* (or the sole vararg) points to rodata, we will then save a memory
* allocation and string copy. In any case, the return value should be
* freed using kfree_const().
*/
const char *kvasprintf_const(gfp_t gfp, const char *fmt, va_list ap)
{
if (!strchr(fmt, '%'))
return kstrdup_const(fmt, gfp);
if (!strcmp(fmt, "%s"))
return kstrdup_const(va_arg(ap, const char*), gfp);
return kvasprintf(gfp, fmt, ap);
}
EXPORT_SYMBOL(kvasprintf_const);
char *kasprintf(gfp_t gfp, const char *fmt, ...) char *kasprintf(gfp_t gfp, const char *fmt, ...)
{ {
va_list ap; va_list ap;