Skip to content

Commit

Permalink
net: mana: Improve mana_set_channels() in low mem conditions
Browse files Browse the repository at this point in the history
The mana_set_channels() function requires detaching the mana
driver and reattaching it with changed channel values.
During this operation if the system is low on memory, the reattach
might fail, causing the network device being down.
To avoid this we pre-allocate buffers at the beginning of set operation,
to prevent complete network loss

Signed-off-by: Shradha Gupta <shradhagupta@linux.microsoft.com>
Reviewed-by: Gerhard Engleder <gerhard@engleder-embedded.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Link: https://patch.msgid.link/1725248734-21760-1-git-send-email-shradhagupta@linux.microsoft.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Shradha Gupta authored and Jakub Kicinski committed Sep 4, 2024
1 parent 7808012 commit 1705341
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 17 deletions.
6 changes: 3 additions & 3 deletions drivers/net/ethernet/microsoft/mana/mana_en.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ static void mana_get_rxbuf_cfg(int mtu, u32 *datasize, u32 *alloc_size,
*datasize = mtu + ETH_HLEN;
}

int mana_pre_alloc_rxbufs(struct mana_port_context *mpc, int new_mtu)
int mana_pre_alloc_rxbufs(struct mana_port_context *mpc, int new_mtu, int num_queues)
{
struct device *dev;
struct page *page;
Expand All @@ -622,7 +622,7 @@ int mana_pre_alloc_rxbufs(struct mana_port_context *mpc, int new_mtu)

dev = mpc->ac->gdma_dev->gdma_context->dev;

num_rxb = mpc->num_queues * mpc->rx_queue_size;
num_rxb = num_queues * mpc->rx_queue_size;

WARN(mpc->rxbufs_pre, "mana rxbufs_pre exists\n");
mpc->rxbufs_pre = kmalloc_array(num_rxb, sizeof(void *), GFP_KERNEL);
Expand Down Expand Up @@ -682,7 +682,7 @@ static int mana_change_mtu(struct net_device *ndev, int new_mtu)
int err;

/* Pre-allocate buffers to prevent failure in mana_attach later */
err = mana_pre_alloc_rxbufs(mpc, new_mtu);
err = mana_pre_alloc_rxbufs(mpc, new_mtu, mpc->num_queues);
if (err) {
netdev_err(ndev, "Insufficient memory for new MTU\n");
return err;
Expand Down
28 changes: 15 additions & 13 deletions drivers/net/ethernet/microsoft/mana/mana_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,27 +345,29 @@ static int mana_set_channels(struct net_device *ndev,
struct mana_port_context *apc = netdev_priv(ndev);
unsigned int new_count = channels->combined_count;
unsigned int old_count = apc->num_queues;
int err, err2;
int err;

err = mana_pre_alloc_rxbufs(apc, ndev->mtu, new_count);
if (err) {
netdev_err(ndev, "Insufficient memory for new allocations");
return err;
}

err = mana_detach(ndev, false);
if (err) {
netdev_err(ndev, "mana_detach failed: %d\n", err);
return err;
goto out;
}

apc->num_queues = new_count;
err = mana_attach(ndev);
if (!err)
return 0;

netdev_err(ndev, "mana_attach failed: %d\n", err);

/* Try to roll it back to the old configuration. */
apc->num_queues = old_count;
err2 = mana_attach(ndev);
if (err2)
netdev_err(ndev, "mana re-attach failed: %d\n", err2);
if (err) {
apc->num_queues = old_count;
netdev_err(ndev, "mana_attach failed: %d\n", err);
}

out:
mana_pre_dealloc_rxbufs(apc);
return err;
}

Expand Down Expand Up @@ -414,7 +416,7 @@ static int mana_set_ringparam(struct net_device *ndev,

/* pre-allocating new buffers to prevent failures in mana_attach() later */
apc->rx_queue_size = new_rx;
err = mana_pre_alloc_rxbufs(apc, ndev->mtu);
err = mana_pre_alloc_rxbufs(apc, ndev->mtu, apc->num_queues);
apc->rx_queue_size = old_rx;
if (err) {
netdev_err(ndev, "Insufficient memory for new allocations\n");
Expand Down
2 changes: 1 addition & 1 deletion include/net/mana/mana.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ struct bpf_prog *mana_xdp_get(struct mana_port_context *apc);
void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog);
int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf);
void mana_query_gf_stats(struct mana_port_context *apc);
int mana_pre_alloc_rxbufs(struct mana_port_context *apc, int mtu);
int mana_pre_alloc_rxbufs(struct mana_port_context *apc, int mtu, int num_queues);
void mana_pre_dealloc_rxbufs(struct mana_port_context *apc);

extern const struct ethtool_ops mana_ethtool_ops;
Expand Down

0 comments on commit 1705341

Please sign in to comment.