Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp4093365pxb; Mon, 8 Feb 2021 07:48:16 -0800 (PST) X-Google-Smtp-Source: ABdhPJxtGtQkuqV1W5wGrxhu6+2fMrqsXNrdTx5CB9PWcTJ/3WLhyuaxVcNlsbdQRlAA6uYEN1pW X-Received: by 2002:aa7:d149:: with SMTP id r9mr16190822edo.38.1612799296132; Mon, 08 Feb 2021 07:48:16 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1612799296; cv=none; d=google.com; s=arc-20160816; b=oKsbBICKPO5EgvvbeW6K1GX70v5l1lj9W2CJYpHT2mzQuyHsJK/47uVjcM0gqIXKoV n4kK7CLfvV0VDOjoy3aZplnojIrpEjpU63Ky6N627JSqdVAmLA9KMq+AR3p/zTxPZdGj wB5mBCZ+KO58RdVMIMx7EfPAIn1WoOEhJhF9RkZq1N4QpC1cGXTM5zQ6MNpZ+8RlrL/W V6EwxIDsQtt+5ed9VODbepjbAKb10+Pvh6im5KCcWC+3AnyY9B3PVSqcFTh1FYF6AJhP H/dTWWg1uNgXjRbZgJMy9nWeHBLHQp/tXf7+dPEHhh2JiB/iXg3MHCf1AGdxVs7zH741 XPcw== 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=V2qn7Rme+wowtsoh2D32ZQokRY4oRtVT7tMXQNkfe38=; b=NCSYlPW+Q7agMvXVBNC6dI0XcRAmkUn1reuGD+bcd1LUWt4xhr7shG8vwqZ02OTRgy G9FKVwfhQ5YEf43TRd/fgxmGQIfWVkQVi179vlnZFhM4IOc/u15bmqNXImrP/fC5YiL6 AmxES8gQOCZ/QbWjgAfk/ZvX+ur9Tpyy9Fm2n4Lqey5ZFGkYfDNdNfqhb8Jku9yXfQ9k +ROmFIUC+m9ReCe9WUgGWTKwTJ8edRAze2JjVaOvK3qq+5wdR/IEaMQ6hDm5VFK0MXG3 U1CE1JIMrxeiB5rbkfOMURronXuJ0anF1Ewt+ASKWGROI/GFGWZ64QkMsZzQ2lssUn+2 v/qg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=erApdiFu; 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 ce27si2191363edb.213.2021.02.08.07.47.51; Mon, 08 Feb 2021 07:48:16 -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=erApdiFu; 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 S233487AbhBHPqy (ORCPT + 99 others); Mon, 8 Feb 2021 10:46:54 -0500 Received: from mail.kernel.org ([198.145.29.99]:51778 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233027AbhBHPGj (ORCPT ); Mon, 8 Feb 2021 10:06:39 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 78C3464ED7; Mon, 8 Feb 2021 15:05:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1612796709; bh=H7Nev5EX96gwW463Lb7ak1BBnu7q9HFQ6fmzmO/KIP8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=erApdiFurzkJWGgAU1TvO2cXmewHd5hyVLCNI6aGFoxehMrDeNY92XldaLkJtVHIn e+y48+dzuXL434Tv15tpBoQXw8yZDVcisgSOrN4EN4TuOBjfT1K6hViBLg7cXatnBU 86pj6/rt5anLI194DXfBwRyoddcV/dsl/GNUcevI= 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 4.9 37/43] mm: thp: fix MADV_REMOVE deadlock on shmem THP Date: Mon, 8 Feb 2021 16:01:03 +0100 Message-Id: <20210208145807.809372156@linuxfoundation.org> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210208145806.281758651@linuxfoundation.org> References: <20210208145806.281758651@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 @@ -1753,7 +1753,7 @@ void __split_huge_pmd(struct vm_area_str spinlock_t *ptl; struct mm_struct *mm = vma->vm_mm; unsigned long haddr = address & HPAGE_PMD_MASK; - bool was_locked = false; + bool do_unlock_page = false; pmd_t _pmd; mmu_notifier_invalidate_range_start(mm, haddr, haddr + HPAGE_PMD_SIZE); @@ -1766,7 +1766,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; } @@ -1775,19 +1774,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)) @@ -1797,7 +1806,7 @@ repeat: __split_huge_pmd_locked(vma, pmd, haddr, freeze); out: spin_unlock(ptl); - if (!was_locked && page) + if (do_unlock_page) unlock_page(page); mmu_notifier_invalidate_range_end(mm, haddr, haddr + HPAGE_PMD_SIZE); }