| @@ -479,12 +479,44 @@ static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink) · 478 unmodified lines |
| 479 | return 0; | 479 | return 0; |
| 480 | } | 480 | } |
| 481 | | 481 | |
| | 482 | struct devlink_reload_combination { |
| | 483 | enum devlink_reload_action action; |
| | 484 | enum devlink_reload_limit limit; |
| | 485 | }; |
| | 486 | |
| | 487 | static const struct devlink_reload_combination devlink_reload_invalid_combinations[] = { |
| | 488 | { |
| | 489 | /* can't reinitialize driver with no down time */ |
| | 490 | .action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT, |
| | 491 | .limit = DEVLINK_RELOAD_LIMIT_NO_RESET, |
| | 492 | }, |
| | 493 | }; |
| | 494 | |
| | 495 | static bool |
| | 496 | devlink_reload_combination_is_invalid(enum devlink_reload_action action, |
| | 497 | enum devlink_reload_limit limit) |
| | 498 | { |
| | 499 | int i; |
| | 500 | |
| | 501 | for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++) |
| | 502 | if (devlink_reload_invalid_combinations[i].action == action && |
| | 503 | devlink_reload_invalid_combinations[i].limit == limit) |
| | 504 | return true; |
| | 505 | return false; |
| | 506 | } |
| | 507 | |
| 482 | static bool | 508 | static bool |
| 483 | devlink_reload_action_is_supported(struct devlink *devlink, enum devlink_reload_action action) | 509 | devlink_reload_action_is_supported(struct devlink *devlink, enum devlink_reload_action action) |
| 484 | { | 510 | { |
| 485 | return test_bit(action, &devlink->ops->reload_actions); | 511 | return test_bit(action, &devlink->ops->reload_actions); |
| 486 | } | 512 | } |
| 487 | | 513 | |
| | 514 | static bool |
| | 515 | devlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_limit limit) |
| | 516 | { |
| | 517 | return test_bit(limit, &devlink->ops->reload_limits); |
| | 518 | } |
| | 519 | |
| 488 | static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, | 520 | static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, |
| 489 | enum devlink_command cmd, u32 portid, | 521 | enum devlink_command cmd, u32 portid, |
| 490 | u32 seq, int flags) | 522 | u32 seq, int flags) |
| @@ -2990,22 +3022,22 @@ bool devlink_is_reload_failed(const struct devlink *devlink) · 2499 unmodified lines |
| 2990 | EXPORT_SYMBOL_GPL(devlink_is_reload_failed); | 3022 | EXPORT_SYMBOL_GPL(devlink_is_reload_failed); |
| 2991 | | 3023 | |
| 2992 | static int devlink_reload(struct devlink *devlink, struct net *dest_net, | 3024 | static int devlink_reload(struct devlink *devlink, struct net *dest_net, |
| 2993 | enum devlink_reload_action action, u32 *actions_performed, | 3025 | enum devlink_reload_action action, enum devlink_reload_limit limit, |
| 2994 | struct netlink_ext_ack *extack) | 3026 | u32 *actions_performed, struct netlink_ext_ack *extack) |
| 2995 | { | 3027 | { |
| 2996 | int err; | 3028 | int err; |
| 2997 | | 3029 | |
| 2998 | if (!devlink->reload_enabled) | 3030 | if (!devlink->reload_enabled) |
| 2999 | return -EOPNOTSUPP; | 3031 | return -EOPNOTSUPP; |
| 3000 | | 3032 | |
| 3001 | err = devlink->ops->reload_down(devlink, !!dest_net, action, extack); | 3033 | err = devlink->ops->reload_down(devlink, !!dest_net, action, limit, extack); |
| 3002 | if (err) | 3034 | if (err) |
| 3003 | return err; | 3035 | return err; |
| 3004 | | 3036 | |
| 3005 | if (dest_net && !net_eq(dest_net, devlink_net(devlink))) | 3037 | if (dest_net && !net_eq(dest_net, devlink_net(devlink))) |
| 3006 | devlink_reload_netns_change(devlink, dest_net); | 3038 | devlink_reload_netns_change(devlink, dest_net); |
| 3007 | | 3039 | |
| 3008 | err = devlink->ops->reload_up(devlink, action, actions_performed, extack); | 3040 | err = devlink->ops->reload_up(devlink, action, limit, actions_performed, extack); |
| 3009 | devlink_reload_failed_set(devlink, !!err); | 3041 | devlink_reload_failed_set(devlink, !!err); |
| 3010 | if (err) | 3042 | if (err) |
| 3011 | return err; | 3043 | return err; |
| @@ -3050,6 +3082,7 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info) · 38 unmodified lines |
| 3050 | { | 3082 | { |
| 3051 | struct devlink *devlink = info->user_ptr[0]; | 3083 | struct devlink *devlink = info->user_ptr[0]; |
| 3052 | enum devlink_reload_action action; | 3084 | enum devlink_reload_action action; |
| | 3085 | enum devlink_reload_limit limit; |
| 3053 | struct net *dest_net = NULL; | 3086 | struct net *dest_net = NULL; |
| 3054 | u32 actions_performed; | 3087 | u32 actions_performed; |
| 3055 | int err; | 3088 | int err; |
| @@ -3082,7 +3115,38 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info) · 26 unmodified lines |
| 3082 | return -EOPNOTSUPP; | 3115 | return -EOPNOTSUPP; |
| 3083 | } | 3116 | } |
| 3084 | | 3117 | |
| 3085 | err = devlink_reload(devlink, dest_net, action, &actions_performed, info->extack); | 3118 | limit = DEVLINK_RELOAD_LIMIT_UNSPEC; |
| | 3119 | if (info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) { |
| | 3120 | struct nla_bitfield32 limits; |
| | 3121 | u32 limits_selected; |
| | 3122 | |
| | 3123 | limits = nla_get_bitfield32(info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]); |
| | 3124 | limits_selected = limits.value & limits.selector; |
| | 3125 | if (!limits_selected) { |
| | 3126 | NL_SET_ERR_MSG_MOD(info->extack, "Invalid limit selected"); |
| | 3127 | return -EINVAL; |
| | 3128 | } |
| | 3129 | for (limit = 0 ; limit <= DEVLINK_RELOAD_LIMIT_MAX ; limit++) |
| | 3130 | if (limits_selected & BIT(limit)) |
| | 3131 | break; |
| | 3132 | /* UAPI enables multiselection, but currently it is not used */ |
| | 3133 | if (limits_selected != BIT(limit)) { |
| | 3134 | NL_SET_ERR_MSG_MOD(info->extack, |
| | 3135 | "Multiselection of limit is not supported"); |
| | 3136 | return -EOPNOTSUPP; |
| | 3137 | } |
| | 3138 | if (!devlink_reload_limit_is_supported(devlink, limit)) { |
| | 3139 | NL_SET_ERR_MSG_MOD(info->extack, |
| | 3140 | "Requested limit is not supported by the driver"); |
| | 3141 | return -EOPNOTSUPP; |
| | 3142 | } |
| | 3143 | if (devlink_reload_combination_is_invalid(action, limit)) { |
| | 3144 | NL_SET_ERR_MSG_MOD(info->extack, |
| | 3145 | "Requested limit is invalid for this action"); |
| | 3146 | return -EINVAL; |
| | 3147 | } |
| | 3148 | } |
| | 3149 | err = devlink_reload(devlink, dest_net, action, limit, &actions_performed, info->extack); |
| 3086 | | 3150 | |
| 3087 | if (dest_net) | 3151 | if (dest_net) |
| 3088 | put_net(dest_net); | 3152 | put_net(dest_net); |
| @@ -3090,7 +3154,7 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info) · 1 unmodified line |
| 3090 | if (err) | 3154 | if (err) |
| 3091 | return err; | 3155 | return err; |
| 3092 | /* For backward compatibility generate reply only if attributes used by user */ | 3156 | /* For backward compatibility generate reply only if attributes used by user */ |
| 3093 | if (!info->attrs[DEVLINK_ATTR_RELOAD_ACTION]) | 3157 | if (!info->attrs[DEVLINK_ATTR_RELOAD_ACTION] && !info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) |
| 3094 | return 0; | 3158 | return 0; |
| 3095 | | 3159 | |
| 3096 | return devlink_nl_reload_actions_performed_snd(devlink, actions_performed, | 3160 | return devlink_nl_reload_actions_performed_snd(devlink, actions_performed, |
| @@ -7347,6 +7411,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { · 4250 unmodified lines |
| 7347 | [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED }, | 7411 | [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED }, |
| 7348 | [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, | 7412 | [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, |
| 7349 | DEVLINK_RELOAD_ACTION_MAX), | 7413 | DEVLINK_RELOAD_ACTION_MAX), |
| | 7414 | [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK), |
| 7350 | }; | 7415 | }; |
| 7351 | | 7416 | |
| 7352 | static const struct genl_small_ops devlink_nl_ops[] = { | 7417 | static const struct genl_small_ops devlink_nl_ops[] = { |
| @@ -7682,6 +7747,9 @@ static struct genl_family devlink_nl_family __ro_after_init = { · 329 unmodified lines |
| 7682 | | 7747 | |
| 7683 | static bool devlink_reload_actions_valid(const struct devlink_ops *ops) | 7748 | static bool devlink_reload_actions_valid(const struct devlink_ops *ops) |
| 7684 | { | 7749 | { |
| | 7750 | const struct devlink_reload_combination *comb; |
| | 7751 | int i; |
| | 7752 | |
| 7685 | if (!devlink_reload_supported(ops)) { | 7753 | if (!devlink_reload_supported(ops)) { |
| 7686 | if (WARN_ON(ops->reload_actions)) | 7754 | if (WARN_ON(ops->reload_actions)) |
| 7687 | return false; | 7755 | return false; |
| @@ -7692,6 +7760,17 @@ static bool devlink_reload_actions_valid(const struct devlink_ops *ops) · 4 unmodified lines |
| 7692 | ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) || | 7760 | ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) || |
| 7693 | ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX))) | 7761 | ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX))) |
| 7694 | return false; | 7762 | return false; |
| | 7763 | |
| | 7764 | if (WARN_ON(ops->reload_limits & BIT(DEVLINK_RELOAD_LIMIT_UNSPEC) || |
| | 7765 | ops->reload_limits >= BIT(__DEVLINK_RELOAD_LIMIT_MAX))) |
| | 7766 | return false; |
| | 7767 | |
| | 7768 | for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++) { |
| | 7769 | comb = &devlink_reload_invalid_combinations[i]; |
| | 7770 | if (ops->reload_actions == BIT(comb->action) && |
| | 7771 | ops->reload_limits == BIT(comb->limit)) |
| | 7772 | return false; |
| | 7773 | } |
| 7695 | return true; | 7774 | return true; |
| 7696 | } | 7775 | } |
| 7697 | | 7776 | |
| @@ -10056,6 +10135,7 @@ static void __net_exit devlink_pernet_pre_exit(struct net *net) · 2358 unmodified lines |
| 10056 | continue; | 10135 | continue; |
| 10057 | err = devlink_reload(devlink, &init_net, | 10136 | err = devlink_reload(devlink, &init_net, |
| 10058 | DEVLINK_RELOAD_ACTION_DRIVER_REINIT, | 10137 | DEVLINK_RELOAD_ACTION_DRIVER_REINIT, |
| | 10138 | DEVLINK_RELOAD_LIMIT_UNSPEC, |
| 10059 | &actions_performed, NULL); | 10139 | &actions_performed, NULL); |
| 10060 | if (err && err != -EOPNOTSUPP) | 10140 | if (err && err != -EOPNOTSUPP) |
| 10061 | pr_warn("Failed to reload devlink instance into init_net\n"); | 10141 | pr_warn("Failed to reload devlink instance into init_net\n"); |