| @@ -479,12 +479,44 @@ static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink) · 478 unmodified lines |
| 479 | 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 | 508 | static bool |
| 483 | 509 | devlink_reload_action_is_supported(struct devlink *devlink, enum devlink_reload_action action) |
| 484 | 510 | { |
| 485 | 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 | 520 | static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, |
| 489 | 521 | enum devlink_command cmd, u32 portid, |
| 490 | 522 | u32 seq, int flags) |
| @@ -2990,22 +3022,22 @@ bool devlink_is_reload_failed(const struct devlink *devlink) · 2499 unmodified lines |
| 2990 | 3022 | EXPORT_SYMBOL_GPL(devlink_is_reload_failed); |
| 2991 | 3023 | |
| 2992 | 3024 | static int devlink_reload(struct devlink *devlink, struct net *dest_net, |
| 2993 | | − enum devlink_reload_action action, u32 *actions_performed, |
| 2994 | | − struct netlink_ext_ack *extack) |
| 3025 | + enum devlink_reload_action action, enum devlink_reload_limit limit, |
| 3026 | + u32 *actions_performed, struct netlink_ext_ack *extack) |
| 2995 | 3027 | { |
| 2996 | 3028 | int err; |
| 2997 | 3029 | |
| 2998 | 3030 | if (!devlink->reload_enabled) |
| 2999 | 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 | 3034 | if (err) |
| 3003 | 3035 | return err; |
| 3004 | 3036 | |
| 3005 | 3037 | if (dest_net && !net_eq(dest_net, devlink_net(devlink))) |
| 3006 | 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 | 3041 | devlink_reload_failed_set(devlink, !!err); |
| 3010 | 3042 | if (err) |
| 3011 | 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 | 3083 | struct devlink *devlink = info->user_ptr[0]; |
| 3052 | 3084 | enum devlink_reload_action action; |
| 3085 | + enum devlink_reload_limit limit; |
| 3053 | 3086 | struct net *dest_net = NULL; |
| 3054 | 3087 | u32 actions_performed; |
| 3055 | 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 | 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 | 3151 | if (dest_net) |
| 3088 | 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 | 3154 | if (err) |
| 3091 | 3155 | return err; |
| 3092 | 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 | 3158 | return 0; |
| 3095 | 3159 | |
| 3096 | 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 | 7411 | [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED }, |
| 7348 | 7412 | [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, |
| 7349 | 7413 | DEVLINK_RELOAD_ACTION_MAX), |
| 7414 | + [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK), |
| 7350 | 7415 | }; |
| 7351 | 7416 | |
| 7352 | 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 | 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 | 7753 | if (!devlink_reload_supported(ops)) { |
| 7686 | 7754 | if (WARN_ON(ops->reload_actions)) |
| 7687 | 7755 | return false; |
| @@ -7692,6 +7760,17 @@ static bool devlink_reload_actions_valid(const struct devlink_ops *ops) · 4 unmodified lines |
| 7692 | 7760 | ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) || |
| 7693 | 7761 | ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX))) |
| 7694 | 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 | 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 | 10135 | continue; |
| 10057 | 10136 | err = devlink_reload(devlink, &init_net, |
| 10058 | 10137 | DEVLINK_RELOAD_ACTION_DRIVER_REINIT, |
| 10138 | + DEVLINK_RELOAD_LIMIT_UNSPEC, |
| 10059 | 10139 | &actions_performed, NULL); |
| 10060 | 10140 | if (err && err != -EOPNOTSUPP) |
| 10061 | 10141 | pr_warn("Failed to reload devlink instance into init_net\n"); |