diff options
author | K. Y. Srinivasan <kys@microsoft.com> | 2011-08-27 11:31:33 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-29 11:05:30 -0700 |
commit | dad76bf73fc20b42d020fe5a93dbe4b4868e7681 (patch) | |
tree | d1ce6dee63e86173b97f27796d515f31d9fdc03d /drivers/staging/hv/channel.c | |
parent | 76c39d429d606d8f9b354ee2b1973b76c8331b1f (diff) | |
download | op-kernel-dev-dad76bf73fc20b42d020fe5a93dbe4b4868e7681.zip op-kernel-dev-dad76bf73fc20b42d020fe5a93dbe4b4868e7681.tar.gz |
Staging: hv: vmbus: Properly deal with de-registering channel callback
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/hv/channel.c')
-rw-r--r-- | drivers/staging/hv/channel.c | 20 |
1 files changed, 5 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); |