Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp4141552pxb; Mon, 8 Feb 2021 08:54:14 -0800 (PST) X-Google-Smtp-Source: ABdhPJy/ddfe2aEy9YxmGqj4CZNPRZFYcgheYfXqoY72CsGLijSlwfnAFOIbWSEWTES0D7c92HTl X-Received: by 2002:a17:906:af58:: with SMTP id ly24mr18127852ejb.208.1612803254107; Mon, 08 Feb 2021 08:54:14 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1612803254; cv=none; d=google.com; s=arc-20160816; b=ykm4iAKdO/vC2S8qK7eIPr7ngQRepMp7FMo8PQTCtgOmH7EOKtWwbiEgqyaRJQ/4jw HO1s+B99rdl5MP/k0tuxApdi9Un6Ec/pZE6oaI+LzXAEZ1hFEdxGp559tu54lNM7Gk+C KIoeoeLhTysU0CfOVMcYeQHGkpS9+XsIcqqv8iLB3w7ssm+JkPWm11vpk+cz/ToUvoW2 J3JsDoMhCT+ppSXpYf1vFEuMeRnOKcDLVFH8sPA5oMaDQh5O2QGhcQ3gQqN0okXLoOLD GCL0L6hjFRnfMDniSyZR3Ucmj/D1ZNPhlmwM269cRSR+V/FpmFXKn51JLy9Dw4BdS8Nh zsgQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=HoTzlaPc1Ff37I40GrTQyzv4mDE+k6c52IXU1B5xfeE=; b=kTE5z7iltZoI0Q4KSRhdv/wkU5DKHOPdJLOaeHE8RfXlXiJToKcFz84h50AqELn1QW l27BVc7DFANkvCOJpvgWkMGZIGx60QGjyNXOtOKmIDoth8WPyArXMdQBE6eLFc97ebQc ShiC/K16962W2Oq4lL0amnLj3y4gQR4nqDfIdOO7dyI+ER6D7W+h+CIa0Z8UeF4N+qWv sELmDrrJ5Fz38yz3lj5dW4gJRkdALo7kGcFBldOKd368hyuuJ2d1vqoSLVPBGMBUi5FG hXFLkgUlo/DIWZv1hPhNXxvJwBS34r9eX7BhahNFWokmS1yxqzfzpMDUguOFod841tuA m79Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="MAi/FAzy"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id fx12si2692209ejb.286.2021.02.08.08.53.49; Mon, 08 Feb 2021 08:54:14 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="MAi/FAzy"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234716AbhBHQxE (ORCPT + 99 others); Mon, 8 Feb 2021 11:53:04 -0500 Received: from mail.kernel.org ([198.145.29.99]:60340 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233497AbhBHPRk (ORCPT ); Mon, 8 Feb 2021 10:17:40 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id E71D564EDA; Mon, 8 Feb 2021 15:12:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1612797129; bh=owMGpEEyis0lUcSHly8vyZxtYSOHMUfwpI4X6GWFKVU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MAi/FAzyXiilznOeuxGXvEfwc21LD663+eweVkA7ePcc53eVeBlKI++PHKkLfWQbn pI0/u0fIszo5V080pYvVn6np0d0/+nMMOdk9Fzpo2dPkjIwet6ACgumvc+sxYwd4Qi /zvodJOBtRL7eR6JASpIZQIdd5x9hRx9IBcMepM8= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Hugh Dickins , Sergey Senozhatsky , Andrea Arcangeli , Andrew Morton , Linus Torvalds Subject: [PATCH 5.4 53/65] mm: thp: fix MADV_REMOVE deadlock on shmem THP Date: Mon, 8 Feb 2021 16:01:25 +0100 Message-Id: <20210208145812.270609346@linuxfoundation.org> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210208145810.230485165@linuxfoundation.org> References: <20210208145810.230485165@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Hugh Dickins commit 1c2f67308af4c102b4e1e6cd6f69819ae59408e0 upstream. Sergey reported deadlock between kswapd correctly doing its usual lock_page(page) followed by down_read(page->mapping->i_mmap_rwsem), and madvise(MADV_REMOVE) on an madvise(MADV_HUGEPAGE) area doing down_write(page->mapping->i_mmap_rwsem) followed by lock_page(page). This happened when shmem_fallocate(punch hole)'s unmap_mapping_range() reaches zap_pmd_range()'s call to __split_huge_pmd(). The same deadlock could occur when partially truncating a mapped huge tmpfs file, or using fallocate(FALLOC_FL_PUNCH_HOLE) on it. __split_huge_pmd()'s page lock was added in 5.8, to make sure that any concurrent use of reuse_swap_page() (holding page lock) could not catch the anon THP's mapcounts and swapcounts while they were being split. Fortunately, reuse_swap_page() is never applied to a shmem or file THP (not even by khugepaged, which checks PageSwapCache before calling), and anonymous THPs are never created in shmem or file areas: so that __split_huge_pmd()'s page lock can only be necessary for anonymous THPs, on which there is no risk of deadlock with i_mmap_rwsem. Link: https://lkml.kernel.org/r/alpine.LSU.2.11.2101161409470.2022@eggly.anvils Fixes: c444eb564fb1 ("mm: thp: make the THP mapcount atomic against __split_huge_pmd_locked()") Signed-off-by: Hugh Dickins Reported-by: Sergey Senozhatsky Reviewed-by: Andrea Arcangeli Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/huge_memory.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2306,7 +2306,7 @@ void __split_huge_pmd(struct vm_area_str { spinlock_t *ptl; struct mmu_notifier_range range; - bool was_locked = false; + bool do_unlock_page = false; pmd_t _pmd; mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm, @@ -2322,7 +2322,6 @@ void __split_huge_pmd(struct vm_area_str VM_BUG_ON(freeze && !page); if (page) { VM_WARN_ON_ONCE(!PageLocked(page)); - was_locked = true; if (page != pmd_page(*pmd)) goto out; } @@ -2331,19 +2330,29 @@ repeat: if (pmd_trans_huge(*pmd)) { if (!page) { page = pmd_page(*pmd); - if (unlikely(!trylock_page(page))) { - get_page(page); - _pmd = *pmd; - spin_unlock(ptl); - lock_page(page); - spin_lock(ptl); - if (unlikely(!pmd_same(*pmd, _pmd))) { - unlock_page(page); + /* + * An anonymous page must be locked, to ensure that a + * concurrent reuse_swap_page() sees stable mapcount; + * but reuse_swap_page() is not used on shmem or file, + * and page lock must not be taken when zap_pmd_range() + * calls __split_huge_pmd() while i_mmap_lock is held. + */ + if (PageAnon(page)) { + if (unlikely(!trylock_page(page))) { + get_page(page); + _pmd = *pmd; + spin_unlock(ptl); + lock_page(page); + spin_lock(ptl); + if (unlikely(!pmd_same(*pmd, _pmd))) { + unlock_page(page); + put_page(page); + page = NULL; + goto repeat; + } put_page(page); - page = NULL; - goto repeat; } - put_page(page); + do_unlock_page = true; } } if (PageMlocked(page)) @@ -2353,7 +2362,7 @@ repeat: __split_huge_pmd_locked(vma, pmd, range.start, freeze); out: spin_unlock(ptl); - if (!was_locked && page) + if (do_unlock_page) unlock_page(page); /* * No need to double call mmu_notifier->invalidate_range() callback.