Some code, most notably the Bluetooth drivers, uses something like the following: char buf[80]; snprintf(buf, sizeof(buf), "Driver: %s\n", driver_name); skb_put_data(skb, buf, strlen(buf)); This looks suboptimal at least because: 1) It yields in BUG() just in case the developer underestimates the size of an skb being used; 2) It requires extra data copy from an external buffer; 3) It uses 'strlen()' redundantly because actual data length is calculated by 'snprintf()' itself. So introduce 'skb_printf()' which aims to address all of these issues. As usual, thoughts and comments are highly appreciated. Signed-off-by: Dmitry Antipov --- include/linux/skbuff.h | 1 + net/core/skbuff.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2bcf78a4de7b..fb4ef55a8f86 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -4292,6 +4292,7 @@ int skb_mpls_update_lse(struct sk_buff *skb, __be32 mpls_lse); int skb_mpls_dec_ttl(struct sk_buff *skb); struct sk_buff *pskb_extract(struct sk_buff *skb, int off, int to_copy, gfp_t gfp); +int skb_printf(struct sk_buff *skb, const char *fmt, ...); static inline int memcpy_from_msg(void *data, struct msghdr *msg, int len) { diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7dad68e3b518..051ab4f28c75 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -6992,6 +6992,24 @@ struct sk_buff *pskb_extract(struct sk_buff *skb, int off, } EXPORT_SYMBOL(pskb_extract); +int skb_printf(struct sk_buff *skb, const char *fmt, ...) +{ + int len, size = skb_availroom(skb); + va_list args; + + va_start(args, fmt); + len = vsnprintf(skb_tail_pointer(skb), size, fmt, args); + va_end(args); + + if (unlikely(len >= size)) + return -ENOSPC; + + skb->tail += len; + skb->len += len; + return len; +} +EXPORT_SYMBOL(skb_printf); + /** * skb_condense - try to get rid of fragments/frag_list if possible * @skb: buffer -- 2.53.0