mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] Use new for_each macro to create hexdumps
@ 2025-01-13 22:17 Nick Child
  2025-01-13 22:17 ` [PATCH 1/3] hexdump: Implement macro for converting large buffers Nick Child
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Nick Child @ 2025-01-13 22:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: nick.child, netdev, Nick Child

Apologies, not sure what mailing list/tree to target. First 2 patches look
like *-next and last patch should go to net-next.

Currently, obtaining a hexdump can be done through one of the following:
 1. hex_dump_to_buffer - takes at most 32 bytes of a buffer and returns a 
     hexdump string representation
 2. print_hex_dump - prints output of hex_dump_to_buffer iteratively over
    a large buffer

There is no functionality for iterating over a large buffer and receiving
the string representation. It seems most users of hex_dump_to_buffer are
calling hex_dump_to_buffer within the body of a loop which iterates
through a buffer.

This patchset creates a for_each macro that accepts a buffer and fills
out an output string with the converted hexdump. This loops over the
buffer and takes care of incrementing pointers. Hopefully this makes
writing sequential calls to hex_dump_to_buffer more straightforward.

From a users perspective there should be no difference in output.

The inspiration here was I wanted to use print_hex_dump in ibmvnic code
but I wanted to print through netdevice printing functions to maintain
formatting. Looking at other users of hex_dump_to_buffer it seems they had
similar intentions.

Side question:
  hex_dump_to_buffer automatically sets groupsize to 1 if user given
  groupsize is not a multiple of len. When printing large buffers this
  makes non-uniform output. For example, this is a 31 byte 8 groupsize
  buffer:
   ibmvnic 30000003 env3: 6c6774732e737561 2e6d62692e736261
   ibmvnic 30000003 env3: 63 6f 6d 00 03 00 05 65 6e 76 33 00 00 00 00
  Since the second line is only 15 bytes, the group size is set to 1. I
  have written a patch which keeps groupsize so output would be:
   ibmvnic 30000003 env3: 6c6774732e737561 2e6d62692e736261
   ibmvnic 30000003 env3: 636f6d0003000565 6e763300000000
  But since I am not sure if this would break some dependency for someone,
  and my justification for change is purely pedantic, I chose to omit
  that patch in this patchset. Let me know if there is any interest and
  I will send a different patchset for that. 

Thanks for your consideration/review.

Nick Child (3):
  hexdump: Implement macro for converting large buffers
  hexdump: Use for_each macro in print_hex_dump
  ibmvnic: Print data buffers with kernel API's

 drivers/net/ethernet/ibm/ibmvnic.c | 23 ++++++++++++++---------
 include/linux/printk.h             | 21 +++++++++++++++++++++
 lib/hexdump.c                      | 11 +++--------
 3 files changed, 38 insertions(+), 17 deletions(-)

-- 
2.47.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] hexdump: Implement macro for converting large buffers
  2025-01-13 22:17 [PATCH 0/3] Use new for_each macro to create hexdumps Nick Child
@ 2025-01-13 22:17 ` Nick Child
  2025-01-14 14:48   ` Simon Horman
  2025-01-13 22:17 ` [PATCH 2/3] hexdump: Use for_each macro in print_hex_dump Nick Child
  2025-01-13 22:17 ` [PATCH 3/3] ibmvnic: Print data buffers with kernel API's Nick Child
  2 siblings, 1 reply; 6+ messages in thread
From: Nick Child @ 2025-01-13 22:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: nick.child, netdev, Nick Child

Define for_each_line_in_hex_dump which loops over a buffer and calls
hex_dump_to_buffer for each segment in the buffer. This allows the
caller to decide what to do with the resulting string and is not
limited by a specific printing format like print_hex_dump.

Signed-off-by: Nick Child <nnac123@linux.ibm.com>
---
 include/linux/printk.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/include/linux/printk.h b/include/linux/printk.h
index 4217a9f412b2..d55968f7ac10 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -755,6 +755,27 @@ enum {
 extern int hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
 			      int groupsize, char *linebuf, size_t linebuflen,
 			      bool ascii);
+/**
+ * for_each_line_in_hex_dump - iterate over buffer, converting into hex ASCII
+ * @i - offset in @buff
+ * @rowsize: number of bytes to print per line; must be 16 or 32
+ * @linebuf: where to put the converted data
+ * @linebuflen: total size of @linebuf, including space for terminating NUL
+ *		IOW >= (@rowsize * 2) + ((@rowsize - 1 / @groupsize)) + 1
+ * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ */
+ #define for_each_line_in_hex_dump(i, rowsize, linebuf, linebuflen, groupsize, \
+				   buf, len) \
+	for ((i) = 0;							\
+	     (i) < (len) &&						\
+	     hex_dump_to_buffer((unsigned char *)(buf) + (i),		\
+				min((len) - (i), rowsize),		\
+				(rowsize), (groupsize), (linebuf),	\
+				(linebuflen), false);			\
+	     (i) += (rowsize) == 16 || (rowsize) == 32 ? (rowsize) : 16	\
+	    )
 #ifdef CONFIG_PRINTK
 extern void print_hex_dump(const char *level, const char *prefix_str,
 			   int prefix_type, int rowsize, int groupsize,
-- 
2.47.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/3] hexdump: Use for_each macro in print_hex_dump
  2025-01-13 22:17 [PATCH 0/3] Use new for_each macro to create hexdumps Nick Child
  2025-01-13 22:17 ` [PATCH 1/3] hexdump: Implement macro for converting large buffers Nick Child
@ 2025-01-13 22:17 ` Nick Child
  2025-01-13 22:17 ` [PATCH 3/3] ibmvnic: Print data buffers with kernel API's Nick Child
  2 siblings, 0 replies; 6+ messages in thread
From: Nick Child @ 2025-01-13 22:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: nick.child, netdev, Nick Child

The looping logic in print_hex_dump can be handled by the macro
for_each_line_in_hex_dump.

Signed-off-by: Nick Child <nnac123@linux.ibm.com>
---
 lib/hexdump.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/lib/hexdump.c b/lib/hexdump.c
index c3db7c3a7643..181b82dfe40d 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -263,19 +263,14 @@ void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
 		    const void *buf, size_t len, bool ascii)
 {
 	const u8 *ptr = buf;
-	int i, linelen, remaining = len;
+	int i;
 	unsigned char linebuf[32 * 3 + 2 + 32 + 1];
 
 	if (rowsize != 16 && rowsize != 32)
 		rowsize = 16;
 
-	for (i = 0; i < len; i += rowsize) {
-		linelen = min(remaining, rowsize);
-		remaining -= rowsize;
-
-		hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
-				   linebuf, sizeof(linebuf), ascii);
-
+	for_each_line_in_hex_dump(i, rowsize, linebuf, sizeof(linebuf),
+				  groupsize, buf, len) {
 		switch (prefix_type) {
 		case DUMP_PREFIX_ADDRESS:
 			printk("%s%s%p: %s\n",
-- 
2.47.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/3] ibmvnic: Print data buffers with kernel API's
  2025-01-13 22:17 [PATCH 0/3] Use new for_each macro to create hexdumps Nick Child
  2025-01-13 22:17 ` [PATCH 1/3] hexdump: Implement macro for converting large buffers Nick Child
  2025-01-13 22:17 ` [PATCH 2/3] hexdump: Use for_each macro in print_hex_dump Nick Child
@ 2025-01-13 22:17 ` Nick Child
  2025-01-14  0:04   ` Jacob Keller
  2 siblings, 1 reply; 6+ messages in thread
From: Nick Child @ 2025-01-13 22:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: nick.child, netdev, Nick Child

Previously, data buffers that were to be printed were cast to 8 byte
integers and printed. This can lead to buffer overflow if the length
of the buffer is not a multiple of 8.

Simplify and safeguard printing by using kernel provided functions
to print these data blobs.

Signed-off-by: Nick Child <nnac123@linux.ibm.com>
---
 drivers/net/ethernet/ibm/ibmvnic.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index e95ae0d39948..a8f1feb9a2e7 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -4834,6 +4834,7 @@ static int send_login(struct ibmvnic_adapter *adapter)
 	struct device *dev = &adapter->vdev->dev;
 	struct vnic_login_client_data *vlcd;
 	dma_addr_t rsp_buffer_token;
+	unsigned char hex_str[16 * 3];
 	dma_addr_t buffer_token;
 	size_t rsp_buffer_size;
 	union ibmvnic_crq crq;
@@ -4937,9 +4938,9 @@ static int send_login(struct ibmvnic_adapter *adapter)
 	vnic_add_client_data(adapter, vlcd);
 
 	netdev_dbg(adapter->netdev, "Login Buffer:\n");
-	for (i = 0; i < (adapter->login_buf_sz - 1) / 8 + 1; i++) {
-		netdev_dbg(adapter->netdev, "%016lx\n",
-			   ((unsigned long *)(adapter->login_buf))[i]);
+	for_each_line_in_hex_dump(i, 16, hex_str, sizeof(hex_str), 8,
+				  adapter->login_buf, adapter->login_buf_sz) {
+		netdev_dbg(adapter->netdev, "%s\n", hex_str);
 	}
 
 	memset(&crq, 0, sizeof(crq));
@@ -5317,15 +5318,17 @@ static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
 {
 	struct device *dev = &adapter->vdev->dev;
 	struct ibmvnic_query_ip_offload_buffer *buf = &adapter->ip_offload_buf;
+	unsigned char hex_str[16 * 3];
 	int i;
 
 	dma_unmap_single(dev, adapter->ip_offload_tok,
 			 sizeof(adapter->ip_offload_buf), DMA_FROM_DEVICE);
 
 	netdev_dbg(adapter->netdev, "Query IP Offload Buffer:\n");
-	for (i = 0; i < (sizeof(adapter->ip_offload_buf) - 1) / 8 + 1; i++)
-		netdev_dbg(adapter->netdev, "%016lx\n",
-			   ((unsigned long *)(buf))[i]);
+	for_each_line_in_hex_dump(i, 16, hex_str, sizeof(hex_str), 8, buf,
+				  sizeof(adapter->ip_offload_buf)) {
+		netdev_dbg(adapter->netdev, "%s\n", hex_str);
+	}
 
 	netdev_dbg(adapter->netdev, "ipv4_chksum = %d\n", buf->ipv4_chksum);
 	netdev_dbg(adapter->netdev, "ipv6_chksum = %d\n", buf->ipv6_chksum);
@@ -5518,6 +5521,7 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
 	struct net_device *netdev = adapter->netdev;
 	struct ibmvnic_login_rsp_buffer *login_rsp = adapter->login_rsp_buf;
 	struct ibmvnic_login_buffer *login = adapter->login_buf;
+	unsigned char hex_str[16 * 3];
 	u64 *tx_handle_array;
 	u64 *rx_handle_array;
 	int num_tx_pools;
@@ -5556,9 +5560,10 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
 	netdev->mtu = adapter->req_mtu - ETH_HLEN;
 
 	netdev_dbg(adapter->netdev, "Login Response Buffer:\n");
-	for (i = 0; i < (adapter->login_rsp_buf_sz - 1) / 8 + 1; i++) {
-		netdev_dbg(adapter->netdev, "%016lx\n",
-			   ((unsigned long *)(adapter->login_rsp_buf))[i]);
+	for_each_line_in_hex_dump(i, 16, hex_str, sizeof(hex_str), 8,
+				  adapter->login_rsp_buf,
+				  adapter->login_rsp_buf_sz) {
+		netdev_dbg(adapter->netdev, "%s\n", hex_str);
 	}
 
 	/* Sanity checks */
-- 
2.47.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] ibmvnic: Print data buffers with kernel API's
  2025-01-13 22:17 ` [PATCH 3/3] ibmvnic: Print data buffers with kernel API's Nick Child
@ 2025-01-14  0:04   ` Jacob Keller
  0 siblings, 0 replies; 6+ messages in thread
From: Jacob Keller @ 2025-01-14  0:04 UTC (permalink / raw)
  To: Nick Child, linux-kernel; +Cc: nick.child, netdev



On 1/13/2025 2:17 PM, Nick Child wrote:
> Previously, data buffers that were to be printed were cast to 8 byte
> integers and printed. This can lead to buffer overflow if the length
> of the buffer is not a multiple of 8.
> 
> Simplify and safeguard printing by using kernel provided functions
> to print these data blobs.
> 
> Signed-off-by: Nick Child <nnac123@linux.ibm.com>
> ---
>  drivers/net/ethernet/ibm/ibmvnic.c | 23 ++++++++++++++---------
>  1 file changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
> index e95ae0d39948..a8f1feb9a2e7 100644
> --- a/drivers/net/ethernet/ibm/ibmvnic.c
> +++ b/drivers/net/ethernet/ibm/ibmvnic.c
> @@ -5556,9 +5560,10 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
>  	netdev->mtu = adapter->req_mtu - ETH_HLEN;
>  
>  	netdev_dbg(adapter->netdev, "Login Response Buffer:\n");
> -	for (i = 0; i < (adapter->login_rsp_buf_sz - 1) / 8 + 1; i++) {
> -		netdev_dbg(adapter->netdev, "%016lx\n",
> -			   ((unsigned long *)(adapter->login_rsp_buf))[i]);
> +	for_each_line_in_hex_dump(i, 16, hex_str, sizeof(hex_str), 8,
> +				  adapter->login_rsp_buf,
> +				  adapter->login_rsp_buf_sz) {
> +		netdev_dbg(adapter->netdev, "%s\n", hex_str);
>  	}

This is nicer to read and a bit more flexible than print_hex_dump. Neat.
Strictly you don't need the {} here, but i think its more readable given
all the arguments you have to pass to the for_each_macro over multiple
lines.

Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>

>  
>  	/* Sanity checks */


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/3] hexdump: Implement macro for converting large buffers
  2025-01-13 22:17 ` [PATCH 1/3] hexdump: Implement macro for converting large buffers Nick Child
@ 2025-01-14 14:48   ` Simon Horman
  0 siblings, 0 replies; 6+ messages in thread
From: Simon Horman @ 2025-01-14 14:48 UTC (permalink / raw)
  To: Nick Child; +Cc: linux-kernel, nick.child, netdev

On Mon, Jan 13, 2025 at 04:17:19PM -0600, Nick Child wrote:
> Define for_each_line_in_hex_dump which loops over a buffer and calls
> hex_dump_to_buffer for each segment in the buffer. This allows the
> caller to decide what to do with the resulting string and is not
> limited by a specific printing format like print_hex_dump.
> 
> Signed-off-by: Nick Child <nnac123@linux.ibm.com>
> ---
>  include/linux/printk.h | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/include/linux/printk.h b/include/linux/printk.h
> index 4217a9f412b2..d55968f7ac10 100644
> --- a/include/linux/printk.h
> +++ b/include/linux/printk.h
> @@ -755,6 +755,27 @@ enum {
>  extern int hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
>  			      int groupsize, char *linebuf, size_t linebuflen,
>  			      bool ascii);
> +/**
> + * for_each_line_in_hex_dump - iterate over buffer, converting into hex ASCII
> + * @i - offset in @buff

nit: scripts/kernel-doc would like this to be "@i: ..." 

> + * @rowsize: number of bytes to print per line; must be 16 or 32
> + * @linebuf: where to put the converted data
> + * @linebuflen: total size of @linebuf, including space for terminating NUL
> + *		IOW >= (@rowsize * 2) + ((@rowsize - 1 / @groupsize)) + 1
> + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
> + * @buf: data blob to dump
> + * @len: number of bytes in the @buf
> + */
> + #define for_each_line_in_hex_dump(i, rowsize, linebuf, linebuflen, groupsize, \
> +				   buf, len) \
> +	for ((i) = 0;							\
> +	     (i) < (len) &&						\
> +	     hex_dump_to_buffer((unsigned char *)(buf) + (i),		\
> +				min((len) - (i), rowsize),		\
> +				(rowsize), (groupsize), (linebuf),	\
> +				(linebuflen), false);			\
> +	     (i) += (rowsize) == 16 || (rowsize) == 32 ? (rowsize) : 16	\
> +	    )
>  #ifdef CONFIG_PRINTK
>  extern void print_hex_dump(const char *level, const char *prefix_str,
>  			   int prefix_type, int rowsize, int groupsize,
> -- 
> 2.47.1
> 
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-01-14 14:48 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-13 22:17 [PATCH 0/3] Use new for_each macro to create hexdumps Nick Child
2025-01-13 22:17 ` [PATCH 1/3] hexdump: Implement macro for converting large buffers Nick Child
2025-01-14 14:48   ` Simon Horman
2025-01-13 22:17 ` [PATCH 2/3] hexdump: Use for_each macro in print_hex_dump Nick Child
2025-01-13 22:17 ` [PATCH 3/3] ibmvnic: Print data buffers with kernel API's Nick Child
2025-01-14  0:04   ` Jacob Keller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®