From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.5 required=3.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED,USER_AGENT_MUTT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 591A5C282C0 for ; Wed, 23 Jan 2019 14:40:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F31E9217D4 for ; Wed, 23 Jan 2019 14:40:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=resnulli-us.20150623.gappssmtp.com header.i=@resnulli-us.20150623.gappssmtp.com header.b="C/EcNuJ8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726887AbfAWOkN (ORCPT ); Wed, 23 Jan 2019 09:40:13 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:44881 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726337AbfAWOkM (ORCPT ); Wed, 23 Jan 2019 09:40:12 -0500 Received: by mail-wr1-f67.google.com with SMTP id z5so2719866wrt.11 for ; Wed, 23 Jan 2019 06:40:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=resnulli-us.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=HiC3ohaRrM/8t6QCW3c7Owk+X8wGS+OZ9cIawlcU/+w=; b=C/EcNuJ8G/gdN89br1E1ExVH1M5WRzGltkjT/lOGxyW/GLdX5Sv4CMC2nB1MxVpiQ0 bvc0vH6E5usLTqrsaVJlmYaYaKxU3VRPCdoxOYsqUZuCfM8ATWwn3u7pQrEnJ1iThJrH d8m0sjRZOcARB+EaweAZG5foWsV+r0OapA0Vqw3gOzDOL1gD0qtnc0wwYoDxWnHU8oCH AKrnn1JtYmRp0Jfp+2D2HJvLeS4HaAgRXAPXIcj+3LOInyPC8PgQKlXfy3vnqnWYWRMp 438y5vTxaZTRWum/mNcr47oHxHUlwFY/Mj8VqTFkx5+h1xeEbUNPUbOA1EW2O6QjqoMn nhSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=HiC3ohaRrM/8t6QCW3c7Owk+X8wGS+OZ9cIawlcU/+w=; b=MRc59oRapXeq1eGLfye/d6vrtNLPnovk32sqckIgeUOnnETK5FBQ/Jv3XsqTBUjJrN ss89iW3YM34uj5CVOm7WXB0bsgtKC9kwOVFKyLvNXnyQEiQagiPy/5/8LTzzAYNBG8nQ YvSlE/nCQRdKy6JrsFliWzNPeYBxt8tR9ZCODJJBEU0WOCYuy1UUYJJ50n1Rex6aChG3 pNotcC0jR+GSfpSho+wMDwU6hLFlKV6Q06aIsT2gFE8hZlX+DArtCjnOCcTTYtB701qR Sm+ATjL7uefK7poI8KtqgcfHwuxNYfgscFm8furw6kFbHOC6zKx4tizw5J36i/LANfFX Ca4w== X-Gm-Message-State: AJcUukfatFSUlznQ5S3THEjSxrTgnw39VcxQN7sR5CVkvvLGDdlYrrn5 QEG8weuxIryre0uW4rYiIqs9MQ== X-Google-Smtp-Source: ALg8bN5i3DZN4hRvbvGtb41U2FFAi03DnJ4PFMWd9xH3DXPXs7wA3hp1bixeZrAh5Y8VDLxKprUATw== X-Received: by 2002:a5d:4a0c:: with SMTP id m12mr3063302wrq.38.1548254409276; Wed, 23 Jan 2019 06:40:09 -0800 (PST) Received: from localhost ([193.47.165.251]) by smtp.gmail.com with ESMTPSA id h62sm44205332wmf.11.2019.01.23.06.40.08 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 23 Jan 2019 06:40:08 -0800 (PST) Date: Wed, 23 Jan 2019 15:31:20 +0100 From: Jiri Pirko To: Eran Ben Elisha Cc: netdev@vger.kernel.org, Jiri Pirko , "David S. Miller" , Saeed Mahameed , Moshe Shemesh , Wei Yongjun Subject: Re: [PATCH net-next 1/7] devlink: Add devlink msg API Message-ID: <20190123143120.GF2191@nanopsycho> References: <1548172644-30862-1-git-send-email-eranbe@mellanox.com> <1548172644-30862-2-git-send-email-eranbe@mellanox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1548172644-30862-2-git-send-email-eranbe@mellanox.com> User-Agent: Mutt/1.9.5 (2018-04-13) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Tue, Jan 22, 2019 at 04:57:18PM CET, eranbe@mellanox.com wrote: >Devlink msg is a mechanism to pass descriptors between drivers and >devlink, in json-like format. The API allows the driver to add objects, >object pair, value array (nested attributes), value and name. > >Driver can use this API to fill the msg context in a format which can be >translated by the devlink to the netlink message later. > >With this API, driver does not need to declare the total size per message >context, and it dynamically add more messages to the context (bounded by >the system memory limitation only). >There is an implicit request to have the preliminary main objects size >created via this API to be upper bounded by netlink SKB size, as those >objects do not get fragmented between different SKBs when passed to the >netlink layer. > >Devlink msg will replace devlink buffers for health reporters. Devlink >buffers which will be deprecated and removed in the downstream patch. > >Signed-off-by: Eran Ben Elisha >CC: Wei Yongjun >Reviewed-by: Moshe Shemesh >--- > include/net/devlink.h | 70 ++++++ > include/uapi/linux/devlink.h | 8 + > net/core/devlink.c | 455 +++++++++++++++++++++++++++++++++++ > 3 files changed, 533 insertions(+) > >diff --git a/include/net/devlink.h b/include/net/devlink.h >index a81a1b7a67d7..fe323e9b14e1 100644 >--- a/include/net/devlink.h >+++ b/include/net/devlink.h >@@ -424,6 +424,7 @@ struct devlink_region; > > typedef void devlink_snapshot_data_dest_t(const void *data); > >+struct devlink_msg_ctx; > struct devlink_health_buffer; > struct devlink_health_reporter; > >@@ -615,6 +616,21 @@ int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len, > u8 *data, u32 snapshot_id, > devlink_snapshot_data_dest_t *data_destructor); > >+int devlink_msg_nest_start(struct devlink_msg_ctx *msg_ctx, int attrtype); devlink_msg_*() functions should work with struct devlink_msg. devlink_msg_ctx*() functions should work with struct devlink_msg_ctx. Please be consistent with the naming. I think you can call this just "struct devlink_msg" of maybe "fmsg" as for "formatted message" - so it is not confused with any other devlink netlink message. >+int devlink_msg_nest_end(struct devlink_msg_ctx *msg_ctx); >+int devlink_msg_put_value(struct devlink_msg_ctx *msg_ctx, >+ void *value, u16 value_len, u8 value_nla_type); >+int devlink_msg_put_name(struct devlink_msg_ctx *msg_ctx, >+ char *name); >+int devlink_msg_put_name_value_pair(struct devlink_msg_ctx *msg_ctx, >+ char *name, void *value, u16 value_len, >+ u8 value_nla_type); >+int devlink_msg_put_name_value_array(struct devlink_msg_ctx *msg_ctx, >+ char *name, void **value, u16 *value_len, >+ u8 *value_nla_type, int array_size); >+int devlink_msg_object_start(struct devlink_msg_ctx *msg_ctx, char *name); >+int devlink_msg_object_end(struct devlink_msg_ctx *msg_ctx, char *name); >+ > int devlink_health_buffer_nest_start(struct devlink_health_buffer *buffer, > int attrtype); > void devlink_health_buffer_nest_end(struct devlink_health_buffer *buffer); >@@ -903,6 +919,60 @@ devlink_region_snapshot_create(struct devlink_region *region, u64 data_len, > return 0; > } > >+static inline int >+devlink_msg_nest_start(struct devlink_msg_ctx *msg_ctx, int attrtype) >+{ >+ return 0; >+} >+ >+static inline int >+devlink_msg_nest_end(struct devlink_msg_ctx *msg_ctx) >+{ >+ return 0; >+} >+ >+static inline int >+devlink_msg_put_value(struct devlink_msg_ctx *msg_ctx, >+ void *value, u16 value_len, u8 value_nla_type) >+{ >+ return 0; >+} >+ >+static inline int >+devlink_msg_put_name(struct devlink_msg_ctx *msg_ctx, >+ char *name) >+{ >+ return 0; >+} >+ >+static inline int >+devlink_msg_put_name_value_pair(struct devlink_msg_ctx *msg_ctx, >+ char *name, void *value, u16 value_len, >+ u8 value_nla_type) >+{ >+ return 0; >+} >+ >+static inline int >+devlink_msg_put_name_value_array(struct devlink_msg_ctx *msg_ctx, >+ char *name, void **value, u16 *value_len, >+ u8 *value_nla_type, int array_size) >+{ >+ return 0; >+} >+ >+static inline int >+devlink_msg_object_start(struct devlink_msg_ctx *msg_ctx, char *name) >+{ >+ return 0; >+} >+ >+static inline int >+devlink_msg_object_end(struct devlink_msg_ctx *msg_ctx, char *name) >+{ >+ return 0; >+} >+ > static inline int > devlink_health_buffer_nest_start(struct devlink_health_buffer *buffer, > int attrtype) >diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h >index 6b26bb2ce4dc..68eeda1d0455 100644 >--- a/include/uapi/linux/devlink.h >+++ b/include/uapi/linux/devlink.h >@@ -300,6 +300,14 @@ enum devlink_attr { > DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_TYPE, /* u8 */ > DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_DATA, /* dynamic */ > >+ DEVLINK_ATTR_MSG_OBJECT, /* nested */ >+ DEVLINK_ATTR_MSG_OBJECT_PAIR, /* nested */ >+ DEVLINK_ATTR_MSG_OBJECT_NAME, /* string */ >+ DEVLINK_ATTR_MSG_OBJECT_VALUE, /* nested */ >+ DEVLINK_ATTR_MSG_OBJECT_VALUE_ARRAY, /* nested */ >+ DEVLINK_ATTR_MSG_OBJECT_VALUE_TYPE, /* u8 */ >+ DEVLINK_ATTR_MSG_OBJECT_VALUE_DATA, /* dynamic */ >+ > DEVLINK_ATTR_HEALTH_REPORTER, /* nested */ > DEVLINK_ATTR_HEALTH_REPORTER_NAME, /* string */ > DEVLINK_ATTR_HEALTH_REPORTER_STATE, /* u8 */ >diff --git a/net/core/devlink.c b/net/core/devlink.c >index 60248a53c0ad..57ca096849b3 100644 >--- a/net/core/devlink.c >+++ b/net/core/devlink.c >@@ -4098,6 +4098,461 @@ devlink_health_buffer_snd(struct genl_info *info, > return err; > } > >+struct devlink_msg { Let's call this "struct devlink_msg_item" >+ struct list_head list; >+ int attrtype; >+ u8 nla_type; >+ u16 len; >+ int value[0]; >+}; >+ >+struct devlink_msg_ctx { >+ struct list_head msg_list; >+ int max_nested_depth; >+ int curr_nest; >+}; >+ >+#define DEVLINK_MSG_MAX_SIZE (4096 - GENL_HDRLEN) >+ >+static struct devlink_msg_ctx *devlink_msg_ctx_alloc(void) >+{ >+ struct devlink_msg_ctx *msg_ctx; >+ >+ msg_ctx = kzalloc(sizeof(*msg_ctx), GFP_KERNEL); >+ if (!msg_ctx) >+ return ERR_PTR(-ENOMEM); >+ >+ INIT_LIST_HEAD(&msg_ctx->msg_list); >+ >+ return msg_ctx; >+} >+ >+static void devlink_msg_ctx_free(struct devlink_msg_ctx *msg_ctx) >+{ >+ struct devlink_msg *msg, *tm; >+ >+ list_for_each_entry_safe(msg, tm, &msg_ctx->msg_list, list) { >+ list_del(&msg->list); >+ kfree(msg); >+ } >+ kfree(msg_ctx); >+} >+ >+int devlink_msg_nest_start(struct devlink_msg_ctx *msg_ctx, int attrtype) >+{ >+ struct devlink_msg *nest_msg; >+ >+ if (attrtype != DEVLINK_ATTR_MSG_OBJECT && >+ attrtype != DEVLINK_ATTR_MSG_OBJECT_PAIR && >+ attrtype != DEVLINK_ATTR_MSG_OBJECT_VALUE && >+ attrtype != DEVLINK_ATTR_MSG_OBJECT_VALUE_ARRAY) >+ return -EINVAL; >+ >+ nest_msg = kzalloc(sizeof(*nest_msg), GFP_KERNEL); >+ if (!nest_msg) >+ return -ENOMEM; >+ >+ nest_msg->attrtype = attrtype; >+ msg_ctx->curr_nest++; >+ msg_ctx->max_nested_depth = max(msg_ctx->max_nested_depth, >+ msg_ctx->curr_nest); >+ list_add_tail(&nest_msg->list, &msg_ctx->msg_list); >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(devlink_msg_nest_start); >+ >+int devlink_msg_nest_end(struct devlink_msg_ctx *msg_ctx) >+{ >+ struct devlink_msg *nest_msg; >+ >+ WARN_ON(!msg_ctx->curr_nest); >+ nest_msg = kzalloc(sizeof(*nest_msg), GFP_KERNEL); >+ if (!nest_msg) >+ return -ENOMEM; >+ >+ msg_ctx->curr_nest--; >+ list_add_tail(&nest_msg->list, &msg_ctx->msg_list); >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(devlink_msg_nest_end); >+ >+int devlink_msg_put_value(struct devlink_msg_ctx *msg_ctx, >+ void *value, u16 value_len, u8 value_nla_type) >+{ >+ struct devlink_msg *value_msg; >+ >+ if (value_len > DEVLINK_MSG_MAX_SIZE) >+ return -EMSGSIZE; >+ >+ if (value_nla_type != NLA_U8 && >+ value_nla_type != NLA_U32 && >+ value_nla_type != NLA_U64 && >+ value_nla_type != NLA_NUL_STRING && >+ value_nla_type != NLA_BINARY) >+ return -EINVAL; >+ >+ value_msg = kzalloc(sizeof(*value_msg) + value_len, GFP_KERNEL); Looks fine. >+ if (!value_msg) >+ return -ENOMEM; >+ >+ value_msg->nla_type = value_nla_type; >+ value_msg->len = value_len; >+ value_msg->attrtype = DEVLINK_ATTR_MSG_OBJECT_VALUE_DATA; >+ memcpy(&value_msg->value, value, value_len); >+ list_add_tail(&value_msg->list, &msg_ctx->msg_list); >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(devlink_msg_put_value); >+ >+int devlink_msg_put_name(struct devlink_msg_ctx *msg_ctx, char *name) >+{ >+ struct devlink_msg *name_msg; >+ >+ if (strlen(name) + 1 > DEVLINK_MSG_MAX_SIZE) >+ return -EMSGSIZE; >+ >+ name_msg = kzalloc(sizeof(*name_msg) + strlen(name) + 1, GFP_KERNEL); >+ if (!name_msg) >+ return -ENOMEM; >+ >+ name_msg->nla_type = NLA_NUL_STRING; >+ name_msg->len = strlen(name) + 1; >+ name_msg->attrtype = DEVLINK_ATTR_MSG_OBJECT_NAME; >+ memcpy(&name_msg->value, name, name_msg->len); >+ list_add_tail(&name_msg->list, &msg_ctx->msg_list); >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(devlink_msg_put_name); >+ >+int devlink_msg_put_name_value_pair(struct devlink_msg_ctx *msg_ctx, >+ char *name, void *value, u16 value_len, >+ u8 value_nla_type) >+{ >+ int err; >+ >+ err = devlink_msg_nest_start(msg_ctx, DEVLINK_ATTR_MSG_OBJECT_PAIR); >+ if (err) >+ return err; >+ >+ err = devlink_msg_put_name(msg_ctx, name); >+ if (err) >+ return err; >+ >+ err = devlink_msg_nest_start(msg_ctx, DEVLINK_ATTR_MSG_OBJECT_VALUE); >+ if (err) >+ return err; >+ >+ err = devlink_msg_put_value(msg_ctx, value, value_len, value_nla_type); >+ if (err) >+ return err; >+ >+ err = devlink_msg_nest_end(msg_ctx); >+ if (err) >+ return err; >+ >+ err = devlink_msg_nest_end(msg_ctx); >+ if (err) >+ return err; >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(devlink_msg_put_name_value_pair); >+ >+int devlink_msg_put_name_value_array(struct devlink_msg_ctx *msg_ctx, >+ char *name, void **value, u16 *value_len, >+ u8 *value_nla_type, int array_size) This is limitting the arrays to plain values. One should be able to nest objects inside. If fact, that is what you can to do with sqs: object start name sqs array start object start index 0 xxx yyy object end object start index 1 xxx yyy object end array end object end So you need to have: devlink_msg_put_array_start() devlink_msg_put_array_end() >+{ >+ int err, i; >+ >+ err = devlink_msg_nest_start(msg_ctx, DEVLINK_ATTR_MSG_OBJECT_PAIR); >+ if (err) >+ return err; >+ >+ err = devlink_msg_put_name(msg_ctx, name); >+ if (err) >+ return err; >+ >+ err = devlink_msg_nest_start(msg_ctx, DEVLINK_ATTR_MSG_OBJECT_VALUE); >+ if (err) >+ return err; >+ >+ err = devlink_msg_nest_start(msg_ctx, >+ DEVLINK_ATTR_MSG_OBJECT_VALUE_ARRAY); >+ if (err) >+ return err; >+ >+ for (i = 0; i < array_size; i++) { >+ err = devlink_msg_nest_start(msg_ctx, >+ DEVLINK_ATTR_MSG_OBJECT_VALUE); >+ if (err) >+ return err; >+ >+ err = devlink_msg_put_value(msg_ctx, value[i], >+ value_len[i], value_nla_type[i]); >+ if (err) >+ return err; >+ err = devlink_msg_nest_end(msg_ctx); >+ if (err) >+ return err; >+ } >+ >+ err = devlink_msg_nest_end(msg_ctx); >+ if (err) >+ return err; >+ >+ err = devlink_msg_nest_end(msg_ctx); >+ if (err) >+ return err; >+ >+ err = devlink_msg_nest_end(msg_ctx); >+ if (err) >+ return err; >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(devlink_msg_put_name_value_array); >+ >+int devlink_msg_object_start(struct devlink_msg_ctx *msg_ctx, char *name) >+{ >+ int err; >+ >+ err = devlink_msg_nest_start(msg_ctx, DEVLINK_ATTR_MSG_OBJECT); >+ if (err) >+ return err; >+ >+ if (!name) >+ return 0; >+ >+ err = devlink_msg_nest_start(msg_ctx, DEVLINK_ATTR_MSG_OBJECT_PAIR); >+ if (err) >+ return err; >+ >+ err = devlink_msg_put_name(msg_ctx, name); >+ if (err) >+ return err; >+ >+ err = devlink_msg_nest_start(msg_ctx, DEVLINK_ATTR_MSG_OBJECT_VALUE); >+ if (err) >+ return err; >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(devlink_msg_object_start); >+ >+int devlink_msg_object_end(struct devlink_msg_ctx *msg_ctx, char *name) >+{ >+ int err; >+ >+ if (!name) >+ goto end_object; >+ >+ err = devlink_msg_nest_end(msg_ctx); /* DEVLINK_ATTR_MSG_OBJECT_VALUE */ >+ if (err) >+ return err; >+ >+ err = devlink_msg_nest_end(msg_ctx); /* DEVLINK_ATTR_MSG_OBJECT_PAIR */ >+ if (err) >+ return err; >+ >+end_object: >+ err = devlink_msg_nest_end(msg_ctx); /* DEVLINK_ATTR_MSG_OBJECT */ >+ if (err) >+ return err; >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(devlink_msg_object_end); >+ >+static int >+devlink_msg_fill_data(struct sk_buff *skb, struct devlink_msg *msg) >+{ >+ int err; >+ >+ switch (msg->nla_type) { >+ case NLA_U8: >+ err = nla_put_u8(skb, DEVLINK_ATTR_MSG_OBJECT_VALUE_DATA, >+ *(u8 *)msg->value); >+ break; >+ case NLA_U32: >+ err = nla_put_u32(skb, DEVLINK_ATTR_MSG_OBJECT_VALUE_DATA, >+ *(u32 *)msg->value); >+ break; >+ case NLA_U64: >+ err = nla_put_u64_64bit(skb, >+ DEVLINK_ATTR_MSG_OBJECT_VALUE_DATA, >+ *(u64 *)msg->value, DEVLINK_ATTR_PAD); >+ break; >+ case NLA_NUL_STRING: >+ err = nla_put_string(skb, >+ DEVLINK_ATTR_MSG_OBJECT_VALUE_DATA, >+ (char *)&msg->value); >+ break; >+ case NLA_BINARY: >+ err = nla_put(skb, DEVLINK_ATTR_MSG_OBJECT_VALUE_DATA, >+ msg->len, (void *)&msg->value); >+ break; >+ default: >+ err = -EINVAL; >+ break; >+ } >+ >+ return err; >+} >+ >+static int >+devlink_msg_fill_type(struct sk_buff *skb, struct devlink_msg *msg) >+{ >+ int err; >+ >+ switch (msg->nla_type) { >+ case NLA_U8: >+ err = nla_put_u8(skb, DEVLINK_ATTR_MSG_OBJECT_VALUE_TYPE, >+ NLA_U8); >+ break; >+ case NLA_U32: >+ err = nla_put_u8(skb, DEVLINK_ATTR_MSG_OBJECT_VALUE_TYPE, >+ NLA_U32); >+ break; >+ case NLA_U64: >+ err = nla_put_u8(skb, DEVLINK_ATTR_MSG_OBJECT_VALUE_TYPE, >+ NLA_U64); >+ break; >+ case NLA_NUL_STRING: >+ err = nla_put_u8(skb, DEVLINK_ATTR_MSG_OBJECT_VALUE_TYPE, >+ NLA_NUL_STRING); >+ break; >+ case NLA_BINARY: >+ err = nla_put_u8(skb, DEVLINK_ATTR_MSG_OBJECT_VALUE_TYPE, >+ NLA_BINARY); >+ break; >+ default: >+ err = -EINVAL; >+ break; >+ } >+ >+ return err; >+} >+ >+static int >+devlink_msg_prepare_skb(struct sk_buff *skb, struct devlink_msg_ctx *msg_ctx, >+ int *start) >+{ >+ struct nlattr **nlattr_arr; >+ struct devlink_msg *msg; >+ int j = 0, i = 0; >+ int err; >+ >+ nlattr_arr = kcalloc(msg_ctx->max_nested_depth, >+ sizeof(*nlattr_arr), GFP_KERNEL); >+ if (!nlattr_arr) >+ return -EINVAL; >+ >+ list_for_each_entry(msg, &msg_ctx->msg_list, list) { >+ if (j < *start) { >+ j++; >+ continue; >+ } >+ >+ switch (msg->attrtype) { >+ case DEVLINK_ATTR_MSG_OBJECT: >+ case DEVLINK_ATTR_MSG_OBJECT_PAIR: >+ case DEVLINK_ATTR_MSG_OBJECT_VALUE: >+ case DEVLINK_ATTR_MSG_OBJECT_VALUE_ARRAY: >+ nlattr_arr[i] = nla_nest_start(skb, msg->attrtype); >+ if (!nlattr_arr[i]) { >+ err = -EMSGSIZE; >+ goto nla_put_failure; >+ } >+ i++; >+ break; >+ case DEVLINK_ATTR_MSG_OBJECT_VALUE_DATA: >+ err = devlink_msg_fill_data(skb, msg); >+ if (err) >+ goto nla_put_failure; >+ err = devlink_msg_fill_type(skb, msg); >+ if (err) >+ goto nla_put_failure; >+ break; >+ case DEVLINK_ATTR_MSG_OBJECT_NAME: >+ err = nla_put_string(skb, msg->attrtype, >+ (char *)&msg->value); >+ if (err) >+ goto nla_put_failure; >+ break; >+ default: /* No attrtype */ >+ nla_nest_end(skb, nlattr_arr[--i]); >+ break; >+ } >+ j++; >+ if (!i) >+ *start = j; >+ } >+ >+ kfree(nlattr_arr); >+ return 0; >+ >+nla_put_failure: >+ for (j = 0; j < i; j++) >+ nla_nest_cancel(skb, nlattr_arr[j]); >+ kfree(nlattr_arr); >+ return err; >+} >+ >+static int devlink_msg_snd(struct genl_info *info, >+ enum devlink_command cmd, int flags, >+ struct devlink_msg_ctx *msg_ctx) >+{ >+ struct sk_buff *skb; >+ struct nlmsghdr *nlh; >+ int err, index = 0; >+ bool last = false; >+ void *hdr; >+ >+ while (!last) { >+ int tmp_index = index; >+ >+ skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); >+ if (!skb) >+ return -ENOMEM; >+ >+ hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, >+ &devlink_nl_family, NLM_F_MULTI, cmd); >+ if (!hdr) >+ goto nla_put_failure; >+ >+ err = devlink_msg_prepare_skb(skb, msg_ctx, &index); >+ if (!err) >+ last = true; >+ else if (err != -EMSGSIZE || tmp_index == index) >+ goto nla_put_failure; >+ >+ genlmsg_end(skb, hdr); >+ err = genlmsg_reply(skb, info); >+ if (err) >+ return err; Looks fine. >+ } >+ >+ skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); >+ if (!skb) >+ return -ENOMEM; >+ nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, >+ NLMSG_DONE, 0, flags | NLM_F_MULTI); >+ err = genlmsg_reply(skb, info); >+ if (err) >+ return err; >+ >+ return 0; >+ >+nla_put_failure: >+ err = -EIO; >+ nlmsg_free(skb); >+ return err; >+} >+ > struct devlink_health_reporter { > struct list_head list; > struct devlink_health_buffer **dump_buffers_array; >-- >2.17.1 >