Received: by 10.213.65.68 with SMTP id h4csp262506imn; Tue, 3 Apr 2018 20:24:56 -0700 (PDT) X-Google-Smtp-Source: AIpwx48F3lJtps3SU+mZ6jtyuHMPfnxLXsPJNPh0PIsulpxr5VNoB3SD5anRcobEDnFRZ969e/gN X-Received: by 10.98.7.152 with SMTP id 24mr7968739pfh.94.1522812296208; Tue, 03 Apr 2018 20:24:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522812296; cv=none; d=google.com; s=arc-20160816; b=cqXefl6PC2UJs2OXOwliMJI2GVw8R9R/WQorltHfyOLsPBDe5V+1sV3SG7UhLG+t3Y jKdOSayQpCAFMM2T/plc2TZ1vM6UKyKeNTnqVhvey8KfzpSo9EwSTCsY7BWCy7ICPtP+ PGPlWzI1JLCQxDHBQW1HT8siEhitchJTJiBX9/wf2RPprmxw7GGkcfH2e2GVbSx1lu5e GtwVb9noV1lPyP1h3UwkNXd7yo0ToLuOwvq8fNPzRple2lEgMs7+K0NkGgGhUxkx1OLC y27wMgaWjaBFGF4RIpMlfh7buxs8bQNjvsTs2y9xdscre2kpjLDMCPY42lz17JjxbPdK Cafg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=t5efnlpE1y5dZyrCwn7mnNZSTuUhwti9KOHD9s1ble8=; b=aSZ9GcEBxMMWwfesXGOr1TCB8MdYmP2Cgx302JMWuC/YP3y88itEEGK6Y1YDiW7CoV aiFJD4FzeHwAyfQgkHJe1tc5phr+RUrU0NG2Ffidrxqjv75jixZpI3cw5pbFUkHgk653 KXTkHSjQ+pNMO0OlviGcxVmqJnoVOcMMnurHWBaR+pW1aOqi5yVUpSwE2+jLLiRov2zQ fCh+hKo5O5HRfW+oqEFRcPcvNsqx7X1K+vCdL1U00qNR6QU0wsfKzsa+4D6eqzBinH8A NFqkQXwd9AJUQrVThe6m2qK3gZsXhjcqCrcnHnnNJWiSyzmY4lRbeBG1fbrF7SwDp1fi fl5g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d68si3292244pfl.337.2018.04.03.20.24.42; Tue, 03 Apr 2018 20:24:56 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753933AbeDDDXN (ORCPT + 99 others); Tue, 3 Apr 2018 23:23:13 -0400 Received: from mga05.intel.com ([192.55.52.43]:43956 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753896AbeDDDXM (ORCPT ); Tue, 3 Apr 2018 23:23:12 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2018 20:23:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.48,404,1517904000"; d="scan'208";a="30847411" Received: from yhuang-dev.sh.intel.com ([10.239.13.118]) by orsmga008.jf.intel.com with ESMTP; 03 Apr 2018 20:23:09 -0700 From: "Huang, Ying" To: Andrew Morton Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, Huang Ying , Al Viro , "Aneesh Kumar K.V" , Dan Williams , Zi Yan , "Kirill A. Shutemov" Subject: [PATCH -mm] mm, gup: prevent pmd checking race in follow_pmd_mask() Date: Wed, 4 Apr 2018 11:22:57 +0800 Message-Id: <20180404032257.11422-1-ying.huang@intel.com> X-Mailer: git-send-email 2.15.1 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Huang Ying mmap_sem will be read locked when calling follow_pmd_mask(). But this cannot prevent PMD from being changed for all cases when PTL is unlocked, for example, from pmd_trans_huge() to pmd_none() via MADV_DONTNEED. So it is possible for the pmd_present() check in follow_pmd_mask() encounter a none PMD. This may cause incorrect VM_BUG_ON() or infinite loop. Fixed this via reading PMD entry again but only once and checking the local variable and pmd_none() in the retry loop. As Kirill pointed out, with PTL unlocked, the *pmd may be changed under us, so read it directly again and again may incur weird bugs. So although using *pmd directly other than pmd_present() checking may be safe, it is still better to replace them to read *pmd once and check the local variable for multiple times. Signed-off-by: "Huang, Ying" # When PTL unlocked, replace all *pmd with local variable Suggested-by: "Kirill A. Shutemov" Cc: Al Viro Cc: "Aneesh Kumar K.V" Cc: Dan Williams Cc: Zi Yan --- mm/gup.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 2e2df7f3e92d..51734292839b 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -213,53 +213,61 @@ static struct page *follow_pmd_mask(struct vm_area_struct *vma, unsigned long address, pud_t *pudp, unsigned int flags, unsigned int *page_mask) { - pmd_t *pmd; + pmd_t *pmd, pmdval; spinlock_t *ptl; struct page *page; struct mm_struct *mm = vma->vm_mm; pmd = pmd_offset(pudp, address); - if (pmd_none(*pmd)) + pmdval = READ_ONCE(*pmd); + if (pmd_none(pmdval)) return no_page_table(vma, flags); - if (pmd_huge(*pmd) && vma->vm_flags & VM_HUGETLB) { + if (pmd_huge(pmdval) && vma->vm_flags & VM_HUGETLB) { page = follow_huge_pmd(mm, address, pmd, flags); if (page) return page; return no_page_table(vma, flags); } - if (is_hugepd(__hugepd(pmd_val(*pmd)))) { + if (is_hugepd(__hugepd(pmd_val(pmdval)))) { page = follow_huge_pd(vma, address, - __hugepd(pmd_val(*pmd)), flags, + __hugepd(pmd_val(pmdval)), flags, PMD_SHIFT); if (page) return page; return no_page_table(vma, flags); } retry: - if (!pmd_present(*pmd)) { + if (!pmd_present(pmdval)) { if (likely(!(flags & FOLL_MIGRATION))) return no_page_table(vma, flags); VM_BUG_ON(thp_migration_supported() && - !is_pmd_migration_entry(*pmd)); - if (is_pmd_migration_entry(*pmd)) + !is_pmd_migration_entry(pmdval)); + if (is_pmd_migration_entry(pmdval)) pmd_migration_entry_wait(mm, pmd); + pmdval = READ_ONCE(*pmd); + if (pmd_none(pmdval)) + return no_page_table(vma, flags); goto retry; } - if (pmd_devmap(*pmd)) { + if (pmd_devmap(pmdval)) { ptl = pmd_lock(mm, pmd); page = follow_devmap_pmd(vma, address, pmd, flags); spin_unlock(ptl); if (page) return page; } - if (likely(!pmd_trans_huge(*pmd))) + if (likely(!pmd_trans_huge(pmdval))) return follow_page_pte(vma, address, pmd, flags); - if ((flags & FOLL_NUMA) && pmd_protnone(*pmd)) + if ((flags & FOLL_NUMA) && pmd_protnone(pmdval)) return no_page_table(vma, flags); retry_locked: ptl = pmd_lock(mm, pmd); + if (unlikely(pmd_none(*pmd))) { + spin_unlock(ptl); + return no_page_table(vma, flags); + } if (unlikely(!pmd_present(*pmd))) { spin_unlock(ptl); if (likely(!(flags & FOLL_MIGRATION))) -- 2.15.1