[dpdk-dev] vhost: fix connect hang in client mode

Message ID 5790A5D4.1090703@samsung.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Ilya Maximets July 21, 2016, 10:37 a.m. UTC
  On 21.07.2016 13:13, Yuanhan Liu wrote:
> On Thu, Jul 21, 2016 at 12:45:32PM +0300, Ilya Maximets wrote:
>> On 21.07.2016 12:37, Yuanhan Liu wrote:
>>> On Thu, Jul 21, 2016 at 11:21:15AM +0300, Ilya Maximets wrote:
>>>> If something abnormal happened to QEMU, 'connect()' can block calling
>>>> thread (e.g. main thread of OVS) forever or for a really long time.
>>>> This can break whole application or block the reconnection thread.
>>>>
>>>> Example with OVS:
>>>>
>>>> 	ovs_rcu(urcu2)|WARN|blocked 512000 ms waiting for main to quiesce
>>>> 	(gdb) bt
>>>> 	#0  connect () from /lib64/libpthread.so.0
>>>> 	#1  vhost_user_create_client (vsocket=0xa816e0)
>>>> 	#2  rte_vhost_driver_register
>>>> 	#3  netdev_dpdk_vhost_user_construct
>>>> 	#4  netdev_open (name=0xa664b0 "vhost1")
>>>> 	[...]
>>>> 	#11 main
>>>>
>>>> Fix that by setting non-blocking mode for client sockets for connection.
>>>>
>>>> Fixes: 64ab701c3d1e ("vhost: add vhost-user client mode")
>>>
>>> Thanks for spotting and fixing yet another bug!
>>>
>>>>  
>>>> +static int
>>>> +vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
>>>
>>> I don't quite understand why this is needed: connect() with O_NONBLOCK
>>> flag set is not enough?
>>
>> There is a little issue with non-blocking connect() call. Connection
>> establishing may be started but '-1' returned with 'errno = EINPROGRESS'.
>> In this case we must wait on fd until it will be available for writing.
>> After that we need to check current status of connection using getsockopt().
>>
>> I don't sure that we're able to get such situation, but it's documented,
>> and, I think, we should handle it.
>>
>> See 'man connect' for details.
> 
> I see. Thanks.
> 
> But basically, I don't like the way of introduing yet another
> fdset here. I'm wondering we could leverage current fdset code
> to achieve that. This might need some work though.
> 
> So how about making it simple and stupid at this stage: sleep a
> while (maybe 1ms, or maybe 1s) when that happens, and give up
> when the connection is still not established?

Hmm, how about this fixup:
------------------------------------------------------------------------------
------------------------------------------------------------------------------
?

We will not check the EINPROGRESS, but subsequent 'connect()' will return
EISCONN if connection already established. getsockopt() is kept just in
case. Subsequent 'connect()' will happen on the next iteration of
reconnection cycle (1 second sleep).

Best regards, Ilya Maximets.
  

Comments

Ilya Maximets July 21, 2016, 11:14 a.m. UTC | #1
On 21.07.2016 13:37, Ilya Maximets wrote:
> 
> 
> On 21.07.2016 13:13, Yuanhan Liu wrote:
>> On Thu, Jul 21, 2016 at 12:45:32PM +0300, Ilya Maximets wrote:
>>> On 21.07.2016 12:37, Yuanhan Liu wrote:
>>>> On Thu, Jul 21, 2016 at 11:21:15AM +0300, Ilya Maximets wrote:
>>>>> If something abnormal happened to QEMU, 'connect()' can block calling
>>>>> thread (e.g. main thread of OVS) forever or for a really long time.
>>>>> This can break whole application or block the reconnection thread.
>>>>>
>>>>> Example with OVS:
>>>>>
>>>>> 	ovs_rcu(urcu2)|WARN|blocked 512000 ms waiting for main to quiesce
>>>>> 	(gdb) bt
>>>>> 	#0  connect () from /lib64/libpthread.so.0
>>>>> 	#1  vhost_user_create_client (vsocket=0xa816e0)
>>>>> 	#2  rte_vhost_driver_register
>>>>> 	#3  netdev_dpdk_vhost_user_construct
>>>>> 	#4  netdev_open (name=0xa664b0 "vhost1")
>>>>> 	[...]
>>>>> 	#11 main
>>>>>
>>>>> Fix that by setting non-blocking mode for client sockets for connection.
>>>>>
>>>>> Fixes: 64ab701c3d1e ("vhost: add vhost-user client mode")
>>>>
>>>> Thanks for spotting and fixing yet another bug!
>>>>
>>>>>  
>>>>> +static int
>>>>> +vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
>>>>
>>>> I don't quite understand why this is needed: connect() with O_NONBLOCK
>>>> flag set is not enough?
>>>
>>> There is a little issue with non-blocking connect() call. Connection
>>> establishing may be started but '-1' returned with 'errno = EINPROGRESS'.
>>> In this case we must wait on fd until it will be available for writing.
>>> After that we need to check current status of connection using getsockopt().
>>>
>>> I don't sure that we're able to get such situation, but it's documented,
>>> and, I think, we should handle it.
>>>
>>> See 'man connect' for details.
>>
>> I see. Thanks.
>>
>> But basically, I don't like the way of introduing yet another
>> fdset here. I'm wondering we could leverage current fdset code
>> to achieve that. This might need some work though.
>>
>> So how about making it simple and stupid at this stage: sleep a
>> while (maybe 1ms, or maybe 1s) when that happens, and give up
>> when the connection is still not established?
> 
> Hmm, how about this fixup:
> ------------------------------------------------------------------------------
> diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c
> index 8626d13..b0f45e6 100644
> --- a/lib/librte_vhost/vhost_user/vhost-net-user.c
> +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
> @@ -537,18 +537,7 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
>  	errno = EINVAL;
>  
>  	ret = connect(fd, un, sz);
> -	if (ret == -1 && errno != EINPROGRESS)
> -		return -1;
> -	if (ret == 0)
> -		goto connected;
> -
> -	FD_ZERO(&fdset);
> -	FD_SET(fd, &fdset);
> -
> -	ret = select(fd + 1, NULL, &fdset, NULL, &tv);
> -	if (!ret)
> -		errno = ETIMEDOUT;
> -	if (ret != 1)
> +	if (ret < 0 && errno != EISCONN)
>  		return -1;
>  
>  	ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
> @@ -558,7 +547,6 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
>  		return -1;
>  	}
>  
> -connected:
>  	flags = fcntl(fd, F_GETFL, 0);
>  	if (flags < 0) {
>  		RTE_LOG(ERR, VHOST_CONFIG,
> ------------------------------------------------------------------------------
> ?
> 
> We will not check the EINPROGRESS, but subsequent 'connect()' will return
> EISCONN if connection already established. getsockopt() is kept just in
> case. Subsequent 'connect()' will happen on the next iteration of
> reconnection cycle (1 second sleep).

I've sent v2 with this changes.

Best regards, Ilya Maximets.
  
Yuanhan Liu July 21, 2016, 11:40 a.m. UTC | #2
On Thu, Jul 21, 2016 at 02:14:59PM +0300, Ilya Maximets wrote:
> > Hmm, how about this fixup:
> > ------------------------------------------------------------------------------
> > diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c
> > index 8626d13..b0f45e6 100644
> > --- a/lib/librte_vhost/vhost_user/vhost-net-user.c
> > +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
> > @@ -537,18 +537,7 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
> >  	errno = EINVAL;
> >  
> >  	ret = connect(fd, un, sz);
> > -	if (ret == -1 && errno != EINPROGRESS)
> > -		return -1;
> > -	if (ret == 0)
> > -		goto connected;
> > -
> > -	FD_ZERO(&fdset);
> > -	FD_SET(fd, &fdset);
> > -
> > -	ret = select(fd + 1, NULL, &fdset, NULL, &tv);
> > -	if (!ret)
> > -		errno = ETIMEDOUT;
> > -	if (ret != 1)
> > +	if (ret < 0 && errno != EISCONN)
> >  		return -1;
> >  
> >  	ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
> > @@ -558,7 +547,6 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
> >  		return -1;
> >  	}
> >  
> > -connected:
> >  	flags = fcntl(fd, F_GETFL, 0);
> >  	if (flags < 0) {
> >  		RTE_LOG(ERR, VHOST_CONFIG,
> > ------------------------------------------------------------------------------
> > ?
> > 
> > We will not check the EINPROGRESS, but subsequent 'connect()' will return
> > EISCONN if connection already established. getsockopt() is kept just in
> > case. Subsequent 'connect()' will happen on the next iteration of
> > reconnection cycle (1 second sleep).
> 
> I've sent v2 with this changes.

Thanks. But still, it doesn't look clean to me. I was thinking following
might be cleaner?

    diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c
    b/lib/librte_vhost/vhost_user/vhost-net-user.
    index f0f92f8..c0ef290 100644
    --- a/lib/librte_vhost/vhost_user/vhost-net-user.c
    +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
    @@ -532,6 +532,10 @@ vhost_user_client_reconnect(void *arg __rte_unused)
                         reconn != NULL; reconn = next) {
                            next = TAILQ_NEXT(reconn, next);
    
    +                       if (reconn->conn_inprogress) {
    +                               /* do connect check here */
    +                       }
    +
                            if (connect(reconn->fd, (struct sockaddr *)&reconn->un,
                                        sizeof(reconn->un)) < 0)
                                    continue;
    @@ -605,6 +609,7 @@ vhost_user_create_client(struct vhost_user_socket *vsocket)
            reconn->un = un;
            reconn->fd = fd;
            reconn->vsocket = vsocket;
    +       reconn->conn_inprogress = errno == EINPROGRESS;
            pthread_mutex_lock(&reconn_list.mutex);
            TAILQ_INSERT_TAIL(&reconn_list.head, reconn, next);
            pthread_mutex_unlock(&reconn_list.mutex);

It's just a rough diff, hopefully it shows my idea clearly. And of
course, we should not call connect() anymore when conn_inprogress
is set.

What do you think of it?

	--yliu
  
Ilya Maximets July 21, 2016, 12:10 p.m. UTC | #3
On 21.07.2016 14:40, Yuanhan Liu wrote:
> On Thu, Jul 21, 2016 at 02:14:59PM +0300, Ilya Maximets wrote:
>>> Hmm, how about this fixup:
>>> ------------------------------------------------------------------------------
>>> diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c
>>> index 8626d13..b0f45e6 100644
>>> --- a/lib/librte_vhost/vhost_user/vhost-net-user.c
>>> +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
>>> @@ -537,18 +537,7 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
>>>  	errno = EINVAL;
>>>  
>>>  	ret = connect(fd, un, sz);
>>> -	if (ret == -1 && errno != EINPROGRESS)
>>> -		return -1;
>>> -	if (ret == 0)
>>> -		goto connected;
>>> -
>>> -	FD_ZERO(&fdset);
>>> -	FD_SET(fd, &fdset);
>>> -
>>> -	ret = select(fd + 1, NULL, &fdset, NULL, &tv);
>>> -	if (!ret)
>>> -		errno = ETIMEDOUT;
>>> -	if (ret != 1)
>>> +	if (ret < 0 && errno != EISCONN)
>>>  		return -1;
>>>  
>>>  	ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
>>> @@ -558,7 +547,6 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
>>>  		return -1;
>>>  	}
>>>  
>>> -connected:
>>>  	flags = fcntl(fd, F_GETFL, 0);
>>>  	if (flags < 0) {
>>>  		RTE_LOG(ERR, VHOST_CONFIG,
>>> ------------------------------------------------------------------------------
>>> ?
>>>
>>> We will not check the EINPROGRESS, but subsequent 'connect()' will return
>>> EISCONN if connection already established. getsockopt() is kept just in
>>> case. Subsequent 'connect()' will happen on the next iteration of
>>> reconnection cycle (1 second sleep).
>>
>> I've sent v2 with this changes.
> 
> Thanks. But still, it doesn't look clean to me. I was thinking following
> might be cleaner?
> 
>     diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c
>     b/lib/librte_vhost/vhost_user/vhost-net-user.
>     index f0f92f8..c0ef290 100644
>     --- a/lib/librte_vhost/vhost_user/vhost-net-user.c
>     +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
>     @@ -532,6 +532,10 @@ vhost_user_client_reconnect(void *arg __rte_unused)
>                          reconn != NULL; reconn = next) {
>                             next = TAILQ_NEXT(reconn, next);
>     
>     +                       if (reconn->conn_inprogress) {
>     +                               /* do connect check here */
>     +                       }
>     +
>                             if (connect(reconn->fd, (struct sockaddr *)&reconn->un,
>                                         sizeof(reconn->un)) < 0)
>                                     continue;
>     @@ -605,6 +609,7 @@ vhost_user_create_client(struct vhost_user_socket *vsocket)
>             reconn->un = un;
>             reconn->fd = fd;
>             reconn->vsocket = vsocket;
>     +       reconn->conn_inprogress = errno == EINPROGRESS;
>             pthread_mutex_lock(&reconn_list.mutex);
>             TAILQ_INSERT_TAIL(&reconn_list.head, reconn, next);
>             pthread_mutex_unlock(&reconn_list.mutex);
> 
> It's just a rough diff, hopefully it shows my idea clearly. And of
> course, we should not call connect() anymore when conn_inprogress
> is set.
> 
> What do you think of it?

I found that we can't check connection status without select/poll
on it. 'getsockopt()' will return 0 with no errors if connection
is not still established just like if it was.
So, I think, the first version of this patch is the only
acceptable solution.

Best regards, Ilya Maximets.
  
Ilya Maximets July 21, 2016, 12:13 p.m. UTC | #4
On 21.07.2016 15:10, Ilya Maximets wrote:
> On 21.07.2016 14:40, Yuanhan Liu wrote:
>> On Thu, Jul 21, 2016 at 02:14:59PM +0300, Ilya Maximets wrote:
>>>> Hmm, how about this fixup:
>>>> ------------------------------------------------------------------------------
>>>> diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c
>>>> index 8626d13..b0f45e6 100644
>>>> --- a/lib/librte_vhost/vhost_user/vhost-net-user.c
>>>> +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
>>>> @@ -537,18 +537,7 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
>>>>  	errno = EINVAL;
>>>>  
>>>>  	ret = connect(fd, un, sz);
>>>> -	if (ret == -1 && errno != EINPROGRESS)
>>>> -		return -1;
>>>> -	if (ret == 0)
>>>> -		goto connected;
>>>> -
>>>> -	FD_ZERO(&fdset);
>>>> -	FD_SET(fd, &fdset);
>>>> -
>>>> -	ret = select(fd + 1, NULL, &fdset, NULL, &tv);
>>>> -	if (!ret)
>>>> -		errno = ETIMEDOUT;
>>>> -	if (ret != 1)
>>>> +	if (ret < 0 && errno != EISCONN)
>>>>  		return -1;
>>>>  
>>>>  	ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
>>>> @@ -558,7 +547,6 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
>>>>  		return -1;
>>>>  	}
>>>>  
>>>> -connected:
>>>>  	flags = fcntl(fd, F_GETFL, 0);
>>>>  	if (flags < 0) {
>>>>  		RTE_LOG(ERR, VHOST_CONFIG,
>>>> ------------------------------------------------------------------------------
>>>> ?
>>>>
>>>> We will not check the EINPROGRESS, but subsequent 'connect()' will return
>>>> EISCONN if connection already established. getsockopt() is kept just in
>>>> case. Subsequent 'connect()' will happen on the next iteration of
>>>> reconnection cycle (1 second sleep).
>>>
>>> I've sent v2 with this changes.
>>
>> Thanks. But still, it doesn't look clean to me. I was thinking following
>> might be cleaner?
>>
>>     diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c
>>     b/lib/librte_vhost/vhost_user/vhost-net-user.
>>     index f0f92f8..c0ef290 100644
>>     --- a/lib/librte_vhost/vhost_user/vhost-net-user.c
>>     +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
>>     @@ -532,6 +532,10 @@ vhost_user_client_reconnect(void *arg __rte_unused)
>>                          reconn != NULL; reconn = next) {
>>                             next = TAILQ_NEXT(reconn, next);
>>     
>>     +                       if (reconn->conn_inprogress) {
>>     +                               /* do connect check here */
>>     +                       }
>>     +
>>                             if (connect(reconn->fd, (struct sockaddr *)&reconn->un,
>>                                         sizeof(reconn->un)) < 0)
>>                                     continue;
>>     @@ -605,6 +609,7 @@ vhost_user_create_client(struct vhost_user_socket *vsocket)
>>             reconn->un = un;
>>             reconn->fd = fd;
>>             reconn->vsocket = vsocket;
>>     +       reconn->conn_inprogress = errno == EINPROGRESS;
>>             pthread_mutex_lock(&reconn_list.mutex);
>>             TAILQ_INSERT_TAIL(&reconn_list.head, reconn, next);
>>             pthread_mutex_unlock(&reconn_list.mutex);
>>
>> It's just a rough diff, hopefully it shows my idea clearly. And of
>> course, we should not call connect() anymore when conn_inprogress
>> is set.
>>
>> What do you think of it?
> 
> I found that we can't check connection status without select/poll
> on it. 'getsockopt()' will return 0 with no errors if connection
> is not still established just like if it was.
> So, I think, the first version of this patch is the only
> acceptable solution.

Sorry, v2 is acceptable too, because it always calls 'connect()'.
  
Yuanhan Liu July 21, 2016, 12:35 p.m. UTC | #5
On Thu, Jul 21, 2016 at 03:13:14PM +0300, Ilya Maximets wrote:
> >>
> >> What do you think of it?
> > 
> > I found that we can't check connection status without select/poll
> > on it. 'getsockopt()' will return 0 with no errors if connection
> > is not still established just like if it was.
> > So, I think, the first version of this patch is the only
> > acceptable solution.
> 
> Sorry, v2 is acceptable too, because it always calls 'connect()'.

So you have done the test that it works? I'm more curious to know
could your above case hit the getsockopt() code path, I mean, the
path that errno is set to EINPROGRESS or EISCONN?

	--yliu
  
Ilya Maximets July 21, 2016, 12:42 p.m. UTC | #6
On 21.07.2016 15:35, Yuanhan Liu wrote:
> On Thu, Jul 21, 2016 at 03:13:14PM +0300, Ilya Maximets wrote:
>>>>
>>>> What do you think of it?
>>>
>>> I found that we can't check connection status without select/poll
>>> on it. 'getsockopt()' will return 0 with no errors if connection
>>> is not still established just like if it was.
>>> So, I think, the first version of this patch is the only
>>> acceptable solution.
>>
>> Sorry, v2 is acceptable too, because it always calls 'connect()'.
> 
> So you have done the test that it works?

No, it's just theory. I don't know how to test this.

> I'm more curious to know
> could your above case hit the getsockopt() code path, I mean, the
> path that errno is set to EINPROGRESS or EISCONN?

As I already told, I don't sure that we're able to get EINPROGRESS
on our AF_UNIX sockets.
In v2 'getsockopt()' check is unnecessary.
  
Ilya Maximets July 21, 2016, 12:58 p.m. UTC | #7
On 21.07.2016 15:58, Yuanhan Liu wrote:
> On Thu, Jul 21, 2016 at 03:42:54PM +0300, Ilya Maximets wrote:
>> On 21.07.2016 15:35, Yuanhan Liu wrote:
>>> On Thu, Jul 21, 2016 at 03:13:14PM +0300, Ilya Maximets wrote:
>>>>>>
>>>>>> What do you think of it?
>>>>>
>>>>> I found that we can't check connection status without select/poll
>>>>> on it. 'getsockopt()' will return 0 with no errors if connection
>>>>> is not still established just like if it was.
>>>>> So, I think, the first version of this patch is the only
>>>>> acceptable solution.
>>>>
>>>> Sorry, v2 is acceptable too, because it always calls 'connect()'.
>>>
>>> So you have done the test that it works?
>>
>> No, it's just theory. I don't know how to test this.
>>
>>> I'm more curious to know
>>> could your above case hit the getsockopt() code path, I mean, the
>>> path that errno is set to EINPROGRESS or EISCONN?
>>
>> As I already told, I don't sure that we're able to get EINPROGRESS
>> on our AF_UNIX sockets.
>> In v2 'getsockopt()' check is unnecessary.
> 
> We then have no reason to keep it?

You want me to re-send v2 without 'getsockopt()' check?
  
Yuanhan Liu July 21, 2016, 12:58 p.m. UTC | #8
On Thu, Jul 21, 2016 at 03:42:54PM +0300, Ilya Maximets wrote:
> On 21.07.2016 15:35, Yuanhan Liu wrote:
> > On Thu, Jul 21, 2016 at 03:13:14PM +0300, Ilya Maximets wrote:
> >>>>
> >>>> What do you think of it?
> >>>
> >>> I found that we can't check connection status without select/poll
> >>> on it. 'getsockopt()' will return 0 with no errors if connection
> >>> is not still established just like if it was.
> >>> So, I think, the first version of this patch is the only
> >>> acceptable solution.
> >>
> >> Sorry, v2 is acceptable too, because it always calls 'connect()'.
> > 
> > So you have done the test that it works?
> 
> No, it's just theory. I don't know how to test this.
> 
> > I'm more curious to know
> > could your above case hit the getsockopt() code path, I mean, the
> > path that errno is set to EINPROGRESS or EISCONN?
> 
> As I already told, I don't sure that we're able to get EINPROGRESS
> on our AF_UNIX sockets.
> In v2 'getsockopt()' check is unnecessary.

We then have no reason to keep it?

	--yliu
  
Yuanhan Liu July 21, 2016, 1:10 p.m. UTC | #9
On Thu, Jul 21, 2016 at 03:58:11PM +0300, Ilya Maximets wrote:
> On 21.07.2016 15:58, Yuanhan Liu wrote:
> > On Thu, Jul 21, 2016 at 03:42:54PM +0300, Ilya Maximets wrote:
> >> On 21.07.2016 15:35, Yuanhan Liu wrote:
> >>> On Thu, Jul 21, 2016 at 03:13:14PM +0300, Ilya Maximets wrote:
> >>>>>>
> >>>>>> What do you think of it?
> >>>>>
> >>>>> I found that we can't check connection status without select/poll
> >>>>> on it. 'getsockopt()' will return 0 with no errors if connection
> >>>>> is not still established just like if it was.
> >>>>> So, I think, the first version of this patch is the only
> >>>>> acceptable solution.
> >>>>
> >>>> Sorry, v2 is acceptable too, because it always calls 'connect()'.
> >>>
> >>> So you have done the test that it works?
> >>
> >> No, it's just theory. I don't know how to test this.
> >>
> >>> I'm more curious to know
> >>> could your above case hit the getsockopt() code path, I mean, the
> >>> path that errno is set to EINPROGRESS or EISCONN?
> >>
> >> As I already told, I don't sure that we're able to get EINPROGRESS
> >> on our AF_UNIX sockets.
> >> In v2 'getsockopt()' check is unnecessary.
> > 
> > We then have no reason to keep it?
> 
> You want me to re-send v2 without 'getsockopt()' check?

Yes, because I'm not sure it will work without select or poll.

	--yliu
  

Patch

diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c
index 8626d13..b0f45e6 100644
--- a/lib/librte_vhost/vhost_user/vhost-net-user.c
+++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
@@ -537,18 +537,7 @@  vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
 	errno = EINVAL;
 
 	ret = connect(fd, un, sz);
-	if (ret == -1 && errno != EINPROGRESS)
-		return -1;
-	if (ret == 0)
-		goto connected;
-
-	FD_ZERO(&fdset);
-	FD_SET(fd, &fdset);
-
-	ret = select(fd + 1, NULL, &fdset, NULL, &tv);
-	if (!ret)
-		errno = ETIMEDOUT;
-	if (ret != 1)
+	if (ret < 0 && errno != EISCONN)
 		return -1;
 
 	ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
@@ -558,7 +547,6 @@  vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
 		return -1;
 	}
 
-connected:
 	flags = fcntl(fd, F_GETFL, 0);
 	if (flags < 0) {
 		RTE_LOG(ERR, VHOST_CONFIG,