net/virtio: fix socket nonblocking mode affects initialization

Message ID 20220617024229.706826-1-yuanx.wang@intel.com (mailing list archive)
State Accepted, archived
Delegated to: Maxime Coquelin
Headers
Series net/virtio: fix socket nonblocking mode affects initialization |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/iol-mellanox-Performance success Performance Testing PASS
ci/Intel-compilation success Compilation OK
ci/iol-aarch64-unit-testing success Testing PASS
ci/iol-aarch64-compile-testing success Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-x86_64-unit-testing success Testing PASS
ci/iol-x86_64-compile-testing success Testing PASS
ci/github-robot: build success github build: passed
ci/intel-Testing success Testing PASS
ci/iol-abi-testing success Testing PASS

Commit Message

Wang, YuanX June 17, 2022, 2:42 a.m. UTC
  The virtio-user initialization requires unix socket to receive backend
messages in block mode. However, vhost_user_update_link_state() sets
the same socket to nonblocking via fcntl, which affects all threads.
Enabling the rxq interrupt can causes both of these behaviors to occur
concurrently, with the result that the initialization may fail
because no messages are received in nonblocking socket.

Thread 1:
virtio_init_device()
--> virtio_user_start_device()
	--> vhost_user_set_memory_table()
		--> vhost_user_check_reply_ack()

Thread 2:
virtio_interrupt_handler()
--> vhost_user_update_link_state()

Fix that by replacing O_NONBLOCK with the recv per-call option
MSG_DONTWAIT.

Fixes: ef53b6030039 ("net/virtio-user: support LSC")
Cc: stable@dpdk.org

Signed-off-by: Yuan Wang <yuanx.wang@intel.com>
---
 drivers/net/virtio/virtio_user/vhost_user.c | 15 +--------------
 1 file changed, 1 insertion(+), 14 deletions(-)
  

Comments

Stephen Hemminger June 17, 2022, 3:05 a.m. UTC | #1
On Fri, 17 Jun 2022 10:42:29 +0800
Yuan Wang <yuanx.wang@intel.com> wrote:

> The virtio-user initialization requires unix socket to receive backend
> messages in block mode. However, vhost_user_update_link_state() sets
> the same socket to nonblocking via fcntl, which affects all threads.
> Enabling the rxq interrupt can causes both of these behaviors to occur
> concurrently, with the result that the initialization may fail
> because no messages are received in nonblocking socket.
> 
> Thread 1:
> virtio_init_device()
> --> virtio_user_start_device()
> 	--> vhost_user_set_memory_table()
> 		--> vhost_user_check_reply_ack()  
> 
> Thread 2:
> virtio_interrupt_handler()
> --> vhost_user_update_link_state()  
> 
> Fix that by replacing O_NONBLOCK with the recv per-call option
> MSG_DONTWAIT.
> 
> Fixes: ef53b6030039 ("net/virtio-user: support LSC")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Yuan Wang <yuanx.wang@intel.com>

Looks good and saves a few system calls.

Acked-by: Stephen Hemminger <stephen@networkplumber.org>
  
Chenbo Xia July 1, 2022, 10:11 a.m. UTC | #2
> -----Original Message-----
> From: Wang, YuanX <yuanx.wang@intel.com>
> Sent: Friday, June 17, 2022 10:42 AM
> To: maxime.coquelin@redhat.com; Xia, Chenbo <chenbo.xia@intel.com>;
> dev@dpdk.org
> Cc: Hu, Jiayu <jiayu.hu@intel.com>; He, Xingguang <xingguang.he@intel.com>;
> Wang, YuanX <yuanx.wang@intel.com>; stable@dpdk.org
> Subject: [PATCH] net/virtio: fix socket nonblocking mode affects
> initialization
> 
> The virtio-user initialization requires unix socket to receive backend
> messages in block mode. However, vhost_user_update_link_state() sets
> the same socket to nonblocking via fcntl, which affects all threads.
> Enabling the rxq interrupt can causes both of these behaviors to occur
> concurrently, with the result that the initialization may fail
> because no messages are received in nonblocking socket.
> 
> Thread 1:
> virtio_init_device()
> --> virtio_user_start_device()
> 	--> vhost_user_set_memory_table()
> 		--> vhost_user_check_reply_ack()
> 
> Thread 2:
> virtio_interrupt_handler()
> --> vhost_user_update_link_state()
> 
> Fix that by replacing O_NONBLOCK with the recv per-call option
> MSG_DONTWAIT.
> 
> Fixes: ef53b6030039 ("net/virtio-user: support LSC")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Yuan Wang <yuanx.wang@intel.com>
> ---
>  drivers/net/virtio/virtio_user/vhost_user.c | 15 +--------------
>  1 file changed, 1 insertion(+), 14 deletions(-)
> 
> diff --git a/drivers/net/virtio/virtio_user/vhost_user.c
> b/drivers/net/virtio/virtio_user/vhost_user.c
> index 7d1749114d..198bd63d3c 100644
> --- a/drivers/net/virtio/virtio_user/vhost_user.c
> +++ b/drivers/net/virtio/virtio_user/vhost_user.c
> @@ -940,15 +940,8 @@ vhost_user_update_link_state(struct virtio_user_dev
> *dev)
> 
>  	if (data->vhostfd >= 0) {
>  		int r;
> -		int flags;
> 
> -		flags = fcntl(data->vhostfd, F_GETFL);
> -		if (fcntl(data->vhostfd, F_SETFL, flags | O_NONBLOCK) == -1) {
> -			PMD_DRV_LOG(ERR, "error setting O_NONBLOCK flag");
> -			return -1;
> -		}
> -
> -		r = recv(data->vhostfd, buf, 128, MSG_PEEK);
> +		r = recv(data->vhostfd, buf, 128, MSG_PEEK | MSG_DONTWAIT);
>  		if (r == 0 || (r < 0 && errno != EAGAIN)) {
>  			dev->net_status &= (~VIRTIO_NET_S_LINK_UP);
>  			PMD_DRV_LOG(ERR, "virtio-user port %u is down", dev-
> >hw.port_id);
> @@ -963,12 +956,6 @@ vhost_user_update_link_state(struct virtio_user_dev
> *dev)
>  		} else {
>  			dev->net_status |= VIRTIO_NET_S_LINK_UP;
>  		}
> -
> -		if (fcntl(data->vhostfd, F_SETFL,
> -					flags & ~O_NONBLOCK) == -1) {
> -			PMD_DRV_LOG(ERR, "error clearing O_NONBLOCK flag");
> -			return -1;
> -		}
>  	} else if (dev->is_server) {
>  		dev->net_status &= (~VIRTIO_NET_S_LINK_UP);
>  		if (virtio_user_dev_server_reconnect(dev) >= 0)
> --
> 2.25.1

Reviewed-by: Chenbo Xia <chenbo.xia@intel.com>
  
Maxime Coquelin July 1, 2022, 1:53 p.m. UTC | #3
On 6/17/22 04:42, Yuan Wang wrote:
> The virtio-user initialization requires unix socket to receive backend
> messages in block mode. However, vhost_user_update_link_state() sets
> the same socket to nonblocking via fcntl, which affects all threads.
> Enabling the rxq interrupt can causes both of these behaviors to occur
> concurrently, with the result that the initialization may fail
> because no messages are received in nonblocking socket.
> 
> Thread 1:
> virtio_init_device()
> --> virtio_user_start_device()
> 	--> vhost_user_set_memory_table()
> 		--> vhost_user_check_reply_ack()
> 
> Thread 2:
> virtio_interrupt_handler()
> --> vhost_user_update_link_state()
> 
> Fix that by replacing O_NONBLOCK with the recv per-call option
> MSG_DONTWAIT.
> 
> Fixes: ef53b6030039 ("net/virtio-user: support LSC")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Yuan Wang <yuanx.wang@intel.com>
> ---
>   drivers/net/virtio/virtio_user/vhost_user.c | 15 +--------------
>   1 file changed, 1 insertion(+), 14 deletions(-)
> 

Applied to dpdk-next-virtio/main.

Thanks,
Maxime
  

Patch

diff --git a/drivers/net/virtio/virtio_user/vhost_user.c b/drivers/net/virtio/virtio_user/vhost_user.c
index 7d1749114d..198bd63d3c 100644
--- a/drivers/net/virtio/virtio_user/vhost_user.c
+++ b/drivers/net/virtio/virtio_user/vhost_user.c
@@ -940,15 +940,8 @@  vhost_user_update_link_state(struct virtio_user_dev *dev)
 
 	if (data->vhostfd >= 0) {
 		int r;
-		int flags;
 
-		flags = fcntl(data->vhostfd, F_GETFL);
-		if (fcntl(data->vhostfd, F_SETFL, flags | O_NONBLOCK) == -1) {
-			PMD_DRV_LOG(ERR, "error setting O_NONBLOCK flag");
-			return -1;
-		}
-
-		r = recv(data->vhostfd, buf, 128, MSG_PEEK);
+		r = recv(data->vhostfd, buf, 128, MSG_PEEK | MSG_DONTWAIT);
 		if (r == 0 || (r < 0 && errno != EAGAIN)) {
 			dev->net_status &= (~VIRTIO_NET_S_LINK_UP);
 			PMD_DRV_LOG(ERR, "virtio-user port %u is down", dev->hw.port_id);
@@ -963,12 +956,6 @@  vhost_user_update_link_state(struct virtio_user_dev *dev)
 		} else {
 			dev->net_status |= VIRTIO_NET_S_LINK_UP;
 		}
-
-		if (fcntl(data->vhostfd, F_SETFL,
-					flags & ~O_NONBLOCK) == -1) {
-			PMD_DRV_LOG(ERR, "error clearing O_NONBLOCK flag");
-			return -1;
-		}
 	} else if (dev->is_server) {
 		dev->net_status &= (~VIRTIO_NET_S_LINK_UP);
 		if (virtio_user_dev_server_reconnect(dev) >= 0)