Skip to content

Commit ee1439c

Browse files
Heng QiNipaLocal
Heng Qi
authored and
NipaLocal
committed
Revert "virtio_net: Add a lock for per queue RX coalesce"
This reverts commit 4d4ac2e. When the following snippet is run, lockdep will report a deadlock[1]. /* Acquire all queues dim_locks */ for (i = 0; i < vi->max_queue_pairs; i++) mutex_lock(&vi->rq[i].dim_lock); There's no deadlock here because the vq locks are always taken in the same order, but lockdep can not figure it out, and we can not make each lock a separate class because there can be more than MAX_LOCKDEP_SUBCLASSES of vqs. However, dropping the lock is harmless: 1. If dim is enabled, modifications made by dim worker to coalescing params may cause the user's query results to be dirty data. 2. In scenarios (a) and (b), a spurious dim worker is scheduled, but this can be handled correctly: (a) 1. dim is on 2. net_dim call schedules a worker 3. dim is turning off 4. The worker checks that dim is off and then exits after restoring dim's state. 5. The worker will not be scheduled until the next time dim is on. (b) 1. dim is on 2. net_dim call schedules a worker 3. The worker checks that dim is on and keeps going 4. dim is turning off 5. The worker successfully configure this parameter to the device. 6. The worker will not be scheduled until the next time dim is on. [1] ======================================================== WARNING: possible recursive locking detected 6.9.0-rc7+ torvalds#319 Not tainted -------------------------------------------- ethtool/962 is trying to acquire lock: but task is already holding lock: other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&vi->rq[i].dim_lock); lock(&vi->rq[i].dim_lock); *** DEADLOCK *** May be due to missing lock nesting notation 3 locks held by ethtool/962: #0: ffffffff82dbaab0 (cb_lock){++++}-{3:3}, at: genl_rcv+0x19/0x40 #1: ffffffff82dad0a8 (rtnl_mutex){+.+.}-{3:3}, at: ethnl_default_set_doit+0xbe/0x1e0 stack backtrace: CPU: 6 PID: 962 Comm: ethtool Not tainted 6.9.0-rc7+ torvalds#319 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x79/0xb0 check_deadlock+0x130/0x220 __lock_acquire+0x861/0x990 lock_acquire.part.0+0x72/0x1d0 ? lock_acquire+0xf8/0x130 __mutex_lock+0x71/0xd50 virtnet_set_coalesce+0x151/0x190 __ethnl_set_coalesce.isra.0+0x3f8/0x4d0 ethnl_set_coalesce+0x34/0x90 ethnl_default_set_doit+0xdd/0x1e0 genl_family_rcv_msg_doit+0xdc/0x130 genl_family_rcv_msg+0x154/0x230 ? __pfx_ethnl_default_set_doit+0x10/0x10 genl_rcv_msg+0x4b/0xa0 ? __pfx_genl_rcv_msg+0x10/0x10 netlink_rcv_skb+0x5a/0x110 genl_rcv+0x28/0x40 netlink_unicast+0x1af/0x280 netlink_sendmsg+0x20e/0x460 __sys_sendto+0x1fe/0x210 ? find_held_lock+0x2b/0x80 ? do_user_addr_fault+0x3a2/0x8a0 ? __lock_release+0x5e/0x160 ? do_user_addr_fault+0x3a2/0x8a0 ? lock_release+0x72/0x140 ? do_user_addr_fault+0x3a7/0x8a0 __x64_sys_sendto+0x29/0x30 do_syscall_64+0x78/0x180 entry_SYSCALL_64_after_hwframe+0x76/0x7e Fixes: 4d4ac2e ("virtio_net: Add a lock for per queue RX coalesce") Signed-off-by: Heng Qi <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent aac9c95 commit ee1439c

File tree

1 file changed

+12
-41
lines changed

1 file changed

+12
-41
lines changed

drivers/net/virtio_net.c

+12-41
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,6 @@ struct receive_queue {
316316
/* Is dynamic interrupt moderation enabled? */
317317
bool dim_enabled;
318318

319-
/* Used to protect dim_enabled and inter_coal */
320-
struct mutex dim_lock;
321-
322319
/* Dynamic Interrupt Moderation */
323320
struct dim dim;
324321

@@ -2368,10 +2365,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
23682365
/* Out of packets? */
23692366
if (received < budget) {
23702367
napi_complete = virtqueue_napi_complete(napi, rq->vq, received);
2371-
/* Intentionally not taking dim_lock here. This may result in a
2372-
* spurious net_dim call. But if that happens virtnet_rx_dim_work
2373-
* will not act on the scheduled work.
2374-
*/
23752368
if (napi_complete && rq->dim_enabled)
23762369
virtnet_rx_dim_update(vi, rq);
23772370
}
@@ -3247,11 +3240,9 @@ static int virtnet_set_ringparam(struct net_device *dev,
32473240
return err;
32483241

32493242
/* The reason is same as the transmit virtqueue reset */
3250-
mutex_lock(&vi->rq[i].dim_lock);
32513243
err = virtnet_send_rx_ctrl_coal_vq_cmd(vi, i,
32523244
vi->intr_coal_rx.max_usecs,
32533245
vi->intr_coal_rx.max_packets);
3254-
mutex_unlock(&vi->rq[i].dim_lock);
32553246
if (err)
32563247
return err;
32573248
}
@@ -4257,7 +4248,6 @@ static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
42574248
struct virtio_net_ctrl_coal_rx *coal_rx __free(kfree) = NULL;
42584249
bool rx_ctrl_dim_on = !!ec->use_adaptive_rx_coalesce;
42594250
struct scatterlist sgs_rx;
4260-
int ret = 0;
42614251
int i;
42624252

42634253
if (rx_ctrl_dim_on && !virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
@@ -4267,22 +4257,16 @@ static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
42674257
ec->rx_max_coalesced_frames != vi->intr_coal_rx.max_packets))
42684258
return -EINVAL;
42694259

4270-
/* Acquire all queues dim_locks */
4271-
for (i = 0; i < vi->max_queue_pairs; i++)
4272-
mutex_lock(&vi->rq[i].dim_lock);
4273-
42744260
if (rx_ctrl_dim_on && !vi->rx_dim_enabled) {
42754261
vi->rx_dim_enabled = true;
42764262
for (i = 0; i < vi->max_queue_pairs; i++)
42774263
vi->rq[i].dim_enabled = true;
4278-
goto unlock;
4264+
return 0;
42794265
}
42804266

42814267
coal_rx = kzalloc(sizeof(*coal_rx), GFP_KERNEL);
4282-
if (!coal_rx) {
4283-
ret = -ENOMEM;
4284-
goto unlock;
4285-
}
4268+
if (!coal_rx)
4269+
return -ENOMEM;
42864270

42874271
if (!rx_ctrl_dim_on && vi->rx_dim_enabled) {
42884272
vi->rx_dim_enabled = false;
@@ -4300,22 +4284,17 @@ static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
43004284

43014285
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
43024286
VIRTIO_NET_CTRL_NOTF_COAL_RX_SET,
4303-
&sgs_rx)) {
4304-
ret = -EINVAL;
4305-
goto unlock;
4306-
}
4287+
&sgs_rx))
4288+
return -EINVAL;
43074289

43084290
vi->intr_coal_rx.max_usecs = ec->rx_coalesce_usecs;
43094291
vi->intr_coal_rx.max_packets = ec->rx_max_coalesced_frames;
43104292
for (i = 0; i < vi->max_queue_pairs; i++) {
43114293
vi->rq[i].intr_coal.max_usecs = ec->rx_coalesce_usecs;
43124294
vi->rq[i].intr_coal.max_packets = ec->rx_max_coalesced_frames;
43134295
}
4314-
unlock:
4315-
for (i = vi->max_queue_pairs - 1; i >= 0; i--)
4316-
mutex_unlock(&vi->rq[i].dim_lock);
43174296

4318-
return ret;
4297+
return 0;
43194298
}
43204299

43214300
static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
@@ -4339,24 +4318,19 @@ static int virtnet_send_rx_notf_coal_vq_cmds(struct virtnet_info *vi,
43394318
u16 queue)
43404319
{
43414320
bool rx_ctrl_dim_on = !!ec->use_adaptive_rx_coalesce;
4321+
bool cur_rx_dim = vi->rq[queue].dim_enabled;
43424322
u32 max_usecs, max_packets;
4343-
bool cur_rx_dim;
43444323
int err;
43454324

4346-
mutex_lock(&vi->rq[queue].dim_lock);
4347-
cur_rx_dim = vi->rq[queue].dim_enabled;
43484325
max_usecs = vi->rq[queue].intr_coal.max_usecs;
43494326
max_packets = vi->rq[queue].intr_coal.max_packets;
43504327

43514328
if (rx_ctrl_dim_on && (ec->rx_coalesce_usecs != max_usecs ||
4352-
ec->rx_max_coalesced_frames != max_packets)) {
4353-
mutex_unlock(&vi->rq[queue].dim_lock);
4329+
ec->rx_max_coalesced_frames != max_packets))
43544330
return -EINVAL;
4355-
}
43564331

43574332
if (rx_ctrl_dim_on && !cur_rx_dim) {
43584333
vi->rq[queue].dim_enabled = true;
4359-
mutex_unlock(&vi->rq[queue].dim_lock);
43604334
return 0;
43614335
}
43624336

@@ -4369,8 +4343,10 @@ static int virtnet_send_rx_notf_coal_vq_cmds(struct virtnet_info *vi,
43694343
err = virtnet_send_rx_ctrl_coal_vq_cmd(vi, queue,
43704344
ec->rx_coalesce_usecs,
43714345
ec->rx_max_coalesced_frames);
4372-
mutex_unlock(&vi->rq[queue].dim_lock);
4373-
return err;
4346+
if (err)
4347+
return err;
4348+
4349+
return 0;
43744350
}
43754351

43764352
static int virtnet_send_notf_coal_vq_cmds(struct virtnet_info *vi,
@@ -4404,7 +4380,6 @@ static void virtnet_rx_dim_work(struct work_struct *work)
44044380

44054381
qnum = rq - vi->rq;
44064382

4407-
mutex_lock(&rq->dim_lock);
44084383
if (!rq->dim_enabled)
44094384
goto out;
44104385

@@ -4420,7 +4395,6 @@ static void virtnet_rx_dim_work(struct work_struct *work)
44204395
}
44214396
out:
44224397
dim->state = DIM_START_MEASURE;
4423-
mutex_unlock(&rq->dim_lock);
44244398
}
44254399

44264400
static int virtnet_coal_params_supported(struct ethtool_coalesce *ec)
@@ -4558,13 +4532,11 @@ static int virtnet_get_per_queue_coalesce(struct net_device *dev,
45584532
return -EINVAL;
45594533

45604534
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL)) {
4561-
mutex_lock(&vi->rq[queue].dim_lock);
45624535
ec->rx_coalesce_usecs = vi->rq[queue].intr_coal.max_usecs;
45634536
ec->tx_coalesce_usecs = vi->sq[queue].intr_coal.max_usecs;
45644537
ec->tx_max_coalesced_frames = vi->sq[queue].intr_coal.max_packets;
45654538
ec->rx_max_coalesced_frames = vi->rq[queue].intr_coal.max_packets;
45664539
ec->use_adaptive_rx_coalesce = vi->rq[queue].dim_enabled;
4567-
mutex_unlock(&vi->rq[queue].dim_lock);
45684540
} else {
45694541
ec->rx_max_coalesced_frames = 1;
45704542

@@ -5396,7 +5368,6 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
53965368

53975369
u64_stats_init(&vi->rq[i].stats.syncp);
53985370
u64_stats_init(&vi->sq[i].stats.syncp);
5399-
mutex_init(&vi->rq[i].dim_lock);
54005371
}
54015372

54025373
return 0;

0 commit comments

Comments
 (0)