Commit f3753771 authored by Shailend Chand's avatar Shailend Chand Committed by Jakub Kicinski

gve: Alloc before freeing when changing features

Previously, existing queues were being freed before the resources for
the new queues were being allocated. This would take down the interface
if someone were to attempt to change feature flags under a resource
crunch.
Signed-off-by: default avatarShailend Chand <shailend@google.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Reviewed-by: default avatarJeroen de Borst <jeroendb@google.com>
Link: https://lore.kernel.org/r/20240122182632.1102721-7-shailend@google.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 5f08cd3d
...@@ -2069,36 +2069,37 @@ static int gve_set_features(struct net_device *netdev, ...@@ -2069,36 +2069,37 @@ static int gve_set_features(struct net_device *netdev,
netdev_features_t features) netdev_features_t features)
{ {
const netdev_features_t orig_features = netdev->features; const netdev_features_t orig_features = netdev->features;
struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
struct gve_priv *priv = netdev_priv(netdev); struct gve_priv *priv = netdev_priv(netdev);
struct gve_qpl_config new_qpl_cfg;
int err; int err;
gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
&tx_alloc_cfg, &rx_alloc_cfg);
/* qpl_cfg is not read-only, it contains a map that gets updated as
* rings are allocated, which is why we cannot use the yet unreleased
* one in priv.
*/
qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
if ((netdev->features & NETIF_F_LRO) != (features & NETIF_F_LRO)) { if ((netdev->features & NETIF_F_LRO) != (features & NETIF_F_LRO)) {
netdev->features ^= NETIF_F_LRO; netdev->features ^= NETIF_F_LRO;
if (netif_carrier_ok(netdev)) { if (netif_carrier_ok(netdev)) {
/* To make this process as simple as possible we err = gve_adjust_config(priv, &qpls_alloc_cfg,
* teardown the device, set the new configuration, &tx_alloc_cfg, &rx_alloc_cfg);
* and then bring the device up again. if (err) {
*/ /* Revert the change on error. */
err = gve_close(netdev); netdev->features = orig_features;
/* We have already tried to reset in close, just fail return err;
* at this point. }
*/
if (err)
goto err;
err = gve_open(netdev);
if (err)
goto err;
} }
} }
return 0; return 0;
err:
/* Reverts the change on error. */
netdev->features = orig_features;
netif_err(priv, drv, netdev,
"Set features failed! !!! DISABLING ALL QUEUES !!!\n");
return err;
} }
static const struct net_device_ops gve_netdev_ops = { static const struct net_device_ops gve_netdev_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment