devlink reload simplification
Subsystems (12)
v2 cover devlink reload simplification
From: Leon Romanovsky <[email protected]>
Changelog:
v2:
* Dropped const removal patch
* Added new patch to hide struct devlink
* Added new patch to annotate devlink API
* Implemented copy of all callback in devlink ops
v1: https://lore.kernel.org/all/[email protected]
* Missed removal of extra WARN_ON
* Added "ops parameter to macro as Dan suggested.
v0: https://lore.kernel.org/all/[email protected]
-------------------------------------------------------------------
Hi,
This series fixes the bug with mlx5 device, which in some configurations doesn't support devlink reload and shouldn't have any reload statistics like any other net device. Unfortunately, it is not the case in the current implementation of devlink reload.
This fix is done by simplification of internal API.
Thanks
Leon Romanovsky (5):
devlink: Reduce struct devlink exposure
devlink: Annotate devlink API calls
devlink: Allow set specific ops callbacks dynamically net/mlx5: Register separate reload devlink ops for multiport device
devlink: Delete reload enable/disable interface
.../hisilicon/hns3/hns3pf/hclge_devlink.c | 3 - .../hisilicon/hns3/hns3vf/hclgevf_devlink.c | 3 - drivers/net/ethernet/mellanox/mlx4/main.c | 2 - .../net/ethernet/mellanox/mlx5/core/devlink.c | 13 +- .../net/ethernet/mellanox/mlx5/core/main.c | 3 - .../mellanox/mlx5/core/sf/dev/driver.c | 5 +- drivers/net/ethernet/mellanox/mlxfw/mlxfw.h | 2 +- drivers/net/ethernet/mellanox/mlxsw/core.c | 10 +- drivers/net/netdevsim/dev.c | 3 - include/net/devlink.h | 57 +-- include/trace/events/devlink.h | 72 ++-- net/core/devlink.c | 390 ++++++++++++------ 12 files changed, 317 insertions(+), 246 deletions(-)
Signature · 1 line
2.31.1
PATCH v2 1/5 devlink: Reduce struct devlink exposure
From: Leon Romanovsky <[email protected]>
The declaration of struct devlink in general header provokes the situation where internal fields can be accidentally used by the driver authors. In order to reduce such possible situations, let's reduce the namespace exposure of struct devlink.
--- drivers/net/ethernet/mellanox/mlxfw/mlxfw.h | 2 +- include/net/devlink.h | 54 ++-------------- include/trace/events/devlink.h | 72 ++++++++++----------- net/core/devlink.c | 59 +++++++++++++++++ 4 files changed, 100 insertions(+), 87 deletions(-)
drivers/net/ethernet/mellanox/mlxfw/mlxfw.h +1 -1
@@ -19,7 +19,7 @@ struct mlxfw_dev {static inline struct device *mlxfw_dev_dev (struct mlxfw_dev *mlxfw_dev) { -return mlxfw_dev->devlink->dev; +return devlink_to_dev (mlxfw_dev->devlink); }#define MLXFW_PRFX "mlxfw: "
include/net/devlink.h +4 -50
66 lines not on this page · raw message
include/trace/events/devlink.h +36 -36
141 lines not on this page · raw message
net/core/devlink.c +59 -0
65 lines not on this page · raw message
Signature · 1 line
2.31.1
PATCH v2 3/5 devlink: Allow set specific ops callbacks dynamically
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
Introduce new devlink call to set specific ops callback during device initialization phase after devlink_alloc() is already called.
This allows us to set specific ops based on device property which is not known at the beginning of driver initialization.
For the sake of simplicity, this API lacks any type of locking and needs to be called before devlink_register() to make sure that no parallel access to the ops is possible at this stage.
--- include/net/devlink.h | 1 + net/core/devlink.c | 270 ++++++++++++++++++++++++++++-------------- 2 files changed, 180 insertions(+), 91 deletions(-)
include/net/devlink.h +1 -0
@@ -1520,6 +1520,7 @@ static inline struct devlink *devlink_alloc(const struct devlink_ops *ops, {return devlink_alloc_ns (ops, priv_size, &init_net, dev); } +void devlink_set_ops (struct devlink *devlink,const struct devlink_ops *ops);void devlink_register (struct devlink *devlink);void devlink_unregister (struct devlink *devlink);void devlink_reload_enable (struct devlink *devlink);
net/core/devlink.c +179 -91
695 lines not on this page · raw message
Signature · 1 line
2.31.1
PATCH v2 2/5 devlink: Annotate devlink API calls
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
Initial annotation patch to separate calls that needs to be executed before or after devlink_register().
--- net/core/devlink.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
net/core/devlink.c +26 -0
@@ -154,6 +154,22 @@ static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ static DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC);#define DEVLINK_REGISTERED XA_MARK_1 +/* devlink instances are open to the access from the user space after +* devlink_register() call. Such logical barrier allows us to have certain +* expectations related to locking. +* +* Before *_register() - we are in initialization stage and no parallel +* access possible to the devlink instance. All drivers perform that phase +* by implicitly holding device_lock. +* +* After *_register() - users and driver can access devlink instance at +* the same time. +*/ +#define ASSERT_DEVLINK_REGISTERED (d) \ + WARN_ON_ONCE(!xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED)) +#define ASSERT_DEVLINK_NOT_REGISTERED (d) \ + WARN_ON_ONCE(xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED)) +/* devlink_mutex * * An overall lock guarding every operation coming from userspace.
@@ -9115,6 +9131,10 @@ static void devlink_notify_unregister(struct devlink *devlink)*/ void devlink_register (struct devlink *devlink) { +ASSERT_DEVLINK_NOT_REGISTERED (devlink); +/* Make sure that we are in .probe() routine */ +device_lock_assert (devlink->dev); +mutex_lock (&devlink_mutex);xa_set_mark (&devlinks, devlink->index,DEVLINK_REGISTERED );devlink_notify_register (devlink);
@@ -9129,6 +9149,10 @@ EXPORT_SYMBOL_GPL(devlink_register);*/ void devlink_unregister (struct devlink *devlink) { +ASSERT_DEVLINK_REGISTERED (devlink); +/* Make sure that we are in .remove() routine */ +device_lock_assert (devlink->dev); +devlink_put (devlink);wait_for_completion (&devlink->comp);
@@ -9183,6 +9207,8 @@ EXPORT_SYMBOL_GPL(devlink_reload_disable);*/ void devlink_free (struct devlink *devlink) { +ASSERT_DEVLINK_NOT_REGISTERED (devlink); +mutex_destroy (&devlink->reporters_lock);mutex_destroy (&devlink->lock);WARN_ON (!list_empty (&devlink->trap_policer_list));
Signature · 1 line
2.31.1
PATCH v2 5/5 devlink: Delete reload enable/disable interface
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
After changes to allow dynamically set the reload_up/_down callbacks, we ensure that properly supported devlink ops are not accessible before devlink_register, which is last command in the initialization sequence.
It makes devlink_reload_enable/_disable not relevant anymore and can be safely deleted.
--- .../hisilicon/hns3/hns3pf/hclge_devlink.c | 3 -- .../hisilicon/hns3/hns3vf/hclgevf_devlink.c | 3 -- drivers/net/ethernet/mellanox/mlx4/main.c | 2 - .../net/ethernet/mellanox/mlx5/core/main.c | 3 -- .../mellanox/mlx5/core/sf/dev/driver.c | 5 +-- drivers/net/ethernet/mellanox/mlxsw/core.c | 10 ++--- drivers/net/netdevsim/dev.c | 3 -- include/net/devlink.h | 2 - net/core/devlink.c | 43 +------------------ 9 files changed, 5 insertions(+), 69 deletions(-)
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c +0 -3
@@ -120,7 +120,6 @@ int hclge_devlink_init(struct hclge_dev *hdev) hdev->devlink = devlink;devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; }
@@ -128,8 +127,6 @@ void hclge_devlink_uninit(struct hclge_dev *hdev) {struct devlink *devlink = hdev->devlink; -devlink_reload_disable (devlink); -devlink_unregister (devlink);devlink_free (devlink);
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c +0 -3
@@ -122,7 +122,6 @@ int hclgevf_devlink_init(struct hclgevf_dev *hdev) hdev->devlink = devlink;devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; }
@@ -130,8 +129,6 @@ void hclgevf_devlink_uninit(struct hclgevf_dev *hdev) {struct devlink *devlink = hdev->devlink; -devlink_reload_disable (devlink); -devlink_unregister (devlink);devlink_free (devlink);
drivers/net/ethernet/mellanox/mlx4/main.c +0 -2
@@ -4026,7 +4026,6 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)pci_save_state (pdev);devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; err_params_unregister:
@@ -4135,7 +4134,6 @@ static void mlx4_remove_one(struct pci_dev *pdev)struct devlink *devlink =priv_to_devlink (priv);int active_vfs =0 ; -devlink_reload_disable (devlink);devlink_unregister (devlink);if (mlx4_is_slave (dev))
drivers/net/ethernet/mellanox/mlx5/core/main.c +0 -3
@@ -1538,8 +1538,6 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)pci_save_state (pdev);devlink_register (devlink); -if (!mlx5_core_is_mp_slave (dev)) -devlink_reload_enable (devlink);return 0 ; err_init_one:
@@ -1559,7 +1557,6 @@ static void remove_one(struct pci_dev *pdev)struct mlx5_core_dev *dev =pci_get_drvdata (pdev);struct devlink *devlink =priv_to_devlink (dev); -devlink_reload_disable (devlink);devlink_unregister (devlink);mlx5_crdump_disable (dev);mlx5_drain_health_wq (dev);
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c +1 -4
@@ -47,7 +47,6 @@ static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxilia goto init_one_err; }devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; init_one_err:
@@ -62,10 +61,8 @@ static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxiliastatic void mlx5_sf_dev_remove (struct auxiliary_device *adev) { struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); -struct devlink *devlink; +struct devlink *devlink =priv_to_devlink (sf_dev->mdev); - devlink =priv_to_devlink (sf_dev->mdev); -devlink_reload_disable (devlink);devlink_unregister (devlink);mlx5_uninit_one (sf_dev->mdev);iounmap (sf_dev->mdev->iseg);
drivers/net/ethernet/mellanox/mlxsw/core.c +3 -7
@@ -2007,11 +2007,8 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, goto err_driver_init; } -if (!reload) { +if (!reload)devlink_register (devlink); -devlink_reload_enable (devlink); - } -return 0 ; err_driver_init:
@@ -2075,10 +2072,9 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, {struct devlink *devlink =priv_to_devlink (mlxsw_core); -if (!reload) { -devlink_reload_disable (devlink); +if (!reload)devlink_unregister (devlink); - } +if (devlink_is_reload_failed (devlink)) {if (!reload)/* Only the parts that were not de-initialized in the
drivers/net/netdevsim/dev.c +0 -3
@@ -1512,7 +1512,6 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->esw_mode =DEVLINK_ESWITCH_MODE_LEGACY ;devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; err_psample_exit:
@@ -1566,9 +1565,7 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)struct nsim_dev *nsim_dev =dev_get_drvdata (&nsim_bus_dev->dev);struct devlink *devlink =priv_to_devlink (nsim_dev); -devlink_reload_disable (devlink);devlink_unregister (devlink); -nsim_dev_reload_destroy (nsim_dev);nsim_bpf_dev_exit (nsim_dev);
include/net/devlink.h +0 -2
@@ -1523,8 +1523,6 @@ static inline struct devlink *devlink_alloc(const struct devlink_ops *ops,void devlink_set_ops (struct devlink *devlink,const struct devlink_ops *ops);void devlink_register (struct devlink *devlink);void devlink_unregister (struct devlink *devlink); -void devlink_reload_enable (struct devlink *devlink); -void devlink_reload_disable (struct devlink *devlink);void devlink_free (struct devlink *devlink); int devlink_port_register(struct devlink *devlink, struct devlink_port *devlink_port,
net/core/devlink.c +1 -42
67 lines not on this page · raw message
Signature · 1 line
2.31.1
PATCH v2 4/5 net/mlx5: Register separate reload devlink ops for multiport device
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
Mulitport slave device doesn't support devlink reload, so instead of complicating initialization flow with devlink_reload_enable() which will be removed in next patch, set specialized devlink ops callbacks for reload operations.
This fixes an error when reload counters exposed (and equal zero) for the mode that is not supported at all.
--- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/devlink.c +10 -3
@@ -314,14 +314,17 @@ static const struct devlink_ops mlx5_devlink_ops = {#endif .flash_update = mlx5_devlink_flash_update, .info_get = mlx5_devlink_info_get, + .trap_init = mlx5_devlink_trap_init, + .trap_fini = mlx5_devlink_trap_fini, + .trap_action_set = mlx5_devlink_trap_action_set, +}; + +static struct devlink_ops mlx5_devlink_reload = { .reload_actions =BIT (DEVLINK_RELOAD_ACTION_DRIVER_REINIT ) |BIT (DEVLINK_RELOAD_ACTION_FW_ACTIVATE ), .reload_limits =BIT (DEVLINK_RELOAD_LIMIT_NO_RESET ), .reload_down = mlx5_devlink_reload_down, .reload_up = mlx5_devlink_reload_up, - .trap_init = mlx5_devlink_trap_init, - .trap_fini = mlx5_devlink_trap_fini, - .trap_action_set = mlx5_devlink_trap_action_set, }; void mlx5_devlink_trap_report(struct mlx5_core_dev *dev, int trap_id, struct sk_buff *skb,
@@ -796,6 +799,7 @@ static void mlx5_devlink_traps_unregister(struct devlink *devlink)int mlx5_devlink_register (struct devlink *devlink) { +struct mlx5_core_dev *dev =devlink_priv (devlink);int err; err = devlink_params_register(devlink, mlx5_devlink_params,
@@ -813,6 +817,9 @@ int mlx5_devlink_register(struct devlink *devlink)if (err) goto traps_reg_err; +if (!mlx5_core_is_mp_slave (dev)) +devlink_set_ops (devlink, &mlx5_devlink_reload); +return 0 ; traps_reg_err:
Signature · 1 line
2.31.1
Re: [PATCH net-next v2 5/5] devlink: Delete reload enable/disable interface
In reply to Leon RomanovskyQuoted 10 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
After changes to allow dynamically set the reload_up/_down callbacks, we ensure that properly supported devlink ops are not accessible before
devlink_register, which is last command in the initialization sequence.It makes devlink_reload_enable/_disable not relevant anymore and can be safely deleted.
Signed-off-by Leon Romanovsky <[email protected]>
[...]
Quoted 13 lines
drivers/net/netdevsim/dev.c +0
-1@@ -1512,7 +1512,6 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->esw_mode =DEVLINK_ESWITCH_MODE_LEGACY ;devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; err_psample_exit:
drivers/net/netdevsim/dev.c void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) · line 1571
Quoted 9 lines
drivers/net/netdevsim/dev.c +0
-2@@ -1566,9 +1565,7 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)struct nsim_dev *nsim_dev =dev_get_drvdata (&nsim_bus_dev->dev);struct devlink *devlink =priv_to_devlink (nsim_dev); -devlink_reload_disable (devlink);devlink_unregister (devlink); -nsim_dev_reload_destroy (nsim_dev);nsim_bpf_dev_exit (nsim_dev);
I didn't remember why devlink_reload_{enable,disable}() were added in the first place so it was not clear to me from the commit message why they can be removed. It is described in commit a0c76345e3d3 ("devlink:
disallow reload operation during device cleanup") with a reproducer.
Tried the reproducer with this series and I cannot reproduce the issue. Wasn't quite sure why, but it does not seem to be related to "changes to allow dynamically set the reload_up/_down callbacks", as this seems to be specific to mlx5.
IIUC, the reason that the race described in above mentioned commit can no longer happen is related to the fact that devlink_unregister() is called first in the device dismantle path, after your previous patches. Since both the reload operation and devlink_unregister() hold 'devlink_mutex', it is not possible for the reload operation to race with device dismantle.
Agree? If so, I think it would be good to explain this in the commit message unless it's clear to everyone else.
Thanks
Re: [PATCH net-next v2 5/5] devlink: Delete reload enable/disable interface
Quoted 35 lines · Ido Schimmel
Quoted 10 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
After changes to allow dynamically set the reload_up/_down callbacks, we ensure that properly supported devlink ops are not accessible before
devlink_register, which is last command in the initialization sequence.It makes devlink_reload_enable/_disable not relevant anymore and can be safely deleted.
Signed-off-by Leon Romanovsky <[email protected]>[...]
Quoted 21 lines
drivers/net/netdevsim/dev.c +0
-3@@ -1512,7 +1512,6 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->esw_mode =DEVLINK_ESWITCH_MODE_LEGACY ;devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; err_psample_exit:@@ -1566,9 +1565,7 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)struct nsim_dev *nsim_dev =dev_get_drvdata (&nsim_bus_dev->dev);struct devlink *devlink =priv_to_devlink (nsim_dev); -devlink_reload_disable (devlink);devlink_unregister (devlink); -nsim_dev_reload_destroy (nsim_dev);
Quoted 6 lines
drivers/net/netdevsim/dev.c void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) · line 1571
Quoted 1 line
drivers/net/netdevsim/dev.c +0
-0nsim_bpf_dev_exit (nsim_dev);I didn't remember why devlink_reload_{enable,disable}() were added in the first place so it was not clear to me from the commit message why they can be removed. It is described in commit
a0c76345e3d3("devlink:
disallow reload operation during device cleanup") with a reproducer.
It was added because devlink ops were accessible by the user space very early in the driver lifetime. All my latest devlink patches are the attempt to fix this arch/design/implementation issue.
Quoted 5 lines
Tried the reproducer with this series and I cannot reproduce the issue. Wasn't quite sure why, but it does not seem to be related to "changes to allow dynamically set the reload_up/_down callbacks", as this seems to be specific to mlx5.
You didn't reproduce because of my series that moved devlink_register()/devlink_unregister() to be last/first commands in .probe()/.remove() flows.
Patch to allow dynamically set ops was needed because mlx5 had logic like this:
if(something)
devlink_reload_enable()
And I needed a way to keep this if ... condition.
Quoted 10 lines
IIUC, the reason that the race described in above mentioned commit can no longer happen is related to the fact that
devlink_unregister()is called first in the device dismantle path, after your previous patches. Since both the reload operation anddevlink_unregister()hold 'devlink_mutex', it is not possible for the reload operation to race with device dismantle.Agree? If so, I think it would be good to explain this in the commit message unless it's clear to everyone else.
I don't agree for very simple reason that devlink_mutex is going to be removed very soon and it is really not a reason why devlink reload is safer now when before.
The reload can't race due to:
1. devlink_unregister(), which works as a barrier to stop accesses from the user space.
2. reference counting that ensures that all in-flight commands are counted.
3. wait_for_completion that blocks till all commands are done.
Thanks
Quoted 2 lines
Thanks
Re: [PATCH net-next v2 5/5] devlink: Delete reload enable/disable interface
Quoted 43 lines · Leon Romanovsky
Quoted 35 lines · Ido Schimmel
Quoted 10 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
After changes to allow dynamically set the reload_up/_down callbacks, we ensure that properly supported devlink ops are not accessible before
devlink_register, which is last command in the initialization sequence.It makes devlink_reload_enable/_disable not relevant anymore and can be safely deleted.
Signed-off-by Leon Romanovsky <[email protected]>[...]
Quoted 21 lines
drivers/net/netdevsim/dev.c +0
-3@@ -1512,7 +1512,6 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->esw_mode =DEVLINK_ESWITCH_MODE_LEGACY ;devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; err_psample_exit:@@ -1566,9 +1565,7 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)struct nsim_dev *nsim_dev =dev_get_drvdata (&nsim_bus_dev->dev);struct devlink *devlink =priv_to_devlink (nsim_dev); -devlink_reload_disable (devlink);devlink_unregister (devlink); -nsim_dev_reload_destroy (nsim_dev);Quoted 6 lines
drivers/net/netdevsim/dev.c void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) · line 1571
Quoted 1 line
drivers/net/netdevsim/dev.c +0
-0nsim_bpf_dev_exit (nsim_dev);I didn't remember why devlink_reload_{enable,disable}() were added in the first place so it was not clear to me from the commit message why they can be removed. It is described in commit
a0c76345e3d3("devlink:
disallow reload operation during device cleanup") with a reproducer.
Quoted 3 lines
It was added because devlink ops were accessible by the user space very early in the driver lifetime. All my latest devlink patches are the attempt to fix this
arch/design/implementationissue.
The reproducer in the commit message executed the reload after the device was fully initialized. IIRC, the problem there was that nothing prevented these two tasks from racing:
devlink dev reload netdevsim/netdevsim10
echo 10 > /sys/bus/netdevsim/del_device
The title also talks about forbidding reload during device cleanup.
Quoted 10 lines
Quoted 6 lines
Tried the reproducer with this series and I cannot reproduce the issue. Wasn't quite sure why, but it does not seem to be related to "changes to allow dynamically set the reload_up/_down callbacks", as this seems to be specific to mlx5.
You didn't reproduce because of my series that moved devlink_register()/devlink_unregister() to be last/first commands in .probe()/.remove() flows.
Agree, that is what I wrote in the next paragraph of my reply.
Quoted 23 lines
Patch to allow dynamically set ops was needed because mlx5 had logic like this:
if(something)
devlink_reload_enable()And I needed a way to keep this if ... condition.
Quoted 10 lines
IIUC, the reason that the race described in above mentioned commit can no longer happen is related to the fact that
devlink_unregister()is called first in the device dismantle path, after your previous patches. Since both the reload operation anddevlink_unregister()hold 'devlink_mutex', it is not possible for the reload operation to race with device dismantle.Agree? If so, I think it would be good to explain this in the commit message unless it's clear to everyone else.
I don't agree for very simple reason that
devlink_mutexis going to be removed very soon and it is really not a reason why devlink reload is safer now when before.
Quoted 5 lines
The reload can't race due to:
1.devlink_unregister(), which works as a barrier to stop accesses from the user space.
2. reference counting that ensures that all in-flight commands are counted.
3.wait_for_completionthat blocks till all commands are done.
So the wait_for_completion() is what prevents the race, not 'devlink_mutex' that is taken later. This needs to be explained in the commit message to make it clear why the removal is safe.
Thanks
Re: [PATCH net-next v2 5/5] devlink: Delete reload enable/disable interface
Quoted 48 lines · Ido Schimmel
Quoted 43 lines · Leon Romanovsky
Quoted 35 lines · Ido Schimmel
Quoted 10 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
After changes to allow dynamically set the reload_up/_down callbacks, we ensure that properly supported devlink ops are not accessible before
devlink_register, which is last command in the initialization sequence.It makes devlink_reload_enable/_disable not relevant anymore and can be safely deleted.
Signed-off-by Leon Romanovsky <[email protected]>[...]
Quoted 21 lines
drivers/net/netdevsim/dev.c +0
-3@@ -1512,7 +1512,6 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->esw_mode =DEVLINK_ESWITCH_MODE_LEGACY ;devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; err_psample_exit:@@ -1566,9 +1565,7 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)struct nsim_dev *nsim_dev =dev_get_drvdata (&nsim_bus_dev->dev);struct devlink *devlink =priv_to_devlink (nsim_dev); -devlink_reload_disable (devlink);devlink_unregister (devlink); -nsim_dev_reload_destroy (nsim_dev);Quoted 6 lines
drivers/net/netdevsim/dev.c void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) · line 1571
Quoted 1 line
drivers/net/netdevsim/dev.c +0
-0nsim_bpf_dev_exit (nsim_dev);I didn't remember why devlink_reload_{enable,disable}() were added in the first place so it was not clear to me from the commit message why they can be removed. It is described in commit
a0c76345e3d3("devlink:
disallow reload operation during device cleanup") with a reproducer.Quoted 3 lines
It was added because devlink ops were accessible by the user space very early in the driver lifetime. All my latest devlink patches are the attempt to fix this
arch/design/implementationissue.
Quoted 8 lines
The reproducer in the commit message executed the reload after the device was fully initialized. IIRC, the problem there was that nothing prevented these two tasks from racing:
devlink dev reload netdevsim/netdevsim10
echo 10 >/sys/bus/netdevsim/del_deviceThe title also talks about forbidding reload during device cleanup.
It is incomplete title and reproducer. In our verification, we observed more than 40 bugs related to devlink reload flows and races around it.
Quoted 43 lines
Quoted 11 lines
Quoted 7 lines
Tried the reproducer with this series and I cannot reproduce the issue. Wasn't quite sure why, but it does not seem to be related to "changes to allow dynamically set the reload_up/_down callbacks", as this seems to be specific to mlx5.
You didn't reproduce because of my series that moved devlink_register()/devlink_unregister() to be last/first commands in .probe()/.remove() flows.
Agree, that is what I wrote in the next paragraph of my reply.
Quoted 23 lines
Patch to allow dynamically set ops was needed because mlx5 had logic like this:
if(something)
devlink_reload_enable()And I needed a way to keep this if ... condition.
Quoted 10 lines
IIUC, the reason that the race described in above mentioned commit can no longer happen is related to the fact that
devlink_unregister()is called first in the device dismantle path, after your previous patches. Since both the reload operation anddevlink_unregister()hold 'devlink_mutex', it is not possible for the reload operation to race with device dismantle.Agree? If so, I think it would be good to explain this in the commit message unless it's clear to everyone else.
I don't agree for very simple reason that
devlink_mutexis going to be removed very soon and it is really not a reason why devlink reload is safer now when before.Quoted 5 lines
The reload can't race due to:
1.devlink_unregister(), which works as a barrier to stop accesses from the user space.
2. reference counting that ensures that all in-flight commands are counted.
3.wait_for_completionthat blocks till all commands are done.
Quoted 3 lines
So the
wait_for_completion()is what prevents the race, not 'devlink_mutex' that is taken later. This needs to be explained in the commit message to make it clear why the removal is safe.
Can you please suggest what exactly should I write in the commit message to make it clear?
I'm too much into this delvink stuff already and for me this patch is trivial. IMHO, that change doesn't need an explanation at all because coding pattern of refcount + wait_for_completion is pretty common in the kernel. So I think that I explained good enough: move of devlink_register/devlink_unregister obsoletes the devlink_reload_* APIs.
I have no problem to update the commit message, just help me with the message.
Thanks
Quoted 2 lines
Thanks
Jakub Kicinski
maintainerRe: [PATCH net-next v2 1/5] devlink: Reduce struct devlink exposure
In reply to Leon RomanovskyQuoted 8 lines · On Sun, 3 Oct 2021 21:12:02 +0300 Leon Romanovsky wrote:
From: Leon Romanovsky <[email protected]>
The declaration of struct devlink in general header provokes the situation where internal fields can be accidentally used by the driver authors. In order to reduce such possible situations, let's reduce the namespace exposure of struct devlink.
Signed-off-by Leon Romanovsky <[email protected]>
100% subjective but every time I decided to hide a structure definition like this I came to regret it later. The fact there is only one minor infraction in drivers poking at members seems to prove this is not in fact needed.
Jakub Kicinski
maintainerRe: [PATCH net-next v2 3/5] devlink: Allow set specific ops callbacks dynamically
In reply to Leon RomanovskyQuoted 6 lines · On Sun, 3 Oct 2021 21:12:04 +0300 Leon Romanovsky wrote:
From: Leon Romanovsky <[email protected]>
Introduce new devlink call to set specific ops callback during device initialization phase after
devlink_alloc()is already called.
Quoted 6 lines
This allows us to set specific ops based on device property which is not known at the beginning of driver initialization.
For the sake of simplicity, this API lacks any type of locking and needs to be called before
devlink_register()to make sure that no parallel access to the ops is possible at this stage.
The fact that it's not registered does not mean that the callbacks won't be invoked. Look at uses of devlink_compat_flash_update().
net/core/devlink.c struct devlink { · line 56
Quoted 10 lines
net/core/devlink.c +1
-1@@ -53,7 +53,7 @@ struct devlink {struct list_head trap_list;struct list_head trap_group_list;struct list_head trap_policer_list; -const struct devlink_ops *ops; +struct devlink_ops ops;
Security people like ops to live in read-only memory. You're making them r/w for every devlink instance now.
Quoted 79 lines
net/core/devlink.c +75
-0struct xarray snapshot_ids;struct devlink_dev_stats stats;struct device *dev; +/** +* devlink_set_ops - Set devlink ops dynamically +* +* @devlink: devlink +* @ops: devlink ops to set +* +* This interface allows us to set ops based on device property +* which is known after devlink_alloc() was already called. +* +* This call sets fields that are not initialized yet and ignores +* already set fields. +* +* It should be called before devlink_register(), so doesn't have any +* protection from concurent access. +*/ +void devlink_set_ops (struct devlink *devlink,const struct devlink_ops *ops) +{ +struct devlink_ops *dev_ops = &devlink->ops; + +WARN_ON (!devlink_reload_actions_valid (ops)); +ASSERT_DEVLINK_NOT_REGISTERED (devlink); + +#define SET_DEVICE_OP (ptr, op, name) \ + do { \ + if ((op)->name) \ + if (!((ptr)->name)) \ + (ptr)->name = (op)->name; \ + } while (0) + +/* Keep sorte alphabetically for readability */ +SET_DEVICE_OP (dev_ops, ops, eswitch_encap_mode_get); +SET_DEVICE_OP (dev_ops, ops, eswitch_encap_mode_set); +SET_DEVICE_OP (dev_ops, ops, eswitch_inline_mode_get); +SET_DEVICE_OP (dev_ops, ops, eswitch_inline_mode_set); +SET_DEVICE_OP (dev_ops, ops, eswitch_mode_get); +SET_DEVICE_OP (dev_ops, ops, eswitch_mode_set); +SET_DEVICE_OP (dev_ops, ops, flash_update); +SET_DEVICE_OP (dev_ops, ops, info_get); +SET_DEVICE_OP (dev_ops, ops, port_del); +SET_DEVICE_OP (dev_ops, ops, port_fn_state_get); +SET_DEVICE_OP (dev_ops, ops, port_fn_state_set); +SET_DEVICE_OP (dev_ops, ops, port_function_hw_addr_get); +SET_DEVICE_OP (dev_ops, ops, port_function_hw_addr_set); +SET_DEVICE_OP (dev_ops, ops, port_new); +SET_DEVICE_OP (dev_ops, ops, port_split); +SET_DEVICE_OP (dev_ops, ops, port_type_set); +SET_DEVICE_OP (dev_ops, ops, port_unsplit); +SET_DEVICE_OP (dev_ops, ops, rate_leaf_parent_set); +SET_DEVICE_OP (dev_ops, ops, rate_leaf_tx_max_set); +SET_DEVICE_OP (dev_ops, ops, rate_leaf_tx_share_set); +SET_DEVICE_OP (dev_ops, ops, rate_node_del); +SET_DEVICE_OP (dev_ops, ops, rate_node_new); +SET_DEVICE_OP (dev_ops, ops, rate_node_parent_set); +SET_DEVICE_OP (dev_ops, ops, rate_node_tx_max_set); +SET_DEVICE_OP (dev_ops, ops, rate_node_tx_share_set); +SET_DEVICE_OP (dev_ops, ops, reload_actions); +SET_DEVICE_OP (dev_ops, ops, reload_down); +SET_DEVICE_OP (dev_ops, ops, reload_limits); +SET_DEVICE_OP (dev_ops, ops, reload_up); +SET_DEVICE_OP (dev_ops, ops, sb_occ_max_clear); +SET_DEVICE_OP (dev_ops, ops, sb_occ_port_pool_get); +SET_DEVICE_OP (dev_ops, ops, sb_occ_snapshot); +SET_DEVICE_OP (dev_ops, ops, sb_occ_tc_port_bind_get); +SET_DEVICE_OP (dev_ops, ops, sb_pool_get); +SET_DEVICE_OP (dev_ops, ops, sb_pool_set); +SET_DEVICE_OP (dev_ops, ops, sb_port_pool_get); +SET_DEVICE_OP (dev_ops, ops, sb_port_pool_set); +SET_DEVICE_OP (dev_ops, ops, sb_tc_pool_bind_get); +SET_DEVICE_OP (dev_ops, ops, sb_tc_pool_bind_set); +SET_DEVICE_OP (dev_ops, ops, supported_flash_update_params); +SET_DEVICE_OP (dev_ops, ops, trap_action_set); +SET_DEVICE_OP (dev_ops, ops, trap_drop_counter_get); +SET_DEVICE_OP (dev_ops, ops, trap_fini); +SET_DEVICE_OP (dev_ops, ops, trap_group_action_set); +SET_DEVICE_OP (dev_ops, ops, trap_group_init);
net/core/devlink.c static bool devlink_reload_actions_valid(const struct devlink_ops *ops) · line 9077
Quoted 10 lines
net/core/devlink.c +10
-0+SET_DEVICE_OP (dev_ops, ops, trap_group_set); +SET_DEVICE_OP (dev_ops, ops, trap_init); +SET_DEVICE_OP (dev_ops, ops, trap_policer_counter_get); +SET_DEVICE_OP (dev_ops, ops, trap_policer_fini); +SET_DEVICE_OP (dev_ops, ops, trap_policer_init); +SET_DEVICE_OP (dev_ops, ops, trap_policer_set); + +#undef SET_DEVICE_OP +} +EXPORT_SYMBOL_GPL (devlink_set_ops);
I still don't like this. IMO using feature bits to dynamically mask-off capabilities has much better properties. We already have static caps in devlink_ops (first 3 members), we should build on top of that.
Re: [PATCH net-next v2 5/5] devlink: Delete reload enable/disable interface
In reply to Leon RomanovskyQuoted 53 lines · Leon Romanovsky
Quoted 52 lines · Ido Schimmel
Quoted 43 lines · Leon Romanovsky
Quoted 35 lines · Ido Schimmel
Quoted 10 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
After changes to allow dynamically set the reload_up/_down callbacks, we ensure that properly supported devlink ops are not accessible before
devlink_register, which is last command in the initialization sequence.It makes devlink_reload_enable/_disable not relevant anymore and can be safely deleted.
Signed-off-by Leon Romanovsky <[email protected]>[...]
Quoted 21 lines
drivers/net/netdevsim/dev.c +0
-3@@ -1512,7 +1512,6 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->esw_mode =DEVLINK_ESWITCH_MODE_LEGACY ;devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; err_psample_exit:@@ -1566,9 +1565,7 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)struct nsim_dev *nsim_dev =dev_get_drvdata (&nsim_bus_dev->dev);struct devlink *devlink =priv_to_devlink (nsim_dev); -devlink_reload_disable (devlink);devlink_unregister (devlink); -nsim_dev_reload_destroy (nsim_dev);Quoted 6 lines
drivers/net/netdevsim/dev.c void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) · line 1571
Quoted 1 line
drivers/net/netdevsim/dev.c +0
-0nsim_bpf_dev_exit (nsim_dev);I didn't remember why devlink_reload_{enable,disable}() were added in the first place so it was not clear to me from the commit message why they can be removed. It is described in commit
a0c76345e3d3("devlink:
disallow reload operation during device cleanup") with a reproducer.Quoted 3 lines
It was added because devlink ops were accessible by the user space very early in the driver lifetime. All my latest devlink patches are the attempt to fix this
arch/design/implementationissue.The reproducer in the commit message executed the reload after the device was fully initialized. IIRC, the problem there was that nothing prevented these two tasks from racing:
Quoted 6 lines
Quoted 4 lines
devlink dev reload netdevsim/netdevsim10
echo 10 >/sys/bus/netdevsim/del_deviceThe title also talks about forbidding reload during device cleanup.
It is incomplete title and reproducer.
How can the reproducer be incomplete when it reproduced the issue 100% of the time?
Quoted 2 lines
In our verification, we observed more than 40 bugs related to devlink reload flows and races around it.
I assume these bugs are related to mlx5. syzkaller is familiar with the devlink messages [1] and we are using it to fuzz over both mlxsw and netdevsim. syzbot is also fuzzing over netdevsim and I'm not aware of any open bugs.
[1] https://github.com/google/syzkaller/blob/master/sys/linux/socket_netlink_generic_devlink.txt
Quoted 51 lines
Quoted 44 lines
Quoted 4 lines
Quoted 4 lines
Quoted 8 lines
Quoted 4 lines
Tried the reproducer with this series and I cannot reproduce the issue. Wasn't quite sure why, but it does not seem to be related to "changes to allow dynamically set the reload_up/_down callbacks", as this seems to be specific to mlx5.
You didn't reproduce because of my series that moved devlink_register()/devlink_unregister() to be last/first commands in .probe()/.remove() flows.
Agree, that is what I wrote in the next paragraph of my reply.
Quoted 23 lines
Patch to allow dynamically set ops was needed because mlx5 had logic like this:
if(something)
devlink_reload_enable()And I needed a way to keep this if ... condition.
Quoted 10 lines
IIUC, the reason that the race described in above mentioned commit can no longer happen is related to the fact that
devlink_unregister()is called first in the device dismantle path, after your previous patches. Since both the reload operation anddevlink_unregister()hold 'devlink_mutex', it is not possible for the reload operation to race with device dismantle.Agree? If so, I think it would be good to explain this in the commit message unless it's clear to everyone else.
I don't agree for very simple reason that
devlink_mutexis going to be removed very soon and it is really not a reason why devlink reload is safer now when before.Quoted 5 lines
The reload can't race due to:
1.devlink_unregister(), which works as a barrier to stop accesses from the user space.
2. reference counting that ensures that all in-flight commands are counted.
3.wait_for_completionthat blocks till all commands are done.Quoted 3 lines
So the
wait_for_completion()is what prevents the race, not 'devlink_mutex' that is taken later. This needs to be explained in the commit message to make it clear why the removal is safe.Can you please suggest what exactly should I write in the commit message to make it clear?
Quoted 8 lines
I'm too much into this delvink stuff already and for me this patch is trivial. IMHO, that change doesn't need an explanation at all because coding pattern of refcount +
wait_for_completionis pretty common in the kernel. So I think that I explained good enough: move of devlink_register/devlink_unregister obsoletes the devlink_reload_* APIs.I have no problem to update the commit message, just help me with the message.
I suggest something like:
"
Commit a0c76345e3d3 ("devlink: disallow reload operation during device cleanup") added devlink_reload_{enable,disable}() APIs to prevent reload operation from racing with device probe / dismantle.
After recent changes to move devlink_register() to the end of device probe and devlink_unregister() to the beginning of device dismantle, these races can no longer happen. Reload operations will be denied if the devlink instance is unregistered and devlink_unregister() will block until all in-flight operations are done.
Therefore, remove these devlink_reload_{enable,disable}() APIs. Tested with the reproducer mentioned in cited commit.
"
Re: [PATCH net-next v2 1/5] devlink: Reduce struct devlink exposure
In reply to Jakub KicinskiQuoted 8 lines · Jakub Kicinski
Quoted 7 lines · On Sun, 3 Oct 2021 21:12:02 +0300 Leon Romanovsky wrote:
From: Leon Romanovsky <[email protected]>
The declaration of struct devlink in general header provokes the situation where internal fields can be accidentally used by the driver authors. In order to reduce such possible situations, let's reduce the namespace exposure of struct devlink.
Quoted 6 lines
Quoted 1 line
Signed-off-by Leon Romanovsky <[email protected]>100% subjective but every time I decided to hide a structure definition like this I came to regret it later. The fact there is only one minor infraction in drivers poking at members seems to prove this is not in fact needed.
Yes, it is subjective, my experience is completely opposite :). Every time the internals were exposed, they were abused.
IMHO, the one user that poked into the struct devlink internals is a pure luck together with lack of devlink adoption outside of the netdev which limited number of devlink API users. The more devlink will be used, the more creative usage will be.
For example, ionic had internal logic based on internal devlink_port state:
* c2255ff47768 ("ionic: cleanly release devlink instance")
* d7907a2b1a3b ("devlink: Remove duplicated registration check")
However, this patch was written not because of having right software abstraction, but because of the next patch, where I needed to have declaration of "struct devlink_ops" before struct devlink itself.
Without this patch, I would need to heavily reshuffle include/net/devlink.h to have structs declarations written in different order. So a lot of churn for something that needs to be fixed anyway (in my opinion).
Thanks
Re: [PATCH net-next v2 3/5] devlink: Allow set specific ops callbacks dynamically
In reply to Jakub KicinskiQuoted 10 lines · Jakub Kicinski
Quoted 9 lines · On Sun, 3 Oct 2021 21:12:04 +0300 Leon Romanovsky wrote:
From: Leon Romanovsky <[email protected]>
Introduce new devlink call to set specific ops callback during device initialization phase after
devlink_alloc()is already called.This allows us to set specific ops based on device property which is not known at the beginning of driver initialization.
Quoted 6 lines
Quoted 3 lines
For the sake of simplicity, this API lacks any type of locking and needs to be called before
devlink_register()to make sure that no parallel access to the ops is possible at this stage.The fact that it's not registered does not mean that the callbacks won't be invoked. Look at uses of
devlink_compat_flash_update().
It is impossible, devlink_register() is part of .probe() flow and if it wasn't called -> probe didn't success -> net_device doesn't exist.
We are not having net_device without "connected" device beneath, aren't we?
At least drivers that I checked are not prepared at all to handle call to devlink->ops.flash_update() if they didn't probe successfully.
Quoted 14 lines
net/core/devlink.c struct devlink { · line 56
Quoted 11 lines
net/core/devlink.c +1
-1@@ -53,7 +53,7 @@ struct devlink {struct list_head trap_list;struct list_head trap_group_list;struct list_head trap_policer_list; -const struct devlink_ops *ops; +struct devlink_ops ops;Security people like ops to live in read-only memory. You're making them r/w for every devlink instance now.
Yes, but we are explicitly copy every function pointer, which is safe.
Quoted 26 lines
Quoted 26 lines
net/core/devlink.c +21
-0struct xarray snapshot_ids;struct devlink_dev_stats stats;struct device *dev; +/** +* devlink_set_ops - Set devlink ops dynamically +* +* @devlink: devlink +* @ops: devlink ops to set +* +* This interface allows us to set ops based on device property +* which is known after devlink_alloc() was already called. +* +* This call sets fields that are not initialized yet and ignores +* already set fields. +* +* It should be called before devlink_register(), so doesn't have any +* protection from concurent access. +*/ +void devlink_set_ops (struct devlink *devlink,const struct devlink_ops *ops) +{ +struct devlink_ops *dev_ops = &devlink->ops; + +WARN_ON (!devlink_reload_actions_valid (ops)); +ASSERT_DEVLINK_NOT_REGISTERED (devlink);
<...>
Quoted 5 lines
Quoted 1 line
+EXPORT_SYMBOL_GPL(devlink_set_ops);
I still don't like this. IMO using feature bits to dynamically mask-off capabilities has much better properties. We already have static caps in
devlink_ops(first 3 members), we should build on top of that.
These capabilities are for specific operation, like flash or reload. They control how these flows will work, they don't control if this flow is valid or not.
You are too focused on reload caps, but mutliport mlx5 device doesn't support eswitch too. I just didn't remove the eswitch callbacks to stay focused on more important work - making devlink better. :)
Even if we decide to use new flag in devlink_ops, we will still need to add this devlink_set_ops() patch, because the value of that new flag will be known very late in initialization phase, after FW capabilities are known and I will need to overwrite RO memory.
Jakub,
Can we please continue with the current approach? It doesn't expose any user visible API and everything here will be easy rewrite differently if such needs arise.
We have so much ahead, like removing devlink_lock, rewriting devlink->lock, fixing devlink reload of IB part, e.t.c
Thanks
Re: [PATCH net-next v2 5/5] devlink: Delete reload enable/disable interface
In reply to Ido SchimmelQuoted 57 lines · Ido Schimmel
Quoted 56 lines · Leon Romanovsky
Quoted 55 lines · Ido Schimmel
Quoted 43 lines · Leon Romanovsky
Quoted 35 lines · Ido Schimmel
Quoted 10 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
After changes to allow dynamically set the reload_up/_down callbacks, we ensure that properly supported devlink ops are not accessible before
devlink_register, which is last command in the initialization sequence.It makes devlink_reload_enable/_disable not relevant anymore and can be safely deleted.
Signed-off-by Leon Romanovsky <[email protected]>[...]
Quoted 21 lines
drivers/net/netdevsim/dev.c +0
-3@@ -1512,7 +1512,6 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->esw_mode =DEVLINK_ESWITCH_MODE_LEGACY ;devlink_register (devlink); -devlink_reload_enable (devlink);return 0 ; err_psample_exit:@@ -1566,9 +1565,7 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)struct nsim_dev *nsim_dev =dev_get_drvdata (&nsim_bus_dev->dev);struct devlink *devlink =priv_to_devlink (nsim_dev); -devlink_reload_disable (devlink);devlink_unregister (devlink); -nsim_dev_reload_destroy (nsim_dev);Quoted 6 lines
drivers/net/netdevsim/dev.c void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) · line 1571
Quoted 1 line
drivers/net/netdevsim/dev.c +0
-0nsim_bpf_dev_exit (nsim_dev);I didn't remember why devlink_reload_{enable,disable}() were added in the first place so it was not clear to me from the commit message why they can be removed. It is described in commit
a0c76345e3d3("devlink:
disallow reload operation during device cleanup") with a reproducer.Quoted 3 lines
It was added because devlink ops were accessible by the user space very early in the driver lifetime. All my latest devlink patches are the attempt to fix this
arch/design/implementationissue.The reproducer in the commit message executed the reload after the device was fully initialized. IIRC, the problem there was that nothing prevented these two tasks from racing:
devlink dev reload netdevsim/netdevsim10
echo 10 >/sys/bus/netdevsim/del_device
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
The title also talks about forbidding reload during device cleanup.
It is incomplete title and reproducer.
How can the reproducer be incomplete when it reproduced the issue 100% of the time?
Incomplete in the sense that other reproducers exists.
Our internally famous one is module load/reload together with devlink reload. More complex includes PCI errors, health recover e.t.c.
Quoted 10 lines
Quoted 3 lines
In our verification, we observed more than 40 bugs related to devlink reload flows and races around it.
I assume these bugs are related to mlx5. syzkaller is familiar with the devlink messages [1] and we are using it to fuzz over both mlxsw and netdevsim. syzbot is also fuzzing over netdevsim and I'm not aware of any open bugs.
[1] https://github.com/google/syzkaller/blob/master/sys/linux/socket_netlink_generic_devlink.txt
We don't know what we don't know.
Quoted 74 lines
Quoted 52 lines
Quoted 45 lines
Quoted 5 lines
Quoted 5 lines
Quoted 8 lines
Quoted 4 lines
Tried the reproducer with this series and I cannot reproduce the issue. Wasn't quite sure why, but it does not seem to be related to "changes to allow dynamically set the reload_up/_down callbacks", as this seems to be specific to mlx5.
You didn't reproduce because of my series that moved devlink_register()/devlink_unregister() to be last/first commands in .probe()/.remove() flows.
Agree, that is what I wrote in the next paragraph of my reply.
Quoted 23 lines
Patch to allow dynamically set ops was needed because mlx5 had logic like this:
if(something)
devlink_reload_enable()And I needed a way to keep this if ... condition.
Quoted 10 lines
IIUC, the reason that the race described in above mentioned commit can no longer happen is related to the fact that
devlink_unregister()is called first in the device dismantle path, after your previous patches. Since both the reload operation anddevlink_unregister()hold 'devlink_mutex', it is not possible for the reload operation to race with device dismantle.Agree? If so, I think it would be good to explain this in the commit message unless it's clear to everyone else.
I don't agree for very simple reason that
devlink_mutexis going to be removed very soon and it is really not a reason why devlink reload is safer now when before.Quoted 5 lines
The reload can't race due to:
1.devlink_unregister(), which works as a barrier to stop accesses from the user space.
2. reference counting that ensures that all in-flight commands are counted.
3.wait_for_completionthat blocks till all commands are done.Quoted 3 lines
So the
wait_for_completion()is what prevents the race, not 'devlink_mutex' that is taken later. This needs to be explained in the commit message to make it clear why the removal is safe.Can you please suggest what exactly should I write in the commit message to make it clear?
Quoted 8 lines
I'm too much into this delvink stuff already and for me this patch is trivial. IMHO, that change doesn't need an explanation at all because coding pattern of refcount +
wait_for_completionis pretty common in the kernel. So I think that I explained good enough: move of devlink_register/devlink_unregister obsoletes the devlink_reload_* APIs.I have no problem to update the commit message, just help me with the message.
I suggest something like:
"
Commita0c76345e3d3("devlink: disallow reload operation during device cleanup") added devlink_reload_{enable,disable}() APIs to prevent reload operation from racing with device probe / dismantle.After recent changes to move
devlink_register()to the end of device probe anddevlink_unregister()to the beginning of device dismantle, these races can no longer happen. Reload operations will be denied if the devlink instance is unregistered anddevlink_unregister()will block until all in-flight operations are done.
Quoted 3 lines
Therefore, remove these devlink_reload_{enable,disable}() APIs. Tested with the reproducer mentioned in cited commit.
"
Sure, thanks.
Can I added your TOB to the patch?
Ido Schimmel
Tested-byRe: [PATCH net-next v2 5/5] devlink: Delete reload enable/disable interface
Quoted 1 line · Leon Romanovsky
Can I added your TOB to the patch?
Yes
Jakub Kicinski
maintainerRe: [PATCH net-next v2 3/5] devlink: Allow set specific ops callbacks dynamically
In reply to Leon RomanovskyQuoted 15 lines · On Tue, 5 Oct 2021 10:32:45 +0300 Leon Romanovsky wrote:
Quoted 14 lines · Jakub Kicinski
Quoted 12 lines · On Sun, 3 Oct 2021 21:12:04 +0300 Leon Romanovsky wrote:
From: Leon Romanovsky <[email protected]>
Introduce new devlink call to set specific ops callback during device initialization phase after
devlink_alloc()is already called.This allows us to set specific ops based on device property which is not known at the beginning of driver initialization.
For the sake of simplicity, this API lacks any type of locking and needs to be called before
devlink_register()to make sure that no parallel access to the ops is possible at this stage.
Quoted 5 lines
Quoted 2 lines
The fact that it's not registered does not mean that the callbacks won't be invoked. Look at uses of
devlink_compat_flash_update().It is impossible,
devlink_register()is part of .probe() flow and if it wasn't called -> probe didn't success ->net_devicedoesn't exist.
Are you talking about reality or the bright future brought by auxbus?
Quoted 4 lines
We are not having
net_devicewithout "connected" device beneath, aren't we?At least drivers that I checked are not prepared at all to handle call to
devlink->ops.flash_update()if they didn't probe successfully.
Last time I checked you moved the devlink_register() at the end of probe which for all no-auxbus drivers means after register_netdev().
Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
net/core/devlink.c +0
-0@@ -53,7 +53,7 @@ struct devlink {Quoted 8 lines
net/core/devlink.c struct devlink { · line 56
Quoted 5 lines
net/core/devlink.c +1
-1struct list_head trap_list;struct list_head trap_group_list;struct list_head trap_policer_list; -const struct devlink_ops *ops; +struct devlink_ops ops;Security people like ops to live in read-only memory. You're making them r/w for every devlink instance now.
Quoted 1 line
Yes, but we are explicitly copy every function pointer, which is safe.
The goal is for ops to live in pages which are mapped read-only, so that heap overflows can overwrite the pointers.
Quoted 14 lines
Quoted 9 lines
net/core/devlink.c struct devlink {
Quoted 5 lines
net/core/devlink.c +1
-0struct xarray snapshot_ids;struct devlink_dev_stats stats;struct device *dev; +EXPORT_SYMBOL_GPL (devlink_set_ops);I still don't like this. IMO using feature bits to dynamically mask-off capabilities has much better properties. We already have static caps in
devlink_ops(first 3 members), we should build on top of that.These capabilities are for specific operation, like flash or reload. They control how these flows will work, they don't control if this flow is valid or not.
Quoted 8 lines
You are too focused on reload caps, but mutliport mlx5 device doesn't support eswitch too. I just didn't remove the eswitch callbacks to stay focused on more important work - making devlink better. :)
Even if we decide to use new flag in
devlink_ops, we will still need to add thisdevlink_set_ops()patch, because the value of that new flag will be known very late in initialization phase, after FW capabilities are known and I will need to overwrite RO memory.
Yes, you can change the caps at run time, that's perfectly reasonable. You'll also be able to define more fine grained caps going forward as needed.
Quoted 8 lines
Jakub,
Can we please continue with the current approach? It doesn't expose any user visible API and everything here will be easy rewrite differently if such needs arise.
We have so much ahead, like removing
devlink_lock, rewritingdevlink->lock, fixing devlink reload of IB part,e.t.c
I don't like it. If you're feeling strongly please gather support of other developers. Right now it's my preference against yours. I don't even see you making arguments that your approach is better, just that mine is not perfect and requires some similar changes.
Re: [PATCH net-next v2 3/5] devlink: Allow set specific ops callbacks dynamically
Quoted 16 lines · Jakub Kicinski
Quoted 15 lines · On Tue, 5 Oct 2021 10:32:45 +0300 Leon Romanovsky wrote:
Quoted 14 lines · Jakub Kicinski
Quoted 12 lines · On Sun, 3 Oct 2021 21:12:04 +0300 Leon Romanovsky wrote:
From: Leon Romanovsky <[email protected]>
Introduce new devlink call to set specific ops callback during device initialization phase after
devlink_alloc()is already called.This allows us to set specific ops based on device property which is not known at the beginning of driver initialization.
For the sake of simplicity, this API lacks any type of locking and needs to be called before
devlink_register()to make sure that no parallel access to the ops is possible at this stage.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
The fact that it's not registered does not mean that the callbacks won't be invoked. Look at uses of
devlink_compat_flash_update().It is impossible,
devlink_register()is part of .probe() flow and if it wasn't called -> probe didn't success ->net_devicedoesn't exist.Are you talking about reality or the bright future brought by auxbus?
I looked on all the drivers which called to devlink_alloc() which is starting point before devlink_register(). All of them used it in the probe. My annotation patch checks that too.
So IMHO, it is reality.
Quoted 8 lines
Quoted 5 lines
We are not having
net_devicewithout "connected" device beneath, aren't we?At least drivers that I checked are not prepared at all to handle call to
devlink->ops.flash_update()if they didn't probe successfully.Last time I checked you moved the
devlink_register()at the end of probe which for all no-auxbus drivers means afterregister_netdev().
I need to add a check of if(devlink_register) inside devlink_compat_flash_update().
Quoted 19 lines
Quoted 15 lines
Quoted 14 lines
net/core/devlink.c struct devlink { · line 56
Quoted 11 lines
net/core/devlink.c +1
-1@@ -53,7 +53,7 @@ struct devlink {struct list_head trap_list;struct list_head trap_group_list;struct list_head trap_policer_list; -const struct devlink_ops *ops; +struct devlink_ops ops;Security people like ops to live in read-only memory. You're making them r/w for every devlink instance now.
Quoted 1 line
Yes, but we are explicitly copy every function pointer, which is safe.
The goal is for ops to live in pages which are mapped read-only, so that heap overflows can overwrite the pointers.
<...>
Quoted 4 lines
I don't like it. If you're feeling strongly please gather support of other developers. Right now it's my preference against yours. I don't even see you making arguments that your approach is better, just that mine is not perfect and requires some similar changes.
I have an idea of how to keep static ops and allow devlink_set_ops() like functionality.
What about if I group ops by some sort of commonalities?
In my case, it will be devlink_reload_ops, which will include reload relevant callbacks and provide devlink_set_reload_ops() wrapper to set them?
It will ensure that all pointers are const without need to have feature bits.
Thanks
Jakub Kicinski
maintainerRe: [PATCH net-next v2 3/5] devlink: Allow set specific ops callbacks dynamically
Quoted 7 lines · On Tue, 5 Oct 2021 22:15:40 +0300 Leon Romanovsky wrote:
Quoted 5 lines · Jakub Kicinski
Quoted 2 lines · On Tue, 5 Oct 2021 10:32:45 +0300 Leon Romanovsky wrote:
It is impossible,
devlink_register()is part of .probe() flow and if it wasn't called -> probe didn't success ->net_devicedoesn't exist.Are you talking about reality or the bright future brought by auxbus?
Quoted 7 lines
I looked on all the drivers which called to
devlink_alloc()which is starting point beforedevlink_register(). All of them used it in the probe. My annotation patch checks that too.So IMHO, it is reality.
You say that yet below you admit flashing is broken :/
Quoted 9 lines
Quoted 7 lines
Quoted 4 lines
We are not having
net_devicewithout "connected" device beneath, aren't we?At least drivers that I checked are not prepared at all to handle call to
devlink->ops.flash_update()if they didn't probe successfully.Last time I checked you moved the
devlink_register()at the end of probe which for all no-auxbus drivers means afterregister_netdev().I need to add a check of
if(devlink_register)insidedevlink_compat_flash_update().
... and the workarounds start to pile up.
Quoted 8 lines
Quoted 4 lines
I don't like it. If you're feeling strongly please gather support of other developers. Right now it's my preference against yours. I don't even see you making arguments that your approach is better, just that mine is not perfect and requires some similar changes.
I have an idea of how to keep static ops and allow
devlink_set_ops()like functionality.
Quoted 8 lines
What about if I group ops by some sort of commonalities?
In my case, it will be
devlink_reload_ops, which will include reload relevant callbacks and providedevlink_set_reload_ops()wrapper to set them?It will ensure that all pointers are const without need to have feature bits.
I don't understand why you keep pushing the op reassignment.
Re: [PATCH net-next v2 3/5] devlink: Allow set specific ops callbacks dynamically
Quoted 12 lines · Jakub Kicinski
Quoted 11 lines · On Tue, 5 Oct 2021 22:15:40 +0300 Leon Romanovsky wrote:
Quoted 5 lines · Jakub Kicinski
Quoted 2 lines · On Tue, 5 Oct 2021 10:32:45 +0300 Leon Romanovsky wrote:
It is impossible,
devlink_register()is part of .probe() flow and if it wasn't called -> probe didn't success ->net_devicedoesn't exist.Are you talking about reality or the bright future brought by auxbus?
I looked on all the drivers which called to
devlink_alloc()which is starting point beforedevlink_register(). All of them used it in the probe. My annotation patch checks that too.
Quoted 5 lines
Quoted 3 lines
So IMHO, it is reality.
You say that yet below you admit flashing is broken :/
I said more than once, lifetime of devlink is broken. It is placed in wrong layer, pretend to implement some of driver core functionality without proper protections and have wrong locks.
At least, I didn't break flash update, there is no change in logic of flash after any of my changes. Exactly like before, user was able to trigger flash update through this devlink_compat_flash_update() call without any protection.
Let's chose random kernel version (v5.11)
https://elixir.bootlin.com/linux/v5.11/source/net/core/devlink.c#L10245
as you can see, it doesn't hold ANY driver core locks, so it can be called in any time during driver .probe() or .remove(). Drivers that have implemented ops.flash_update() have no idea about that.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
We are not having
net_devicewithout "connected" device beneath, aren't we?At least drivers that I checked are not prepared at all to handle call to
devlink->ops.flash_update()if they didn't probe successfully.
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
Last time I checked you moved the
devlink_register()at the end of probe which for all no-auxbus drivers means afterregister_netdev().I need to add a check of
if(devlink_register)insidedevlink_compat_flash_update().... and the workarounds start to pile up.
It is not a workaround, but attempt to fix this mess.
I separated devlink netlink callers from the kernel flow and just need to continue to fix these external to devlink callers.
Quoted 11 lines
Quoted 11 lines
Quoted 5 lines
I don't like it. If you're feeling strongly please gather support of other developers. Right now it's my preference against yours. I don't even see you making arguments that your approach is better, just that mine is not perfect and requires some similar changes.
I have an idea of how to keep static ops and allow
devlink_set_ops()like functionality.What about if I group ops by some sort of commonalities?
Quoted 8 lines
Quoted 6 lines
In my case, it will be
devlink_reload_ops, which will include reload relevant callbacks and providedevlink_set_reload_ops()wrapper to set them?It will ensure that all pointers are const without need to have feature bits.
I don't understand why you keep pushing the op reassignment.
It is not reassignment, but ability to assign proper callbacks from the beginning.
The idea is to make sure that lifetime of devlink is managed by proper ops callbacks, based on them we can control everything inside devlink by ensuring right locks, order e.t.c.
I want to get rid from random *_enabled flags that always forgotten and adds complexity that don't give any advantage only issues.
I'm also changing devlink to allow parallel execution and for that I need to have reliable devlink instance with minimal number of locks.
Thanks
Jakub Kicinski
maintainerRe: [PATCH net-next v2 3/5] devlink: Allow set specific ops callbacks dynamically
Quoted 3 lines · On Wed, 6 Oct 2021 06:37:44 +0300 Leon Romanovsky wrote:
Let's chose random kernel version (v5.11)
https://elixir.bootlin.com/linux/v5.11/source/net/core/devlink.c#L10245
as you can see, it doesn't hold ANY driver core locks,
Nope, that is not what I see.
Quoted 1 line
so it can be called in any time during driver .probe() or .remove().
Having a callback invoked after registering to a subsystem (which used to be the case for devlink before the changes) is _normal_.
You keep talking about .probe() like it's some magic period of complete quiescence.
Quoted 1 line
Drivers that have implemented
ops.flash_update()have no idea about that.
I bet.
I don't think this discussion is going anywhere, count me out.
Re: [PATCH net-next v2 3/5] devlink: Allow set specific ops callbacks dynamically
Quoted 1 line · Jakub Kicinski
On Wed, 6 Oct 2021 06:37:44 +0300 Leon Romanovsky wrote:
<...>
Quoted 1 line
I don't think this discussion is going anywhere, count me out.
At least here, we agree on something.