Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp4186442pxb; Mon, 8 Feb 2021 09:55:42 -0800 (PST) X-Google-Smtp-Source: ABdhPJzENG5794Ow+qEXoMF0PWc6kp94HJ9SkZyZiXnd90AahEjh9UHlipxePiCOBVZHcSn39hCn X-Received: by 2002:a05:651c:1394:: with SMTP id k20mr12006944ljb.38.1612806942388; Mon, 08 Feb 2021 09:55:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1612806942; cv=none; d=google.com; s=arc-20160816; b=u8my9xlO7eU4ZxfySNnwgezskqlIS3KnqyNqqL1y5YStpUqvLzwVASenAMvzKT07H/ f2C1Vs4hSPewpJACOg1x5gTI9Tc8ey8XTePLp5+usv2TfdwN2v68wDizavttQe7sAT5Q h4aDFCZxv3vuGZ0o7iVNpZjPUy/NZQVHXVYnu5Iqvu/9TOWuLAQiNfEgClhOaWfdBJbm ByVVQodGoKaZE1LU5G8qO0WMJKkbQ4NqB1TzhNgCAiewzzHhpXb11T8WHcZ8ir6FqoBn VDuY6bjqY3uIaZeaH9Q4pDv87XhnYWwiUsDnJLKdyTnZVhChY+/BglpEvNNcKfY3ok6r u0KA== 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=APx5BQzQgtvc6UL+KSus7sGi8Po8Cm9TRkGnBIkbtVk=; b=Vr2c8s8Rby79QEXUOJB3qxttMGuDZLrVW4NnRHlfKT0KQ4Va2N6p528Sz8v+Gbq/xn RZys0bvr9Ky/dmPWuSjpNN2IoJHvE52r7SKL2Kh3vp9uy9hg1q3PydbBTCE7h6oFzTIo lpSbDV9UqKpB+rfrSPy5Dgic30q/URruxw9fMX3cENfVWA0u4JawUCf/GOGh9FKh4SJ8 A95vkkh65bMZFYWOxoXLVnA7KQ6NfvpazUIw4C6IeGmsa6yGxHxBBT6CU6opxl6Jcyz0 9BGGaSmBjmoyTQ/oe9KtlSdNDZUlRZ2ekna7uTF93x2orfFOVOV3f6PnPdp6kXld2f67 cGpA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=bs1vy7H9; 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 c24si1643853edv.48.2021.02.08.09.55.17; Mon, 08 Feb 2021 09:55:42 -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=bs1vy7H9; 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 S235029AbhBHRyk (ORCPT + 99 others); Mon, 8 Feb 2021 12:54:40 -0500 Received: from mail.kernel.org ([198.145.29.99]:38212 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232584AbhBHPdL (ORCPT ); Mon, 8 Feb 2021 10:33:11 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 8CECC64F47; Mon, 8 Feb 2021 15:18:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1612797489; bh=SI3CWuc4KjwgkE8RgZeNombFuH94Ed7cEEdI0vFxfns=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bs1vy7H9bN1X/LoyToS9m88hjiBxgs1J5SeldgiQ9l3cG4of+XxEZnXWHY38zVQuM tNM6h0CwfgHiYx5fgKxczc8kPTVhtzg+ehGiay9Y2EMBDUu+nwlsifNsgMaga868mp KoGbecam3d26wfDVEnlQZvoBWiMsrj1Hv0vQzVzY= 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.10 104/120] mm: thp: fix MADV_REMOVE deadlock on shmem THP Date: Mon, 8 Feb 2021 16:01:31 +0100 Message-Id: <20210208145822.527241143@linuxfoundation.org> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210208145818.395353822@linuxfoundation.org> References: <20210208145818.395353822@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 @@ -2188,7 +2188,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, @@ -2204,7 +2204,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; } @@ -2213,19 +2212,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)) @@ -2235,7 +2244,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.