* [RFC PATCH 0/3] fix *pbl format support
@ 2015-09-16 9:08 Maurizio Lombardi
2015-09-16 9:08 ` [RFC PATCH 1/3] lib/vsprintf.c: Do not pass printf_spec by value on stack Maurizio Lombardi
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Maurizio Lombardi @ 2015-09-16 9:08 UTC (permalink / raw)
To: tj; +Cc: joe, linux, linux-kernel
Hi,
I tried to fix the "*pb[l]" format issue while taking care of the problems
discussed in this thread:
https://lkml.org/lkml/2015/9/9/153
I would like to know whether this approach is more acceptable to you:
PATCH 1 modifies the code so that the printf_spec struct is not passed by value
anymore, instead a const pointer is used and the structure is copied to
a local variable only when necessary.
PATCH 2 modifies the bitmap_*_string() functions so they'll append "..." to the
output string whenever the buffer is not sufficiently large.
example of output:
*pb: cccccccc,...
*pbl: 1-2,5-7,...
PATCH 3 increases the size of printf_spec.field_width (from s16 to s32).
Maurizio Lombardi (3):
lib/vsprintf.c: Do not pass printf_spec by value on stack.
lib/vsprintf.c: append "..." if the *pb[l] output has been truncated.
lib/vsprintf.c: increase the size of the field_width variable
lib/vsprintf.c | 275 +++++++++++++++++++++++++++++++++++----------------------
1 file changed, 167 insertions(+), 108 deletions(-)
--
Maurizio Lombardi
^ permalink raw reply [flat|nested] 10+ messages in thread* [RFC PATCH 1/3] lib/vsprintf.c: Do not pass printf_spec by value on stack. 2015-09-16 9:08 [RFC PATCH 0/3] fix *pbl format support Maurizio Lombardi @ 2015-09-16 9:08 ` Maurizio Lombardi 2015-09-16 9:08 ` [RFC PATCH 2/3] lib/vsprintf.c: append "..." if the *pb[l] output has been truncated Maurizio Lombardi ` (2 subsequent siblings) 3 siblings, 0 replies; 10+ messages in thread From: Maurizio Lombardi @ 2015-09-16 9:08 UTC (permalink / raw) To: tj; +Cc: joe, linux, linux-kernel 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 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 2/3] lib/vsprintf.c: append "..." if the *pb[l] output has been truncated. 2015-09-16 9:08 [RFC PATCH 0/3] fix *pbl format support Maurizio Lombardi 2015-09-16 9:08 ` [RFC PATCH 1/3] lib/vsprintf.c: Do not pass printf_spec by value on stack Maurizio Lombardi @ 2015-09-16 9:08 ` Maurizio Lombardi 2015-09-16 9:08 ` [RFC PATCH 3/3] lib/vsprintf.c: increase the size of the field_width variable Maurizio Lombardi 2015-09-16 12:27 ` [RFC PATCH 0/3] fix *pbl format support Rasmus Villemoes 3 siblings, 0 replies; 10+ messages in thread From: Maurizio Lombardi @ 2015-09-16 9:08 UTC (permalink / raw) To: tj; +Cc: joe, linux, linux-kernel The *pb[l] format may generate a very long string that could exaust the output buffer capacity; when such event happens the output could be misleading, it may appear valid but part of it has been truncated. This patch modifies the bitmap_*_string() functions so they will append "..." to the output to inform the user that a truncation happened. Signed-off-by: Maurizio Lombardi <mlombard@redhat.com> --- lib/vsprintf.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 8707d91..f49bf54 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -816,6 +816,7 @@ char *bitmap_string(char *buf, char *end, unsigned long *bitmap, int i, chunksz; bool first = true; struct printf_spec spec = *specp; + const char *buf_start = buf; /* reused to print numbers */ spec = (struct printf_spec){ .flags = SMALL | ZEROPAD, .base = 16 }; @@ -846,6 +847,29 @@ char *bitmap_string(char *buf, char *end, unsigned long *bitmap, chunksz = CHUNKSZ; } + + if (buf >= end && buf_start != end) { + int spc = 0; + char *trunc = end - 1; + + while (trunc > buf_start) { + if (*trunc == ',' && spc > 3) { + trunc++; + break; + } + trunc--; + spc++; + } + + if (spc > 3) { + trunc[0] = '.'; + trunc[1] = '.'; + trunc[2] = '.'; + trunc[3] = '\0'; + } else + trunc[0] = '\0'; + } + return buf; } @@ -858,6 +882,7 @@ char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap, int cur, rbot, rtop; bool first = true; struct printf_spec spec = *specp; + const char *buf_start = buf; /* reused to print numbers */ spec = (struct printf_spec){ .base = 10 }; @@ -887,6 +912,29 @@ char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap, rbot = cur; } + + if (buf >= end && buf_start != end) { + int spc = 0; + char *trunc = end - 1; + + while (trunc > buf_start) { + if (*trunc == ',' && spc > 3) { + trunc++; + break; + } + trunc--; + spc++; + } + + if (spc > 3) { + trunc[0] = '.'; + trunc[1] = '.'; + trunc[2] = '.'; + trunc[3] = '\0'; + } else + trunc[0] = '\0'; + } + return buf; } -- Maurizio Lombardi ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 3/3] lib/vsprintf.c: increase the size of the field_width variable 2015-09-16 9:08 [RFC PATCH 0/3] fix *pbl format support Maurizio Lombardi 2015-09-16 9:08 ` [RFC PATCH 1/3] lib/vsprintf.c: Do not pass printf_spec by value on stack Maurizio Lombardi 2015-09-16 9:08 ` [RFC PATCH 2/3] lib/vsprintf.c: append "..." if the *pb[l] output has been truncated Maurizio Lombardi @ 2015-09-16 9:08 ` Maurizio Lombardi 2015-09-16 12:27 ` [RFC PATCH 0/3] fix *pbl format support Rasmus Villemoes 3 siblings, 0 replies; 10+ messages in thread From: Maurizio Lombardi @ 2015-09-16 9:08 UTC (permalink / raw) To: tj; +Cc: joe, linux, linux-kernel When printing a bitmap using the "%*pb[l]" printk format a 16 bit variable (field_width) is used to store the size of the bitmap. In some cases 16 bits are not sufficient, the variable overflows and printk does not work as expected. This patch fixes the problem by changing the type of field_width to s32. How to reproduce the bug: 1.load scsi_debug # modprobe scsi-debug dev_size_mb=256 lbpu=1 lbpws10=1 2.create VG # vgcreate tsvg /dev/sdb Physical volume "/dev/sdb" successfully created Volume group "tsvg" successfully created 3. Bitmap should be set, but still empty # cat /sys/bus/pseudo/drivers/scsi_debug/map Expected results: # cat /sys/bus/pseudo/drivers/scsi_debug/map 0-15 Signed-off-by: Maurizio Lombardi <mlombard@redhat.com> --- lib/vsprintf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index f49bf54..9712260 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -384,8 +384,8 @@ struct printf_spec { u8 flags; /* flags to number() */ u8 base; /* number base, 8, 10 or 16 only */ u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */ - s16 field_width; /* width of output field */ s16 precision; /* # of digits/chars */ + s32 field_width; /* width of output field */ }; static noinline_for_stack -- Maurizio Lombardi ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/3] fix *pbl format support 2015-09-16 9:08 [RFC PATCH 0/3] fix *pbl format support Maurizio Lombardi ` (2 preceding siblings ...) 2015-09-16 9:08 ` [RFC PATCH 3/3] lib/vsprintf.c: increase the size of the field_width variable Maurizio Lombardi @ 2015-09-16 12:27 ` Rasmus Villemoes 2015-09-16 12:53 ` Maurizio Lombardi 2015-09-16 17:45 ` Tejun Heo 3 siblings, 2 replies; 10+ messages in thread From: Rasmus Villemoes @ 2015-09-16 12:27 UTC (permalink / raw) To: Maurizio Lombardi; +Cc: tj, joe, linux-kernel On Wed, Sep 16 2015, Maurizio Lombardi <mlombard@redhat.com> wrote: > Hi, > > I tried to fix the "*pb[l]" format issue while taking care of the problems > discussed in this thread: > > https://lkml.org/lkml/2015/9/9/153 > > I would like to know whether this approach is more acceptable to you: > > PATCH 1 modifies the code so that the printf_spec struct is not passed by value > anymore, instead a const pointer is used and the structure is copied to > a local variable only when necessary. > If we want to fix the problem with 3/3, then this seems obviously necessary. There may be stuff we want to optimize later (for example, I don't think we should always make a local copy of the entire struct; if we're only modifying one of the fields, it's better to copy that field to a local variable and use that). Nit: Please don't say that the parameter is passed around _on the stack_. Making it fit in 8 bytes is very much so that sane architectures have a chance to pass it in a register, and _how_ parameters are passed around is in any case very arch-dependent. Just say "struct printf_spec is passed by value". > > PATCH 2 modifies the bitmap_*_string() functions so they'll append >"..." to the > output string whenever the buffer is not sufficiently large. > > example of output: > > *pb: cccccccc,... > *pbl: 1-2,5-7,... This part I really don't like. We shouldn't make the output depend on the size of the output buffer (other than truncating it if necessary, of course). I haven't looked carefully at your code, but it does seem that you make sure that at least the return value is as expected, which will make kasprintf work. But it seems there is another kasprintf problem. [reminder: kasprintf works by doing a va_copy, then doing a first call of vsnprintf, passing NULL for the buffer and 0 for the length to determine the size to allocate, and then doing the actual formatting with a second call] + if (buf >= end && buf_start != end) { + int spc = 0; + char *trunc = end - 1; + + while (trunc > buf_start) { + if (*trunc == ',' && spc > 3) { + trunc++; + break; + } + trunc--; + spc++; + } On the first call from kasprintf, we have end == NULL + 0 == NULL. Suppose the format is "hello world %pb". By the time the bitmap helper is called, we have advanced buf away from end, so the stored buf_start is != end, and also of course buf >= end. Then we set trunc = (void*)-1, and trunc will continue to be > buf_start for a very very long time... I may have misread, or it might be fixable, but I really don't like playing these subtle games. snprintf already provides a method to reliably detect truncation; it is up to the user to decide whether and how to deal with that. But yes, this of course requires that snprintf actually attempted to format the entire bitmap, which in turn requires some way to pass the correct size all the way through to the bitmap formatter. > PATCH 3 increases the size of printf_spec.field_width (from s16 to s32). I'm not yet completely convinced this is the right solution. Obviously, if other problems with the small .field_width size show up, this might be necessary, but as long as it's only the %pb formatter (and so far only a single user of that), I think smaller/other hammers should be thought about. So far I think there've been two alternatives: (1) reintroduce the dedicated bitmap pretty printer(s), (2) my half-ugly proposal allowing the user to pass struct printf_bitmap to the %pbh[l] specifier. I'll try to actually code up (2). Rasmus ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/3] fix *pbl format support 2015-09-16 12:27 ` [RFC PATCH 0/3] fix *pbl format support Rasmus Villemoes @ 2015-09-16 12:53 ` Maurizio Lombardi 2015-09-16 17:45 ` Tejun Heo 1 sibling, 0 replies; 10+ messages in thread From: Maurizio Lombardi @ 2015-09-16 12:53 UTC (permalink / raw) To: Rasmus Villemoes; +Cc: tj, joe, linux-kernel Hi, On 09/16/2015 02:27 PM, Rasmus Villemoes wrote: > > If we want to fix the problem with 3/3, then this seems obviously > necessary. There may be stuff we want to optimize later (for example, I > don't think we should always make a local copy of the entire struct; Yes I know, I just tried not to break anything in the process, optimizations can be done later. > I haven't looked carefully at your code, but it does seem that you make > sure that at least the return value is as expected, which will make > kasprintf work. But it seems there is another kasprintf > problem. [reminder: kasprintf works by doing a va_copy, then doing a > first call of vsnprintf, passing NULL for the buffer and 0 for the > length to determine the size to allocate, and then doing the actual > formatting with a second call] Ah, you're right, PATCH 2 is broken because I didn't think to the case you described. Please ignore it, thanks for catching this. > I'm not yet completely convinced this is the right solution. Obviously, > if other problems with the small .field_width size show up, this might > be necessary, but as long as it's only the %pb formatter (and so far > only a single user of that), I think smaller/other hammers should be > thought about. So far I think there've been two alternatives: (1) > reintroduce the dedicated bitmap pretty printer(s) I have no problem with that, at least it will work again. Thanks for the review, Maurizio Lombardi ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/3] fix *pbl format support 2015-09-16 12:27 ` [RFC PATCH 0/3] fix *pbl format support Rasmus Villemoes 2015-09-16 12:53 ` Maurizio Lombardi @ 2015-09-16 17:45 ` Tejun Heo 2015-09-16 20:35 ` Rasmus Villemoes 1 sibling, 1 reply; 10+ messages in thread From: Tejun Heo @ 2015-09-16 17:45 UTC (permalink / raw) To: Rasmus Villemoes; +Cc: Maurizio Lombardi, joe, linux-kernel Hello, On Wed, Sep 16, 2015 at 02:27:23PM +0200, Rasmus Villemoes wrote: > If we want to fix the problem with 3/3, then this seems obviously > necessary. There may be stuff we want to optimize later (for example, I > don't think we should always make a local copy of the entire struct; if > we're only modifying one of the fields, it's better to copy that field > to a local variable and use that). Yeap. ... > I may have misread, or it might be fixable, but I really don't like > playing these subtle games. snprintf already provides a method to > reliably detect truncation; it is up to the user to decide whether and > how to deal with that. But yes, this of course requires that snprintf > actually attempted to format the entire bitmap, which in turn requires > some way to pass the correct size all the way through to the bitmap > formatter. Agreed again. > > PATCH 3 increases the size of printf_spec.field_width (from s16 to s32). > > I'm not yet completely convinced this is the right solution. Obviously, > if other problems with the small .field_width size show up, this might > be necessary, but as long as it's only the %pb formatter (and so far > only a single user of that), I think smaller/other hammers should be > thought about. So far I think there've been two alternatives: (1) > reintroduce the dedicated bitmap pretty printer(s), (2) my half-ugly > proposal allowing the user to pass struct printf_bitmap to the %pbh[l] > specifier. I'll try to actually code up (2). I suppose (2) could work too but we really should strive to provide something convenient to print[fk] users. The balance here is pretty one-sided. Thanks. -- tejun ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/3] fix *pbl format support 2015-09-16 17:45 ` Tejun Heo @ 2015-09-16 20:35 ` Rasmus Villemoes 2015-09-21 14:54 ` Maurizio Lombardi 0 siblings, 1 reply; 10+ messages in thread From: Rasmus Villemoes @ 2015-09-16 20:35 UTC (permalink / raw) To: Tejun Heo; +Cc: Maurizio Lombardi, joe, linux-kernel On Wed, Sep 16 2015, Tejun Heo <tj@kernel.org> wrote: > > I suppose (2) could work too but we really should strive to provide > something convenient to print[fk] users. The balance here is pretty > one-sided. > I just remembered: I noticed a while ago that the qualifier member is only used inside format_decode (in the end, the information is folded into the type member), so one might as well use a local variable for that. This gives option (3): Make field_width a 24 bit bitfield. I think that should be sufficient for any realistic bitmap that one would print. The patch is also rather small. Surprisingly, bloat-o-meter even says that it's also a net win in code size: add/remove: 18/16 grow/shrink: 3/2 up/down: 5551/-5775 (-224) (the huge absolute numbers are due to stuff like pointer - 1148 +1148 pointer.isra 1116 - -1116 so the functions haven't actually changed that much). I'll have to check how this can be (smaller might still be worse), but at least it doesn't seem to be a catastrophe in terms of .text bloat. [Grr, why don't we have a way to do a compile-time assert outside function context?] Only compile-tested. From: Rasmus Villemoes <linux@rasmusvillemoes.dk> Date: Wed, 16 Sep 2015 22:06:14 +0200 Subject: [RFC] lib/vsprintf.c: expand field_width to 24 bits Maurizio Lombardi reported a problem with the %pb extension: It doesn't work for sufficiently large bitmaps, since the size is stashed in the field_width field of the struct printf_spec, which is currently an s16. Concretely, this manifested itself in /sys/bus/pseudo/drivers/scsi_debug/map being empty, since the bitmap printer got a size of 0, which is the 16 bit truncation of the actual bitmap size. We do want to keep struct printf_spec at 8 bytes so that it can cheaply be passed by value. The qualifier field is only used for internal bookkeeping in format_decode, so we might as well use a local variable for that. This gives us an additional 8 bits, which we can then use for the field width. To stay in 8 bytes, we need to do a little rearranging and make the type member a bitfield as well. Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> --- lib/vsprintf.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 95cd63b43b99..cce2a780a82e 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -380,13 +380,13 @@ enum format_type { }; struct printf_spec { - u8 type; /* format_type enum */ + u8 type:8; /* format_type enum */ + s32 field_width:24; /* width of output field */ u8 flags; /* flags to number() */ u8 base; /* number base, 8, 10 or 16 only */ - u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */ - s16 field_width; /* width of output field */ s16 precision; /* # of digits/chars */ }; +extern char __check_printf_spec[1-2*(sizeof(struct printf_spec) != 8)]; static noinline_for_stack char *number(char *buf, char *end, unsigned long long num, @@ -1633,6 +1633,7 @@ static noinline_for_stack int format_decode(const char *fmt, struct printf_spec *spec) { const char *start = fmt; + char qualifier; /* we finished early by reading the field width */ if (spec->type == FORMAT_TYPE_WIDTH) { @@ -1715,16 +1716,16 @@ precision: qualifier: /* get the conversion qualifier */ - spec->qualifier = -1; + qualifier = 0; if (*fmt == 'h' || _tolower(*fmt) == 'l' || _tolower(*fmt) == 'z' || *fmt == 't') { - spec->qualifier = *fmt++; - if (unlikely(spec->qualifier == *fmt)) { - if (spec->qualifier == 'l') { - spec->qualifier = 'L'; + qualifier = *fmt++; + if (unlikely(qualifier == *fmt)) { + if (qualifier == 'l') { + qualifier = 'L'; ++fmt; - } else if (spec->qualifier == 'h') { - spec->qualifier = 'H'; + } else if (qualifier == 'h') { + qualifier = 'H'; ++fmt; } } @@ -1781,19 +1782,19 @@ qualifier: return fmt - start; } - if (spec->qualifier == 'L') + if (qualifier == 'L') spec->type = FORMAT_TYPE_LONG_LONG; - else if (spec->qualifier == 'l') { + else if (qualifier == 'l') { BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG); spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN); - } else if (_tolower(spec->qualifier) == 'z') { + } else if (_tolower(qualifier) == 'z') { spec->type = FORMAT_TYPE_SIZE_T; - } else if (spec->qualifier == 't') { + } else if (qualifier == 't') { spec->type = FORMAT_TYPE_PTRDIFF; - } else if (spec->qualifier == 'H') { + } else if (qualifier == 'H') { BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE); spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN); - } else if (spec->qualifier == 'h') { + } else if (qualifier == 'h') { BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT); spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN); } else { -- 2.1.3 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/3] fix *pbl format support 2015-09-16 20:35 ` Rasmus Villemoes @ 2015-09-21 14:54 ` Maurizio Lombardi 2015-09-21 16:24 ` Rasmus Villemoes 0 siblings, 1 reply; 10+ messages in thread From: Maurizio Lombardi @ 2015-09-21 14:54 UTC (permalink / raw) To: Rasmus Villemoes, Tejun Heo; +Cc: joe, linux-kernel, linux-scsi, dgilbert Hi Rasmus, On 09/16/2015 10:35 PM, Rasmus Villemoes wrote: > > I just remembered: I noticed a while ago that the qualifier member is > only used inside format_decode (in the end, the information is folded > into the type member), so one might as well use a local variable for > that. This gives option (3): Make field_width a 24 bit bitfield. I think > that should be sufficient for any realistic bitmap that one would > print. The patch is also rather small. Surprisingly, bloat-o-meter even > says that it's also a net win in code size: I tested your patch with scsi-debug and it works for me: # modprobe scsi-debug dev_size_mb=256 lbpu=1 lbpws10=1 # cat /sys/bus/pseudo/drivers/scsi_debug/map # vgcreate tsvg /dev/sdb Physical volume "/dev/sdb" successfully created Volume group "tsvg" successfully created # cat /sys/bus/pseudo/drivers/scsi_debug/map 0-15 # lvcreate -V200m -l99%FREE -T tsvg/pool -n lv1 --discards ignore Logical volume "lv1" created. # cat /sys/bus/pseudo/drivers/scsi_debug/map 0-31,2048-2055,501760-501871 Thanks, Maurizio Lombardi > > add/remove: 18/16 grow/shrink: 3/2 up/down: 5551/-5775 (-224) > > (the huge absolute numbers are due to stuff like > > pointer - 1148 +1148 > pointer.isra 1116 - -1116 > > so the functions haven't actually changed that much). I'll have to check > how this can be (smaller might still be worse), but at least it doesn't > seem to be a catastrophe in terms of .text bloat. > > [Grr, why don't we have a way to do a compile-time assert outside > function context?] > > Only compile-tested. > > From: Rasmus Villemoes <linux@rasmusvillemoes.dk> > Date: Wed, 16 Sep 2015 22:06:14 +0200 > Subject: [RFC] lib/vsprintf.c: expand field_width to 24 bits > > Maurizio Lombardi reported a problem with the %pb extension: It > doesn't work for sufficiently large bitmaps, since the size is stashed > in the field_width field of the struct printf_spec, which is currently > an s16. Concretely, this manifested itself in > /sys/bus/pseudo/drivers/scsi_debug/map being empty, since the bitmap > printer got a size of 0, which is the 16 bit truncation of the actual > bitmap size. > > We do want to keep struct printf_spec at 8 bytes so that it can > cheaply be passed by value. The qualifier field is only used for > internal bookkeeping in format_decode, so we might as well use a local > variable for that. This gives us an additional 8 bits, which we can > then use for the field width. To stay in 8 bytes, we need to do a > little rearranging and make the type member a bitfield as well. > > Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> > --- > lib/vsprintf.c | 33 +++++++++++++++++---------------- > 1 file changed, 17 insertions(+), 16 deletions(-) > > diff --git a/lib/vsprintf.c b/lib/vsprintf.c > index 95cd63b43b99..cce2a780a82e 100644 > --- a/lib/vsprintf.c > +++ b/lib/vsprintf.c > @@ -380,13 +380,13 @@ enum format_type { > }; > > struct printf_spec { > - u8 type; /* format_type enum */ > + u8 type:8; /* format_type enum */ > + s32 field_width:24; /* width of output field */ > u8 flags; /* flags to number() */ > u8 base; /* number base, 8, 10 or 16 only */ > - u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */ > - s16 field_width; /* width of output field */ > s16 precision; /* # of digits/chars */ > }; > +extern char __check_printf_spec[1-2*(sizeof(struct printf_spec) != 8)]; > > static noinline_for_stack > char *number(char *buf, char *end, unsigned long long num, > @@ -1633,6 +1633,7 @@ static noinline_for_stack > int format_decode(const char *fmt, struct printf_spec *spec) > { > const char *start = fmt; > + char qualifier; > > /* we finished early by reading the field width */ > if (spec->type == FORMAT_TYPE_WIDTH) { > @@ -1715,16 +1716,16 @@ precision: > > qualifier: > /* get the conversion qualifier */ > - spec->qualifier = -1; > + qualifier = 0; > if (*fmt == 'h' || _tolower(*fmt) == 'l' || > _tolower(*fmt) == 'z' || *fmt == 't') { > - spec->qualifier = *fmt++; > - if (unlikely(spec->qualifier == *fmt)) { > - if (spec->qualifier == 'l') { > - spec->qualifier = 'L'; > + qualifier = *fmt++; > + if (unlikely(qualifier == *fmt)) { > + if (qualifier == 'l') { > + qualifier = 'L'; > ++fmt; > - } else if (spec->qualifier == 'h') { > - spec->qualifier = 'H'; > + } else if (qualifier == 'h') { > + qualifier = 'H'; > ++fmt; > } > } > @@ -1781,19 +1782,19 @@ qualifier: > return fmt - start; > } > > - if (spec->qualifier == 'L') > + if (qualifier == 'L') > spec->type = FORMAT_TYPE_LONG_LONG; > - else if (spec->qualifier == 'l') { > + else if (qualifier == 'l') { > BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG); > spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN); > - } else if (_tolower(spec->qualifier) == 'z') { > + } else if (_tolower(qualifier) == 'z') { > spec->type = FORMAT_TYPE_SIZE_T; > - } else if (spec->qualifier == 't') { > + } else if (qualifier == 't') { > spec->type = FORMAT_TYPE_PTRDIFF; > - } else if (spec->qualifier == 'H') { > + } else if (qualifier == 'H') { > BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE); > spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN); > - } else if (spec->qualifier == 'h') { > + } else if (qualifier == 'h') { > BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT); > spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN); > } else { > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/3] fix *pbl format support 2015-09-21 14:54 ` Maurizio Lombardi @ 2015-09-21 16:24 ` Rasmus Villemoes 0 siblings, 0 replies; 10+ messages in thread From: Rasmus Villemoes @ 2015-09-21 16:24 UTC (permalink / raw) To: Maurizio Lombardi; +Cc: Tejun Heo, joe, linux-kernel, linux-scsi, dgilbert On Mon, Sep 21 2015, Maurizio Lombardi <mlombard@redhat.com> wrote: > Hi Rasmus, > > On 09/16/2015 10:35 PM, Rasmus Villemoes wrote: >> >> I just remembered: I noticed a while ago that the qualifier member is >> only used inside format_decode (in the end, the information is folded >> into the type member), so one might as well use a local variable for >> that. This gives option (3): Make field_width a 24 bit bitfield. I think >> that should be sufficient for any realistic bitmap that one would >> print. The patch is also rather small. Surprisingly, bloat-o-meter even >> says that it's also a net win in code size: > > I tested your patch with scsi-debug and it works for me: Thanks for testing it! What do people think of this option? Rasmus ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-09-21 16:24 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-09-16 9:08 [RFC PATCH 0/3] fix *pbl format support Maurizio Lombardi 2015-09-16 9:08 ` [RFC PATCH 1/3] lib/vsprintf.c: Do not pass printf_spec by value on stack Maurizio Lombardi 2015-09-16 9:08 ` [RFC PATCH 2/3] lib/vsprintf.c: append "..." if the *pb[l] output has been truncated Maurizio Lombardi 2015-09-16 9:08 ` [RFC PATCH 3/3] lib/vsprintf.c: increase the size of the field_width variable Maurizio Lombardi 2015-09-16 12:27 ` [RFC PATCH 0/3] fix *pbl format support Rasmus Villemoes 2015-09-16 12:53 ` Maurizio Lombardi 2015-09-16 17:45 ` Tejun Heo 2015-09-16 20:35 ` Rasmus Villemoes 2015-09-21 14:54 ` Maurizio Lombardi 2015-09-21 16:24 ` Rasmus Villemoes
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).