mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 20:32:22 +00:00
devlink: hold the instance lock during eswitch_mode callbacks
Make the devlink core hold the instance lock during eswitch_mode callbacks. Cheat in case of mlx5 (see the cover letter). Reviewed-by: Leon Romanovsky <leonro@nvidia.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
aff3a92509
commit
14e426bf1a
@ -559,44 +559,34 @@ int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct bnxt *bp = bnxt_get_bp_from_dl(devlink);
|
||||
int rc = 0;
|
||||
|
||||
devl_lock(devlink);
|
||||
if (bp->eswitch_mode == mode) {
|
||||
netdev_info(bp->dev, "already in %s eswitch mode\n",
|
||||
mode == DEVLINK_ESWITCH_MODE_LEGACY ?
|
||||
"legacy" : "switchdev");
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case DEVLINK_ESWITCH_MODE_LEGACY:
|
||||
bnxt_vf_reps_destroy(bp);
|
||||
break;
|
||||
return 0;
|
||||
|
||||
case DEVLINK_ESWITCH_MODE_SWITCHDEV:
|
||||
if (bp->hwrm_spec_code < 0x10803) {
|
||||
netdev_warn(bp->dev, "FW does not support SRIOV E-Switch SWITCHDEV mode\n");
|
||||
rc = -ENOTSUPP;
|
||||
goto done;
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (pci_num_vf(bp->pdev) == 0) {
|
||||
netdev_info(bp->dev, "Enable VFs before setting switchdev mode\n");
|
||||
rc = -EPERM;
|
||||
goto done;
|
||||
return -EPERM;
|
||||
}
|
||||
rc = bnxt_vf_reps_create(bp);
|
||||
break;
|
||||
return bnxt_vf_reps_create(bp);
|
||||
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
return -EINVAL;
|
||||
}
|
||||
done:
|
||||
devl_unlock(devlink);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -3337,6 +3337,27 @@ static int eswitch_devlink_esw_mode_check(const struct mlx5_eswitch *esw)
|
||||
!mlx5_core_is_ecpf_esw_manager(esw->dev)) ? -EOPNOTSUPP : 0;
|
||||
}
|
||||
|
||||
/* FIXME: devl_unlock() followed by devl_lock() inside driver callback
|
||||
* is never correct and prone to races. It's a transitional workaround,
|
||||
* never repeat this pattern.
|
||||
*
|
||||
* This code MUST be fixed before removing devlink_mutex as it is safe
|
||||
* to do only because of that mutex.
|
||||
*/
|
||||
static void mlx5_eswtich_mode_callback_enter(struct devlink *devlink,
|
||||
struct mlx5_eswitch *esw)
|
||||
{
|
||||
devl_unlock(devlink);
|
||||
down_write(&esw->mode_lock);
|
||||
}
|
||||
|
||||
static void mlx5_eswtich_mode_callback_exit(struct devlink *devlink,
|
||||
struct mlx5_eswitch *esw)
|
||||
{
|
||||
up_write(&esw->mode_lock);
|
||||
devl_lock(devlink);
|
||||
}
|
||||
|
||||
int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
@ -3351,6 +3372,15 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
|
||||
if (esw_mode_from_devlink(mode, &mlx5_mode))
|
||||
return -EINVAL;
|
||||
|
||||
/* FIXME: devl_unlock() followed by devl_lock() inside driver callback
|
||||
* is never correct and prone to races. It's a transitional workaround,
|
||||
* never repeat this pattern.
|
||||
*
|
||||
* This code MUST be fixed before removing devlink_mutex as it is safe
|
||||
* to do only because of that mutex.
|
||||
*/
|
||||
devl_unlock(devlink);
|
||||
|
||||
mlx5_lag_disable_change(esw->dev);
|
||||
err = mlx5_esw_try_lock(esw);
|
||||
if (err < 0) {
|
||||
@ -3381,6 +3411,7 @@ unlock:
|
||||
mlx5_esw_unlock(esw);
|
||||
enable_lag:
|
||||
mlx5_lag_enable_change(esw->dev);
|
||||
devl_lock(devlink);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -3393,14 +3424,14 @@ int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
|
||||
if (IS_ERR(esw))
|
||||
return PTR_ERR(esw);
|
||||
|
||||
down_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_enter(devlink, esw);
|
||||
err = eswitch_devlink_esw_mode_check(esw);
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
err = esw_mode_to_devlink(esw->mode, mode);
|
||||
unlock:
|
||||
up_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_exit(devlink, esw);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -3447,7 +3478,7 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
|
||||
if (IS_ERR(esw))
|
||||
return PTR_ERR(esw);
|
||||
|
||||
down_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_enter(devlink, esw);
|
||||
err = eswitch_devlink_esw_mode_check(esw);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -3484,11 +3515,11 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
|
||||
goto out;
|
||||
|
||||
esw->offloads.inline_mode = mlx5_mode;
|
||||
up_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_exit(devlink, esw);
|
||||
return 0;
|
||||
|
||||
out:
|
||||
up_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_exit(devlink, esw);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -3501,14 +3532,14 @@ int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
|
||||
if (IS_ERR(esw))
|
||||
return PTR_ERR(esw);
|
||||
|
||||
down_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_enter(devlink, esw);
|
||||
err = eswitch_devlink_esw_mode_check(esw);
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
err = esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
|
||||
unlock:
|
||||
up_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_exit(devlink, esw);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -3524,7 +3555,7 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
|
||||
if (IS_ERR(esw))
|
||||
return PTR_ERR(esw);
|
||||
|
||||
down_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_enter(devlink, esw);
|
||||
err = eswitch_devlink_esw_mode_check(esw);
|
||||
if (err)
|
||||
goto unlock;
|
||||
@ -3570,7 +3601,7 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
|
||||
}
|
||||
|
||||
unlock:
|
||||
up_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_exit(devlink, esw);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -3584,15 +3615,14 @@ int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
|
||||
if (IS_ERR(esw))
|
||||
return PTR_ERR(esw);
|
||||
|
||||
|
||||
down_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_enter(devlink, esw);
|
||||
err = eswitch_devlink_esw_mode_check(esw);
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
*encap = esw->offloads.encap;
|
||||
unlock:
|
||||
up_write(&esw->mode_lock);
|
||||
mlx5_eswtich_mode_callback_exit(devlink, esw);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -144,13 +144,8 @@ static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nfp_pf *pf = devlink_priv(devlink);
|
||||
int ret;
|
||||
|
||||
devl_lock(devlink);
|
||||
ret = nfp_app_eswitch_mode_set(pf->app, mode);
|
||||
devl_unlock(devlink);
|
||||
|
||||
return ret;
|
||||
return nfp_app_eswitch_mode_set(pf->app, mode);
|
||||
}
|
||||
|
||||
static const struct nfp_devlink_versions_simple {
|
||||
|
@ -615,22 +615,16 @@ static int nsim_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nsim_dev *nsim_dev = devlink_priv(devlink);
|
||||
int err = 0;
|
||||
|
||||
devl_lock(devlink);
|
||||
if (mode == nsim_dev->esw_mode)
|
||||
goto unlock;
|
||||
return 0;
|
||||
|
||||
if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
|
||||
err = nsim_esw_legacy_enable(nsim_dev, extack);
|
||||
else if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
|
||||
err = nsim_esw_switchdev_enable(nsim_dev, extack);
|
||||
else
|
||||
err = -EINVAL;
|
||||
return nsim_esw_legacy_enable(nsim_dev, extack);
|
||||
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
|
||||
return nsim_esw_switchdev_enable(nsim_dev, extack);
|
||||
|
||||
unlock:
|
||||
devl_unlock(devlink);
|
||||
return err;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int nsim_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
|
||||
|
@ -2868,15 +2868,11 @@ static int devlink_rate_nodes_check(struct devlink *devlink, u16 mode,
|
||||
{
|
||||
struct devlink_rate *devlink_rate;
|
||||
|
||||
/* Take the lock to sync with destroy */
|
||||
mutex_lock(&devlink->lock);
|
||||
list_for_each_entry(devlink_rate, &devlink->rate_list, list)
|
||||
if (devlink_rate_is_node(devlink_rate)) {
|
||||
mutex_unlock(&devlink->lock);
|
||||
NL_SET_ERR_MSG_MOD(extack, "Rate node(s) exists.");
|
||||
return -EBUSY;
|
||||
}
|
||||
mutex_unlock(&devlink->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -8735,14 +8731,12 @@ static const struct genl_small_ops devlink_nl_ops[] = {
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = devlink_nl_cmd_eswitch_get_doit,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
|
||||
},
|
||||
{
|
||||
.cmd = DEVLINK_CMD_ESWITCH_SET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = devlink_nl_cmd_eswitch_set_doit,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
|
||||
},
|
||||
{
|
||||
.cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
|
||||
|
Loading…
Reference in New Issue
Block a user