lkml.org 
[lkml]   [2011]   [Jul]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 115/117] Staging: hv: vmbus: Properly deal with de-registering channel callback
    Date
    Ensure that we correctly handle racing invocations of the channel callback
    when the channel is being closed. We do this using the channel's inbound_lock.
    A side-effect of this strategy is that we avoid repeatedly picking up this lock
    as we drain the inbound ring-buffer.

    Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
    Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
    ---
    drivers/staging/hv/channel.c | 20 +++++---------------
    drivers/staging/hv/connection.c | 3 +++
    2 files changed, 8 insertions(+), 15 deletions(-)

    diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c
    index ac92c1f..b6f3d38 100644
    --- a/drivers/staging/hv/channel.c
    +++ b/drivers/staging/hv/channel.c
    @@ -513,9 +513,12 @@ void vmbus_close(struct vmbus_channel *channel)
    {
    struct vmbus_channel_close_channel *msg;
    int ret;
    + unsigned long flags;

    /* Stop callback and cancel the timer asap */
    + spin_lock_irqsave(&channel->inbound_lock, flags);
    channel->onchannel_callback = NULL;
    + spin_unlock_irqrestore(&channel->inbound_lock, flags);

    /* Send a closing message */

    @@ -735,19 +738,15 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
    u32 packetlen;
    u32 userlen;
    int ret;
    - unsigned long flags;

    *buffer_actual_len = 0;
    *requestid = 0;

    - spin_lock_irqsave(&channel->inbound_lock, flags);

    ret = hv_ringbuffer_peek(&channel->inbound, &desc,
    sizeof(struct vmpacket_descriptor));
    - if (ret != 0) {
    - spin_unlock_irqrestore(&channel->inbound_lock, flags);
    + if (ret != 0)
    return 0;
    - }

    packetlen = desc.len8 << 3;
    userlen = packetlen - (desc.offset8 << 3);
    @@ -755,7 +754,6 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
    *buffer_actual_len = userlen;

    if (userlen > bufferlen) {
    - spin_unlock_irqrestore(&channel->inbound_lock, flags);

    pr_err("Buffer too small - got %d needs %d\n",
    bufferlen, userlen);
    @@ -768,7 +766,6 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
    ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen,
    (desc.offset8 << 3));

    - spin_unlock_irqrestore(&channel->inbound_lock, flags);

    return 0;
    }
    @@ -785,19 +782,15 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
    u32 packetlen;
    u32 userlen;
    int ret;
    - unsigned long flags;

    *buffer_actual_len = 0;
    *requestid = 0;

    - spin_lock_irqsave(&channel->inbound_lock, flags);

    ret = hv_ringbuffer_peek(&channel->inbound, &desc,
    sizeof(struct vmpacket_descriptor));
    - if (ret != 0) {
    - spin_unlock_irqrestore(&channel->inbound_lock, flags);
    + if (ret != 0)
    return 0;
    - }


    packetlen = desc.len8 << 3;
    @@ -806,8 +799,6 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
    *buffer_actual_len = packetlen;

    if (packetlen > bufferlen) {
    - spin_unlock_irqrestore(&channel->inbound_lock, flags);
    -
    pr_err("Buffer too small - needed %d bytes but "
    "got space for only %d bytes\n",
    packetlen, bufferlen);
    @@ -819,7 +810,6 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
    /* Copy over the entire packet to the user buffer */
    ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0);

    - spin_unlock_irqrestore(&channel->inbound_lock, flags);
    return 0;
    }
    EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
    diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c
    index 7a3ec75..6aab802 100644
    --- a/drivers/staging/hv/connection.c
    +++ b/drivers/staging/hv/connection.c
    @@ -215,6 +215,7 @@ struct vmbus_channel *relid2channel(u32 relid)
    static void process_chn_event(u32 relid)
    {
    struct vmbus_channel *channel;
    + unsigned long flags;

    /*
    * Find the channel based on this relid and invokes the
    @@ -222,11 +223,13 @@ static void process_chn_event(u32 relid)
    */
    channel = relid2channel(relid);

    + spin_lock_irqsave(&channel->inbound_lock, flags);
    if (channel && (channel->onchannel_callback != NULL)) {
    channel->onchannel_callback(channel->channel_callback_context);
    } else {
    pr_err("channel not found for relid - %u\n", relid);
    }
    + spin_unlock_irqrestore(&channel->inbound_lock, flags);
    }

    /*
    --
    1.7.4.1


    \
     
     \ /
      Last update: 2011-07-15 19:35    [W:2.144 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site