qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 4/5] net: introduce lock to protect NetClient


From: Paolo Bonzini
Subject: Re: [Qemu-devel] [PATCH v2 4/5] net: introduce lock to protect NetClientState's peer's access
Date: Wed, 13 Mar 2013 11:39:25 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130219 Thunderbird/17.0.3

Il 13/03/2013 02:26, liu ping fan ha scritto:
> On Tue, Mar 12, 2013 at 4:55 PM, Paolo Bonzini <address@hidden> wrote:
>> Il 07/03/2013 03:53, Liu Ping Fan ha scritto:
>>> From: Liu Ping Fan <address@hidden>
>>>
>>> Introduce nc->send_lock, it shield off the race of nc->peer's reader and
>>> deleter. With it, after deleter finish, no new qemu_send_packet_xx()
>>> can reach ->send_queue, so no new reference(packet->sender) to nc will
>>> be appended to nc->peer->send_queue.
>>>
>>> Signed-off-by: Liu Ping Fan <address@hidden>
>>> ---
>>>  include/net/net.h |    4 +++
>>>  net/hub.c         |   18 ++++++++++++
>>>  net/net.c         |   77 
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++---
>>>  net/queue.c       |    4 +-
>>>  4 files changed, 97 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/include/net/net.h b/include/net/net.h
>>> index 9c2b357..45779d2 100644
>>> --- a/include/net/net.h
>>> +++ b/include/net/net.h
>>> @@ -66,6 +66,8 @@ struct NetClientState {
>>>      NetClientInfo *info;
>>>      int link_down;
>>>      QTAILQ_ENTRY(NetClientState) next;
>>> +    /* protect the race access of peer between deleter and sender */
>>> +    QemuMutex send_lock;
>>>      NetClientState *peer;
>>>      NetQueue *send_queue;
>>>      char *model;
>>> @@ -78,6 +80,7 @@ struct NetClientState {
>>>
>>>  typedef struct NICState {
>>>      NetClientState *ncs;
>>> +    NetClientState **pending_peer;
>>>      NICConf *conf;
>>>      void *opaque;
>>>      bool peer_deleted;
>>> @@ -105,6 +108,7 @@ NetClientState *qemu_find_vlan_client_by_name(Monitor 
>>> *mon, int vlan_id,
>>>                                                const char *client_str);
>>>  typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque);
>>>  void qemu_foreach_nic(qemu_nic_foreach func, void *opaque);
>>> +int qemu_can_send_packet_nolock(NetClientState *sender);
>>>  int qemu_can_send_packet(NetClientState *nc);
>>>  ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov,
>>>                            int iovcnt);
>>> diff --git a/net/hub.c b/net/hub.c
>>> index 47fe72c..d953a99 100644
>>> --- a/net/hub.c
>>> +++ b/net/hub.c
>>> @@ -57,8 +57,14 @@ static ssize_t net_hub_receive(NetHub *hub, NetHubPort 
>>> *source_port,
>>>              continue;
>>>          }
>>>
>>> +        qemu_mutex_lock(&port->nc.send_lock);
>>> +        if (!port->nc.peer) {
>>> +            qemu_mutex_unlock(&port->nc.send_lock);
>>> +            continue;
>>> +        }
>>>          qemu_net_queue_append(port->nc.peer->send_queue, &port->nc,
>>>                              QEMU_NET_PACKET_FLAG_NONE, buf, len, NULL);
>>> +        qemu_mutex_unlock(&port->nc.send_lock);
>>
>> Do you really need to lock everything?  Can you just wrap the peer with
>> a ref/unref, like
>>
>> NetClientState *net_client_get_peer(NetClientState *nc)
>> {
>>     NetClientState *peer;
>>     qemu_mutex_lock(&nc->send_lock);
>>     peer = nc->peer;
>>     if (peer) {
>>         net_client_ref(peer);
>>     }
>>     qemu_mutex_unlock(&nc->send_lock);
>>     return peer;
>> }
>>
>> and then
>>
>> -        qemu_net_queue_append(port->nc.peer->send_queue, &port->nc,
>> +        peer = net_client_get_peer(&port->nc);
>> +        if (!peer) {
>> +            continue;
>> +        }
>> +        qemu_net_queue_append(peer->send_queue, &port->nc,
>>                              QEMU_NET_PACKET_FLAG_NONE, buf, len, NULL);
>> +        net_client_unref(peer);
>>
> Oh, seems that I do not explain very clearly in the commit log.  The
> lock does not only protect against the reclaimer( and this can be
> achieved by refcnt as your codes),  but also sync between remover and
> sender.   If the NetClientState being removed, the remover will be
> like:
>              nc->peer = NULL;
>               ----------> Here opens the gap for in-flight sender, and
> refcnt can not work
>              flush out reference from its peer's send_queue;

What's the problem if the dying peer is still used momentarily?  The
next unref will drop the last reference and qemu_del_net_queue will free
the packet that was just appended.

Paolo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]