From patchwork Mon Jan 9 09:56:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lv Zheng X-Patchwork-Id: 9504277 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B7A7D6071A for ; Mon, 9 Jan 2017 09:56:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CB1752841E for ; Mon, 9 Jan 2017 09:56:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BDD8E28442; Mon, 9 Jan 2017 09:56:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 30A3E2841E for ; Mon, 9 Jan 2017 09:56:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934841AbdAIJ41 (ORCPT ); Mon, 9 Jan 2017 04:56:27 -0500 Received: from mga04.intel.com ([192.55.52.120]:10849 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934800AbdAIJ40 (ORCPT ); Mon, 9 Jan 2017 04:56:26 -0500 Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga104.fm.intel.com with ESMTP; 09 Jan 2017 01:56:20 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.33,339,1477983600"; d="scan'208";a="50846573" Received: from unknown (HELO lvzheng-z530.sh.intel.com) ([10.239.159.54]) by orsmga005.jf.intel.com with ESMTP; 09 Jan 2017 01:56:18 -0800 From: Lv Zheng To: "Rafael J. Wysocki" , "Rafael J. Wysocki" , Len Brown Cc: Lv Zheng , Lv Zheng , , linux-acpi@vger.kernel.org, Huang Ying , Borislav Petkov Subject: [PATCH] ACPI / OSL: Fix rcu synchronization logic Date: Mon, 9 Jan 2017 17:56:09 +0800 Message-Id: <1483955769-9579-1-git-send-email-lv.zheng@intel.com> X-Mailer: git-send-email 1.7.10 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The rcu synchronization logic is originally provided to protect apei_read()/apei_write() as in the APEI drivers, there is NMI event source requiring non spinlock based synchronization mechanism. After that, ACPI developers think FADT registers may also require same facility, so they moved the RCU stuffs to generic ACPI layer. So now non-task-context ACPI map lookup is only protected by RCU. This triggers problem as acpi_os_map_memory()/acpi_os_unmap_memory() can be used to map/unmap tables as long as to map/unmap ACPI registers. When it is used for the ACPI tables, the caller could invoke this very early. When it is invoked earlier than workqueue_init() and later than check_early_ioremp_leak(), invoking synchronize_rcu_expedited() can cause a kernel hang. Actually this facility is only used to protect non-task-context ACPI map lookup, and such mappings are only introduced by acpi_os_map_generic_address(). So before it is invoked, there is no need to invoke synchronize_rcu_expedited(). Suggested-by: Huang Ying Signed-off-by: Lv Zheng Cc: Huang Ying Cc: Borislav Petkov --- drivers/acpi/osl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index a404ff4..3d93633 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -77,6 +77,7 @@ static int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a, static bool acpi_os_initialized; unsigned int acpi_sci_irq = INVALID_ACPI_IRQ; bool acpi_permanent_mmap = false; +bool acpi_synchronize_rcu = false; /* * This list of permanent mappings is for memory that may be accessed from @@ -378,7 +379,8 @@ static void acpi_os_drop_map_ref(struct acpi_ioremap *map) static void acpi_os_map_cleanup(struct acpi_ioremap *map) { if (!map->refcount) { - synchronize_rcu_expedited(); + if (acpi_synchronize_rcu) + synchronize_rcu_expedited(); acpi_unmap(map->phys, map->virt); kfree(map); } @@ -444,6 +446,7 @@ int acpi_os_map_generic_address(struct acpi_generic_address *gas) if (!virt) return -EIO; + acpi_synchronize_rcu = true; return 0; } EXPORT_SYMBOL(acpi_os_map_generic_address);