diff options
Diffstat (limited to 'net/devlink')
| -rw-r--r-- | net/devlink/core.c | 22 | ||||
| -rw-r--r-- | net/devlink/dev.c | 17 | ||||
| -rw-r--r-- | net/devlink/devl_internal.h | 20 | ||||
| -rw-r--r-- | net/devlink/dpipe.c | 14 | ||||
| -rw-r--r-- | net/devlink/health.c | 12 | ||||
| -rw-r--r-- | net/devlink/linecard.c | 4 | ||||
| -rw-r--r-- | net/devlink/netlink.c | 82 | ||||
| -rw-r--r-- | net/devlink/netlink_gen.c | 26 | ||||
| -rw-r--r-- | net/devlink/netlink_gen.h | 8 | ||||
| -rw-r--r-- | net/devlink/param.c | 136 | ||||
| -rw-r--r-- | net/devlink/port.c | 26 | ||||
| -rw-r--r-- | net/devlink/rate.c | 352 | ||||
| -rw-r--r-- | net/devlink/region.c | 6 | ||||
| -rw-r--r-- | net/devlink/resource.c | 16 | ||||
| -rw-r--r-- | net/devlink/sb.c | 22 | ||||
| -rw-r--r-- | net/devlink/trap.c | 12 |
16 files changed, 576 insertions, 199 deletions
diff --git a/net/devlink/core.c b/net/devlink/core.c index eeb6a71f5f56..c53a42e17a58 100644 --- a/net/devlink/core.c +++ b/net/devlink/core.c @@ -67,6 +67,22 @@ static void __devlink_rel_put(struct devlink_rel *rel) devlink_rel_free(rel); } +struct devlink *__must_check devlink_nested_in_get_lock(struct devlink *devlink) +{ + devl_assert_locked(devlink); + if (!devlink->rel) + return NULL; + devlink = devlinks_xa_get(devlink->rel->nested_in.devlink_index); + if (!devlink) + return NULL; + devl_lock(devlink); + if (devl_is_registered(devlink)) + return devlink; + devl_unlock(devlink); + devlink_put(devlink); + return NULL; +} + static void devlink_rel_nested_in_notify_work(struct work_struct *work) { struct devlink_rel *rel = container_of(work, struct devlink_rel, @@ -518,6 +534,11 @@ void devlink_free(struct devlink *devlink) { ASSERT_DEVLINK_NOT_REGISTERED(devlink); + devl_lock(devlink); + WARN_ON(devlink_rates_check(devlink, NULL, NULL)); + devl_unlock(devlink); + devlink_rel_put(devlink); + WARN_ON(!list_empty(&devlink->trap_policer_list)); WARN_ON(!list_empty(&devlink->trap_group_list)); WARN_ON(!list_empty(&devlink->trap_list)); @@ -526,7 +547,6 @@ void devlink_free(struct devlink *devlink) WARN_ON(!list_empty(&devlink->resource_list)); WARN_ON(!list_empty(&devlink->dpipe_table_list)); WARN_ON(!list_empty(&devlink->sb_list)); - WARN_ON(devlink_rates_check(devlink, NULL, NULL)); WARN_ON(!list_empty(&devlink->linecard_list)); WARN_ON(!xa_empty(&devlink->ports)); diff --git a/net/devlink/dev.c b/net/devlink/dev.c index 57b2b8f03543..55959b0ff5ab 100644 --- a/net/devlink/dev.c +++ b/net/devlink/dev.c @@ -222,7 +222,7 @@ static void devlink_notify(struct devlink *devlink, enum devlink_command cmd) int devlink_nl_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct sk_buff *msg; int err; @@ -519,7 +519,7 @@ free_msg: int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; enum devlink_reload_action action; enum devlink_reload_limit limit; struct net *dest_net = NULL; @@ -578,6 +578,7 @@ int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info) action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) { NL_SET_ERR_MSG_MOD(info->extack, "Changing namespace is only supported for reinit action"); + put_net(dest_net); return -EOPNOTSUPP; } } @@ -683,7 +684,7 @@ nla_put_failure: int devlink_nl_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct sk_buff *msg; int err; @@ -704,7 +705,7 @@ int devlink_nl_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info) int devlink_nl_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; const struct devlink_ops *ops = devlink->ops; enum devlink_eswitch_encap_mode encap_mode; u8 inline_mode; @@ -906,7 +907,7 @@ err_cancel_msg: int devlink_nl_info_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct sk_buff *msg; int err; @@ -1134,7 +1135,7 @@ int devlink_nl_flash_update_doit(struct sk_buff *skb, struct genl_info *info) { struct nlattr *nla_overwrite_mask, *nla_file_name; struct devlink_flash_update_params params = {}; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; const char *file_name; u32 supported_params; int ret; @@ -1302,7 +1303,7 @@ err_cancel_msg: int devlink_nl_selftests_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct sk_buff *msg; int err; @@ -1372,7 +1373,7 @@ static const struct nla_policy devlink_selftest_nl_policy[DEVLINK_ATTR_SELFTEST_ int devlink_nl_selftests_run_doit(struct sk_buff *skb, struct genl_info *info) { struct nlattr *tb[DEVLINK_ATTR_SELFTEST_ID_MAX + 1]; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct nlattr *attrs, *selftests; struct sk_buff *msg; void *hdr; diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h index e4e48ee2da5a..cdf894ba5a9d 100644 --- a/net/devlink/devl_internal.h +++ b/net/devlink/devl_internal.h @@ -136,6 +136,10 @@ typedef void devlink_rel_notify_cb_t(struct devlink *devlink, u32 obj_index); typedef void devlink_rel_cleanup_cb_t(struct devlink *devlink, u32 obj_index, u32 rel_index); +/* Returns the locked+referenced nested-in instance or NULL. */ +struct devlink *__must_check +devlink_nested_in_get_lock(struct devlink *devlink); + void devlink_rel_nested_in_clear(u32 rel_index); int devlink_rel_nested_in_add(u32 *rel_index, u32 devlink_index, u32 obj_index, devlink_rel_notify_cb_t *notify_cb, @@ -147,6 +151,20 @@ int devlink_rel_devlink_handle_put(struct sk_buff *msg, struct devlink *devlink, bool *msg_updated); /* Netlink */ +struct devlink_nl_ctx { + struct devlink *devlink; + struct devlink_port *devlink_port; + struct devlink *parent_devlink; +}; + +static inline struct devlink_nl_ctx * +devlink_nl_ctx(struct genl_info *info) +{ + BUILD_BUG_ON(sizeof(struct devlink_nl_ctx) > + sizeof_field(struct genl_info, ctx)); + return (struct devlink_nl_ctx *)info->ctx; +} + enum devlink_multicast_groups { DEVLINK_MCGRP_CONFIG, }; @@ -180,6 +198,8 @@ typedef int devlink_nl_dump_one_func_t(struct sk_buff *msg, struct devlink * devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs, bool dev_lock); +struct devlink * +devlink_get_parent_from_attrs_lock(struct net *net, struct nlattr **attrs); int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb, devlink_nl_dump_one_func_t *dump_one); diff --git a/net/devlink/dpipe.c b/net/devlink/dpipe.c index c8d4a4374ae1..08c7b66fc3e8 100644 --- a/net/devlink/dpipe.c +++ b/net/devlink/dpipe.c @@ -213,7 +213,7 @@ static int devlink_dpipe_tables_fill(struct genl_info *info, struct list_head *dpipe_tables, const char *table_name) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_dpipe_table *table; struct nlattr *tables_attr; struct sk_buff *skb = NULL; @@ -290,7 +290,7 @@ err_table_put: int devlink_nl_dpipe_table_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; const char *table_name = NULL; if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]) @@ -478,7 +478,7 @@ int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx) if (!dump_ctx->hdr) goto nla_put_failure; - devlink = dump_ctx->info->user_ptr[0]; + devlink = devlink_nl_ctx(dump_ctx->info)->devlink; if (devlink_nl_put_handle(dump_ctx->skb, devlink)) goto nla_put_failure; dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb, @@ -563,7 +563,7 @@ send_done: int devlink_nl_dpipe_entries_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_dpipe_table *table; const char *table_name; @@ -650,7 +650,7 @@ static int devlink_dpipe_headers_fill(struct genl_info *info, struct devlink_dpipe_headers * dpipe_headers) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct nlattr *headers_attr; struct sk_buff *skb = NULL; struct nlmsghdr *nlh; @@ -713,7 +713,7 @@ err_table_put: int devlink_nl_dpipe_headers_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; if (!devlink->dpipe_headers) return -EOPNOTSUPP; @@ -747,7 +747,7 @@ static int devlink_dpipe_table_counters_set(struct devlink *devlink, int devlink_nl_dpipe_table_counters_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; const char *table_name; bool counters_enable; diff --git a/net/devlink/health.c b/net/devlink/health.c index ea7a334e939b..8ce6cd399cb7 100644 --- a/net/devlink/health.c +++ b/net/devlink/health.c @@ -358,7 +358,7 @@ devlink_health_reporter_get_from_info(struct devlink *devlink, int devlink_nl_health_reporter_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_health_reporter *reporter; struct sk_buff *msg; int err; @@ -456,7 +456,7 @@ int devlink_nl_health_reporter_get_dumpit(struct sk_buff *skb, int devlink_nl_health_reporter_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_health_reporter *reporter; reporter = devlink_health_reporter_get_from_info(devlink, info); @@ -715,7 +715,7 @@ EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update); int devlink_nl_health_reporter_recover_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_health_reporter *reporter; reporter = devlink_health_reporter_get_from_info(devlink, info); @@ -1157,7 +1157,7 @@ nla_put_failure: int devlink_nl_health_reporter_diagnose_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_health_reporter *reporter; struct devlink_fmsg *fmsg; int err; @@ -1252,7 +1252,7 @@ unlock: int devlink_nl_health_reporter_dump_clear_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_health_reporter *reporter; reporter = devlink_health_reporter_get_from_info(devlink, info); @@ -1269,7 +1269,7 @@ int devlink_nl_health_reporter_dump_clear_doit(struct sk_buff *skb, int devlink_nl_health_reporter_test_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_health_reporter *reporter; reporter = devlink_health_reporter_get_from_info(devlink, info); diff --git a/net/devlink/linecard.c b/net/devlink/linecard.c index 8315d35cb91d..fd18f2759770 100644 --- a/net/devlink/linecard.c +++ b/net/devlink/linecard.c @@ -171,7 +171,7 @@ void devlink_linecards_notify_unregister(struct devlink *devlink) int devlink_nl_linecard_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_linecard *linecard; struct sk_buff *msg; int err; @@ -371,7 +371,7 @@ out: int devlink_nl_linecard_set_doit(struct sk_buff *skb, struct genl_info *info) { struct netlink_ext_ack *extack = info->extack; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_linecard *linecard; int err; diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c index ae4afc739678..300580c1a217 100644 --- a/net/devlink/netlink.c +++ b/net/devlink/netlink.c @@ -12,6 +12,7 @@ #define DEVLINK_NL_FLAG_NEED_PORT BIT(0) #define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) #define DEVLINK_NL_FLAG_NEED_DEV_LOCK BIT(2) +#define DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV BIT(3) static const struct genl_multicast_group devlink_nl_mcgrps[] = { [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME }, @@ -239,37 +240,82 @@ found: return ERR_PTR(-ENODEV); } +struct devlink * +devlink_get_parent_from_attrs_lock(struct net *net, struct nlattr **attrs) +{ + unsigned int maxtype = ARRAY_SIZE(devlink_dl_parent_dev_nl_policy) - 1; + struct devlink *devlink; + struct nlattr **tb; + int err; + + if (!attrs[DEVLINK_ATTR_PARENT_DEV]) + return ERR_PTR(-EINVAL); + + tb = kcalloc(maxtype + 1, sizeof(*tb), GFP_KERNEL); + if (!tb) + return ERR_PTR(-ENOMEM); + + err = nla_parse_nested(tb, maxtype, attrs[DEVLINK_ATTR_PARENT_DEV], + devlink_dl_parent_dev_nl_policy, NULL); + if (err) + goto out; + + devlink = devlink_get_from_attrs_lock(net, tb, false); + kfree(tb); + return devlink; +out: + kfree(tb); + return ERR_PTR(err); +} + static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info, u8 flags) { + bool parent_dev = flags & DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV; bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK; + struct devlink *devlink, *parent_devlink = NULL; + struct net *net = genl_info_net(info); + struct nlattr **attrs = info->attrs; struct devlink_port *devlink_port; - struct devlink *devlink; int err; - devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs, - dev_lock); - if (IS_ERR(devlink)) - return PTR_ERR(devlink); + if (parent_dev && attrs[DEVLINK_ATTR_PARENT_DEV]) { + parent_devlink = devlink_get_parent_from_attrs_lock(net, attrs); + if (IS_ERR(parent_devlink)) + return PTR_ERR(parent_devlink); + devlink_nl_ctx(info)->parent_devlink = parent_devlink; + /* Drop the parent devlink lock but don't release the reference. + * This will keep it alive until the end of the request. + */ + devl_unlock(parent_devlink); + } - info->user_ptr[0] = devlink; + devlink = devlink_get_from_attrs_lock(net, attrs, dev_lock); + if (IS_ERR(devlink)) { + err = PTR_ERR(devlink); + goto parent_put; + } + devlink_nl_ctx(info)->devlink = devlink; if (flags & DEVLINK_NL_FLAG_NEED_PORT) { devlink_port = devlink_port_get_from_info(devlink, info); if (IS_ERR(devlink_port)) { err = PTR_ERR(devlink_port); goto unlock; } - info->user_ptr[1] = devlink_port; + devlink_nl_ctx(info)->devlink_port = devlink_port; } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) { devlink_port = devlink_port_get_from_info(devlink, info); if (!IS_ERR(devlink_port)) - info->user_ptr[1] = devlink_port; + devlink_nl_ctx(info)->devlink_port = devlink_port; } return 0; unlock: devl_dev_unlock(devlink, dev_lock); devlink_put(devlink); +parent_put: + if (parent_dev && parent_devlink) + devlink_put(parent_devlink); return err; } @@ -298,15 +344,25 @@ int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops, return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT); } +int devlink_nl_pre_doit_parent_dev_optional(const struct genl_split_ops *ops, + struct sk_buff *skb, + struct genl_info *info) +{ + return __devlink_nl_pre_doit(skb, info, + DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV); +} + static void __devlink_nl_post_doit(struct sk_buff *skb, struct genl_info *info, u8 flags) { bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK; struct devlink *devlink; - devlink = info->user_ptr[0]; + devlink = devlink_nl_ctx(info)->devlink; devl_dev_unlock(devlink, dev_lock); devlink_put(devlink); + if (devlink_nl_ctx(info)->parent_devlink) + devlink_put(devlink_nl_ctx(info)->parent_devlink); } void devlink_nl_post_doit(const struct genl_split_ops *ops, @@ -322,6 +378,14 @@ devlink_nl_post_doit_dev_lock(const struct genl_split_ops *ops, __devlink_nl_post_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEV_LOCK); } +void +devlink_nl_post_doit_parent_dev_optional(const struct genl_split_ops *ops, + struct sk_buff *skb, + struct genl_info *info) +{ + __devlink_nl_post_doit(skb, info, DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV); +} + static int devlink_nl_inst_single_dumpit(struct sk_buff *msg, struct netlink_callback *cb, int flags, devlink_nl_dump_one_func_t *dump_one, diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c index 81899786fd98..dec00133178d 100644 --- a/net/devlink/netlink_gen.c +++ b/net/devlink/netlink_gen.c @@ -37,6 +37,8 @@ devlink_attr_param_type_validate(const struct nlattr *attr, case DEVLINK_VAR_ATTR_TYPE_NUL_STRING: fallthrough; case DEVLINK_VAR_ATTR_TYPE_BINARY: + fallthrough; + case DEVLINK_VAR_ATTR_TYPE_U64_ARRAY: return 0; } NL_SET_ERR_MSG_ATTR(extack, attr, "invalid enum value"); @@ -44,6 +46,12 @@ devlink_attr_param_type_validate(const struct nlattr *attr, } /* Common nested types */ +const struct nla_policy devlink_dl_parent_dev_nl_policy[DEVLINK_ATTR_INDEX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range), +}; + const struct nla_policy devlink_dl_port_function_nl_policy[DEVLINK_PORT_FN_ATTR_CAPS + 1] = { [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY, }, [DEVLINK_PORT_FN_ATTR_STATE] = NLA_POLICY_MAX(NLA_U8, 1), @@ -606,7 +614,7 @@ static const struct nla_policy devlink_rate_get_dump_nl_policy[DEVLINK_ATTR_INDE }; /* DEVLINK_CMD_RATE_SET - do */ -static const struct nla_policy devlink_rate_set_nl_policy[DEVLINK_ATTR_INDEX + 1] = { +static const struct nla_policy devlink_rate_set_nl_policy[DEVLINK_ATTR_PARENT_DEV + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, [DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range), @@ -617,10 +625,11 @@ static const struct nla_policy devlink_rate_set_nl_policy[DEVLINK_ATTR_INDEX + 1 [DEVLINK_ATTR_RATE_TX_WEIGHT] = { .type = NLA_U32, }, [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING, }, [DEVLINK_ATTR_RATE_TC_BWS] = NLA_POLICY_NESTED(devlink_dl_rate_tc_bws_nl_policy), + [DEVLINK_ATTR_PARENT_DEV] = NLA_POLICY_NESTED(devlink_dl_parent_dev_nl_policy), }; /* DEVLINK_CMD_RATE_NEW - do */ -static const struct nla_policy devlink_rate_new_nl_policy[DEVLINK_ATTR_INDEX + 1] = { +static const struct nla_policy devlink_rate_new_nl_policy[DEVLINK_ATTR_PARENT_DEV + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, [DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range), @@ -631,6 +640,7 @@ static const struct nla_policy devlink_rate_new_nl_policy[DEVLINK_ATTR_INDEX + 1 [DEVLINK_ATTR_RATE_TX_WEIGHT] = { .type = NLA_U32, }, [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING, }, [DEVLINK_ATTR_RATE_TC_BWS] = NLA_POLICY_NESTED(devlink_dl_rate_tc_bws_nl_policy), + [DEVLINK_ATTR_PARENT_DEV] = NLA_POLICY_NESTED(devlink_dl_parent_dev_nl_policy), }; /* DEVLINK_CMD_RATE_DEL - do */ @@ -1288,21 +1298,21 @@ const struct genl_split_ops devlink_nl_ops[75] = { { .cmd = DEVLINK_CMD_RATE_SET, .validate = GENL_DONT_VALIDATE_STRICT, - .pre_doit = devlink_nl_pre_doit, + .pre_doit = devlink_nl_pre_doit_parent_dev_optional, .doit = devlink_nl_rate_set_doit, - .post_doit = devlink_nl_post_doit, + .post_doit = devlink_nl_post_doit_parent_dev_optional, .policy = devlink_rate_set_nl_policy, - .maxattr = DEVLINK_ATTR_INDEX, + .maxattr = DEVLINK_ATTR_PARENT_DEV, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { .cmd = DEVLINK_CMD_RATE_NEW, .validate = GENL_DONT_VALIDATE_STRICT, - .pre_doit = devlink_nl_pre_doit, + .pre_doit = devlink_nl_pre_doit_parent_dev_optional, .doit = devlink_nl_rate_new_doit, - .post_doit = devlink_nl_post_doit, + .post_doit = devlink_nl_post_doit_parent_dev_optional, .policy = devlink_rate_new_nl_policy, - .maxattr = DEVLINK_ATTR_INDEX, + .maxattr = DEVLINK_ATTR_PARENT_DEV, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { diff --git a/net/devlink/netlink_gen.h b/net/devlink/netlink_gen.h index 20034b0929a8..a70e0e4769aa 100644 --- a/net/devlink/netlink_gen.h +++ b/net/devlink/netlink_gen.h @@ -13,6 +13,7 @@ #include <uapi/linux/devlink.h> /* Common nested types */ +extern const struct nla_policy devlink_dl_parent_dev_nl_policy[DEVLINK_ATTR_INDEX + 1]; extern const struct nla_policy devlink_dl_port_function_nl_policy[DEVLINK_PORT_FN_ATTR_CAPS + 1]; extern const struct nla_policy devlink_dl_rate_tc_bws_nl_policy[DEVLINK_RATE_TC_ATTR_BW + 1]; extern const struct nla_policy devlink_dl_selftest_id_nl_policy[DEVLINK_ATTR_SELFTEST_ID_FLASH + 1]; @@ -29,12 +30,19 @@ int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops, struct genl_info *info); int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); +int devlink_nl_pre_doit_parent_dev_optional(const struct genl_split_ops *ops, + struct sk_buff *skb, + struct genl_info *info); void devlink_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); void devlink_nl_post_doit_dev_lock(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); +void +devlink_nl_post_doit_parent_dev_optional(const struct genl_split_ops *ops, + struct sk_buff *skb, + struct genl_info *info); int devlink_nl_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); diff --git a/net/devlink/param.c b/net/devlink/param.c index cf95268da5b0..8ca0f3ed646c 100644 --- a/net/devlink/param.c +++ b/net/devlink/param.c @@ -117,6 +117,11 @@ static const struct devlink_param devlink_param_generic[] = { .name = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_NAME, .type = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_TYPE, }, + { + .id = DEVLINK_PARAM_GENERIC_ID_MAX_SFS, + .name = DEVLINK_PARAM_GENERIC_MAX_SFS_NAME, + .type = DEVLINK_PARAM_GENERIC_MAX_SFS_TYPE, + }, }; static int devlink_param_generic_verify(const struct devlink_param *param) @@ -216,28 +221,28 @@ static int devlink_param_reset_default(struct devlink *devlink, static int devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type, - int nla_type, union devlink_param_value val, + int nla_type, union devlink_param_value *val, bool flag_as_u8) { switch (type) { case DEVLINK_PARAM_TYPE_U8: - if (nla_put_u8(msg, nla_type, val.vu8)) + if (nla_put_u8(msg, nla_type, val->vu8)) return -EMSGSIZE; break; case DEVLINK_PARAM_TYPE_U16: - if (nla_put_u16(msg, nla_type, val.vu16)) + if (nla_put_u16(msg, nla_type, val->vu16)) return -EMSGSIZE; break; case DEVLINK_PARAM_TYPE_U32: - if (nla_put_u32(msg, nla_type, val.vu32)) + if (nla_put_u32(msg, nla_type, val->vu32)) return -EMSGSIZE; break; case DEVLINK_PARAM_TYPE_U64: - if (devlink_nl_put_u64(msg, nla_type, val.vu64)) + if (devlink_nl_put_u64(msg, nla_type, val->vu64)) return -EMSGSIZE; break; case DEVLINK_PARAM_TYPE_STRING: - if (nla_put_string(msg, nla_type, val.vstr)) + if (nla_put_string(msg, nla_type, val->vstr)) return -EMSGSIZE; break; case DEVLINK_PARAM_TYPE_BOOL: @@ -245,10 +250,19 @@ devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type, * false can be distinguished from not present */ if (flag_as_u8) { - if (nla_put_u8(msg, nla_type, val.vbool)) + if (nla_put_u8(msg, nla_type, val->vbool)) return -EMSGSIZE; } else { - if (val.vbool && nla_put_flag(msg, nla_type)) + if (val->vbool && nla_put_flag(msg, nla_type)) + return -EMSGSIZE; + } + break; + case DEVLINK_PARAM_TYPE_U64_ARRAY: + if (val->u64arr.size > __DEVLINK_PARAM_MAX_ARRAY_SIZE) + return -EMSGSIZE; + + for (int i = 0; i < val->u64arr.size; i++) { + if (nla_put_uint(msg, nla_type, val->u64arr.val[i])) return -EMSGSIZE; } break; @@ -260,8 +274,8 @@ static int devlink_nl_param_value_fill_one(struct sk_buff *msg, enum devlink_param_type type, enum devlink_param_cmode cmode, - union devlink_param_value val, - union devlink_param_value default_val, + union devlink_param_value *val, + union devlink_param_value *default_val, bool has_default) { struct nlattr *param_value_attr; @@ -304,56 +318,79 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink, u32 portid, u32 seq, int flags, struct netlink_ext_ack *extack) { - union devlink_param_value default_value[DEVLINK_PARAM_CMODE_MAX + 1]; - union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1]; bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {}; bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {}; const struct devlink_param *param = param_item->param; - struct devlink_param_gset_ctx ctx; + union devlink_param_value *default_value; + union devlink_param_value *param_value; + struct devlink_param_gset_ctx *ctx; struct nlattr *param_values_list; struct nlattr *param_attr; void *hdr; int err; int i; + default_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1, + sizeof(*default_value), GFP_KERNEL); + if (!default_value) + return -ENOMEM; + + param_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1, + sizeof(*param_value), GFP_KERNEL); + if (!param_value) { + kfree(default_value); + return -ENOMEM; + } + + ctx = kzalloc_obj(*ctx); + if (!ctx) { + kfree(param_value); + kfree(default_value); + return -ENOMEM; + } + /* Get value from driver part to driverinit configuration mode */ for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) { if (!devlink_param_cmode_is_supported(param, i)) continue; if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) { - if (param_item->driverinit_value_new_valid) + if (param_item->driverinit_value_new_valid) { param_value[i] = param_item->driverinit_value_new; - else if (param_item->driverinit_value_valid) + } else if (param_item->driverinit_value_valid) { param_value[i] = param_item->driverinit_value; - else - return -EOPNOTSUPP; + } else { + err = -EOPNOTSUPP; + goto get_put_fail; + } if (param_item->driverinit_value_valid) { default_value[i] = param_item->driverinit_default; default_value_set[i] = true; } } else { - ctx.cmode = i; - err = devlink_param_get(devlink, param, &ctx, extack); + ctx->cmode = i; + err = devlink_param_get(devlink, param, ctx, extack); if (err) - return err; - param_value[i] = ctx.val; + goto get_put_fail; + + param_value[i] = ctx->val; - err = devlink_param_get_default(devlink, param, &ctx, + err = devlink_param_get_default(devlink, param, ctx, extack); if (!err) { - default_value[i] = ctx.val; + default_value[i] = ctx->val; default_value_set[i] = true; } else if (err != -EOPNOTSUPP) { - return err; + goto get_put_fail; } } param_value_set[i] = true; } + err = -EMSGSIZE; hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); if (!hdr) - return -EMSGSIZE; + goto get_put_fail; if (devlink_nl_put_handle(msg, devlink)) goto genlmsg_cancel; @@ -383,8 +420,8 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink, if (!param_value_set[i]) continue; err = devlink_nl_param_value_fill_one(msg, param->type, - i, param_value[i], - default_value[i], + i, ¶m_value[i], + &default_value[i], default_value_set[i]); if (err) goto values_list_nest_cancel; @@ -393,6 +430,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink, nla_nest_end(msg, param_values_list); nla_nest_end(msg, param_attr); genlmsg_end(msg, hdr); + kfree(default_value); + kfree(param_value); + kfree(ctx); return 0; values_list_nest_cancel: @@ -401,7 +441,11 @@ param_nest_cancel: nla_nest_cancel(msg, param_attr); genlmsg_cancel: genlmsg_cancel(msg, hdr); - return -EMSGSIZE; +get_put_fail: + kfree(default_value); + kfree(param_value); + kfree(ctx); + return err; } static void devlink_param_notify(struct devlink *devlink, @@ -507,7 +551,7 @@ devlink_param_value_get_from_info(const struct devlink_param *param, union devlink_param_value *value) { struct nlattr *param_data; - int len; + int len, cnt, rem; param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]; @@ -547,6 +591,28 @@ devlink_param_value_get_from_info(const struct devlink_param *param, return -EINVAL; value->vbool = nla_get_flag(param_data); break; + + case DEVLINK_PARAM_TYPE_U64_ARRAY: + cnt = 0; + nla_for_each_attr_type(param_data, + DEVLINK_ATTR_PARAM_VALUE_DATA, + genlmsg_data(info->genlhdr), + genlmsg_len(info->genlhdr), rem) { + if (cnt >= __DEVLINK_PARAM_MAX_ARRAY_SIZE) + return -EMSGSIZE; + + if ((nla_len(param_data) != sizeof(u64)) && + (nla_len(param_data) != sizeof(u32))) { + NL_SET_BAD_ATTR(info->extack, param_data); + return -EINVAL; + } + + value->u64arr.val[cnt] = nla_get_uint(param_data); + cnt++; + } + + value->u64arr.size = cnt; + break; } return 0; } @@ -566,7 +632,7 @@ devlink_param_get_from_info(struct xarray *params, struct genl_info *info) int devlink_nl_param_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_param_item *param_item; struct sk_buff *msg; int err; @@ -621,7 +687,7 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink, if (err) return err; if (param->validate) { - err = param->validate(devlink, param->id, value, + err = param->validate(devlink, param->id, &value, info->extack); if (err) return err; @@ -667,7 +733,7 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink, int devlink_nl_param_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->params, info, DEVLINK_CMD_PARAM_NEW); @@ -888,7 +954,7 @@ EXPORT_SYMBOL_GPL(devl_param_driverinit_value_get); * configuration mode default value. */ void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id, - union devlink_param_value init_val) + union devlink_param_value *init_val) { struct devlink_param_item *param_item; @@ -902,9 +968,9 @@ void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id, DEVLINK_PARAM_CMODE_DRIVERINIT))) return; - param_item->driverinit_value = init_val; + param_item->driverinit_value = *init_val; param_item->driverinit_value_valid = true; - param_item->driverinit_default = init_val; + param_item->driverinit_default = *init_val; devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW); } diff --git a/net/devlink/port.c b/net/devlink/port.c index 485029d43428..1528f2d148df 100644 --- a/net/devlink/port.c +++ b/net/devlink/port.c @@ -267,6 +267,8 @@ static int devlink_nl_port_attrs_put(struct sk_buff *msg, nla_put_u32(msg, DEVLINK_ATTR_PORT_PCI_SF_NUMBER, attrs->pci_sf.sf)) return -EMSGSIZE; + if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_sf.external)) + return -EMSGSIZE; break; case DEVLINK_PORT_FLAVOUR_PHYSICAL: case DEVLINK_PORT_FLAVOUR_CPU: @@ -594,7 +596,7 @@ void devlink_ports_notify_unregister(struct devlink *devlink) int devlink_nl_port_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; + struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port; struct sk_buff *msg; int err; @@ -830,7 +832,7 @@ static int devlink_port_function_set(struct devlink_port *port, int devlink_nl_port_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; + struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port; int err; if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) { @@ -856,8 +858,8 @@ int devlink_nl_port_set_doit(struct sk_buff *skb, struct genl_info *info) int devlink_nl_port_split_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; - struct devlink *devlink = info->user_ptr[0]; + struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; u32 count; if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PORT_SPLIT_COUNT)) @@ -887,8 +889,8 @@ int devlink_nl_port_split_doit(struct sk_buff *skb, struct genl_info *info) int devlink_nl_port_unsplit_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; - struct devlink *devlink = info->user_ptr[0]; + struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; if (!devlink_port->ops->port_unsplit) return -EOPNOTSUPP; @@ -899,7 +901,7 @@ int devlink_nl_port_new_doit(struct sk_buff *skb, struct genl_info *info) { struct netlink_ext_ack *extack = info->extack; struct devlink_port_new_attrs new_attrs = {}; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_port *devlink_port; struct sk_buff *msg; int err; @@ -961,9 +963,9 @@ err_out_port_del: int devlink_nl_port_del_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; + struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port; struct netlink_ext_ack *extack = info->extack; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; if (!devlink_port->ops->port_del) return -EOPNOTSUPP; @@ -1529,7 +1531,7 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, WARN_ON(1); return -EINVAL; case DEVLINK_PORT_FLAVOUR_PCI_PF: - if (attrs->pci_pf.external) { + if (attrs->pci_pf.external || attrs->pci_pf.controller) { n = snprintf(name, len, "c%u", attrs->pci_pf.controller); if (n >= len) return -EINVAL; @@ -1539,7 +1541,7 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, n = snprintf(name, len, "pf%u", attrs->pci_pf.pf); break; case DEVLINK_PORT_FLAVOUR_PCI_VF: - if (attrs->pci_vf.external) { + if (attrs->pci_vf.external || attrs->pci_vf.controller) { n = snprintf(name, len, "c%u", attrs->pci_vf.controller); if (n >= len) return -EINVAL; @@ -1550,7 +1552,7 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, attrs->pci_vf.pf, attrs->pci_vf.vf); break; case DEVLINK_PORT_FLAVOUR_PCI_SF: - if (attrs->pci_sf.external) { + if (attrs->pci_sf.external || attrs->pci_sf.controller) { n = snprintf(name, len, "c%u", attrs->pci_sf.controller); if (n >= len) return -EINVAL; diff --git a/net/devlink/rate.c b/net/devlink/rate.c index 41be2d6c2954..e727c8b8b33e 100644 --- a/net/devlink/rate.c +++ b/net/devlink/rate.c @@ -30,13 +30,53 @@ devlink_rate_leaf_get_from_info(struct devlink *devlink, struct genl_info *info) return devlink_rate ?: ERR_PTR(-ENODEV); } +/* Repeatedly walks the nested devlink chain while cross device rate nodes are + * supported and finds the topmost instance where rates should be stored. + * That instance is locked, referenced and returned. + * When cross device rate nodes aren't supported the original devlink instance + * is returned. + */ +static struct devlink *devl_rate_lock(struct devlink *devlink) +{ + struct devlink *rate_devlink = devlink, *parent; + + devl_assert_locked(devlink); + + while (rate_devlink->ops && + rate_devlink->ops->supported_cross_device_rate_nodes) { + parent = devlink_nested_in_get_lock(rate_devlink); + if (!parent) + break; + if (rate_devlink != devlink) { + /* Unlock intermediate instances. */ + devl_unlock(rate_devlink); + devlink_put(rate_devlink); + } + rate_devlink = parent; + } + return rate_devlink; +} + +/* Unlocks and puts 'rate devlink' if different than 'devlink'. */ +static void devl_rate_unlock(struct devlink *devlink, + struct devlink *rate_devlink) +{ + if (devlink == rate_devlink) + return; + + devl_unlock(rate_devlink); + devlink_put(rate_devlink); +} + static struct devlink_rate * -devlink_rate_node_get_by_name(struct devlink *devlink, const char *node_name) +devlink_rate_node_get_by_name(struct devlink *rate_devlink, + struct devlink *devlink, const char *node_name) { struct devlink_rate *devlink_rate; - list_for_each_entry(devlink_rate, &devlink->rate_list, list) { - if (devlink_rate_is_node(devlink_rate) && + list_for_each_entry(devlink_rate, &rate_devlink->rate_list, list) { + if (devlink_rate->devlink == devlink && + devlink_rate_is_node(devlink_rate) && !strcmp(node_name, devlink_rate->name)) return devlink_rate; } @@ -44,7 +84,8 @@ devlink_rate_node_get_by_name(struct devlink *devlink, const char *node_name) } static struct devlink_rate * -devlink_rate_node_get_from_attrs(struct devlink *devlink, struct nlattr **attrs) +devlink_rate_node_get_from_attrs(struct devlink *rate_devlink, + struct devlink *devlink, struct nlattr **attrs) { const char *rate_node_name; size_t len; @@ -57,24 +98,30 @@ devlink_rate_node_get_from_attrs(struct devlink *devlink, struct nlattr **attrs) if (!len || strspn(rate_node_name, "0123456789") == len) return ERR_PTR(-EINVAL); - return devlink_rate_node_get_by_name(devlink, rate_node_name); + return devlink_rate_node_get_by_name(rate_devlink, devlink, + rate_node_name); } static struct devlink_rate * -devlink_rate_node_get_from_info(struct devlink *devlink, struct genl_info *info) +devlink_rate_node_get_from_info(struct devlink *rate_devlink, + struct devlink *devlink, + struct genl_info *info) { - return devlink_rate_node_get_from_attrs(devlink, info->attrs); + return devlink_rate_node_get_from_attrs(rate_devlink, devlink, + info->attrs); } static struct devlink_rate * -devlink_rate_get_from_info(struct devlink *devlink, struct genl_info *info) +devlink_rate_get_from_info(struct devlink *rate_devlink, + struct devlink *devlink, struct genl_info *info) { struct nlattr **attrs = info->attrs; if (attrs[DEVLINK_ATTR_PORT_INDEX]) return devlink_rate_leaf_get_from_info(devlink, info); else if (attrs[DEVLINK_ATTR_RATE_NODE_NAME]) - return devlink_rate_node_get_from_info(devlink, info); + return devlink_rate_node_get_from_info(rate_devlink, devlink, + info); else return ERR_PTR(-EINVAL); } @@ -102,6 +149,25 @@ nla_put_failure: return -EMSGSIZE; } +static int devlink_nl_rate_parent_fill(struct sk_buff *msg, + struct devlink_rate *devlink_rate) +{ + struct devlink_rate *parent = devlink_rate->parent; + struct devlink *devlink = parent->devlink; + + if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME, + parent->name)) + return -EMSGSIZE; + + if (devlink != devlink_rate->devlink && + devlink_nl_put_nested_handle(msg, + devlink_net(devlink_rate->devlink), + devlink, DEVLINK_ATTR_PARENT_DEV)) + return -EMSGSIZE; + + return 0; +} + static int devlink_nl_rate_fill(struct sk_buff *msg, struct devlink_rate *devlink_rate, enum devlink_command cmd, u32 portid, u32 seq, @@ -146,10 +212,9 @@ static int devlink_nl_rate_fill(struct sk_buff *msg, devlink_rate->tx_weight)) goto nla_put_failure; - if (devlink_rate->parent) - if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME, - devlink_rate->parent->name)) - goto nla_put_failure; + if (devlink_rate->parent && + devlink_nl_rate_parent_fill(msg, devlink_rate)) + goto nla_put_failure; if (devlink_rate_put_tc_bws(msg, devlink_rate->tc_bw)) goto nla_put_failure; @@ -190,17 +255,25 @@ static void devlink_rate_notify(struct devlink_rate *devlink_rate, void devlink_rates_notify_register(struct devlink *devlink) { struct devlink_rate *rate_node; + struct devlink *rate_devlink; - list_for_each_entry(rate_node, &devlink->rate_list, list) - devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW); + rate_devlink = devl_rate_lock(devlink); + list_for_each_entry(rate_node, &rate_devlink->rate_list, list) + if (rate_node->devlink == devlink) + devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW); + devl_rate_unlock(devlink, rate_devlink); } void devlink_rates_notify_unregister(struct devlink *devlink) { struct devlink_rate *rate_node; + struct devlink *rate_devlink; - list_for_each_entry_reverse(rate_node, &devlink->rate_list, list) - devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL); + rate_devlink = devl_rate_lock(devlink); + list_for_each_entry_reverse(rate_node, &rate_devlink->rate_list, list) + if (rate_node->devlink == devlink) + devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL); + devl_rate_unlock(devlink, rate_devlink); } static int @@ -209,17 +282,20 @@ devlink_nl_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink, { struct devlink_nl_dump_state *state = devlink_dump_state(cb); struct devlink_rate *devlink_rate; + struct devlink *rate_devlink; int idx = 0; int err = 0; - list_for_each_entry(devlink_rate, &devlink->rate_list, list) { + rate_devlink = devl_rate_lock(devlink); + list_for_each_entry(devlink_rate, &rate_devlink->rate_list, list) { enum devlink_command cmd = DEVLINK_CMD_RATE_NEW; u32 id = NETLINK_CB(cb->skb).portid; - if (idx < state->idx) { + if (idx < state->idx || devlink_rate->devlink != devlink) { idx++; continue; } + err = devlink_nl_rate_fill(msg, devlink_rate, cmd, id, cb->nlh->nlmsg_seq, flags, NULL); if (err) { @@ -228,6 +304,7 @@ devlink_nl_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink, } idx++; } + devl_rate_unlock(devlink, rate_devlink); return err; } @@ -239,28 +316,38 @@ int devlink_nl_rate_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) int devlink_nl_rate_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *rate_devlink, *devlink = devlink_nl_ctx(info)->devlink; struct devlink_rate *devlink_rate; struct sk_buff *msg; int err; - devlink_rate = devlink_rate_get_from_info(devlink, info); - if (IS_ERR(devlink_rate)) - return PTR_ERR(devlink_rate); + rate_devlink = devl_rate_lock(devlink); + devlink_rate = devlink_rate_get_from_info(rate_devlink, devlink, info); + if (IS_ERR(devlink_rate)) { + err = PTR_ERR(devlink_rate); + goto unlock; + } msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; + if (!msg) { + err = -ENOMEM; + goto unlock; + } err = devlink_nl_rate_fill(msg, devlink_rate, DEVLINK_CMD_RATE_NEW, info->snd_portid, info->snd_seq, 0, info->extack); - if (err) { - nlmsg_free(msg); - return err; - } + if (err) + goto err_fill; + devl_rate_unlock(devlink, rate_devlink); return genlmsg_reply(msg, info); + +err_fill: + nlmsg_free(msg); +unlock: + devl_rate_unlock(devlink, rate_devlink); + return err; } static bool @@ -277,16 +364,18 @@ devlink_rate_is_parent_node(struct devlink_rate *devlink_rate, static int devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate, + struct devlink *rate_devlink, struct genl_info *info, struct nlattr *nla_parent) { - struct devlink *devlink = devlink_rate->devlink; + struct devlink *devlink = devlink_rate->devlink, *parent_devlink; const char *parent_name = nla_data(nla_parent); const struct devlink_ops *ops = devlink->ops; size_t len = strlen(parent_name); struct devlink_rate *parent; int err = -EOPNOTSUPP; + parent_devlink = devlink_nl_ctx(info)->parent_devlink ? : devlink; parent = devlink_rate->parent; if (parent && !len) { @@ -304,7 +393,14 @@ devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate, refcount_dec(&parent->refcnt); devlink_rate->parent = NULL; } else if (len) { - parent = devlink_rate_node_get_by_name(devlink, parent_name); + /* parent_devlink (when different than devlink) isn't locked, + * but the rate node devlink instance is, so nobody from the + * same group of devices sharing rates could change the used + * fields or unregister the parent. + */ + parent = devlink_rate_node_get_by_name(rate_devlink, + parent_devlink, + parent_name); if (IS_ERR(parent)) return -ENODEV; @@ -423,6 +519,7 @@ static int devlink_nl_rate_tc_bw_set(struct devlink_rate *devlink_rate, } static int devlink_nl_rate_set(struct devlink_rate *devlink_rate, + struct devlink *rate_devlink, const struct devlink_ops *ops, struct genl_info *info) { @@ -486,16 +583,20 @@ static int devlink_nl_rate_set(struct devlink_rate *devlink_rate, devlink_rate->tx_weight = weight; } - nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]; - if (nla_parent) { - err = devlink_nl_rate_parent_node_set(devlink_rate, info, - nla_parent); + if (attrs[DEVLINK_ATTR_RATE_TC_BWS]) { + err = devlink_nl_rate_tc_bw_set(devlink_rate, info); if (err) return err; } - if (attrs[DEVLINK_ATTR_RATE_TC_BWS]) { - err = devlink_nl_rate_tc_bw_set(devlink_rate, info); + /* Keep parent setting last because it takes a reference. This function + * has no rollback, so failing after taking the ref would leak it. + */ + nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]; + if (nla_parent) { + err = devlink_nl_rate_parent_node_set(devlink_rate, + rate_devlink, info, + nla_parent); if (err) return err; } @@ -585,31 +686,51 @@ static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops, int devlink_nl_rate_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink_nl_ctx *ctx = devlink_nl_ctx(info); + struct devlink *devlink = ctx->devlink; struct devlink_rate *devlink_rate; const struct devlink_ops *ops; + struct devlink *rate_devlink; int err; - devlink_rate = devlink_rate_get_from_info(devlink, info); - if (IS_ERR(devlink_rate)) - return PTR_ERR(devlink_rate); + rate_devlink = devl_rate_lock(devlink); + devlink_rate = devlink_rate_get_from_info(rate_devlink, devlink, info); + if (IS_ERR(devlink_rate)) { + err = PTR_ERR(devlink_rate); + goto unlock; + } ops = devlink->ops; - if (!ops || !devlink_rate_set_ops_supported(ops, info, devlink_rate->type)) - return -EOPNOTSUPP; + if (!ops || + !devlink_rate_set_ops_supported(ops, info, devlink_rate->type)) { + err = -EOPNOTSUPP; + goto unlock; + } - err = devlink_nl_rate_set(devlink_rate, ops, info); + if (ctx->parent_devlink && ctx->parent_devlink != devlink && + !ops->supported_cross_device_rate_nodes) { + NL_SET_ERR_MSG(info->extack, + "Cross-device rate parents aren't supported"); + err = -EOPNOTSUPP; + goto unlock; + } + + err = devlink_nl_rate_set(devlink_rate, rate_devlink, ops, info); if (!err) devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW); +unlock: + devl_rate_unlock(devlink, rate_devlink); return err; } int devlink_nl_rate_new_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink_nl_ctx *ctx = devlink_nl_ctx(info); + struct devlink *devlink = ctx->devlink; struct devlink_rate *rate_node; const struct devlink_ops *ops; + struct devlink *rate_devlink; int err; ops = devlink->ops; @@ -621,15 +742,29 @@ int devlink_nl_rate_new_doit(struct sk_buff *skb, struct genl_info *info) if (!devlink_rate_set_ops_supported(ops, info, DEVLINK_RATE_TYPE_NODE)) return -EOPNOTSUPP; - rate_node = devlink_rate_node_get_from_attrs(devlink, info->attrs); - if (!IS_ERR(rate_node)) - return -EEXIST; - else if (rate_node == ERR_PTR(-EINVAL)) - return -EINVAL; + if (ctx->parent_devlink && ctx->parent_devlink != devlink && + !ops->supported_cross_device_rate_nodes) { + NL_SET_ERR_MSG(info->extack, + "Cross-device rate parents aren't supported"); + return -EOPNOTSUPP; + } + + rate_devlink = devl_rate_lock(devlink); + rate_node = devlink_rate_node_get_from_attrs(rate_devlink, devlink, + info->attrs); + if (!IS_ERR(rate_node)) { + err = -EEXIST; + goto unlock; + } else if (rate_node == ERR_PTR(-EINVAL)) { + err = -EINVAL; + goto unlock; + } rate_node = kzalloc_obj(*rate_node); - if (!rate_node) - return -ENOMEM; + if (!rate_node) { + err = -ENOMEM; + goto unlock; + } rate_node->devlink = devlink; rate_node->type = DEVLINK_RATE_TYPE_NODE; @@ -643,13 +778,14 @@ int devlink_nl_rate_new_doit(struct sk_buff *skb, struct genl_info *info) if (err) goto err_node_new; - err = devlink_nl_rate_set(rate_node, ops, info); + err = devlink_nl_rate_set(rate_node, rate_devlink, ops, info); if (err) goto err_rate_set; refcount_set(&rate_node->refcnt, 1); - list_add(&rate_node->list, &devlink->rate_list); + list_add(&rate_node->list, &rate_devlink->rate_list); devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW); + devl_rate_unlock(devlink, rate_devlink); return 0; err_rate_set: @@ -658,22 +794,29 @@ err_node_new: kfree(rate_node->name); err_strdup: kfree(rate_node); +unlock: + devl_rate_unlock(devlink, rate_devlink); return err; } int devlink_nl_rate_del_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *rate_devlink, *devlink = devlink_nl_ctx(info)->devlink; struct devlink_rate *rate_node; int err; - rate_node = devlink_rate_node_get_from_info(devlink, info); - if (IS_ERR(rate_node)) - return PTR_ERR(rate_node); + rate_devlink = devl_rate_lock(devlink); + rate_node = devlink_rate_node_get_from_info(rate_devlink, devlink, + info); + if (IS_ERR(rate_node)) { + err = PTR_ERR(rate_node); + goto unlock; + } if (refcount_read(&rate_node->refcnt) > 1) { NL_SET_ERR_MSG(info->extack, "Node has children. Cannot delete node."); - return -EBUSY; + err = -EBUSY; + goto unlock; } devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL); @@ -684,6 +827,8 @@ int devlink_nl_rate_del_doit(struct sk_buff *skb, struct genl_info *info) list_del(&rate_node->list); kfree(rate_node->name); kfree(rate_node); +unlock: + devl_rate_unlock(devlink, rate_devlink); return err; } @@ -692,14 +837,20 @@ int devlink_rates_check(struct devlink *devlink, struct netlink_ext_ack *extack) { struct devlink_rate *devlink_rate; + struct devlink *rate_devlink; + int err = 0; - list_for_each_entry(devlink_rate, &devlink->rate_list, list) - if (!rate_filter || rate_filter(devlink_rate)) { + rate_devlink = devl_rate_lock(devlink); + list_for_each_entry(devlink_rate, &rate_devlink->rate_list, list) + if (devlink_rate->devlink == devlink && + (!rate_filter || rate_filter(devlink_rate))) { if (extack) NL_SET_ERR_MSG(extack, "Rate node(s) exists."); - return -EBUSY; + err = -EBUSY; + break; } - return 0; + devl_rate_unlock(devlink, rate_devlink); + return err; } /** @@ -716,18 +867,20 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name, struct devlink_rate *parent) { struct devlink_rate *rate_node; - - rate_node = devlink_rate_node_get_by_name(devlink, node_name); - if (!IS_ERR(rate_node)) - return ERR_PTR(-EEXIST); + struct devlink *rate_devlink; + + rate_devlink = devl_rate_lock(devlink); + rate_node = devlink_rate_node_get_by_name(rate_devlink, devlink, + node_name); + if (!IS_ERR(rate_node)) { + rate_node = ERR_PTR(-EEXIST); + goto unlock; + } rate_node = kzalloc_obj(*rate_node); - if (!rate_node) - return ERR_PTR(-ENOMEM); - - if (parent) { - rate_node->parent = parent; - refcount_inc(&rate_node->parent->refcnt); + if (!rate_node) { + rate_node = ERR_PTR(-ENOMEM); + goto unlock; } rate_node->type = DEVLINK_RATE_TYPE_NODE; @@ -737,12 +890,20 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name, rate_node->name = kstrdup(node_name, GFP_KERNEL); if (!rate_node->name) { kfree(rate_node); - return ERR_PTR(-ENOMEM); + rate_node = ERR_PTR(-ENOMEM); + goto unlock; + } + + if (parent) { + rate_node->parent = parent; + refcount_inc(&rate_node->parent->refcnt); } refcount_set(&rate_node->refcnt, 1); - list_add(&rate_node->list, &devlink->rate_list); + list_add(&rate_node->list, &rate_devlink->rate_list); devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW); +unlock: + devl_rate_unlock(devlink, rate_devlink); return rate_node; } EXPORT_SYMBOL_GPL(devl_rate_node_create); @@ -758,10 +919,10 @@ EXPORT_SYMBOL_GPL(devl_rate_node_create); int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv, struct devlink_rate *parent) { - struct devlink *devlink = devlink_port->devlink; + struct devlink *rate_devlink, *devlink = devlink_port->devlink; struct devlink_rate *devlink_rate; - devl_assert_locked(devlink_port->devlink); + devl_assert_locked(devlink); if (WARN_ON(devlink_port->devlink_rate)) return -EBUSY; @@ -770,6 +931,7 @@ int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv, if (!devlink_rate) return -ENOMEM; + rate_devlink = devl_rate_lock(devlink); if (parent) { devlink_rate->parent = parent; refcount_inc(&devlink_rate->parent->refcnt); @@ -779,9 +941,10 @@ int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv, devlink_rate->devlink = devlink; devlink_rate->devlink_port = devlink_port; devlink_rate->priv = priv; - list_add_tail(&devlink_rate->list, &devlink->rate_list); + list_add_tail(&devlink_rate->list, &rate_devlink->rate_list); devlink_port->devlink_rate = devlink_rate; devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW); + devl_rate_unlock(devlink, rate_devlink); return 0; } @@ -797,16 +960,19 @@ EXPORT_SYMBOL_GPL(devl_rate_leaf_create); void devl_rate_leaf_destroy(struct devlink_port *devlink_port) { struct devlink_rate *devlink_rate = devlink_port->devlink_rate; + struct devlink *rate_devlink, *devlink = devlink_port->devlink; - devl_assert_locked(devlink_port->devlink); + devl_assert_locked(devlink); if (!devlink_rate) return; + rate_devlink = devl_rate_lock(devlink); devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_DEL); if (devlink_rate->parent) refcount_dec(&devlink_rate->parent->refcnt); list_del(&devlink_rate->list); devlink_port->devlink_rate = NULL; + devl_rate_unlock(devlink, rate_devlink); kfree(devlink_rate); } EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy); @@ -815,20 +981,30 @@ EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy); * devl_rate_nodes_destroy - destroy all devlink rate nodes on device * @devlink: devlink instance * - * Unset parent for all rate objects and destroy all rate nodes - * on specified device. + * Unset parent for all rate objects involving this device and destroy all rate + * nodes on it. */ void devl_rate_nodes_destroy(struct devlink *devlink) { - const struct devlink_ops *ops = devlink->ops; struct devlink_rate *devlink_rate, *tmp; + const struct devlink_ops *ops; + struct devlink *rate_devlink; devl_assert_locked(devlink); + rate_devlink = devl_rate_lock(devlink); - list_for_each_entry(devlink_rate, &devlink->rate_list, list) { - if (!devlink_rate->parent) + list_for_each_entry(devlink_rate, &rate_devlink->rate_list, list) { + if (!devlink_rate->parent || + (devlink_rate->devlink != devlink && + devlink_rate->parent->devlink != devlink)) continue; + /* This could destroy rate objects on other devlinks in the + * same hierarchy under 'rate_devlink'. This is safe because + * the shared common ancestor is locked so there can be no + * other concurrent rate operations on devlink_rate->devlink. + */ + ops = devlink_rate->devlink->ops; if (devlink_rate_is_leaf(devlink_rate)) ops->rate_leaf_parent_set(devlink_rate, NULL, devlink_rate->priv, NULL, NULL); @@ -839,13 +1015,17 @@ void devl_rate_nodes_destroy(struct devlink *devlink) refcount_dec(&devlink_rate->parent->refcnt); devlink_rate->parent = NULL; } - list_for_each_entry_safe(devlink_rate, tmp, &devlink->rate_list, list) { - if (devlink_rate_is_node(devlink_rate)) { + ops = devlink->ops; + list_for_each_entry_safe(devlink_rate, tmp, &rate_devlink->rate_list, + list) { + if (devlink_rate->devlink == devlink && + devlink_rate_is_node(devlink_rate)) { ops->rate_node_del(devlink_rate, devlink_rate->priv, NULL); list_del(&devlink_rate->list); kfree(devlink_rate->name); kfree(devlink_rate); } } + devl_rate_unlock(devlink, rate_devlink); } EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy); diff --git a/net/devlink/region.c b/net/devlink/region.c index 5588e3d560b9..537779bbff07 100644 --- a/net/devlink/region.c +++ b/net/devlink/region.c @@ -469,7 +469,7 @@ static void devlink_region_snapshot_del(struct devlink_region *region, int devlink_nl_region_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_port *port = NULL; struct devlink_region *region; const char *region_name; @@ -588,7 +588,7 @@ int devlink_nl_region_get_dumpit(struct sk_buff *skb, int devlink_nl_region_del_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_snapshot *snapshot; struct devlink_port *port = NULL; struct devlink_region *region; @@ -633,7 +633,7 @@ int devlink_nl_region_del_doit(struct sk_buff *skb, struct genl_info *info) int devlink_nl_region_new_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_snapshot *snapshot; struct devlink_port *port = NULL; struct nlattr *snapshot_id_attr; diff --git a/net/devlink/resource.c b/net/devlink/resource.c index 3d2f42bc2fb5..c3cfda7ea070 100644 --- a/net/devlink/resource.c +++ b/net/devlink/resource.c @@ -117,7 +117,7 @@ devlink_resource_validate_size(struct devlink_resource *resource, u64 size, int devlink_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_resource *resource; u64 resource_id; u64 size; @@ -251,8 +251,9 @@ static int devlink_resource_list_fill(struct sk_buff *skb, static int devlink_resource_fill(struct genl_info *info, enum devlink_command cmd, int flags) { - struct devlink_port *devlink_port = info->user_ptr[1]; - struct devlink *devlink = info->user_ptr[0]; + struct devlink_nl_ctx *ctx = devlink_nl_ctx(info); + struct devlink *devlink = ctx->devlink; + struct devlink_port *devlink_port; struct devlink_resource *resource; struct list_head *resource_list; struct nlattr *resources_attr; @@ -263,6 +264,7 @@ static int devlink_resource_fill(struct genl_info *info, int i; int err; + devlink_port = ctx->devlink_port; resource_list = devlink_port ? &devlink_port->resource_list : &devlink->resource_list; resource = list_first_entry(resource_list, @@ -326,10 +328,12 @@ err_resource_put: int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; - struct devlink *devlink = info->user_ptr[0]; + struct devlink_nl_ctx *ctx = devlink_nl_ctx(info); + struct devlink *devlink = ctx->devlink; + struct devlink_port *devlink_port; struct list_head *resource_list; + devlink_port = ctx->devlink_port; if (info->attrs[DEVLINK_ATTR_PORT_INDEX] && !devlink_port) return -ENODEV; @@ -486,6 +490,8 @@ __devl_resource_register(struct devlink *devlink, struct list_head *resource_list; bool top_hierarchy; + WARN_ON(resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP); + lockdep_assert_held(&devlink->lock); top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP; diff --git a/net/devlink/sb.c b/net/devlink/sb.c index 49fcbfe08f15..129bd016e302 100644 --- a/net/devlink/sb.c +++ b/net/devlink/sb.c @@ -204,7 +204,7 @@ nla_put_failure: int devlink_nl_sb_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_sb *devlink_sb; struct sk_buff *msg; int err; @@ -306,7 +306,7 @@ nla_put_failure: int devlink_nl_sb_pool_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_sb *devlink_sb; struct sk_buff *msg; u16 pool_index; @@ -415,7 +415,7 @@ static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index, int devlink_nl_sb_pool_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; enum devlink_sb_threshold_type threshold_type; struct devlink_sb *devlink_sb; u16 pool_index; @@ -506,7 +506,7 @@ sb_occ_get_failure: int devlink_nl_sb_port_pool_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; + struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port; struct devlink *devlink = devlink_port->devlink; struct devlink_sb *devlink_sb; struct sk_buff *msg; @@ -624,8 +624,8 @@ static int devlink_sb_port_pool_set(struct devlink_port *devlink_port, int devlink_nl_sb_port_pool_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; - struct devlink *devlink = info->user_ptr[0]; + struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_sb *devlink_sb; u16 pool_index; u32 threshold; @@ -716,7 +716,7 @@ nla_put_failure: int devlink_nl_sb_tc_pool_bind_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; + struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port; struct devlink *devlink = devlink_port->devlink; struct devlink_sb *devlink_sb; struct sk_buff *msg; @@ -864,8 +864,8 @@ static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port, int devlink_nl_sb_tc_pool_bind_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink_port *devlink_port = info->user_ptr[1]; - struct devlink *devlink = info->user_ptr[0]; + struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; enum devlink_sb_pool_type pool_type; struct devlink_sb *devlink_sb; u16 tc_index; @@ -902,7 +902,7 @@ int devlink_nl_sb_tc_pool_bind_set_doit(struct sk_buff *skb, int devlink_nl_sb_occ_snapshot_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; const struct devlink_ops *ops = devlink->ops; struct devlink_sb *devlink_sb; @@ -918,7 +918,7 @@ int devlink_nl_sb_occ_snapshot_doit(struct sk_buff *skb, struct genl_info *info) int devlink_nl_sb_occ_max_clear_doit(struct sk_buff *skb, struct genl_info *info) { - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; const struct devlink_ops *ops = devlink->ops; struct devlink_sb *devlink_sb; diff --git a/net/devlink/trap.c b/net/devlink/trap.c index 8edb31654a68..793ffc66dc11 100644 --- a/net/devlink/trap.c +++ b/net/devlink/trap.c @@ -302,7 +302,7 @@ nla_put_failure: int devlink_nl_trap_get_doit(struct sk_buff *skb, struct genl_info *info) { struct netlink_ext_ack *extack = info->extack; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_trap_item *trap_item; struct sk_buff *msg; int err; @@ -412,7 +412,7 @@ static int devlink_trap_action_set(struct devlink *devlink, int devlink_nl_trap_set_doit(struct sk_buff *skb, struct genl_info *info) { struct netlink_ext_ack *extack = info->extack; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_trap_item *trap_item; if (list_empty(&devlink->trap_list)) @@ -511,7 +511,7 @@ nla_put_failure: int devlink_nl_trap_group_get_doit(struct sk_buff *skb, struct genl_info *info) { struct netlink_ext_ack *extack = info->extack; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_trap_group_item *group_item; struct sk_buff *msg; int err; @@ -682,7 +682,7 @@ static int devlink_trap_group_set(struct devlink *devlink, int devlink_nl_trap_group_set_doit(struct sk_buff *skb, struct genl_info *info) { struct netlink_ext_ack *extack = info->extack; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct devlink_trap_group_item *group_item; bool modified = false; int err; @@ -804,7 +804,7 @@ int devlink_nl_trap_policer_get_doit(struct sk_buff *skb, { struct devlink_trap_policer_item *policer_item; struct netlink_ext_ack *extack = info->extack; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; struct sk_buff *msg; int err; @@ -924,7 +924,7 @@ int devlink_nl_trap_policer_set_doit(struct sk_buff *skb, { struct devlink_trap_policer_item *policer_item; struct netlink_ext_ack *extack = info->extack; - struct devlink *devlink = info->user_ptr[0]; + struct devlink *devlink = devlink_nl_ctx(info)->devlink; if (list_empty(&devlink->trap_policer_list)) return -EOPNOTSUPP; |
