2012-06-29 15:58:56

by Andy Shevchenko

[permalink] [raw]
Subject: [RFC][PATCH 1/2] lib: printf: append support of '%*p[Mm][FR]'

There are many places in the kernel where the drivers print small buffers as a
hex string. This patch adds a support of the variable width buffer to print it
as a hex string with a delimiter. The idea came from Pavel Roskin here:
http://www.digipedia.pl/usenet/thread/18835/17449/

Sample output of
pr_info("buf[%d:%d] %*pM\n", from, len, len, &buf[from]);
could be like this:
[ 0.726130] buf[51:8] e8:16:b6:ef:e3:74:45:6e
[ 0.750736] buf[59:15] 31:81:b8:3f:35:49:06:ae:df:32:06:05:4a:af:55
[ 0.757602] buf[17:5] ac:16:d5:2c:ef

Signed-off-by: Andy Shevchenko <[email protected]>
---
lib/vsprintf.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index a0b5f15..1645d7e 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -655,11 +655,12 @@ char *resource_string(char *buf, char *end, struct resource *res,
}

static noinline_for_stack
-char *mac_address_string(char *buf, char *end, u8 *addr,
- struct printf_spec spec, const char *fmt)
+char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
+ const char *fmt)
{
- char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
- char *p = mac_addr;
+ char hex_str[64*3]; /* support up to 64 bytes to print */
+ int len = 6; /* default length is 6 bytes */
+ char *p = hex_str;
int i;
char separator;
bool reversed = false;
@@ -678,18 +679,21 @@ char *mac_address_string(char *buf, char *end, u8 *addr,
break;
}

- for (i = 0; i < 6; i++) {
+ if (spec.field_width > 0)
+ len = min_t(int, spec.field_width, 64);
+
+ for (i = 0; i < len; i++) {
if (reversed)
- p = hex_byte_pack(p, addr[5 - i]);
+ p = hex_byte_pack(p, addr[len - 1 - i]);
else
p = hex_byte_pack(p, addr[i]);

- if (fmt[0] == 'M' && i != 5)
+ if (fmt[0] == 'M' && i != len - 1)
*p++ = separator;
}
*p = '\0';

- return string(buf, end, mac_addr, spec);
+ return string(buf, end, hex_str, spec);
}

static noinline_for_stack
@@ -1011,7 +1015,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
case 'm': /* Contiguous: 000102030405 */
/* [mM]F (FDDI) */
/* [mM]R (Reverse order; Bluetooth) */
- return mac_address_string(buf, end, ptr, spec, fmt);
+ return hex_string(buf, end, ptr, spec, fmt);
case 'I': /* Formatted IP supported
* 4: 1.2.3.4
* 6: 0001:0203:...:0708
--
1.7.10


2012-06-29 15:59:14

by Andy Shevchenko

[permalink] [raw]
Subject: [RFC][PATCH 2/2] wireless: at76c50x: eliminate hex2str()

The hex2str() is substituted by '%*pMF' specificator.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/net/wireless/at76c50x-usb.c | 54 ++++++++---------------------------
1 file changed, 12 insertions(+), 42 deletions(-)

diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index efc162e..f82f76b 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -498,36 +498,6 @@ exit:
return ret;
}

-#define HEX2STR_BUFFERS 4
-#define HEX2STR_MAX_LEN 64
-
-/* Convert binary data into hex string */
-static char *hex2str(void *buf, size_t len)
-{
- static atomic_t a = ATOMIC_INIT(0);
- static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1];
- char *ret = bufs[atomic_inc_return(&a) & (HEX2STR_BUFFERS - 1)];
- char *obuf = ret;
- u8 *ibuf = buf;
-
- if (len > HEX2STR_MAX_LEN)
- len = HEX2STR_MAX_LEN;
-
- if (len == 0)
- goto exit;
-
- while (len--) {
- obuf = hex_byte_pack(obuf, *ibuf++);
- *obuf++ = '-';
- }
- obuf--;
-
-exit:
- *obuf = '\0';
-
- return ret;
-}
-
/* LED trigger */
static int tx_activity;
static void at76_ledtrig_tx_timerfunc(unsigned long data);
@@ -1004,9 +974,9 @@ static void at76_dump_mib_mac_wep(struct at76_priv *priv)
WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN;

for (i = 0; i < WEP_KEYS; i++)
- at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %s",
+ at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %*pMF",
wiphy_name(priv->hw->wiphy), i,
- hex2str(m->wep_default_keyvalue[i], key_len));
+ key_len, m->wep_default_keyvalue[i]);
exit:
kfree(m);
}
@@ -1031,7 +1001,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration "
"%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d "
"CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d "
- "current_bssid %pM current_essid %s current_bss_type %d "
+ "current_bssid %pM current_essid %*pMF current_bss_type %d "
"pm_mode %d ibss_change %d res %d "
"multi_domain_capability_implemented %d "
"international_roaming %d country_string %.3s",
@@ -1041,7 +1011,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window),
m->CFP_mode, m->privacy_option_implemented, m->DTIM_period,
m->CFP_period, m->current_bssid,
- hex2str(m->current_essid, IW_ESSID_MAX_SIZE),
+ IW_ESSID_MAX_SIZE, m->current_essid,
m->current_bss_type, m->power_mgmt_mode, m->ibss_change,
m->res, m->multi_domain_capability_implemented,
m->multi_domain_capability_enabled, m->country_string);
@@ -1069,7 +1039,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv)
"cwmin %d cwmax %d short_retry_time %d long_retry_time %d "
"scan_type %d scan_channel %d probe_delay %u "
"min_channel_time %d max_channel_time %d listen_int %d "
- "desired_ssid %s desired_bssid %pM desired_bsstype %d",
+ "desired_ssid %*pMF desired_bssid %pM desired_bsstype %d",
wiphy_name(priv->hw->wiphy),
le32_to_cpu(m->max_tx_msdu_lifetime),
le32_to_cpu(m->max_rx_lifetime),
@@ -1080,7 +1050,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv)
le16_to_cpu(m->min_channel_time),
le16_to_cpu(m->max_channel_time),
le16_to_cpu(m->listen_interval),
- hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE),
+ IW_ESSID_MAX_SIZE, m->desired_ssid,
m->desired_bssid, m->desired_bsstype);
exit:
kfree(m);
@@ -1160,13 +1130,13 @@ static void at76_dump_mib_mdomain(struct at76_priv *priv)
goto exit;
}

- at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s",
+ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %*pMF",
wiphy_name(priv->hw->wiphy),
- hex2str(m->channel_list, sizeof(m->channel_list)));
+ sizeof(m->channel_list), m->channel_list);

- at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %s",
+ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %*pMF",
wiphy_name(priv->hw->wiphy),
- hex2str(m->tx_powerlevel, sizeof(m->tx_powerlevel)));
+ sizeof(m->tx_powerlevel), m->tx_powerlevel);
exit:
kfree(m);
}
@@ -1369,9 +1339,9 @@ static int at76_startup_device(struct at76_priv *priv)
int ret;

at76_dbg(DBG_PARAMS,
- "%s param: ssid %.*s (%s) mode %s ch %d wep %s key %d "
+ "%s param: ssid %.*s (%*pMF) mode %s ch %d wep %s key %d "
"keylen %d", wiphy_name(priv->hw->wiphy), priv->essid_size,
- priv->essid, hex2str(priv->essid, IW_ESSID_MAX_SIZE),
+ priv->essid, IW_ESSID_MAX_SIZE, priv->essid,
priv->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra",
priv->channel, priv->wep_enabled ? "enabled" : "disabled",
priv->wep_key_id, priv->wep_keys_len[priv->wep_key_id]);
--
1.7.10

2012-06-29 16:08:09

by Joe Perches

[permalink] [raw]
Subject: Re: [RFC][PATCH 1/2] lib: printf: append support of '%*p[Mm][FR]'

On Fri, 2012-06-29 at 18:58 +0300, Andy Shevchenko wrote:
> There are many places in the kernel where the drivers print small buffers as a
> hex string. This patch adds a support of the variable width buffer to print it
> as a hex string with a delimiter. The idea came from Pavel Roskin here:
> http://www.digipedia.pl/usenet/thread/18835/17449/

Seems sensible, but one stack caveat below

> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
[]
> @@ -655,11 +655,12 @@ char *resource_string(char *buf, char *end, struct resource *res,
> }
>
> static noinline_for_stack
> -char *mac_address_string(char *buf, char *end, u8 *addr,
> - struct printf_spec spec, const char *fmt)
> +char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
> + const char *fmt)
> {
> - char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
> - char *p = mac_addr;
> + char hex_str[64*3]; /* support up to 64 bytes to print */

Might be too much stack though.

2012-06-29 16:35:09

by Larry Finger

[permalink] [raw]
Subject: Re: [RFC][PATCH 2/2] wireless: at76c50x: eliminate hex2str()

On 06/29/2012 10:58 AM, Andy Shevchenko wrote:
> The hex2str() is substituted by '%*pMF' specificator.
>
> Signed-off-by: Andy Shevchenko <[email protected]>
> ---
> drivers/net/wireless/at76c50x-usb.c | 54 ++++++++---------------------------
> 1 file changed, 12 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
> index efc162e..f82f76b 100644
> --- a/drivers/net/wireless/at76c50x-usb.c
> +++ b/drivers/net/wireless/at76c50x-usb.c
> @@ -498,36 +498,6 @@ exit:
> return ret;
> }
>
> -#define HEX2STR_BUFFERS 4
> -#define HEX2STR_MAX_LEN 64
> -
> -/* Convert binary data into hex string */
> -static char *hex2str(void *buf, size_t len)
> -{
> - static atomic_t a = ATOMIC_INIT(0);
> - static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1];
> - char *ret = bufs[atomic_inc_return(&a) & (HEX2STR_BUFFERS - 1)];
> - char *obuf = ret;
> - u8 *ibuf = buf;
> -
> - if (len > HEX2STR_MAX_LEN)
> - len = HEX2STR_MAX_LEN;
> -
> - if (len == 0)
> - goto exit;
> -
> - while (len--) {
> - obuf = hex_byte_pack(obuf, *ibuf++);
> - *obuf++ = '-';
> - }
> - obuf--;
> -
> -exit:
> - *obuf = '\0';
> -
> - return ret;
> -}
> -
> /* LED trigger */
> static int tx_activity;
> static void at76_ledtrig_tx_timerfunc(unsigned long data);
> @@ -1004,9 +974,9 @@ static void at76_dump_mib_mac_wep(struct at76_priv *priv)
> WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN;
>
> for (i = 0; i < WEP_KEYS; i++)
> - at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %s",
> + at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %*pMF",
> wiphy_name(priv->hw->wiphy), i,
> - hex2str(m->wep_default_keyvalue[i], key_len));
> + key_len, m->wep_default_keyvalue[i]);
> exit:
> kfree(m);
> }
> @@ -1031,7 +1001,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
> at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration "
> "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d "
> "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d "
> - "current_bssid %pM current_essid %s current_bss_type %d "
> + "current_bssid %pM current_essid %*pMF current_bss_type %d "
> "pm_mode %d ibss_change %d res %d "
> "multi_domain_capability_implemented %d "
> "international_roaming %d country_string %.3s",
> @@ -1041,7 +1011,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
> le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window),
> m->CFP_mode, m->privacy_option_implemented, m->DTIM_period,
> m->CFP_period, m->current_bssid,
> - hex2str(m->current_essid, IW_ESSID_MAX_SIZE),
> + IW_ESSID_MAX_SIZE, m->current_essid,
> m->current_bss_type, m->power_mgmt_mode, m->ibss_change,
> m->res, m->multi_domain_capability_implemented,
> m->multi_domain_capability_enabled, m->country_string);
> @@ -1069,7 +1039,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv)
> "cwmin %d cwmax %d short_retry_time %d long_retry_time %d "
> "scan_type %d scan_channel %d probe_delay %u "
> "min_channel_time %d max_channel_time %d listen_int %d "
> - "desired_ssid %s desired_bssid %pM desired_bsstype %d",
> + "desired_ssid %*pMF desired_bssid %pM desired_bsstype %d",
> wiphy_name(priv->hw->wiphy),
> le32_to_cpu(m->max_tx_msdu_lifetime),
> le32_to_cpu(m->max_rx_lifetime),
> @@ -1080,7 +1050,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv)
> le16_to_cpu(m->min_channel_time),
> le16_to_cpu(m->max_channel_time),
> le16_to_cpu(m->listen_interval),
> - hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE),
> + IW_ESSID_MAX_SIZE, m->desired_ssid,
> m->desired_bssid, m->desired_bsstype);
> exit:
> kfree(m);
> @@ -1160,13 +1130,13 @@ static void at76_dump_mib_mdomain(struct at76_priv *priv)
> goto exit;
> }
>
> - at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s",
> + at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %*pMF",
> wiphy_name(priv->hw->wiphy),
> - hex2str(m->channel_list, sizeof(m->channel_list)));
> + sizeof(m->channel_list), m->channel_list);
>
> - at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %s",
> + at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %*pMF",
> wiphy_name(priv->hw->wiphy),
> - hex2str(m->tx_powerlevel, sizeof(m->tx_powerlevel)));
> + sizeof(m->tx_powerlevel), m->tx_powerlevel);
> exit:
> kfree(m);
> }
> @@ -1369,9 +1339,9 @@ static int at76_startup_device(struct at76_priv *priv)
> int ret;
>
> at76_dbg(DBG_PARAMS,
> - "%s param: ssid %.*s (%s) mode %s ch %d wep %s key %d "
> + "%s param: ssid %.*s (%*pMF) mode %s ch %d wep %s key %d "
> "keylen %d", wiphy_name(priv->hw->wiphy), priv->essid_size,
> - priv->essid, hex2str(priv->essid, IW_ESSID_MAX_SIZE),
> + priv->essid, IW_ESSID_MAX_SIZE, priv->essid,
> priv->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra",
> priv->channel, priv->wep_enabled ? "enabled" : "disabled",
> priv->wep_key_id, priv->wep_keys_len[priv->wep_key_id]);
>

I have not yet tested this patch, but it generates warnings on a 64-bit system
as follows:

CC [M] drivers/net/wireless/at76c50x-usb.o
drivers/net/wireless/at76c50x-usb.c: In function ‘at76_dump_mib_mdomain’:
drivers/net/wireless/at76c50x-usb.c:1133:2: warning: field width specifier ‘*’
expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’
[-Wformat]
drivers/net/wireless/at76c50x-usb.c:1137:2: warning: field width specifier ‘*’
expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’
[-Wformat]

Replacing "sizeof" by "(int)sizeof" removes the warning.

Larry

2012-06-29 23:26:52

by Andrew Morton

[permalink] [raw]
Subject: Re: [RFC][PATCH 1/2] lib: printf: append support of '%*p[Mm][FR]'

On Fri, 29 Jun 2012 09:08:06 -0700
Joe Perches <[email protected]> wrote:

> > diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> []
> > @@ -655,11 +655,12 @@ char *resource_string(char *buf, char *end, struct resource *res,
> > }
> >
> > static noinline_for_stack
> > -char *mac_address_string(char *buf, char *end, u8 *addr,
> > - struct printf_spec spec, const char *fmt)
> > +char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
> > + const char *fmt)
> > {
> > - char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
> > - char *p = mac_addr;
> > + char hex_str[64*3]; /* support up to 64 bytes to print */
>
> Might be too much stack though.

Yes, it's a bit marginal, as this new capability might be used in debug
or crash situations where we're deep into the stack. The average case
could be improved by using alloca()-style allocation.

Documentation/printk-formats.txt would need to be updated please. Also
the big comment over vsnprintf().

2012-06-30 14:48:56

by Joe Perches

[permalink] [raw]
Subject: Re: [RFC][PATCH 1/2] lib: printf: append support of '%*p[Mm][FR]'

On Fri, 2012-06-29 at 16:26 -0700, Andrew Morton wrote:
> On Fri, 29 Jun 2012 09:08:06 -0700
> Joe Perches <[email protected]> wrote:
>
> > > diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> > []
> > > @@ -655,11 +655,12 @@ char *resource_string(char *buf, char *end, struct resource *res,
> > > }
> > >
> > > static noinline_for_stack
> > > -char *mac_address_string(char *buf, char *end, u8 *addr,
> > > - struct printf_spec spec, const char *fmt)
> > > +char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
> > > + const char *fmt)
> > > {
> > > - char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
> > > - char *p = mac_addr;
> > > + char hex_str[64*3]; /* support up to 64 bytes to print */
> >
> > Might be too much stack though.
>
> Yes, it's a bit marginal, as this new capability might be used in debug
> or crash situations where we're deep into the stack. The average case
> could be improved by using alloca()-style allocation.

Or maybe support larger sizes with a smaller
stack buffer and a while loop.