Skip to content

Commit 9af0fea

Browse files
Jiri Pirkorleon
authored andcommitted
RDMA/core: Fix stale RoCE GIDs during netdev events at registration
RoCE GID entries become stale when netdev properties change during the IB device registration window. This is reproducible with a udev rule that sets a MAC address when a VF netdev appears: ACTION=="add", SUBSYSTEM=="net", KERNEL=="eth4", \ RUN+="/sbin/ip link set eth4 address 88:22:33:44:55:66" After VF creation, show_gids displays GIDs derived from the original random MAC rather than the configured one. The root cause is a race between netdev event processing and device registration: CPU 0 (driver) CPU 1 (udev/workqueue) ────────────── ────────────────────── ib_register_device() ib_cache_setup_one() gid_table_setup_one() _gid_table_setup_one() ← GID table allocated rdma_roce_rescan_device() ← GIDs populated with OLD MAC ip link set eth4 addr NEW_MAC NETDEV_CHANGEADDR queued netdevice_event_work_handler() ib_enum_all_roce_netdevs() ← Iterates DEVICE_REGISTERED ← Device NOT marked yet, SKIP! enable_device_and_get() xa_set_mark(DEVICE_REGISTERED) ← Too late, event was lost The netdev event handler uses ib_enum_all_roce_netdevs() which only iterates devices marked DEVICE_REGISTERED. However, this mark is set late in the registration process, after the GID cache is already populated. Events arriving in this window are silently dropped. Fix this by introducing a new xarray mark DEVICE_GID_UPDATES that is set immediately after the GID table is allocated and initialized. Use the new mark in ib_enum_all_roce_netdevs() function to iterate devices instead of DEVICE_REGISTERED. This is safe because: - After _gid_table_setup_one(), all required structures exist (port_data, immutable, cache.gid) - The GID table mutex serializes concurrent access between the initial rescan and event handlers - Event handlers correctly update stale GIDs even when racing with rescan - The mark is cleared in ib_cache_cleanup_one() before teardown This also fixes similar races for IP address events (inetaddr_event, inet6addr_event) which use the same enumeration path. Fixes: 0df91bb ("RDMA/devices: Use xarray to store the client_data") Signed-off-by: Jiri Pirko <jiri@nvidia.com> Link: https://patch.msgid.link/20260127093839.126291-1-jiri@resnulli.us Reported-by: syzbot+881d65229ca4f9ae8c84@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=881d65229ca4f9ae8c84 Signed-off-by: Leon Romanovsky <leon@kernel.org>
1 parent 16cb1a6 commit 9af0fea

3 files changed

Lines changed: 49 additions & 1 deletion

File tree

drivers/infiniband/core/cache.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,13 @@ static int gid_table_setup_one(struct ib_device *ib_dev)
926926
if (err)
927927
return err;
928928

929+
/*
930+
* Mark the device as ready for GID cache updates. This allows netdev
931+
* event handlers to update the GID cache even before the device is
932+
* fully registered.
933+
*/
934+
ib_device_enable_gid_updates(ib_dev);
935+
929936
rdma_roce_rescan_device(ib_dev);
930937

931938
return err;
@@ -1637,6 +1644,12 @@ void ib_cache_release_one(struct ib_device *device)
16371644

16381645
void ib_cache_cleanup_one(struct ib_device *device)
16391646
{
1647+
/*
1648+
* Clear the GID updates mark first to prevent event handlers from
1649+
* accessing the device while it's being torn down.
1650+
*/
1651+
ib_device_disable_gid_updates(device);
1652+
16401653
/* The cleanup function waits for all in-progress workqueue
16411654
* elements and cleans up the GID cache. This function should be
16421655
* called after the device was removed from the devices list and

drivers/infiniband/core/core_priv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter,
100100
roce_netdev_callback cb,
101101
void *cookie);
102102

103+
void ib_device_enable_gid_updates(struct ib_device *device);
104+
void ib_device_disable_gid_updates(struct ib_device *device);
105+
103106
typedef int (*nldev_callback)(struct ib_device *device,
104107
struct sk_buff *skb,
105108
struct netlink_callback *cb,

drivers/infiniband/core/device.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ static struct workqueue_struct *ib_unreg_wq;
9393
static DEFINE_XARRAY_FLAGS(devices, XA_FLAGS_ALLOC);
9494
static DECLARE_RWSEM(devices_rwsem);
9595
#define DEVICE_REGISTERED XA_MARK_1
96+
#define DEVICE_GID_UPDATES XA_MARK_2
9697

9798
static u32 highest_client_id;
9899
#define CLIENT_REGISTERED XA_MARK_1
@@ -2412,11 +2413,42 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter,
24122413
unsigned long index;
24132414

24142415
down_read(&devices_rwsem);
2415-
xa_for_each_marked (&devices, index, dev, DEVICE_REGISTERED)
2416+
xa_for_each_marked(&devices, index, dev, DEVICE_GID_UPDATES)
24162417
ib_enum_roce_netdev(dev, filter, filter_cookie, cb, cookie);
24172418
up_read(&devices_rwsem);
24182419
}
24192420

2421+
/**
2422+
* ib_device_enable_gid_updates - Mark device as ready for GID cache updates
2423+
* @device: Device to mark
2424+
*
2425+
* Called after GID table is allocated and initialized. After this mark is set,
2426+
* netdevice event handlers can update the device's GID cache. This allows
2427+
* events that arrive during device registration to be processed, avoiding
2428+
* stale GID entries when netdev properties change during the device
2429+
* registration process.
2430+
*/
2431+
void ib_device_enable_gid_updates(struct ib_device *device)
2432+
{
2433+
down_write(&devices_rwsem);
2434+
xa_set_mark(&devices, device->index, DEVICE_GID_UPDATES);
2435+
up_write(&devices_rwsem);
2436+
}
2437+
2438+
/**
2439+
* ib_device_disable_gid_updates - Clear the GID updates mark
2440+
* @device: Device to unmark
2441+
*
2442+
* Called before GID table cleanup to prevent event handlers from accessing
2443+
* the device while it's being torn down.
2444+
*/
2445+
void ib_device_disable_gid_updates(struct ib_device *device)
2446+
{
2447+
down_write(&devices_rwsem);
2448+
xa_clear_mark(&devices, device->index, DEVICE_GID_UPDATES);
2449+
up_write(&devices_rwsem);
2450+
}
2451+
24202452
/*
24212453
* ib_enum_all_devs - enumerate all ib_devices
24222454
* @cb: Callback to call for each found ib_device

0 commit comments

Comments
 (0)