Messages in this thread Patch in this message | | | From | Maurizio Lombardi <> | Subject | [RFC PATCH 1/3] lib/vsprintf.c: Do not pass printf_spec by value on stack. | Date | Wed, 16 Sep 2015 11:08:41 +0200 |
| |
The original code passes the structure by value on the stack, this limits the size of the printf_spec structure because of performance reasons. This patch modifies the code so only a const pointer to the structure is passed on the stack.
Signed-off-by: Maurizio Lombardi <mlombard@redhat.com> --- lib/vsprintf.c | 225 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 118 insertions(+), 107 deletions(-)
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 95cd63b..8707d91 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -390,9 +390,10 @@ struct printf_spec { static noinline_for_stack char *number(char *buf, char *end, unsigned long long num, - struct printf_spec spec) + const struct printf_spec *specp) { /* put_dec requires 2-byte alignment of the buffer. */ + struct printf_spec spec = *specp; char tmp[3 * sizeof(num)] __aligned(2); char sign; char locase; @@ -508,9 +509,10 @@ char *number(char *buf, char *end, unsigned long long num, } static noinline_for_stack -char *string(char *buf, char *end, const char *s, struct printf_spec spec) +char *string(char *buf, char *end, const char *s, const struct printf_spec *specp) { int len, i; + struct printf_spec spec = *specp; if ((unsigned long)s < PAGE_SIZE) s = "(null)"; @@ -557,7 +559,7 @@ static void widen(char *buf, char *end, unsigned len, unsigned spaces) } static noinline_for_stack -char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec, +char *dentry_name(char *buf, char *end, const struct dentry *d, const struct printf_spec *specp, const char *fmt) { const char *array[4], *s; @@ -585,7 +587,7 @@ char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_sp } } s = array[--i]; - for (n = 0; n != spec.precision; n++, buf++) { + for (n = 0; n != specp->precision; n++, buf++) { char c = *s++; if (!c) { if (!i) @@ -597,10 +599,10 @@ char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_sp *buf = c; } rcu_read_unlock(); - if (n < spec.field_width) { + if (n < specp->field_width) { /* we want to pad the sucker */ - unsigned spaces = spec.field_width - n; - if (!(spec.flags & LEFT)) { + unsigned spaces = specp->field_width - n; + if (!(specp->flags & LEFT)) { widen(buf - n, end, n, spaces); return buf + spaces; } @@ -615,9 +617,10 @@ char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_sp static noinline_for_stack char *symbol_string(char *buf, char *end, void *ptr, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { unsigned long value; + struct printf_spec spec = *specp; #ifdef CONFIG_KALLSYMS char sym[KSYM_SYMBOL_LEN]; #endif @@ -634,19 +637,19 @@ char *symbol_string(char *buf, char *end, void *ptr, else sprint_symbol_no_offset(sym, value); - return string(buf, end, sym, spec); + return string(buf, end, sym, &spec); #else spec.field_width = 2 * sizeof(void *); spec.flags |= SPECIAL | SMALL | ZEROPAD; spec.base = 16; - return number(buf, end, value, spec); + return number(buf, end, value, &spec); #endif } static noinline_for_stack char *resource_string(char *buf, char *end, struct resource *res, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { #ifndef IO_RSRC_PRINTK_SIZE #define IO_RSRC_PRINTK_SIZE 6 @@ -700,73 +703,73 @@ char *resource_string(char *buf, char *end, struct resource *res, char *p = sym, *pend = sym + sizeof(sym); int decode = (fmt[0] == 'R') ? 1 : 0; - const struct printf_spec *specp; + const struct printf_spec *sp; *p++ = '['; if (res->flags & IORESOURCE_IO) { - p = string(p, pend, "io ", str_spec); - specp = &io_spec; + p = string(p, pend, "io ", &str_spec); + sp = &io_spec; } else if (res->flags & IORESOURCE_MEM) { - p = string(p, pend, "mem ", str_spec); - specp = &mem_spec; + p = string(p, pend, "mem ", &str_spec); + sp = &mem_spec; } else if (res->flags & IORESOURCE_IRQ) { - p = string(p, pend, "irq ", str_spec); - specp = &dec_spec; + p = string(p, pend, "irq ", &str_spec); + sp = &dec_spec; } else if (res->flags & IORESOURCE_DMA) { - p = string(p, pend, "dma ", str_spec); - specp = &dec_spec; + p = string(p, pend, "dma ", &str_spec); + sp = &dec_spec; } else if (res->flags & IORESOURCE_BUS) { - p = string(p, pend, "bus ", str_spec); - specp = &bus_spec; + p = string(p, pend, "bus ", &str_spec); + sp = &bus_spec; } else { - p = string(p, pend, "??? ", str_spec); - specp = &mem_spec; + p = string(p, pend, "??? ", &str_spec); + sp = &mem_spec; decode = 0; } if (decode && res->flags & IORESOURCE_UNSET) { - p = string(p, pend, "size ", str_spec); - p = number(p, pend, resource_size(res), *specp); + p = string(p, pend, "size ", &str_spec); + p = number(p, pend, resource_size(res), sp); } else { - p = number(p, pend, res->start, *specp); + p = number(p, pend, res->start, sp); if (res->start != res->end) { *p++ = '-'; - p = number(p, pend, res->end, *specp); + p = number(p, pend, res->end, sp); } } if (decode) { if (res->flags & IORESOURCE_MEM_64) - p = string(p, pend, " 64bit", str_spec); + p = string(p, pend, " 64bit", &str_spec); if (res->flags & IORESOURCE_PREFETCH) - p = string(p, pend, " pref", str_spec); + p = string(p, pend, " pref", &str_spec); if (res->flags & IORESOURCE_WINDOW) - p = string(p, pend, " window", str_spec); + p = string(p, pend, " window", &str_spec); if (res->flags & IORESOURCE_DISABLED) - p = string(p, pend, " disabled", str_spec); + p = string(p, pend, " disabled", &str_spec); } else { - p = string(p, pend, " flags ", str_spec); - p = number(p, pend, res->flags, flag_spec); + p = string(p, pend, " flags ", &str_spec); + p = number(p, pend, res->flags, &flag_spec); } *p++ = ']'; *p = '\0'; - return string(buf, end, sym, spec); + return string(buf, end, sym, specp); } static noinline_for_stack -char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec, +char *hex_string(char *buf, char *end, u8 *addr, const struct printf_spec *specp, const char *fmt) { int i, len = 1; /* if we pass '%ph[CDN]', field width remains negative value, fallback to the default */ char separator; - if (spec.field_width == 0) + if (specp->field_width == 0) /* nothing to print */ return buf; if (ZERO_OR_NULL_PTR(addr)) /* NULL pointer */ - return string(buf, end, NULL, spec); + return string(buf, end, NULL, specp); switch (fmt[1]) { case 'C': @@ -783,8 +786,8 @@ char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec, break; } - if (spec.field_width > 0) - len = min_t(int, spec.field_width, 64); + if (specp->field_width > 0) + len = min_t(int, specp->field_width, 64); for (i = 0; i < len; ++i) { if (buf < end) @@ -806,12 +809,13 @@ char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec, static noinline_for_stack char *bitmap_string(char *buf, char *end, unsigned long *bitmap, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { const int CHUNKSZ = 32; - int nr_bits = max_t(int, spec.field_width, 0); + int nr_bits = max_t(int, specp->field_width, 0); int i, chunksz; bool first = true; + struct printf_spec spec = *specp; /* reused to print numbers */ spec = (struct printf_spec){ .flags = SMALL | ZEROPAD, .base = 16 }; @@ -838,7 +842,7 @@ char *bitmap_string(char *buf, char *end, unsigned long *bitmap, first = false; spec.field_width = DIV_ROUND_UP(chunksz, 4); - buf = number(buf, end, val, spec); + buf = number(buf, end, val, &spec); chunksz = CHUNKSZ; } @@ -847,12 +851,13 @@ char *bitmap_string(char *buf, char *end, unsigned long *bitmap, static noinline_for_stack char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { - int nr_bits = max_t(int, spec.field_width, 0); + int nr_bits = max_t(int, specp->field_width, 0); /* current bit is 'cur', most recently seen range is [rbot, rtop] */ int cur, rbot, rtop; bool first = true; + struct printf_spec spec = *specp; /* reused to print numbers */ spec = (struct printf_spec){ .base = 10 }; @@ -871,13 +876,13 @@ char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap, } first = false; - buf = number(buf, end, rbot, spec); + buf = number(buf, end, rbot, &spec); if (rbot < rtop) { if (buf < end) *buf = '-'; buf++; - buf = number(buf, end, rtop, spec); + buf = number(buf, end, rtop, &spec); } rbot = cur; @@ -887,7 +892,7 @@ char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap, static noinline_for_stack char *mac_address_string(char *buf, char *end, u8 *addr, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; char *p = mac_addr; @@ -920,7 +925,7 @@ char *mac_address_string(char *buf, char *end, u8 *addr, } *p = '\0'; - return string(buf, end, mac_addr, spec); + return string(buf, end, mac_addr, specp); } static noinline_for_stack @@ -1074,7 +1079,7 @@ char *ip6_string(char *p, const char *addr, const char *fmt) static noinline_for_stack char *ip6_addr_string(char *buf, char *end, const u8 *addr, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; @@ -1083,23 +1088,23 @@ char *ip6_addr_string(char *buf, char *end, const u8 *addr, else ip6_string(ip6_addr, addr, fmt); - return string(buf, end, ip6_addr, spec); + return string(buf, end, ip6_addr, specp); } static noinline_for_stack char *ip4_addr_string(char *buf, char *end, const u8 *addr, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { char ip4_addr[sizeof("255.255.255.255")]; ip4_string(ip4_addr, addr, fmt); - return string(buf, end, ip4_addr, spec); + return string(buf, end, ip4_addr, specp); } static noinline_for_stack char *ip6_addr_string_sa(char *buf, char *end, const struct sockaddr_in6 *sa, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { bool have_p = false, have_s = false, have_f = false, have_c = false; char ip6_addr[sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") + @@ -1143,25 +1148,25 @@ char *ip6_addr_string_sa(char *buf, char *end, const struct sockaddr_in6 *sa, if (have_p) { *p++ = ':'; - p = number(p, pend, ntohs(sa->sin6_port), spec); + p = number(p, pend, ntohs(sa->sin6_port), specp); } if (have_f) { *p++ = '/'; p = number(p, pend, ntohl(sa->sin6_flowinfo & - IPV6_FLOWINFO_MASK), spec); + IPV6_FLOWINFO_MASK), specp); } if (have_s) { *p++ = '%'; - p = number(p, pend, sa->sin6_scope_id, spec); + p = number(p, pend, sa->sin6_scope_id, specp); } *p = '\0'; - return string(buf, end, ip6_addr, spec); + return string(buf, end, ip6_addr, specp); } static noinline_for_stack char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { bool have_p = false; char *p, ip4_addr[sizeof("255.255.255.255") + sizeof(":12345")]; @@ -1187,15 +1192,15 @@ char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa, p = ip4_string(ip4_addr, addr, fmt4); if (have_p) { *p++ = ':'; - p = number(p, pend, ntohs(sa->sin_port), spec); + p = number(p, pend, ntohs(sa->sin_port), specp); } *p = '\0'; - return string(buf, end, ip4_addr, spec); + return string(buf, end, ip4_addr, specp); } static noinline_for_stack -char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec, +char *escaped_string(char *buf, char *end, u8 *addr, const struct printf_spec *specp, const char *fmt) { bool found = true; @@ -1203,11 +1208,11 @@ char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec, unsigned int flags = 0; int len; - if (spec.field_width == 0) + if (specp->field_width == 0) return buf; /* nothing to print */ if (ZERO_OR_NULL_PTR(addr)) - return string(buf, end, NULL, spec); /* NULL pointer */ + return string(buf, end, NULL, specp); /* NULL pointer */ do { @@ -1242,7 +1247,7 @@ char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec, if (!flags) flags = ESCAPE_ANY_NP; - len = spec.field_width < 0 ? 1 : spec.field_width; + len = specp->field_width < 0 ? 1 : specp->field_width; /* * string_escape_mem() writes as many characters as it can to @@ -1256,7 +1261,7 @@ char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec, static noinline_for_stack char *uuid_string(char *buf, char *end, const u8 *addr, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { char uuid[sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; char *p = uuid; @@ -1298,26 +1303,28 @@ char *uuid_string(char *buf, char *end, const u8 *addr, } while (*(++p)); } - return string(buf, end, uuid, spec); + return string(buf, end, uuid, specp); } static char *netdev_feature_string(char *buf, char *end, const u8 *addr, - struct printf_spec spec) + const struct printf_spec *specp) { + struct printf_spec spec = *specp; spec.flags |= SPECIAL | SMALL | ZEROPAD; if (spec.field_width == -1) spec.field_width = 2 + 2 * sizeof(netdev_features_t); spec.base = 16; - return number(buf, end, *(const netdev_features_t *)addr, spec); + return number(buf, end, *(const netdev_features_t *)addr, &spec); } static noinline_for_stack char *address_val(char *buf, char *end, const void *addr, - struct printf_spec spec, const char *fmt) + const struct printf_spec *specp, const char *fmt) { unsigned long long num; + struct printf_spec spec = *specp; spec.flags |= SPECIAL | SMALL | ZEROPAD; spec.base = 16; @@ -1334,29 +1341,32 @@ char *address_val(char *buf, char *end, const void *addr, break; } - return number(buf, end, num, spec); + return number(buf, end, num, &spec); } static noinline_for_stack -char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, +char *clock(char *buf, char *end, struct clk *clk, const struct printf_spec *specp, const char *fmt) { if (!IS_ENABLED(CONFIG_HAVE_CLK) || !clk) - return string(buf, end, NULL, spec); + return string(buf, end, NULL, specp); switch (fmt[1]) { case 'r': - return number(buf, end, clk_get_rate(clk), spec); + return number(buf, end, clk_get_rate(clk), specp); case 'n': default: #ifdef CONFIG_COMMON_CLK - return string(buf, end, __clk_get_name(clk), spec); + return string(buf, end, __clk_get_name(clk), specp); #else - spec.base = 16; - spec.field_width = sizeof(unsigned long) * 2 + 2; - spec.flags |= SPECIAL | SMALL | ZEROPAD; - return number(buf, end, (unsigned long)clk, spec); + { + struct printf_spec spec = *specp; + spec.base = 16; + spec.field_width = sizeof(unsigned long) * 2 + 2; + spec.flags |= SPECIAL | SMALL | ZEROPAD; + return number(buf, end, (unsigned long)clk, &spec); + } #endif } } @@ -1455,8 +1465,9 @@ int kptr_restrict __read_mostly; */ static noinline_for_stack char *pointer(const char *fmt, char *buf, char *end, void *ptr, - struct printf_spec spec) + const struct printf_spec *specp) { + struct printf_spec spec = *specp; int default_width = 2 * sizeof(void *) + (spec.flags & SPECIAL ? 2 : 0); if (!ptr && *fmt != 'K') { @@ -1466,7 +1477,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, */ if (spec.field_width == -1) spec.field_width = default_width; - return string(buf, end, "(null)", spec); + return string(buf, end, "(null)", &spec); } switch (*fmt) { @@ -1477,24 +1488,24 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, case 'S': case 's': case 'B': - return symbol_string(buf, end, ptr, spec, fmt); + return symbol_string(buf, end, ptr, &spec, fmt); case 'R': case 'r': - return resource_string(buf, end, ptr, spec, fmt); + return resource_string(buf, end, ptr, &spec, fmt); case 'h': - return hex_string(buf, end, ptr, spec, fmt); + return hex_string(buf, end, ptr, &spec, fmt); case 'b': switch (fmt[1]) { case 'l': - return bitmap_list_string(buf, end, ptr, spec, fmt); + return bitmap_list_string(buf, end, ptr, &spec, fmt); default: - return bitmap_string(buf, end, ptr, spec, fmt); + return bitmap_string(buf, end, ptr, &spec, fmt); } case 'M': /* Colon separated: 00:01:02:03:04:05 */ case 'm': /* Contiguous: 000102030405 */ /* [mM]F (FDDI) */ /* [mM]R (Reverse order; Bluetooth) */ - return mac_address_string(buf, end, ptr, spec, fmt); + return mac_address_string(buf, end, ptr, &spec, fmt); case 'I': /* Formatted IP supported * 4: 1.2.3.4 * 6: 0001:0203:...:0708 @@ -1506,9 +1517,9 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, */ switch (fmt[1]) { case '6': - return ip6_addr_string(buf, end, ptr, spec, fmt); + return ip6_addr_string(buf, end, ptr, &spec, fmt); case '4': - return ip4_addr_string(buf, end, ptr, spec, fmt); + return ip4_addr_string(buf, end, ptr, &spec, fmt); case 'S': { const union { struct sockaddr raw; @@ -1518,18 +1529,18 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, switch (sa->raw.sa_family) { case AF_INET: - return ip4_addr_string_sa(buf, end, &sa->v4, spec, fmt); + return ip4_addr_string_sa(buf, end, &sa->v4, &spec, fmt); case AF_INET6: - return ip6_addr_string_sa(buf, end, &sa->v6, spec, fmt); + return ip6_addr_string_sa(buf, end, &sa->v6, &spec, fmt); default: - return string(buf, end, "(invalid address)", spec); + return string(buf, end, "(invalid address)", &spec); }} } break; case 'E': - return escaped_string(buf, end, ptr, spec, fmt); + return escaped_string(buf, end, ptr, &spec, fmt); case 'U': - return uuid_string(buf, end, ptr, spec, fmt); + return uuid_string(buf, end, ptr, &spec, fmt); case 'V': { va_list va; @@ -1549,7 +1560,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, in_nmi())) { if (spec.field_width == -1) spec.field_width = default_width; - return string(buf, end, "pK-error", spec); + return string(buf, end, "pK-error", &spec); } switch (kptr_restrict) { @@ -1585,19 +1596,19 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, case 'N': switch (fmt[1]) { case 'F': - return netdev_feature_string(buf, end, ptr, spec); + return netdev_feature_string(buf, end, ptr, &spec); } break; case 'a': - return address_val(buf, end, ptr, spec, fmt); + return address_val(buf, end, ptr, &spec, fmt); case 'd': - return dentry_name(buf, end, ptr, spec, fmt); + return dentry_name(buf, end, ptr, &spec, fmt); case 'C': - return clock(buf, end, ptr, spec, fmt); + return clock(buf, end, ptr, &spec, fmt); case 'D': return dentry_name(buf, end, ((const struct file *)ptr)->f_path.dentry, - spec, fmt); + &spec, fmt); } spec.flags |= SMALL; if (spec.field_width == -1) { @@ -1606,7 +1617,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, } spec.base = 16; - return number(buf, end, (unsigned long) ptr, spec); + return number(buf, end, (unsigned long) ptr, &spec); } /* @@ -1927,12 +1938,12 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) } case FORMAT_TYPE_STR: - str = string(str, end, va_arg(args, char *), spec); + str = string(str, end, va_arg(args, char *), &spec); break; case FORMAT_TYPE_PTR: str = pointer(fmt, str, end, va_arg(args, void *), - spec); + &spec); while (isalnum(*fmt)) fmt++; break; @@ -1988,7 +1999,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) num = va_arg(args, unsigned int); } - str = number(str, end, num, spec); + str = number(str, end, num, &spec); } } @@ -2364,12 +2375,12 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf) case FORMAT_TYPE_STR: { const char *str_arg = args; args += strlen(str_arg) + 1; - str = string(str, end, (char *)str_arg, spec); + str = string(str, end, (char *)str_arg, &spec); break; } case FORMAT_TYPE_PTR: - str = pointer(fmt, str, end, get_arg(void *), spec); + str = pointer(fmt, str, end, get_arg(void *), &spec); while (isalnum(*fmt)) fmt++; break; @@ -2418,7 +2429,7 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf) num = get_arg(int); } - str = number(str, end, num, spec); + str = number(str, end, num, &spec); } /* default: */ } /* switch(spec.type) */ } /* while(*fmt) */ -- Maurizio Lombardi
| |