Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751968AbbGMPKn (ORCPT ); Mon, 13 Jul 2015 11:10:43 -0400 Received: from mail-bn1bon0144.outbound.protection.outlook.com ([157.56.111.144]:61285 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751808AbbGMPKl convert rfc822-to-8bit (ORCPT ); Mon, 13 Jul 2015 11:10:41 -0400 From: KY Srinivasan To: Vitaly Kuznetsov , "devel@linuxdriverproject.org" CC: Haiyang Zhang , Dexuan Cui , "linux-kernel@vger.kernel.org" Subject: RE: [PATCH] Drivers: hv: vmbus: prevent new subchannel creation on device shutdown Thread-Topic: [PATCH] Drivers: hv: vmbus: prevent new subchannel creation on device shutdown Thread-Index: AQHQvWYZDQ3nQCJkBU2Sq3NyVNZ99J3Zf5hQ Date: Mon, 13 Jul 2015 15:10:31 +0000 Message-ID: References: <1436789934-11566-1-git-send-email-vkuznets@redhat.com> In-Reply-To: <1436789934-11566-1-git-send-email-vkuznets@redhat.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: redhat.com; dkim=none (message not signed) header.d=none; x-originating-ip: [50.135.110.52] x-microsoft-exchange-diagnostics: 1;BY2PR0301MB0773;5:18G3PKGJ+jlrEOLQM51crthUGPbPKraffRNr7gKneIQAs+0eWMu/QWfw5MTT2I8OOK77WYIfNo5W+folCGzmJlH6AH7hKSid7BBzVBg53yJx2h+Dko638NcaRbAW0nf6gtnR/G2vwVonPA9Cq61QRA==;24:9YzUJOX4xART8WN/fStBVhuTOn1tbcin/c4hvExei73bqLggwEClCAMnzC29jG+owEftQszfbFwUPcywi1Glkm5nMpps17Xsjzc0+tDo5c4=;20:aYueU+M6Phvw1MQ1ikwB1rkVrBmQDpDTUGgahsf4qgeAV+30oVdgxltNDotarAQHNy/Dqtm6XKLnvBYdmG+mQA== x-microsoft-antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2PR0301MB0773; by2pr0301mb0773: X-MS-Exchange-Organization-RulesExecuted x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:; x-exchange-antispam-report-cfa-test: BCL:0;PCL:0;RULEID:(601004)(2401001)(5005006)(3002001);SRVR:BY2PR0301MB0773;BCL:0;PCL:0;RULEID:;SRVR:BY2PR0301MB0773; x-forefront-prvs: 0636271852 x-forefront-antispam-report: SFV:NSPM;SFS:(10019020)(979002)(6009001)(13464003)(51704005)(377454003)(77156002)(40100003)(46102003)(122556002)(2950100001)(2900100001)(106116001)(102836002)(19580395003)(62966003)(87936001)(2656002)(99286002)(66066001)(92566002)(101416001)(5002640100001)(50986999)(5003600100002)(54356999)(76176999)(76576001)(19580405001)(86612001)(74316001)(189998001)(77096005)(2501003)(33656002)(5001960100002)(86362001)(5001770100001)(969003)(989001)(999001)(1009001)(1019001);DIR:OUT;SFP:1102;SCL:1;SRVR:BY2PR0301MB0773;H:BY2PR0301MB1654.namprd03.prod.outlook.com;FPR:;SPF:None;MLV:ovrnspm;PTR:InfoNoRecords;LANG:en; Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 8BIT MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-originalarrivaltime: 13 Jul 2015 15:10:31.7560 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2PR0301MB0773 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6065 Lines: 181 > -----Original Message----- > From: Vitaly Kuznetsov [mailto:vkuznets@redhat.com] > Sent: Monday, July 13, 2015 5:19 AM > To: devel@linuxdriverproject.org > Cc: KY Srinivasan; Haiyang Zhang; Dexuan Cui; linux-kernel@vger.kernel.org > Subject: [PATCH] Drivers: hv: vmbus: prevent new subchannel creation on > device shutdown > > When a new subchannel offer from host comes during device shutdown > (e.g. > when a netvsc/storvsc module is unloadedshortly after it was loaded) a > crash can happen as vmbus_process_offer() is not anyhow serialized with > vmbus_remove(). As an example we can try calling subchannel create > callback when the module is already unloaded. > The following crash was observed while keeping loading/unloading > hv_netvsc > module on 64-CPU guest: > > hv_netvsc vmbus_14: net device safe to remove > BUG: unable to handle kernel paging request at 000000000000a118 > IP: [] netvsc_sc_open+0x31/0xb0 [hv_netvsc] > PGD 1f3946a067 PUD 1f38a5f067 PMD 0 > Oops: 0000 [#1] SMP > ... > Call Trace: > [] vmbus_onoffer+0x477/0x530 [hv_vmbus] > [] ? move_linked_works+0x5f/0x80 > [] vmbus_onmessage+0x33/0xa0 [hv_vmbus] > [] vmbus_onmessage_work+0x21/0x30 [hv_vmbus] > [] process_one_work+0x18e/0x4e0 > ... > > The issue cannot be solved by just resetting sc_creation_callback on > driver removal as while we search for the parent channel with channel_lock > held we release it after the channel was found and it can disapper beneath > our feet while we're still in vmbus_process_offer(); > > Introduce new sc_create_lock mutex and take it in vmbus_remove() to > ensure > no new subchannels are created after we started the removal procedure. > Check its state with mutex_trylock in vmbus_process_offer(). > > Signed-off-by: Vitaly Kuznetsov Thanks Vitaly; strangely enough, I too am looking at this exact problem. I was planning to address this problem a little differently: I was planning to hold the context that performed the initial (primary) channel open until all of the "open activity" was completed and this would include opening of the sub-channels for multi-channel devices. Regards, K. Y > --- > drivers/hv/channel.c | 3 +++ > drivers/hv/channel_mgmt.c | 20 ++++++++++++++++++-- > drivers/hv/vmbus_drv.c | 6 ++++++ > include/linux/hyperv.h | 4 ++++ > 4 files changed, 31 insertions(+), 2 deletions(-) > > diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c > index 603ce97..faa91fe 100644 > --- a/drivers/hv/channel.c > +++ b/drivers/hv/channel.c > @@ -555,6 +555,9 @@ static int vmbus_close_internal(struct vmbus_channel > *channel) > if (channel->rescind) > hv_process_channel_removal(channel, > channel->offermsg.child_relid); > + else if (mutex_is_locked(&channel->sc_create_lock)) > + mutex_unlock(&channel->sc_create_lock); > + > return ret; > } > > diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c > index 4506a66..96f8b96 100644 > --- a/drivers/hv/channel_mgmt.c > +++ b/drivers/hv/channel_mgmt.c > @@ -150,6 +150,8 @@ static struct vmbus_channel *alloc_channel(void) > INIT_LIST_HEAD(&channel->sc_list); > INIT_LIST_HEAD(&channel->percpu_list); > > + mutex_init(&channel->sc_create_lock); > + > return channel; > } > > @@ -158,6 +160,7 @@ static struct vmbus_channel *alloc_channel(void) > */ > static void free_channel(struct vmbus_channel *channel) > { > + mutex_destroy(&channel->sc_create_lock); > kfree(channel); > } > > @@ -247,8 +250,18 @@ static void vmbus_process_offer(struct > vmbus_channel *newchannel) > newchannel->offermsg.offer.if_type) && > !uuid_le_cmp(channel->offermsg.offer.if_instance, > newchannel->offermsg.offer.if_instance)) { > - fnew = false; > - break; > + if (mutex_trylock(&channel->sc_create_lock)) { > + fnew = false; > + break; > + } > + /* > + * If we fail to acquire mutex here it means we're > + * closing parent channel at this moment. We can't > + * create new subchannel in this case. > + */ > + > spin_unlock_irqrestore(&vmbus_connection.channel_lock, > + flags); > + goto err_free_chan; > } > } > > @@ -297,6 +310,7 @@ static void vmbus_process_offer(struct > vmbus_channel *newchannel) > if (!fnew) { > if (channel->sc_creation_callback != NULL) > channel->sc_creation_callback(newchannel); > + mutex_unlock(&channel->sc_create_lock); > return; > } > > @@ -340,6 +354,8 @@ err_deq_chan: > } > > err_free_chan: > + if (!fnew) > + mutex_unlock(&channel->sc_create_lock); > free_channel(newchannel); > } > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c > index cf20400..7ad7fcc 100644 > --- a/drivers/hv/vmbus_drv.c > +++ b/drivers/hv/vmbus_drv.c > @@ -539,6 +539,12 @@ static int vmbus_remove(struct device > *child_device) > struct hv_device *dev = device_to_hv_device(child_device); > u32 relid = dev->channel->offermsg.child_relid; > > + /* > + * Device is being removed, prevent creating new subchannels. > Mutex > + * will be released in vmbus_close_internal(). > + */ > + mutex_lock(&dev->channel->sc_create_lock); > + > if (child_device->driver) { > drv = drv_to_hv_drv(child_device->driver); > if (drv->remove) > diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h > index 30d3a1f..f1af05c 100644 > --- a/include/linux/hyperv.h > +++ b/include/linux/hyperv.h > @@ -748,6 +748,10 @@ struct vmbus_channel { > */ > struct vmbus_channel *primary_channel; > /* > + * Protects sub-channel create path. > + */ > + struct mutex sc_create_lock; > + /* > * Support per-channel state for use by vmbus drivers. > */ > void *per_channel_state; > -- > 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/