From patchwork Tue Jun 20 17:27:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcelo Henrique Cerri X-Patchwork-Id: 778427 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 3wsZYz1WtTz9s7m; Wed, 21 Jun 2017 03:28:23 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=canonical-com.20150623.gappssmtp.com header.i=@canonical-com.20150623.gappssmtp.com header.b="Mezh13sS"; dkim-atps=neutral Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1dNMwu-0001of-6w; Tue, 20 Jun 2017 17:28:20 +0000 Received: from mail-ua0-f177.google.com ([209.85.217.177]) by huckleberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1dNMwh-0001hr-Kg for kernel-team@lists.ubuntu.com; Tue, 20 Jun 2017 17:28:07 +0000 Received: by mail-ua0-f177.google.com with SMTP id d45so48628578uai.1 for ; Tue, 20 Jun 2017 10:28:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=LyRT4b8NrPchZhUQgTekO4zidrI8BBDpNQflIH0zQOM=; b=Mezh13sSl4K7q9ceCC0496KlVjcmDtJEfJw5hgRGMWCENnRYS6Nzn3dSQghI6SzHme FzkLYAusn/0i0nD35SwS2PdDFunkQfiMbaik1DeWlkWKMHu7BSdDPEicJAEf5CRzGpkM CfMpTJLWyYXtHXehJo21wiUMwAMSXZ2ibUz1VL7DW7Tt5/ze4i5VFR6dBZ97vG4DFOso XNIeh4d0OJRQptYQbkURS5VHegFjEDbwiORw2XJ/QdpoTV33aGr+xPenOdm9dw2dENcw QxmT+GZX/4oDE7ghsHuEhVxEg21HIclaEOZoZZy7AnTcGsxUY8YfYGP3jkO7NKaN9I6p q/cw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=LyRT4b8NrPchZhUQgTekO4zidrI8BBDpNQflIH0zQOM=; b=ncGNmE3lQLq5AgvEHf6+lA8Gsx3TPFUl8jzB6uwCzMGfDyvuiNFm67fnD8Nths7Cfg Fk4+edUSbSfP4G0DlXrypHy4/Kdkc/pJmWCZEOW920BjQIFDYvgAbLDOCf40GzqiMhiA gXkBS1a+XBfzh76t9l9sprcSm5eAz6FFv/eiTpDxTe66LiKHunxBwZEz6op+UwzkHMW9 d9BVze75R3sLzuumzkA4Jf/0mSIsOr6LD8GQzgooN3CUvWPVcD+TzbbT6tw+qLWuhGbt vah6AtL906ktAN7ZwDE5tAbAVBsfNVwwKRpZFLDy+7/NQKlu2oX70ZQQH4iiuEML5Nju BIJg== X-Gm-Message-State: AKS2vOzJL1nYkdxvqAoJf/au9+b4KL3/DIDZ+OYer/Ben40u53ILGiH0 iTLGVG9O2pfD5uHaLTE= X-Received: by 10.176.4.97 with SMTP id 88mr8735921uav.47.1497979686301; Tue, 20 Jun 2017 10:28:06 -0700 (PDT) Received: from localhost.localdomain ([191.8.96.73]) by smtp.gmail.com with ESMTPSA id x2sm4922955vkd.35.2017.06.20.10.28.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 20 Jun 2017 10:28:05 -0700 (PDT) From: Marcelo Henrique Cerri To: kernel-team@lists.ubuntu.com Subject: [azure][PATCH 12/14] UBUNTU: SAUCE: vmbus: fix hv_percpu_channel_deq/enq race Date: Tue, 20 Jun 2017 14:27:32 -0300 Message-Id: <1497979654-27251-13-git-send-email-marcelo.cerri@canonical.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497979654-27251-1-git-send-email-marcelo.cerri@canonical.com> References: <1497979654-27251-1-git-send-email-marcelo.cerri@canonical.com> Cc: "K . Y . Srinivasan" , Dexuan Cui , Cheng-mean Liu X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: kernel-team-bounces@lists.ubuntu.com From: Dexuan Cui BugLink: http://bugs.launchpad.net/bugs/1698425 Signed-off-by: Dexuan Cui Signed-off-by: Marcelo Henrique Cerri --- drivers/hv/channel_mgmt.c | 32 +++++++++++++++++++++---- drivers/hv/connection.c | 11 +++++++++ drivers/hv/hyperv_vmbus.h | 1 + drivers/hv/vmbus_drv.c | 59 ++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 95 insertions(+), 8 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index f5296548cdc9..19ad79099492 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -365,11 +365,16 @@ static void percpu_channel_enq(void *arg) void hv_percpu_channel_enq(struct vmbus_channel *channel) { + unsigned long flags; + if (channel->target_cpu != get_cpu()) smp_call_function_single(channel->target_cpu, percpu_channel_enq, channel, true); - else + else { + local_irq_save(flags); percpu_channel_enq(channel); + local_irq_restore(flags); + } put_cpu(); } @@ -383,11 +388,16 @@ static void percpu_channel_deq(void *arg) void hv_percpu_channel_deq(struct vmbus_channel *channel) { + unsigned long flags; + if (channel->target_cpu != get_cpu()) smp_call_function_single(channel->target_cpu, percpu_channel_deq, channel, true); - else + else { + local_irq_save(flags); percpu_channel_deq(channel); + local_irq_restore(flags); + } put_cpu(); } @@ -495,7 +505,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) channel->num_sc++; spin_unlock_irqrestore(&channel->lock, flags); } else { - atomic_dec(&vmbus_connection.offer_in_progress); goto err_free_chan; } } @@ -549,6 +558,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) return; err_deq_chan: + atomic_dec(&vmbus_connection.offer_in_progress); mutex_lock(&vmbus_connection.channel_mutex); list_del(&newchannel->listentry); mutex_unlock(&vmbus_connection.channel_mutex); @@ -915,16 +925,28 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) } } +static void vmbus_stop_rescind_handling_work(struct work_struct *work) +{ + atomic_inc(&vmbus_connection.offer_in_progress); +} + void vmbus_hvsock_device_unregister(struct vmbus_channel *channel) { - mutex_lock(&vmbus_connection.channel_mutex); + struct work_struct work; BUG_ON(!is_hvsock_channel(channel)); + /* Prevent chn_rescind_callback from running in the rescind path */ + INIT_WORK(&work, vmbus_stop_rescind_handling_work); + queue_work_on(vmbus_connection.connect_cpu, + vmbus_connection.work_queue_rescind, &work); + flush_work(&work); + channel->rescind = true; vmbus_device_unregister(channel->device_obj); - mutex_unlock(&vmbus_connection.channel_mutex); + /* Unblock the rescind handling */ + atomic_dec(&vmbus_connection.offer_in_progress); } EXPORT_SYMBOL_GPL(vmbus_hvsock_device_unregister); diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 13e2e148067b..9e4a3d099836 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -156,6 +156,12 @@ int vmbus_connect(void) goto cleanup; } + vmbus_connection.work_queue_rescind = create_workqueue("hv_vmbus_rsd"); + if (!vmbus_connection.work_queue_rescind) { + ret = -ENOMEM; + goto cleanup; + } + INIT_LIST_HEAD(&vmbus_connection.chn_msg_list); spin_lock_init(&vmbus_connection.channelmsg_lock); @@ -246,6 +252,11 @@ void vmbus_disconnect(void) */ vmbus_initiate_unload(false); + if (vmbus_connection.work_queue_rescind) { + drain_workqueue(vmbus_connection.work_queue_rescind); + destroy_workqueue(vmbus_connection.work_queue_rescind); + } + if (vmbus_connection.work_queue) { drain_workqueue(vmbus_connection.work_queue); destroy_workqueue(vmbus_connection.work_queue); diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 8ce4ae1c78d0..7b8603a00555 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -339,6 +339,7 @@ struct vmbus_connection { struct mutex channel_mutex; struct workqueue_struct *work_queue; + struct workqueue_struct *work_queue_rescind; }; diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 59bb3efa6e10..fd221cffeb4d 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -837,6 +837,52 @@ static void vmbus_onmessage_work(struct work_struct *work) kfree(ctx); } +static void vmbus_dispatch_msg_work(struct work_struct *work) +{ + struct vmbus_channel_message_header *hdr; + struct onmessage_work_context *ctx, *context; + + ctx = container_of(work, struct onmessage_work_context, work); + hdr = (struct vmbus_channel_message_header *)ctx->msg.u.payload; + + context = kmalloc(sizeof(*context), GFP_KERNEL | __GFP_NOFAIL); + INIT_WORK(&context->work, vmbus_onmessage_work); + memcpy(&context->msg, &ctx->msg, sizeof(struct hv_message)); + + /* + * The host can generate a rescind message while we + * may still be handling the original offer. We deal with + * this condition by ensuring the processing is done on the + * same CPU. + */ + switch (hdr->msgtype) { + case CHANNELMSG_RESCIND_CHANNELOFFER: + /* + * If we are handling the rescind message; + * schedule the work on the global work queue. + */ + queue_work_on(vmbus_connection.connect_cpu, + vmbus_connection.work_queue_rescind, + &context->work); + break; + + case CHANNELMSG_OFFERCHANNEL: + /* XXX */ + flush_workqueue(vmbus_connection.work_queue_rescind); + + atomic_inc(&vmbus_connection.offer_in_progress); + queue_work_on(vmbus_connection.connect_cpu, + vmbus_connection.work_queue, + &context->work); + break; + + default: + queue_work(vmbus_connection.work_queue, &context->work); + } + + kfree(ctx); +} + static void hv_process_timer_expiration(struct hv_message *msg, struct hv_per_cpu_context *hv_cpu) { @@ -876,9 +922,10 @@ void vmbus_on_msg_dpc(unsigned long data) if (ctx == NULL) return; - INIT_WORK(&ctx->work, vmbus_onmessage_work); + INIT_WORK(&ctx->work, vmbus_dispatch_msg_work); memcpy(&ctx->msg, msg, sizeof(*msg)); +#if 0 /* * The host can generate a rescind message while we * may still be handling the original offer. We deal with @@ -891,8 +938,9 @@ void vmbus_on_msg_dpc(unsigned long data) * If we are handling the rescind message; * schedule the work on the global work queue. */ - schedule_work_on(vmbus_connection.connect_cpu, - &ctx->work); + queue_work_on(vmbus_connection.connect_cpu, + vmbus_connection.work_queue_rescind, + &ctx->work); break; case CHANNELMSG_OFFERCHANNEL: @@ -905,6 +953,9 @@ void vmbus_on_msg_dpc(unsigned long data) default: queue_work(vmbus_connection.work_queue, &ctx->work); } +#else + schedule_work(&ctx->work); +#endif } else entry->message_handler(hdr); @@ -1202,6 +1253,8 @@ int vmbus_device_register(struct hv_device *child_device_obj) child_device_obj->device.parent = &hv_acpi_dev->dev; child_device_obj->device.release = vmbus_device_release; + if (is_hvsock_channel(child_device_obj->channel)) + dev_set_uevent_suppress(&child_device_obj->device, 1); /* * Register with the LDM. This will kick off the driver/device * binding...which will eventually call vmbus_match() and vmbus_probe()