> -----Original Message----- > From: Vitaly Kuznetsov [mailto:vkuznets@xxxxxxxxxx] > Sent: Wednesday, February 4, 2015 1:01 AM > To: KY Srinivasan; devel@xxxxxxxxxxxxxxxxxxxxxx > Cc: Haiyang Zhang; linux-kernel@xxxxxxxxxxxxxxx; Dexuan Cui; Jason Wang > Subject: [PATCH 4/4] hyperv: netvsc: improve protection against rescind offer > > The check added in commit c3582a2c4d0b ("hyperv: Add support for vNIC hot > removal") is incomplete as there is no synchronization between > vmbus_onoffer_rescind() and netvsc_send(). In case we get the offer after we > checked out_channel->rescind and before netvsc_send() finishes its job we can > get a crash as we'll be dealing with already freed channel. > > Make netvsc_send() take additional reference to the channel with newly > introduced vmbus_get_channel(), this guarantees we won't lose the channel. > We > can still get rescind while we're processing but this won't cause a crash. > > Reported-by: Jason Wang <jasowang@xxxxxxxxxx> > Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> > --- > drivers/net/hyperv/netvsc.c | 10 ++++++++-- > 1 file changed, 8 insertions(+), 2 deletions(-) > > diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c > index 9f49c01..d9b13a1 100644 > --- a/drivers/net/hyperv/netvsc.c > +++ b/drivers/net/hyperv/netvsc.c > @@ -763,11 +763,16 @@ int netvsc_send(struct hv_device *device, > out_channel = net_device->chn_table[packet->q_idx]; > if (out_channel == NULL) > out_channel = device->channel; > - packet->channel = out_channel; > + packet->channel = vmbus_get_channel(out_channel); > > - if (out_channel->rescind) > + if (!packet->channel) > return -ENODEV; > > + if (out_channel->rescind) { > + vmbus_put_channel(out_channel); IMO the patch doesn't resolve the real issue. At most it prevents the channel from disappearing in netvsc_send() only, while actually we also need to make sure the channel is not freed before the driver runs netvsc_remove() -> rndis_filter_device_remove() -> -> netvsc_device_remove() -> vmbus_close(). I suggest we add vmbus_get/put_channel() in vmbus_open/close()? -- Dexuan > + return -ENODEV; > + } > + > if (packet->page_buf_cnt) { > ret = vmbus_sendpacket_pagebuffer(out_channel, > packet->page_buf, > @@ -810,6 +815,7 @@ int netvsc_send(struct hv_device *device, > packet, ret); > } > > + vmbus_put_channel(packet->channel); > return ret; > } > > -- _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel