mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-27 15:17:04 -04:00
netdev_queue_get_dma_dev() uses "compat" locking assert which wants
either the rtnl_lock or netdev instance lock. This is not right,
the callers are taking the instance lock unconditionally. All entry
points for queue config are purely instance locked.
In other words the callers use netdev_get_by_index_lock(), not
netdev_get_by_index_lock_ops_compat(). All the state we will
access is effectively instance lock protected (it's const for
devices which are not ops-locked).
Update the assert to avoid false positive warnings.
Cc: stable@vger.kernel.org
Fixes: b6c5f9454e ("io_uring/zcrx: call netdev_queue_get_dma_dev() under instance lock")
Reported-by: syzbot+a78926bdac2adb52dc0e@syzkaller.appspotmail.com
Reviewed-by: Simon Horman <horms@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://patch.msgid.link/20260806225627.3998672-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
119 lines
3.2 KiB
C
119 lines
3.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include <net/netdev_queues.h>
|
|
#include <net/netdev_rx_queue.h>
|
|
#include <net/xdp_sock_drv.h>
|
|
|
|
#include "dev.h"
|
|
|
|
static struct device *
|
|
__netdev_queue_get_dma_dev(struct net_device *dev, unsigned int idx)
|
|
{
|
|
const struct netdev_queue_mgmt_ops *queue_ops = dev->queue_mgmt_ops;
|
|
struct device *dma_dev;
|
|
|
|
if (queue_ops && queue_ops->ndo_queue_get_dma_dev)
|
|
dma_dev = queue_ops->ndo_queue_get_dma_dev(dev, idx);
|
|
else
|
|
dma_dev = dev->dev.parent;
|
|
|
|
return dma_dev && dma_dev->dma_mask ? dma_dev : NULL;
|
|
}
|
|
|
|
/**
|
|
* netdev_queue_get_dma_dev() - get dma device for zero-copy operations
|
|
* @dev: net_device
|
|
* @idx: queue index
|
|
* @type: queue type (RX or TX)
|
|
*
|
|
* Get dma device for zero-copy operations to be used for this queue. If
|
|
* the queue is an RX queue leased from a physical queue, we retrieve the
|
|
* physical queue's dma device. When the dma device is not available or
|
|
* valid, the function will return NULL.
|
|
*
|
|
* Return: Device or NULL on error
|
|
*/
|
|
struct device *netdev_queue_get_dma_dev(struct net_device *dev,
|
|
unsigned int idx,
|
|
enum netdev_queue_type type)
|
|
{
|
|
struct netdev_rx_queue *hw_rxq;
|
|
struct device *dma_dev;
|
|
|
|
netdev_assert_locked(dev);
|
|
|
|
/* Only RX side supports queue leasing today. */
|
|
if (type != NETDEV_QUEUE_TYPE_RX || !netif_rxq_is_leased(dev, idx))
|
|
return __netdev_queue_get_dma_dev(dev, idx);
|
|
if (!netif_is_queue_leasee(dev))
|
|
return NULL;
|
|
|
|
hw_rxq = __netif_get_rx_queue(dev, idx)->lease;
|
|
|
|
netdev_lock(hw_rxq->dev);
|
|
idx = get_netdev_rx_queue_index(hw_rxq);
|
|
dma_dev = __netdev_queue_get_dma_dev(hw_rxq->dev, idx);
|
|
netdev_unlock(hw_rxq->dev);
|
|
|
|
return dma_dev;
|
|
}
|
|
|
|
bool netdev_can_create_queue(const struct net_device *dev,
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
if (dev->dev.parent) {
|
|
NL_SET_ERR_MSG(extack, "Device is not a virtual device");
|
|
return false;
|
|
}
|
|
if (!dev->queue_mgmt_ops ||
|
|
!dev->queue_mgmt_ops->ndo_queue_create) {
|
|
NL_SET_ERR_MSG(extack, "Device does not support queue creation");
|
|
return false;
|
|
}
|
|
if (dev->real_num_rx_queues < 1 ||
|
|
dev->real_num_tx_queues < 1) {
|
|
NL_SET_ERR_MSG(extack, "Device must have at least one real queue");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool netdev_can_lease_queue(const struct net_device *dev,
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
if (!dev->dev.parent) {
|
|
NL_SET_ERR_MSG(extack, "Lease device is a virtual device");
|
|
return false;
|
|
}
|
|
if (!netif_device_present(dev)) {
|
|
NL_SET_ERR_MSG(extack, "Lease device has been removed from the system");
|
|
return false;
|
|
}
|
|
if (!dev->queue_mgmt_ops) {
|
|
NL_SET_ERR_MSG(extack, "Lease device does not support queue management operations");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool netdev_queue_busy(struct net_device *dev, unsigned int idx,
|
|
enum netdev_queue_type type,
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
if (xsk_get_pool_from_qid(dev, idx)) {
|
|
NL_SET_ERR_MSG(extack, "Device queue in use by AF_XDP");
|
|
return true;
|
|
}
|
|
if (type == NETDEV_QUEUE_TYPE_TX)
|
|
return false;
|
|
if (netif_rxq_is_leased(dev, idx)) {
|
|
NL_SET_ERR_MSG(extack, "Device queue in use due to queue leasing");
|
|
return true;
|
|
}
|
|
if (netif_rxq_has_mp(dev, idx)) {
|
|
NL_SET_ERR_MSG(extack, "Device queue in use by memory provider");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|