| From 78c2256f773d928fdcd40665916c842cd46d08c0 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 28 Jan 2026 15:44:38 +0000 |
| Subject: net: liquidio: Initialize netdev pointer before queue setup |
| |
| From: Zilin Guan <zilin@seu.edu.cn> |
| |
| [ Upstream commit 926ede0c85e1e57c97d64d9612455267d597bb2c ] |
| |
| In setup_nic_devices(), the netdev is allocated using alloc_etherdev_mq(). |
| However, the pointer to this structure is stored in oct->props[i].netdev |
| only after the calls to netif_set_real_num_rx_queues() and |
| netif_set_real_num_tx_queues(). |
| |
| If either of these functions fails, setup_nic_devices() returns an error |
| without freeing the allocated netdev. Since oct->props[i].netdev is still |
| NULL at this point, the cleanup function liquidio_destroy_nic_device() |
| will fail to find and free the netdev, resulting in a memory leak. |
| |
| Fix this by initializing oct->props[i].netdev before calling the queue |
| setup functions. This ensures that the netdev is properly accessible for |
| cleanup in case of errors. |
| |
| Compile tested only. Issue found using a prototype static analysis tool |
| and code review. |
| |
| Fixes: c33c997346c3 ("liquidio: enhanced ethtool --set-channels feature") |
| Signed-off-by: Zilin Guan <zilin@seu.edu.cn> |
| Reviewed-by: Kory Maincent <kory.maincent@bootlin.com> |
| Link: https://patch.msgid.link/20260128154440.278369-2-zilin@seu.edu.cn |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| .../net/ethernet/cavium/liquidio/lio_main.c | 34 +++++++++---------- |
| 1 file changed, 17 insertions(+), 17 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c |
| index fd7c80edb6e8a..f27393c84ba48 100644 |
| --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c |
| +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c |
| @@ -3525,6 +3525,23 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) |
| */ |
| netdev->netdev_ops = &lionetdevops; |
| |
| + lio = GET_LIO(netdev); |
| + |
| + memset(lio, 0, sizeof(struct lio)); |
| + |
| + lio->ifidx = ifidx_or_pfnum; |
| + |
| + props = &octeon_dev->props[i]; |
| + props->gmxport = resp->cfg_info.linfo.gmxport; |
| + props->netdev = netdev; |
| + |
| + /* Point to the properties for octeon device to which this |
| + * interface belongs. |
| + */ |
| + lio->oct_dev = octeon_dev; |
| + lio->octprops = props; |
| + lio->netdev = netdev; |
| + |
| retval = netif_set_real_num_rx_queues(netdev, num_oqueues); |
| if (retval) { |
| dev_err(&octeon_dev->pci_dev->dev, |
| @@ -3541,16 +3558,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) |
| goto setup_nic_dev_free; |
| } |
| |
| - lio = GET_LIO(netdev); |
| - |
| - memset(lio, 0, sizeof(struct lio)); |
| - |
| - lio->ifidx = ifidx_or_pfnum; |
| - |
| - props = &octeon_dev->props[i]; |
| - props->gmxport = resp->cfg_info.linfo.gmxport; |
| - props->netdev = netdev; |
| - |
| lio->linfo.num_rxpciq = num_oqueues; |
| lio->linfo.num_txpciq = num_iqueues; |
| for (j = 0; j < num_oqueues; j++) { |
| @@ -3616,13 +3623,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) |
| netdev->min_mtu = LIO_MIN_MTU_SIZE; |
| netdev->max_mtu = LIO_MAX_MTU_SIZE; |
| |
| - /* Point to the properties for octeon device to which this |
| - * interface belongs. |
| - */ |
| - lio->oct_dev = octeon_dev; |
| - lio->octprops = props; |
| - lio->netdev = netdev; |
| - |
| dev_dbg(&octeon_dev->pci_dev->dev, |
| "if%d gmx: %d hw_addr: 0x%llx\n", i, |
| lio->linfo.gmxport, CVM_CAST64(lio->linfo.hw_addr)); |
| -- |
| 2.51.0 |
| |