@@ -312,6 +312,9 @@ struct receive_queue {
312312 /* Is dynamic interrupt moderation enabled? */
313313 bool dim_enabled ;
314314
315+ /* Used to protect dim_enabled and inter_coal */
316+ struct mutex dim_lock ;
317+
315318 /* Dynamic Interrupt Moderation */
316319 struct dim dim ;
317320
@@ -2365,6 +2368,10 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
23652368 /* Out of packets? */
23662369 if (received < budget ) {
23672370 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+ */
23682375 if (napi_complete && rq -> dim_enabled )
23692376 virtnet_rx_dim_update (vi , rq );
23702377 }
@@ -3247,9 +3254,11 @@ static int virtnet_set_ringparam(struct net_device *dev,
32473254 return err ;
32483255
32493256 /* The reason is same as the transmit virtqueue reset */
3257+ mutex_lock (& vi -> rq [i ].dim_lock );
32503258 err = virtnet_send_rx_ctrl_coal_vq_cmd (vi , i ,
32513259 vi -> intr_coal_rx .max_usecs ,
32523260 vi -> intr_coal_rx .max_packets );
3261+ mutex_unlock (& vi -> rq [i ].dim_lock );
32533262 if (err )
32543263 return err ;
32553264 }
@@ -4255,6 +4264,7 @@ static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
42554264 struct virtio_net_ctrl_coal_rx * coal_rx __free (kfree ) = NULL ;
42564265 bool rx_ctrl_dim_on = !!ec -> use_adaptive_rx_coalesce ;
42574266 struct scatterlist sgs_rx ;
4267+ int ret = 0 ;
42584268 int i ;
42594269
42604270 if (rx_ctrl_dim_on && !virtio_has_feature (vi -> vdev , VIRTIO_NET_F_VQ_NOTF_COAL ))
@@ -4264,16 +4274,22 @@ static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
42644274 ec -> rx_max_coalesced_frames != vi -> intr_coal_rx .max_packets ))
42654275 return - EINVAL ;
42664276
4277+ /* Acquire all queues dim_locks */
4278+ for (i = 0 ; i < vi -> max_queue_pairs ; i ++ )
4279+ mutex_lock (& vi -> rq [i ].dim_lock );
4280+
42674281 if (rx_ctrl_dim_on && !vi -> rx_dim_enabled ) {
42684282 vi -> rx_dim_enabled = true;
42694283 for (i = 0 ; i < vi -> max_queue_pairs ; i ++ )
42704284 vi -> rq [i ].dim_enabled = true;
4271- return 0 ;
4285+ goto unlock ;
42724286 }
42734287
42744288 coal_rx = kzalloc (sizeof (* coal_rx ), GFP_KERNEL );
4275- if (!coal_rx )
4276- return - ENOMEM ;
4289+ if (!coal_rx ) {
4290+ ret = - ENOMEM ;
4291+ goto unlock ;
4292+ }
42774293
42784294 if (!rx_ctrl_dim_on && vi -> rx_dim_enabled ) {
42794295 vi -> rx_dim_enabled = false;
@@ -4291,17 +4307,22 @@ static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
42914307
42924308 if (!virtnet_send_command (vi , VIRTIO_NET_CTRL_NOTF_COAL ,
42934309 VIRTIO_NET_CTRL_NOTF_COAL_RX_SET ,
4294- & sgs_rx ))
4295- return - EINVAL ;
4310+ & sgs_rx )) {
4311+ ret = - EINVAL ;
4312+ goto unlock ;
4313+ }
42964314
42974315 vi -> intr_coal_rx .max_usecs = ec -> rx_coalesce_usecs ;
42984316 vi -> intr_coal_rx .max_packets = ec -> rx_max_coalesced_frames ;
42994317 for (i = 0 ; i < vi -> max_queue_pairs ; i ++ ) {
43004318 vi -> rq [i ].intr_coal .max_usecs = ec -> rx_coalesce_usecs ;
43014319 vi -> rq [i ].intr_coal .max_packets = ec -> rx_max_coalesced_frames ;
43024320 }
4321+ unlock :
4322+ for (i = vi -> max_queue_pairs - 1 ; i >= 0 ; i -- )
4323+ mutex_unlock (& vi -> rq [i ].dim_lock );
43034324
4304- return 0 ;
4325+ return ret ;
43054326}
43064327
43074328static int virtnet_send_notf_coal_cmds (struct virtnet_info * vi ,
@@ -4325,19 +4346,24 @@ static int virtnet_send_rx_notf_coal_vq_cmds(struct virtnet_info *vi,
43254346 u16 queue )
43264347{
43274348 bool rx_ctrl_dim_on = !!ec -> use_adaptive_rx_coalesce ;
4328- bool cur_rx_dim = vi -> rq [queue ].dim_enabled ;
43294349 u32 max_usecs , max_packets ;
4350+ bool cur_rx_dim ;
43304351 int err ;
43314352
4353+ mutex_lock (& vi -> rq [queue ].dim_lock );
4354+ cur_rx_dim = vi -> rq [queue ].dim_enabled ;
43324355 max_usecs = vi -> rq [queue ].intr_coal .max_usecs ;
43334356 max_packets = vi -> rq [queue ].intr_coal .max_packets ;
43344357
43354358 if (rx_ctrl_dim_on && (ec -> rx_coalesce_usecs != max_usecs ||
4336- ec -> rx_max_coalesced_frames != max_packets ))
4359+ ec -> rx_max_coalesced_frames != max_packets )) {
4360+ mutex_unlock (& vi -> rq [queue ].dim_lock );
43374361 return - EINVAL ;
4362+ }
43384363
43394364 if (rx_ctrl_dim_on && !cur_rx_dim ) {
43404365 vi -> rq [queue ].dim_enabled = true;
4366+ mutex_unlock (& vi -> rq [queue ].dim_lock );
43414367 return 0 ;
43424368 }
43434369
@@ -4350,10 +4376,8 @@ static int virtnet_send_rx_notf_coal_vq_cmds(struct virtnet_info *vi,
43504376 err = virtnet_send_rx_ctrl_coal_vq_cmd (vi , queue ,
43514377 ec -> rx_coalesce_usecs ,
43524378 ec -> rx_max_coalesced_frames );
4353- if (err )
4354- return err ;
4355-
4356- return 0 ;
4379+ mutex_unlock (& vi -> rq [queue ].dim_lock );
4380+ return err ;
43574381}
43584382
43594383static int virtnet_send_notf_coal_vq_cmds (struct virtnet_info * vi ,
@@ -4390,6 +4414,7 @@ static void virtnet_rx_dim_work(struct work_struct *work)
43904414
43914415 qnum = rq - vi -> rq ;
43924416
4417+ mutex_lock (& rq -> dim_lock );
43934418 if (!rq -> dim_enabled )
43944419 goto out ;
43954420
@@ -4405,6 +4430,7 @@ static void virtnet_rx_dim_work(struct work_struct *work)
44054430 dim -> state = DIM_START_MEASURE ;
44064431 }
44074432out :
4433+ mutex_unlock (& rq -> dim_lock );
44084434 rtnl_unlock ();
44094435}
44104436
@@ -4543,11 +4569,13 @@ static int virtnet_get_per_queue_coalesce(struct net_device *dev,
45434569 return - EINVAL ;
45444570
45454571 if (virtio_has_feature (vi -> vdev , VIRTIO_NET_F_VQ_NOTF_COAL )) {
4572+ mutex_lock (& vi -> rq [queue ].dim_lock );
45464573 ec -> rx_coalesce_usecs = vi -> rq [queue ].intr_coal .max_usecs ;
45474574 ec -> tx_coalesce_usecs = vi -> sq [queue ].intr_coal .max_usecs ;
45484575 ec -> tx_max_coalesced_frames = vi -> sq [queue ].intr_coal .max_packets ;
45494576 ec -> rx_max_coalesced_frames = vi -> rq [queue ].intr_coal .max_packets ;
45504577 ec -> use_adaptive_rx_coalesce = vi -> rq [queue ].dim_enabled ;
4578+ mutex_unlock (& vi -> rq [queue ].dim_lock );
45514579 } else {
45524580 ec -> rx_max_coalesced_frames = 1 ;
45534581
@@ -5377,6 +5405,7 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
53775405
53785406 u64_stats_init (& vi -> rq [i ].stats .syncp );
53795407 u64_stats_init (& vi -> sq [i ].stats .syncp );
5408+ mutex_init (& vi -> rq [i ].dim_lock );
53805409 }
53815410
53825411 return 0 ;
0 commit comments