Skip to content

Commit

Permalink
Staging: hv: vmbus: Properly deal with de-registering channel callback
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
K. Y. Srinivasan authored and Greg Kroah-Hartman committed Aug 29, 2011
1 parent 76c39d4 commit dad76bf
Show file tree
Hide file tree
Showing 4 changed files with 8 additions and 21 deletions.
20 changes: 5 additions & 15 deletions drivers/staging/hv/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -735,27 +738,22 @@ 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);

*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);
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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);
3 changes: 3 additions & 0 deletions drivers/staging/hv/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,18 +215,21 @@ 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
* channel callback to process the event
*/
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);
}

/*
Expand Down
3 changes: 0 additions & 3 deletions drivers/staging/hv/netvsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
{
struct netvsc_device *net_device;
unsigned long flags;

spin_lock_irqsave(&device->channel->inbound_lock, flags);
net_device = device->ext;

if (!net_device)
Expand All @@ -75,7 +73,6 @@ static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
net_device = NULL;

get_in_err:
spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
return net_device;
}

Expand Down
3 changes: 0 additions & 3 deletions drivers/staging/hv/storvsc_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,7 @@ static inline struct storvsc_device *get_in_stor_device(
struct hv_device *device)
{
struct storvsc_device *stor_device;
unsigned long flags;

spin_lock_irqsave(&device->channel->inbound_lock, flags);
stor_device = (struct storvsc_device *)device->ext;

if (!stor_device)
Expand All @@ -370,7 +368,6 @@ static inline struct storvsc_device *get_in_stor_device(
stor_device = NULL;

get_in_err:
spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
return stor_device;

}
Expand Down

0 comments on commit dad76bf

Please sign in to comment.