From patchwork Wed Dec 6 10:36:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suren Baghdasaryan X-Patchwork-Id: 13481427 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45DB5C10F04 for ; Wed, 6 Dec 2023 10:37:11 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id DBF826B00A0; Wed, 6 Dec 2023 05:37:10 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id D710A6B00A1; Wed, 6 Dec 2023 05:37:10 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id C11106B00A2; Wed, 6 Dec 2023 05:37:10 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id A87186B00A0 for ; Wed, 6 Dec 2023 05:37:10 -0500 (EST) Received: from smtpin03.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id 82339A0137 for ; Wed, 6 Dec 2023 10:37:10 +0000 (UTC) X-FDA: 81536041020.03.15B7687 Received: from mail-yb1-f201.google.com (mail-yb1-f201.google.com [209.85.219.201]) by imf07.hostedemail.com (Postfix) with ESMTP id BB1C440014 for ; Wed, 6 Dec 2023 10:37:08 +0000 (UTC) Authentication-Results: imf07.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=VIef0YmM; dmarc=pass (policy=reject) header.from=google.com; spf=pass (imf07.hostedemail.com: domain of 3005wZQYKCGQUWTGPDIQQING.EQONKPWZ-OOMXCEM.QTI@flex--surenb.bounces.google.com designates 209.85.219.201 as permitted sender) smtp.mailfrom=3005wZQYKCGQUWTGPDIQQING.EQONKPWZ-OOMXCEM.QTI@flex--surenb.bounces.google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1701859028; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=9XWOv5VjGfqn4Ye4rb6vL096BWUdHwApYaIgHelXwhw=; b=bcuW2Fq7epTPq8wr6/btZkKch4LwyPaMLRpvMRotyznQIx7KlkebUa8UgrZav1IcFxBt7O GM1PuiGcvFASE0e2HsGTSgvcq7/a9LLXx32IC9uKblXLL5SfjvKrfWJ2q825XAqh2kfsrA dY2yhGQuBoSumOVYzEFRpHeY9IVWc6g= ARC-Authentication-Results: i=1; imf07.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=VIef0YmM; dmarc=pass (policy=reject) header.from=google.com; spf=pass (imf07.hostedemail.com: domain of 3005wZQYKCGQUWTGPDIQQING.EQONKPWZ-OOMXCEM.QTI@flex--surenb.bounces.google.com designates 209.85.219.201 as permitted sender) smtp.mailfrom=3005wZQYKCGQUWTGPDIQQING.EQONKPWZ-OOMXCEM.QTI@flex--surenb.bounces.google.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1701859028; a=rsa-sha256; cv=none; b=IS/6jJIWJpe1jxHJ11waVIlzx6uwGOQ93XK1Zdb/L1oQQQsbMWuJm6MXmdvjHec8MMZiqT CLu+1NgBQDcj3ay9Dh1OOenVbdYrRx6FkDSzEP9oswyB6Jg6XbYvaQt9SLdywnuUah2Wt/ D+jiVzU8AZ2xH8k6ic/JDS7WsEck1ww= Received: by mail-yb1-f201.google.com with SMTP id 3f1490d57ef6-d9a541b720aso6008369276.0 for ; Wed, 06 Dec 2023 02:37:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1701859028; x=1702463828; darn=kvack.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=9XWOv5VjGfqn4Ye4rb6vL096BWUdHwApYaIgHelXwhw=; b=VIef0YmMjeSFqb/6fOL24v6C9EI7I2kM5V6D1uOD4KFIB9oHbvghykejLILpKvMON0 8JVFXRa+HtxAbEU+b+kfMWC16+aFOvb2W8g/xdHG+lxhJ7T9ibueMJsYNeI9rBnXtA8L sEgHUgH24MViLPOIPf8+pfg1POtxYLc/FmPtkYppJi6egSjEzIGn/JxqC0nB7Xb1RA9N nEeh6fLdniyZ5JUQFe0GkmPy1aURZuv0uCWWBlKKWiWqf/uSJeR/eAeV21O7wNggSS/9 VU2Blyy+xccasdIEG64INYp1l9wEjoSq0QLrxgbFX/yS32ladVK5Is/E1gq21tYbPW50 k+fg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701859028; x=1702463828; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=9XWOv5VjGfqn4Ye4rb6vL096BWUdHwApYaIgHelXwhw=; b=J7Tx7bBzCUUFayKqsxVGVKh2geAOnnE+0fEYTdBpgWsCExH5H6zNjQYYLGGObAC55w 6TZ4mvgH4+jYexQF30uT56HbMbYHnErKIpBQvfEWwBxst8FobVf5OK87qFf6sZD+4v7M ao3S+ojBkORvMgAOk3EF4DlZj875Da6+uHgGkuyFKtItUECXfSpXczDvVUfdSovUWc/T t3RiFScNLLLU6gP7wJjyBrvvInJNmo8bvIgVw25Z1uPwftxetWxv+QXWkZGWS+HWeELE BmzQqGOcia2E+UDitEL9nuJFnvHf4Z+wueAQwNd288JBiaOhFkD7hwals1DfJs4rXwA2 KTAA== X-Gm-Message-State: AOJu0YwGuQUJ1ZWvNT1HxLryrhDUZZKv7RlGyWqqHUVerdKZ9KZgOQKW tjoULW5wSkuVKvC4YnHziLXVPlUUJQo= X-Google-Smtp-Source: AGHT+IGCulkBJ+T0+9Lwp1vGAWeNFtPWyIYRPjeboNOQrA1z+wrU7Uo8XHJ4cQLDzSxZ9W28kHwF5PDUnGI= X-Received: from surenb-desktop.mtv.corp.google.com ([2620:15c:211:201:73f6:b5e2:415:6ba5]) (user=surenb job=sendgmr) by 2002:a25:7690:0:b0:db4:6936:48b7 with SMTP id r138-20020a257690000000b00db4693648b7mr5580ybc.2.1701859027736; Wed, 06 Dec 2023 02:37:07 -0800 (PST) Date: Wed, 6 Dec 2023 02:36:55 -0800 In-Reply-To: <20231206103702.3873743-1-surenb@google.com> Mime-Version: 1.0 References: <20231206103702.3873743-1-surenb@google.com> X-Mailer: git-send-email 2.43.0.rc2.451.g8631bc7472-goog Message-ID: <20231206103702.3873743-2-surenb@google.com> Subject: [PATCH v6 1/5] mm/rmap: support move to different root anon_vma in folio_move_anon_rmap() From: Suren Baghdasaryan To: akpm@linux-foundation.org Cc: viro@zeniv.linux.org.uk, brauner@kernel.org, shuah@kernel.org, aarcange@redhat.com, lokeshgidra@google.com, peterx@redhat.com, david@redhat.com, ryan.roberts@arm.com, hughd@google.com, mhocko@suse.com, axelrasmussen@google.com, rppt@kernel.org, willy@infradead.org, Liam.Howlett@oracle.com, jannh@google.com, zhangpeng362@huawei.com, bgeffon@google.com, kaleshsingh@google.com, ngeoffray@google.com, jdduke@google.com, surenb@google.com, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-team@android.com X-Rspamd-Server: rspam09 X-Rspamd-Queue-Id: BB1C440014 X-Stat-Signature: dzbwi376h8gj6j8zx767thi5b8upc169 X-Rspam-User: X-HE-Tag: 1701859028-979204 X-HE-Meta: U2FsdGVkX1+uSnl3gGjRDjjO5mHXGSGYVZOhAQAIL5sdZBEx3i2GBzBpIRV1sH4vesZTXefuRHCTEkcQohjIvR1kJYoTWmUvYxt9aNh9MskUkQ+fZ3ghhGaqtUtBZ84pYmNBhuI0We/6aWT8d+Nzr4w5mKK99qA9XiDxPCESuHxT4lP5j6Hw5zQkZqPinzCB3pLYxT9swMRF3Q6TeRcqcXCY2d1TCPQWTl/Suof3PyhEozmLjQ1NVq3ZAUSQTRfB40VsZRGDUFMJvcg/9yZIuNVut2Q5CNiqd9RSghmaWoRX6NUT2e5Ps8wac7tnziy2IaqF4v2rOcgnCkRZlvqLIQAPWnZSgRJ+04T0HLPpuSHA6IknMIwRYELqw6Nokez+RWMj0vYQALpFRAEzyJc07QwljugtVzfE2lnWnE0/ewlOIqFMJs/HiXxpQx23mOiJ9brpRlQGGNxz89UGFtmJl0Ld78cSQC5++7WeLlkBgcKzia/SFJM+Kc5twm7kmW/NL4bV0gsDP83U1mg/NEQ1HvzI03MN2+kQCep+T1T/4MjYhxIroNkjpS2rPLRs5m7kAyPkWUzwQELODH4dLqrlTMBNOIM6n1dAQW0CeVFJGpcLy5vtLWAGZlA2JhXg9BJNtsEYthsPmTgcyN8nfGhIfx38RmtoFnUdc/TB1SL3Bazpnw+KKm9n4L6Rnea62x8nvTMuq0Mtzj34Hoq04Xfhy0MxU06GjRxzr7zk1F1uctv8K/WCAQ/P8t3bizxpt3DfJOcyt8dMssjQ7cSSyWRoNC2sE6sxz467sbfs/UhAyEqYhyeYvn8GoIKbEgByXuEDI9I4iYgZzd1Aqz88ImvuVrGu3030sOo+9gaALBquSv5/pCzAdrWLyxo8x298WaWXoBf/mprv96/NJwyA4Oa8XDKDikhtNHfVPhRdyOZENrrOUctFjbxjs/wP3/7YxEukTDLXSctJ1JgHNef0DOx JgAmGz7D k2C+tE8asSLf0qOlMi/uN+0No/XHYceP0YYyokJ6LVuuawtOW473zt2WuZ7TP8GMYX2i43IVx10iqpPsES4HhVazGrkKrEatJrFulWZqOcgupYnSpmsWgZoZGkIsLn2ATkRdVAtO6ZNIUnpdl+MQFrixXeEb+Ajh0fNHvtr1P/a6LNVLa6KdKpj4nMIOqDWMIFuhFVlstfa5vcO0tQ7QpXqKAo3TwxJRmGpttZPplw31dt2pvQtLslgeJGvIkMc04DGbnUvlp1wwndy6y5BnNjjYMPvMddHIMWac7HdPDru0sDQ7D+poQp+GZhJG2hZWKstbxI9UrJzkPjGkAVrwwQCNLgZHljAYz7dqM008trA+31jJEOIQ8jRrOfX52iuVa16lK2VSvBG6c9/lpk0t75TfReSaaoiK6HzxpLOPQE0IgFhEUTIPHBA2lrFnE6ORyv6MuuFWYC6xVqajQsA66NKbClxChPlsTC6/ZbZIDamy/ZiEi3rzQ4emB3ZKiTERpc3klUkf4ELHdLbDOiF01jdlza9Qsj+orfrLaz3elfiGMyXw6LI+HNaSRjSDm80fCVkR5v5lLmvLyo5wjASg9748Tfys61peQkJmExQI9ss3gcxsntIXD+ogSYxmufk8OSLVfO0VeHjK7f8Hv1cUh0O0xGPEvx40kEHoNR27i3NfFrGtwaHwnboiyMA== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Andrea Arcangeli For now, folio_move_anon_rmap() was only used to move a folio to a different anon_vma after fork(), whereby the root anon_vma stayed unchanged. For that, it was sufficient to hold the folio lock when calling folio_move_anon_rmap(). However, we want to make use of folio_move_anon_rmap() to move folios between VMAs that have a different root anon_vma. As folio_referenced() performs an RMAP walk without holding the folio lock but only holding the anon_vma in read mode, holding the folio lock is insufficient. When moving to an anon_vma with a different root anon_vma, we'll have to hold both, the folio lock and the anon_vma lock in write mode. Consequently, whenever we succeeded in folio_lock_anon_vma_read() to read-lock the anon_vma, we have to re-check if the mapping was changed in the meantime. If that was the case, we have to retry. Note that folio_move_anon_rmap() must only be called if the anon page is exclusive to a process, and must not be called on KSM folios. This is a preparation for UFFDIO_MOVE, which will hold the folio lock, the anon_vma lock in write mode, and the mmap_lock in read mode. Signed-off-by: Andrea Arcangeli Signed-off-by: Suren Baghdasaryan Acked-by: Peter Xu --- mm/rmap.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/mm/rmap.c b/mm/rmap.c index 7a27a2b41802..525c5bc0b0b3 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -542,6 +542,7 @@ struct anon_vma *folio_lock_anon_vma_read(struct folio *folio, struct anon_vma *root_anon_vma; unsigned long anon_mapping; +retry: rcu_read_lock(); anon_mapping = (unsigned long)READ_ONCE(folio->mapping); if ((anon_mapping & PAGE_MAPPING_FLAGS) != PAGE_MAPPING_ANON) @@ -552,6 +553,17 @@ struct anon_vma *folio_lock_anon_vma_read(struct folio *folio, anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON); root_anon_vma = READ_ONCE(anon_vma->root); if (down_read_trylock(&root_anon_vma->rwsem)) { + /* + * folio_move_anon_rmap() might have changed the anon_vma as we + * might not hold the folio lock here. + */ + if (unlikely((unsigned long)READ_ONCE(folio->mapping) != + anon_mapping)) { + up_read(&root_anon_vma->rwsem); + rcu_read_unlock(); + goto retry; + } + /* * If the folio is still mapped, then this anon_vma is still * its anon_vma, and holding the mutex ensures that it will @@ -586,6 +598,18 @@ struct anon_vma *folio_lock_anon_vma_read(struct folio *folio, rcu_read_unlock(); anon_vma_lock_read(anon_vma); + /* + * folio_move_anon_rmap() might have changed the anon_vma as we might + * not hold the folio lock here. + */ + if (unlikely((unsigned long)READ_ONCE(folio->mapping) != + anon_mapping)) { + anon_vma_unlock_read(anon_vma); + put_anon_vma(anon_vma); + anon_vma = NULL; + goto retry; + } + if (atomic_dec_and_test(&anon_vma->refcount)) { /* * Oops, we held the last refcount, release the lock From patchwork Wed Dec 6 10:36:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Suren Baghdasaryan X-Patchwork-Id: 13481428 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id CF7CEC10DC1 for ; Wed, 6 Dec 2023 10:37:13 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 694D96B00A3; Wed, 6 Dec 2023 05:37:13 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 644146B00A4; Wed, 6 Dec 2023 05:37:13 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 470466B00A5; Wed, 6 Dec 2023 05:37:13 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 3059F6B00A3 for ; Wed, 6 Dec 2023 05:37:13 -0500 (EST) Received: from smtpin14.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 000D2160176 for ; Wed, 6 Dec 2023 10:37:12 +0000 (UTC) X-FDA: 81536041104.14.E147387 Received: from mail-yb1-f202.google.com (mail-yb1-f202.google.com [209.85.219.202]) by imf01.hostedemail.com (Postfix) with ESMTP id F40A540017 for ; Wed, 6 Dec 2023 10:37:10 +0000 (UTC) Authentication-Results: imf01.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=aw6ShJFl; spf=pass (imf01.hostedemail.com: domain of 31U5wZQYKCGYWYVIRFKSSKPI.GSQPMRYb-QQOZEGO.SVK@flex--surenb.bounces.google.com designates 209.85.219.202 as permitted sender) smtp.mailfrom=31U5wZQYKCGYWYVIRFKSSKPI.GSQPMRYb-QQOZEGO.SVK@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1701859031; a=rsa-sha256; cv=none; b=Gzgms/LNRb3WsWSpLq9A64BD7CmWG21nNS1ZBfCDdghPEC2RfdAMyrMIhVW2K9UymmKhsj uVeC+sj1xod68E0lUXW1d0ZjsK2KcIKzstFRRhKW4ALu9eJ7FNBF3nBxfUL/ZyCum7VsuJ CLERDoPQ+oLLAa7IGwXkqwmxLO6Z53o= ARC-Authentication-Results: i=1; imf01.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=aw6ShJFl; spf=pass (imf01.hostedemail.com: domain of 31U5wZQYKCGYWYVIRFKSSKPI.GSQPMRYb-QQOZEGO.SVK@flex--surenb.bounces.google.com designates 209.85.219.202 as permitted sender) smtp.mailfrom=31U5wZQYKCGYWYVIRFKSSKPI.GSQPMRYb-QQOZEGO.SVK@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1701859031; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=1m+fAfmNhLIONbOjkWQQKWRbqhbbihQEwxB4uoft6eI=; b=u5yU3dbZfJglUQwJdH0bgyhtOTEz7XM0Ijdk/jx9Hcn8UPsBgA/S04QYdfOLuR8NbA42ZT 13iNvJMTkCmjBteKRjYmirUOXds6MpITjdBffzzYPzVwY1uKeFLzkwh5FFEiIZGNRsJBYH yDZ2+5Dc/W9fffJm3gALc1wNpr4VVBY= Received: by mail-yb1-f202.google.com with SMTP id 3f1490d57ef6-da3dd6a72a7so6869144276.0 for ; Wed, 06 Dec 2023 02:37:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1701859030; x=1702463830; darn=kvack.org; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:from:to:cc:subject:date:message-id :reply-to; bh=1m+fAfmNhLIONbOjkWQQKWRbqhbbihQEwxB4uoft6eI=; b=aw6ShJFlvQ339b9k0QFwvl9hgxfP+WpaXA/vFjXTMA/XRgcG+o2poT8UazneJzRfnC 6S9EChJFxmIl1cm87NQ5ZTtfAxvC76X93ul1yEfyvM4idHRFNKX/vobZmu3B9Xy8Iwv0 T5NhmaegVyUj8IN6bC2osDATwvu/SOw7sVf2QCG86pLWtXMC9F1L5aQo+29yJmZPPnyW /Hhx/9GKp/XrX7BjzPW4D7bPf3zMmBw+5cnoyp3w7T4Pt4NPNyCdig+uRFI7e+RE4ysX GWYkrejqlTcnpzg9A1aCsXFMAwYNLWVnxb8JqMYN2vZeUdXCJLMgvhz8D+15g3yZ78dD HPyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701859030; x=1702463830; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to; bh=1m+fAfmNhLIONbOjkWQQKWRbqhbbihQEwxB4uoft6eI=; b=WAiItnSO8N35SpE9XEP1XzAkxA0u6CC8Yz6fO8ds1hB4PdhIwUhtdMm8eqpdm2LTZL TvSgnPwcf0j+um3x84n8/fzzbTWkWX38nymP5dyQp+WvrFoLHj7v1iwuh7iT5n1cMmJ3 /oiEskyV6cOzPwiXJmHGT+JRdZNI4MFe+XBYBGxrsjZLB4wHTOdSOdGJkIttlmAjltNB 0/ttxUisJ2hUXFAYf+Sen1HBgPbhV3a0OcxfV8vBN+1vTYav4eeKb0MZeCJQ/4YTT8YN LhpDlyH+gQQV7H7lTqMtPuIRCwfWbJXfxoIie8e6M/uG7Sl28JtzazZJwJWWMy6jiqCb ZMrQ== X-Gm-Message-State: AOJu0YypRZs7odYAp9msoSKrlg9u+Y4E3GRtDVKLJIPWZBxyNZhOxnWr KfzYvolB+Xw5k3y0h9BPlPgM+ruQbw4= X-Google-Smtp-Source: AGHT+IE/2+gixRsV1fXkFej8Rl4B7gEAlABGjtRE2KjHe0XWh9Ru/OR46ApI8ofMCJcTY8FQbRHOo5uB9RM= X-Received: from surenb-desktop.mtv.corp.google.com ([2620:15c:211:201:73f6:b5e2:415:6ba5]) (user=surenb job=sendgmr) by 2002:a25:d288:0:b0:db5:4a39:feb8 with SMTP id j130-20020a25d288000000b00db54a39feb8mr4990ybg.8.1701859029918; Wed, 06 Dec 2023 02:37:09 -0800 (PST) Date: Wed, 6 Dec 2023 02:36:56 -0800 In-Reply-To: <20231206103702.3873743-1-surenb@google.com> Mime-Version: 1.0 References: <20231206103702.3873743-1-surenb@google.com> X-Mailer: git-send-email 2.43.0.rc2.451.g8631bc7472-goog Message-ID: <20231206103702.3873743-3-surenb@google.com> Subject: [PATCH v6 2/5] userfaultfd: UFFDIO_MOVE uABI From: Suren Baghdasaryan To: akpm@linux-foundation.org Cc: viro@zeniv.linux.org.uk, brauner@kernel.org, shuah@kernel.org, aarcange@redhat.com, lokeshgidra@google.com, peterx@redhat.com, david@redhat.com, ryan.roberts@arm.com, hughd@google.com, mhocko@suse.com, axelrasmussen@google.com, rppt@kernel.org, willy@infradead.org, Liam.Howlett@oracle.com, jannh@google.com, zhangpeng362@huawei.com, bgeffon@google.com, kaleshsingh@google.com, ngeoffray@google.com, jdduke@google.com, surenb@google.com, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-team@android.com X-Rspamd-Server: rspam08 X-Rspamd-Queue-Id: F40A540017 X-Stat-Signature: edsd3acdwd8d5etmyi3egi5pdwqsxaf6 X-Rspam-User: X-HE-Tag: 1701859030-794160 X-HE-Meta: U2FsdGVkX1/sFCEXn1SO+uY29Tv7fdfatrMEPEQoEAdPkO4amU8S46eYIR0FVtUW+E7Kvsxi2iHyIp6/gcX8oWwh468t2etggZQc84n/IDcraagVUfewiOZsFC8l1X9rMt3DvGzb4eBMXRI4rX+sSiIHY3DsdcOHDLQHkVmO2B2KC70lq25hcrOEiQ7JQI9WlvWN2LgwB0y+8vsjluuUBMS3+glQ33bVf2qzpb2ZBTmQe3x3UByKoKRDOv+OkBxkOWQvgbsgSW3LmFiY5Qk92UMcz9pOzC+eM4zZaUbQcLLyxbt+0WgxYJwsoRAM8lXMqNxG3CaRXRzPf6p90Lh3gwzhGSqms7CxBpDRav0ZR6cLYkbQV7UNWBk99YQQFlB4VxilAxpv38nRrLBLNWFeFLqQXTnbOlyNtHLqgjxlYldxtEm/hinABi0Wwk7OpA6zT2wmcMKZHcT9rXM03rwaG8e7DHXOz0R6tI29Jv55MIYV2Y1czGbe3eLICISQIMQzKSlcropc5tXtcv9asi3tUqPVsb2wLu363QbY++oLIXDaDrFJrlZpNwp6wf7DIpKlkOjefi5P5xWMuR3Y9LGmS+n31uHucIXByCCX3QQHhdgIX7+iFA7B/8TnIHPLgGDwNhrU6VGXf8k7dTJiPIR4lbDB3ymlBcYgj9e18bWpOpS7OFP32kGf+Vxyi+9+SDNgC5zpE6qadg/3xOrkA65HX+lgxCB2j+TJ2AHCp34uvaDw7yFK/wX6SGqjZjLSvqPlkifmQj6phs0CILJMjRzqqIHIUHTy26i8gUgdgnNOzXuhJh56RzBTo4BNnj3GyitXp/OXkYAl5seAJLk3YcNgMWkESH8SoZCXeSSA9Rg11mrbo4oWYiK3Vn3mJFPLMA5GyqBAEkl0FNwRS2LmcxlzG4iSMe8mRcCKcURwOudgU/2OO21zdkXqZHsppxcWKAXmrrsy9L2ablSoD3tRjRO lfOOQ1Un KI9g46xmP03xbe9mOVkJjTRzhe2UhZSOL5lpbH9T3yNrZ/PAsc4NZHHha8NDCPK1a4aqhE3IC4HYXdxPZP6MLRqDklspiSTtkY26pJbKslxz93rgs5qyVwfVnmhc7gELnzeH6aBjxlLhGZlhCoKd4AxLGhsYUsZotCB0sDinMAGXQgI3p0j+XclNomCJIuxWXMMxBvVIB18wiRL21c4BSMdEO/BMPSKa85DXqOUeh+WkOoZeSXcmudp4j64DMVBuuTy4R06OlMLhWN/d+iN2yDgD9GdNVNfPiWPeFRXOm/+SIdP8Vl+Fj8wZ1WoM+jBsWxdD5BBd8rKPAlVJzVPUH5Rwggu6zDodTcLKF5p9/94u77z4KXO7o+ZbmKsH/jeeuPATGC5p2IL9+gGD8ec8dvwAqpSohhmfnfXnZ35H2+9hQtkSD0MRHRM+ouzFZ7EnmT1azI0xtv9cmMdsNppIAJq+5w2yEd96UNcod+/Geuqx2B1JbnKA6KNl9qNTXWSRoaNBKOzrBOLTXXp36xaEOQT3GWwsO4a1kClSWcXvbcy1Bm1aoDvhbyiziVCxYJsvZKMqHJviWKnOQQygBSQbb9UBo77ZoHGOtVa35JzsRGPCUrBc2X8PR/y3xRpDex8Sj6ONkrn3ZPuqpw4/xdhmXqdq7uPXpXwNmWT42iUii8ziowEzvmvnpJWuLO1MbY6LWJ230fySvFZzowH9k0KUcbZVYqGJ25JI6q0bzJulky0aFKm/YWnrkJDfgkvTV99H6r+Re X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Andrea Arcangeli Implement the uABI of UFFDIO_MOVE ioctl. UFFDIO_COPY performs ~20% better than UFFDIO_MOVE when the application needs pages to be allocated [1]. However, with UFFDIO_MOVE, if pages are available (in userspace) for recycling, as is usually the case in heap compaction algorithms, then we can avoid the page allocation and memcpy (done by UFFDIO_COPY). Also, since the pages are recycled in the userspace, we avoid the need to release (via madvise) the pages back to the kernel [2]. We see over 40% reduction (on a Google pixel 6 device) in the compacting thread’s completion time by using UFFDIO_MOVE vs. UFFDIO_COPY. This was measured using a benchmark that emulates a heap compaction implementation using userfaultfd (to allow concurrent accesses by application threads). More details of the usecase are explained in [2]. Furthermore, UFFDIO_MOVE enables moving swapped-out pages without touching them within the same vma. Today, it can only be done by mremap, however it forces splitting the vma. [1] https://lore.kernel.org/all/1425575884-2574-1-git-send-email-aarcange@redhat.com/ [2] https://lore.kernel.org/linux-mm/CA+EESO4uO84SSnBhArH4HvLNhaUQ5nZKNKXqxRCyjniNVjp0Aw@mail.gmail.com/ Update for the ioctl_userfaultfd(2) manpage: UFFDIO_MOVE (Since Linux xxx) Move a continuous memory chunk into the userfault registered range and optionally wake up the blocked thread. The source and destination addresses and the number of bytes to move are specified by the src, dst, and len fields of the uffdio_move structure pointed to by argp: struct uffdio_move { __u64 dst; /* Destination of move */ __u64 src; /* Source of move */ __u64 len; /* Number of bytes to move */ __u64 mode; /* Flags controlling behavior of move */ __s64 move; /* Number of bytes moved, or negated error */ }; The following value may be bitwise ORed in mode to change the behavior of the UFFDIO_MOVE operation: UFFDIO_MOVE_MODE_DONTWAKE Do not wake up the thread that waits for page-fault resolution UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES Allow holes in the source virtual range that is being moved. When not specified, the holes will result in ENOENT error. When specified, the holes will be accounted as successfully moved memory. This is mostly useful to move hugepage aligned virtual regions without knowing if there are transparent hugepages in the regions or not, but preventing the risk of having to split the hugepage during the operation. The move field is used by the kernel to return the number of bytes that was actually moved, or an error (a negated errno- style value). If the value returned in move doesn't match the value that was specified in len, the operation fails with the error EAGAIN. The move field is output-only; it is not read by the UFFDIO_MOVE operation. The operation may fail for various reasons. Usually, remapping of pages that are not exclusive to the given process fail; once KSM might deduplicate pages or fork() COW-shares pages during fork() with child processes, they are no longer exclusive. Further, the kernel might only perform lightweight checks for detecting whether the pages are exclusive, and return -EBUSY in case that check fails. To make the operation more likely to succeed, KSM should be disabled, fork() should be avoided or MADV_DONTFORK should be configured for the source VMA before fork(). This ioctl(2) operation returns 0 on success. In this case, the entire area was moved. On error, -1 is returned and errno is set to indicate the error. Possible errors include: EAGAIN The number of bytes moved (i.e., the value returned in the move field) does not equal the value that was specified in the len field. EINVAL Either dst or len was not a multiple of the system page size, or the range specified by src and len or dst and len was invalid. EINVAL An invalid bit was specified in the mode field. ENOENT The source virtual memory range has unmapped holes and UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES is not set. EEXIST The destination virtual memory range is fully or partially mapped. EBUSY The pages in the source virtual memory range are either pinned or not exclusive to the process. The kernel might only perform lightweight checks for detecting whether the pages are exclusive. To make the operation more likely to succeed, KSM should be disabled, fork() should be avoided or MADV_DONTFORK should be configured for the source virtual memory area before fork(). ENOMEM Allocating memory needed for the operation failed. ESRCH The target process has exited at the time of a UFFDIO_MOVE operation. Signed-off-by: Andrea Arcangeli Signed-off-by: Suren Baghdasaryan --- Documentation/admin-guide/mm/userfaultfd.rst | 3 + fs/userfaultfd.c | 72 +++ include/linux/rmap.h | 5 + include/linux/userfaultfd_k.h | 11 + include/uapi/linux/userfaultfd.h | 29 +- mm/huge_memory.c | 122 ++++ mm/khugepaged.c | 3 + mm/rmap.c | 6 + mm/userfaultfd.c | 614 +++++++++++++++++++ 9 files changed, 864 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/mm/userfaultfd.rst b/Documentation/admin-guide/mm/userfaultfd.rst index 203e26da5f92..e5cc8848dcb3 100644 --- a/Documentation/admin-guide/mm/userfaultfd.rst +++ b/Documentation/admin-guide/mm/userfaultfd.rst @@ -113,6 +113,9 @@ events, except page fault notifications, may be generated: areas. ``UFFD_FEATURE_MINOR_SHMEM`` is the analogous feature indicating support for shmem virtual memory areas. +- ``UFFD_FEATURE_MOVE`` indicates that the kernel supports moving an + existing page contents from userspace. + The userland application should set the feature flags it intends to use when invoking the ``UFFDIO_API`` ioctl, to request that those features be enabled if supported. diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index e8af40b05549..6e2a4d6a0d8f 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -2005,6 +2005,75 @@ static inline unsigned int uffd_ctx_features(__u64 user_features) return (unsigned int)user_features | UFFD_FEATURE_INITIALIZED; } +static int userfaultfd_move(struct userfaultfd_ctx *ctx, + unsigned long arg) +{ + __s64 ret; + struct uffdio_move uffdio_move; + struct uffdio_move __user *user_uffdio_move; + struct userfaultfd_wake_range range; + struct mm_struct *mm = ctx->mm; + + user_uffdio_move = (struct uffdio_move __user *) arg; + + if (atomic_read(&ctx->mmap_changing)) + return -EAGAIN; + + if (copy_from_user(&uffdio_move, user_uffdio_move, + /* don't copy "move" last field */ + sizeof(uffdio_move)-sizeof(__s64))) + return -EFAULT; + + /* Do not allow cross-mm moves. */ + if (mm != current->mm) + return -EINVAL; + + ret = validate_range(mm, uffdio_move.dst, uffdio_move.len); + if (ret) + return ret; + + ret = validate_range(mm, uffdio_move.src, uffdio_move.len); + if (ret) + return ret; + + if (uffdio_move.mode & ~(UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES| + UFFDIO_MOVE_MODE_DONTWAKE)) + return -EINVAL; + + if (mmget_not_zero(mm)) { + mmap_read_lock(mm); + + /* Re-check after taking mmap_lock */ + if (likely(!atomic_read(&ctx->mmap_changing))) + ret = move_pages(ctx, mm, uffdio_move.dst, uffdio_move.src, + uffdio_move.len, uffdio_move.mode); + else + ret = -EINVAL; + + mmap_read_unlock(mm); + mmput(mm); + } else { + return -ESRCH; + } + + if (unlikely(put_user(ret, &user_uffdio_move->move))) + return -EFAULT; + if (ret < 0) + goto out; + + /* len == 0 would wake all */ + VM_WARN_ON(!ret); + range.len = ret; + if (!(uffdio_move.mode & UFFDIO_MOVE_MODE_DONTWAKE)) { + range.start = uffdio_move.dst; + wake_userfault(ctx, &range); + } + ret = range.len == uffdio_move.len ? 0 : -EAGAIN; + +out: + return ret; +} + /* * userland asks for a certain API version and we return which bits * and ioctl commands are implemented in this kernel for such API @@ -2097,6 +2166,9 @@ static long userfaultfd_ioctl(struct file *file, unsigned cmd, case UFFDIO_ZEROPAGE: ret = userfaultfd_zeropage(ctx, arg); break; + case UFFDIO_MOVE: + ret = userfaultfd_move(ctx, arg); + break; case UFFDIO_WRITEPROTECT: ret = userfaultfd_writeprotect(ctx, arg); break; diff --git a/include/linux/rmap.h b/include/linux/rmap.h index b26fe858fd44..8034eda972e5 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -121,6 +121,11 @@ static inline void anon_vma_lock_write(struct anon_vma *anon_vma) down_write(&anon_vma->root->rwsem); } +static inline int anon_vma_trylock_write(struct anon_vma *anon_vma) +{ + return down_write_trylock(&anon_vma->root->rwsem); +} + static inline void anon_vma_unlock_write(struct anon_vma *anon_vma) { up_write(&anon_vma->root->rwsem); diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h index f2dc19f40d05..e4056547fbe6 100644 --- a/include/linux/userfaultfd_k.h +++ b/include/linux/userfaultfd_k.h @@ -93,6 +93,17 @@ extern int mwriteprotect_range(struct mm_struct *dst_mm, extern long uffd_wp_range(struct vm_area_struct *vma, unsigned long start, unsigned long len, bool enable_wp); +/* move_pages */ +void double_pt_lock(spinlock_t *ptl1, spinlock_t *ptl2); +void double_pt_unlock(spinlock_t *ptl1, spinlock_t *ptl2); +ssize_t move_pages(struct userfaultfd_ctx *ctx, struct mm_struct *mm, + unsigned long dst_start, unsigned long src_start, + unsigned long len, __u64 flags); +int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pmd_t dst_pmdval, + struct vm_area_struct *dst_vma, + struct vm_area_struct *src_vma, + unsigned long dst_addr, unsigned long src_addr); + /* mm helpers */ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma, struct vm_userfaultfd_ctx vm_ctx) diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h index 0dbc81015018..2841e4ea8f2c 100644 --- a/include/uapi/linux/userfaultfd.h +++ b/include/uapi/linux/userfaultfd.h @@ -41,7 +41,8 @@ UFFD_FEATURE_WP_HUGETLBFS_SHMEM | \ UFFD_FEATURE_WP_UNPOPULATED | \ UFFD_FEATURE_POISON | \ - UFFD_FEATURE_WP_ASYNC) + UFFD_FEATURE_WP_ASYNC | \ + UFFD_FEATURE_MOVE) #define UFFD_API_IOCTLS \ ((__u64)1 << _UFFDIO_REGISTER | \ (__u64)1 << _UFFDIO_UNREGISTER | \ @@ -50,6 +51,7 @@ ((__u64)1 << _UFFDIO_WAKE | \ (__u64)1 << _UFFDIO_COPY | \ (__u64)1 << _UFFDIO_ZEROPAGE | \ + (__u64)1 << _UFFDIO_MOVE | \ (__u64)1 << _UFFDIO_WRITEPROTECT | \ (__u64)1 << _UFFDIO_CONTINUE | \ (__u64)1 << _UFFDIO_POISON) @@ -73,6 +75,7 @@ #define _UFFDIO_WAKE (0x02) #define _UFFDIO_COPY (0x03) #define _UFFDIO_ZEROPAGE (0x04) +#define _UFFDIO_MOVE (0x05) #define _UFFDIO_WRITEPROTECT (0x06) #define _UFFDIO_CONTINUE (0x07) #define _UFFDIO_POISON (0x08) @@ -92,6 +95,8 @@ struct uffdio_copy) #define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \ struct uffdio_zeropage) +#define UFFDIO_MOVE _IOWR(UFFDIO, _UFFDIO_MOVE, \ + struct uffdio_move) #define UFFDIO_WRITEPROTECT _IOWR(UFFDIO, _UFFDIO_WRITEPROTECT, \ struct uffdio_writeprotect) #define UFFDIO_CONTINUE _IOWR(UFFDIO, _UFFDIO_CONTINUE, \ @@ -222,6 +227,9 @@ struct uffdio_api { * asynchronous mode is supported in which the write fault is * automatically resolved and write-protection is un-set. * It implies UFFD_FEATURE_WP_UNPOPULATED. + * + * UFFD_FEATURE_MOVE indicates that the kernel supports moving an + * existing page contents from userspace. */ #define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) #define UFFD_FEATURE_EVENT_FORK (1<<1) @@ -239,6 +247,7 @@ struct uffdio_api { #define UFFD_FEATURE_WP_UNPOPULATED (1<<13) #define UFFD_FEATURE_POISON (1<<14) #define UFFD_FEATURE_WP_ASYNC (1<<15) +#define UFFD_FEATURE_MOVE (1<<16) __u64 features; __u64 ioctls; @@ -347,6 +356,24 @@ struct uffdio_poison { __s64 updated; }; +struct uffdio_move { + __u64 dst; + __u64 src; + __u64 len; + /* + * Especially if used to atomically remove memory from the + * address space the wake on the dst range is not needed. + */ +#define UFFDIO_MOVE_MODE_DONTWAKE ((__u64)1<<0) +#define UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES ((__u64)1<<1) + __u64 mode; + /* + * "move" is written by the ioctl and must be at the end: the + * copy_from_user will not read the last 8 bytes. + */ + __s64 move; +}; + /* * Flags for the userfaultfd(2) system call itself. */ diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 4f542444a91f..315968db1ca4 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1964,6 +1964,128 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, return ret; } +#ifdef CONFIG_USERFAULTFD +/* + * The PT lock for src_pmd and the mmap_lock for reading are held by + * the caller, but it must return after releasing the page_table_lock. + * Just move the page from src_pmd to dst_pmd if possible. + * Return zero if succeeded in moving the page, -EAGAIN if it needs to be + * repeated by the caller, or other errors in case of failure. + */ +int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pmd_t dst_pmdval, + struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma, + unsigned long dst_addr, unsigned long src_addr) +{ + pmd_t _dst_pmd, src_pmdval; + struct page *src_page; + struct folio *src_folio; + struct anon_vma *src_anon_vma; + spinlock_t *src_ptl, *dst_ptl; + pgtable_t src_pgtable; + struct mmu_notifier_range range; + int err = 0; + + src_pmdval = *src_pmd; + src_ptl = pmd_lockptr(mm, src_pmd); + + lockdep_assert_held(src_ptl); + mmap_assert_locked(mm); + + /* Sanity checks before the operation */ + if (WARN_ON_ONCE(!pmd_none(dst_pmdval)) || WARN_ON_ONCE(src_addr & ~HPAGE_PMD_MASK) || + WARN_ON_ONCE(dst_addr & ~HPAGE_PMD_MASK)) { + spin_unlock(src_ptl); + return -EINVAL; + } + + if (!pmd_trans_huge(src_pmdval)) { + spin_unlock(src_ptl); + if (is_pmd_migration_entry(src_pmdval)) { + pmd_migration_entry_wait(mm, &src_pmdval); + return -EAGAIN; + } + return -ENOENT; + } + + src_page = pmd_page(src_pmdval); + if (unlikely(!PageAnonExclusive(src_page))) { + spin_unlock(src_ptl); + return -EBUSY; + } + + src_folio = page_folio(src_page); + folio_get(src_folio); + spin_unlock(src_ptl); + + flush_cache_range(src_vma, src_addr, src_addr + HPAGE_PMD_SIZE); + mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, mm, src_addr, + src_addr + HPAGE_PMD_SIZE); + mmu_notifier_invalidate_range_start(&range); + + folio_lock(src_folio); + + /* + * split_huge_page walks the anon_vma chain without the page + * lock. Serialize against it with the anon_vma lock, the page + * lock is not enough. + */ + src_anon_vma = folio_get_anon_vma(src_folio); + if (!src_anon_vma) { + err = -EAGAIN; + goto unlock_folio; + } + anon_vma_lock_write(src_anon_vma); + + dst_ptl = pmd_lockptr(mm, dst_pmd); + double_pt_lock(src_ptl, dst_ptl); + if (unlikely(!pmd_same(*src_pmd, src_pmdval) || + !pmd_same(*dst_pmd, dst_pmdval))) { + err = -EAGAIN; + goto unlock_ptls; + } + if (folio_maybe_dma_pinned(src_folio) || + !PageAnonExclusive(&src_folio->page)) { + err = -EBUSY; + goto unlock_ptls; + } + + if (WARN_ON_ONCE(!folio_test_head(src_folio)) || + WARN_ON_ONCE(!folio_test_anon(src_folio))) { + err = -EBUSY; + goto unlock_ptls; + } + + folio_move_anon_rmap(src_folio, dst_vma); + WRITE_ONCE(src_folio->index, linear_page_index(dst_vma, dst_addr)); + + src_pmdval = pmdp_huge_clear_flush(src_vma, src_addr, src_pmd); + /* Folio got pinned from under us. Put it back and fail the move. */ + if (folio_maybe_dma_pinned(src_folio)) { + set_pmd_at(mm, src_addr, src_pmd, src_pmdval); + err = -EBUSY; + goto unlock_ptls; + } + + _dst_pmd = mk_huge_pmd(&src_folio->page, dst_vma->vm_page_prot); + /* Follow mremap() behavior and treat the entry dirty after the move */ + _dst_pmd = pmd_mkwrite(pmd_mkdirty(_dst_pmd), dst_vma); + set_pmd_at(mm, dst_addr, dst_pmd, _dst_pmd); + + src_pgtable = pgtable_trans_huge_withdraw(mm, src_pmd); + pgtable_trans_huge_deposit(mm, dst_pmd, src_pgtable); +unlock_ptls: + double_pt_unlock(src_ptl, dst_ptl); + anon_vma_unlock_write(src_anon_vma); + put_anon_vma(src_anon_vma); +unlock_folio: + /* unblock rmap walks */ + folio_unlock(src_folio); + mmu_notifier_invalidate_range_end(&range); + folio_put(src_folio); + return err; +} +#endif /* CONFIG_USERFAULTFD */ + /* * Returns page table lock pointer if a given pmd maps a thp, NULL otherwise. * diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 064654717843..0da6937572cf 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -1139,6 +1139,9 @@ static int collapse_huge_page(struct mm_struct *mm, unsigned long address, * Prevent all access to pagetables with the exception of * gup_fast later handled by the ptep_clear_flush and the VM * handled by the anon_vma lock + PG_lock. + * + * UFFDIO_MOVE is prevented to race as well thanks to the + * mmap_lock. */ mmap_write_lock(mm); result = hugepage_vma_revalidate(mm, address, true, &vma, cc); diff --git a/mm/rmap.c b/mm/rmap.c index 525c5bc0b0b3..de9426ad0f1b 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -490,6 +490,12 @@ void __init anon_vma_init(void) * page_remove_rmap() that the anon_vma pointer from page->mapping is valid * if there is a mapcount, we can dereference the anon_vma after observing * those. + * + * NOTE: the caller should normally hold folio lock when calling this. If + * not, the caller needs to double check the anon_vma didn't change after + * taking the anon_vma lock for either read or write (UFFDIO_MOVE can modify it + * concurrently without folio lock protection). See folio_lock_anon_vma_read() + * which has already covered that, and comment above remap_pages(). */ struct anon_vma *folio_get_anon_vma(struct folio *folio) { diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 0b6ca553bebe..9ec814e47e99 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -842,3 +842,617 @@ int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start, mmap_read_unlock(dst_mm); return err; } + + +void double_pt_lock(spinlock_t *ptl1, + spinlock_t *ptl2) + __acquires(ptl1) + __acquires(ptl2) +{ + spinlock_t *ptl_tmp; + + if (ptl1 > ptl2) { + /* exchange ptl1 and ptl2 */ + ptl_tmp = ptl1; + ptl1 = ptl2; + ptl2 = ptl_tmp; + } + /* lock in virtual address order to avoid lock inversion */ + spin_lock(ptl1); + if (ptl1 != ptl2) + spin_lock_nested(ptl2, SINGLE_DEPTH_NESTING); + else + __acquire(ptl2); +} + +void double_pt_unlock(spinlock_t *ptl1, + spinlock_t *ptl2) + __releases(ptl1) + __releases(ptl2) +{ + spin_unlock(ptl1); + if (ptl1 != ptl2) + spin_unlock(ptl2); + else + __release(ptl2); +} + + +static int move_present_pte(struct mm_struct *mm, + struct vm_area_struct *dst_vma, + struct vm_area_struct *src_vma, + unsigned long dst_addr, unsigned long src_addr, + pte_t *dst_pte, pte_t *src_pte, + pte_t orig_dst_pte, pte_t orig_src_pte, + spinlock_t *dst_ptl, spinlock_t *src_ptl, + struct folio *src_folio) +{ + int err = 0; + + double_pt_lock(dst_ptl, src_ptl); + + if (!pte_same(*src_pte, orig_src_pte) || + !pte_same(*dst_pte, orig_dst_pte)) { + err = -EAGAIN; + goto out; + } + if (folio_test_large(src_folio) || + folio_maybe_dma_pinned(src_folio) || + !PageAnonExclusive(&src_folio->page)) { + err = -EBUSY; + goto out; + } + + folio_move_anon_rmap(src_folio, dst_vma); + WRITE_ONCE(src_folio->index, linear_page_index(dst_vma, dst_addr)); + + orig_src_pte = ptep_clear_flush(src_vma, src_addr, src_pte); + /* Folio got pinned from under us. Put it back and fail the move. */ + if (folio_maybe_dma_pinned(src_folio)) { + set_pte_at(mm, src_addr, src_pte, orig_src_pte); + err = -EBUSY; + goto out; + } + + orig_dst_pte = mk_pte(&src_folio->page, dst_vma->vm_page_prot); + /* Follow mremap() behavior and treat the entry dirty after the move */ + orig_dst_pte = pte_mkwrite(pte_mkdirty(orig_dst_pte), dst_vma); + + set_pte_at(mm, dst_addr, dst_pte, orig_dst_pte); +out: + double_pt_unlock(dst_ptl, src_ptl); + return err; +} + +static int move_swap_pte(struct mm_struct *mm, + unsigned long dst_addr, unsigned long src_addr, + pte_t *dst_pte, pte_t *src_pte, + pte_t orig_dst_pte, pte_t orig_src_pte, + spinlock_t *dst_ptl, spinlock_t *src_ptl) +{ + if (!pte_swp_exclusive(orig_src_pte)) + return -EBUSY; + + double_pt_lock(dst_ptl, src_ptl); + + if (!pte_same(*src_pte, orig_src_pte) || + !pte_same(*dst_pte, orig_dst_pte)) { + double_pt_unlock(dst_ptl, src_ptl); + return -EAGAIN; + } + + orig_src_pte = ptep_get_and_clear(mm, src_addr, src_pte); + set_pte_at(mm, dst_addr, dst_pte, orig_src_pte); + double_pt_unlock(dst_ptl, src_ptl); + + return 0; +} + +/* + * The mmap_lock for reading is held by the caller. Just move the page + * from src_pmd to dst_pmd if possible, and return true if succeeded + * in moving the page. + */ +static int move_pages_pte(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, + struct vm_area_struct *dst_vma, + struct vm_area_struct *src_vma, + unsigned long dst_addr, unsigned long src_addr, + __u64 mode) +{ + swp_entry_t entry; + pte_t orig_src_pte, orig_dst_pte; + pte_t src_folio_pte; + spinlock_t *src_ptl, *dst_ptl; + pte_t *src_pte = NULL; + pte_t *dst_pte = NULL; + + struct folio *src_folio = NULL; + struct anon_vma *src_anon_vma = NULL; + struct mmu_notifier_range range; + int err = 0; + + flush_cache_range(src_vma, src_addr, src_addr + PAGE_SIZE); + mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, mm, + src_addr, src_addr + PAGE_SIZE); + mmu_notifier_invalidate_range_start(&range); +retry: + dst_pte = pte_offset_map_nolock(mm, dst_pmd, dst_addr, &dst_ptl); + + /* Retry if a huge pmd materialized from under us */ + if (unlikely(!dst_pte)) { + err = -EAGAIN; + goto out; + } + + src_pte = pte_offset_map_nolock(mm, src_pmd, src_addr, &src_ptl); + + /* + * We held the mmap_lock for reading so MADV_DONTNEED + * can zap transparent huge pages under us, or the + * transparent huge page fault can establish new + * transparent huge pages under us. + */ + if (unlikely(!src_pte)) { + err = -EAGAIN; + goto out; + } + + /* Sanity checks before the operation */ + if (WARN_ON_ONCE(pmd_none(*dst_pmd)) || WARN_ON_ONCE(pmd_none(*src_pmd)) || + WARN_ON_ONCE(pmd_trans_huge(*dst_pmd)) || WARN_ON_ONCE(pmd_trans_huge(*src_pmd))) { + err = -EINVAL; + goto out; + } + + spin_lock(dst_ptl); + orig_dst_pte = *dst_pte; + spin_unlock(dst_ptl); + if (!pte_none(orig_dst_pte)) { + err = -EEXIST; + goto out; + } + + spin_lock(src_ptl); + orig_src_pte = *src_pte; + spin_unlock(src_ptl); + if (pte_none(orig_src_pte)) { + if (!(mode & UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES)) + err = -ENOENT; + else /* nothing to do to move a hole */ + err = 0; + goto out; + } + + /* If PTE changed after we locked the folio them start over */ + if (src_folio && unlikely(!pte_same(src_folio_pte, orig_src_pte))) { + err = -EAGAIN; + goto out; + } + + if (pte_present(orig_src_pte)) { + /* + * Pin and lock both source folio and anon_vma. Since we are in + * RCU read section, we can't block, so on contention have to + * unmap the ptes, obtain the lock and retry. + */ + if (!src_folio) { + struct folio *folio; + + /* + * Pin the page while holding the lock to be sure the + * page isn't freed under us + */ + spin_lock(src_ptl); + if (!pte_same(orig_src_pte, *src_pte)) { + spin_unlock(src_ptl); + err = -EAGAIN; + goto out; + } + + folio = vm_normal_folio(src_vma, src_addr, orig_src_pte); + if (!folio || !PageAnonExclusive(&folio->page)) { + spin_unlock(src_ptl); + err = -EBUSY; + goto out; + } + + folio_get(folio); + src_folio = folio; + src_folio_pte = orig_src_pte; + spin_unlock(src_ptl); + + if (!folio_trylock(src_folio)) { + pte_unmap(&orig_src_pte); + pte_unmap(&orig_dst_pte); + src_pte = dst_pte = NULL; + /* now we can block and wait */ + folio_lock(src_folio); + goto retry; + } + + if (WARN_ON_ONCE(!folio_test_anon(src_folio))) { + err = -EBUSY; + goto out; + } + } + + /* at this point we have src_folio locked */ + if (folio_test_large(src_folio)) { + err = split_folio(src_folio); + if (err) + goto out; + } + + if (!src_anon_vma) { + /* + * folio_referenced walks the anon_vma chain + * without the folio lock. Serialize against it with + * the anon_vma lock, the folio lock is not enough. + */ + src_anon_vma = folio_get_anon_vma(src_folio); + if (!src_anon_vma) { + /* page was unmapped from under us */ + err = -EAGAIN; + goto out; + } + if (!anon_vma_trylock_write(src_anon_vma)) { + pte_unmap(&orig_src_pte); + pte_unmap(&orig_dst_pte); + src_pte = dst_pte = NULL; + /* now we can block and wait */ + anon_vma_lock_write(src_anon_vma); + goto retry; + } + } + + err = move_present_pte(mm, dst_vma, src_vma, + dst_addr, src_addr, dst_pte, src_pte, + orig_dst_pte, orig_src_pte, + dst_ptl, src_ptl, src_folio); + } else { + entry = pte_to_swp_entry(orig_src_pte); + if (non_swap_entry(entry)) { + if (is_migration_entry(entry)) { + pte_unmap(&orig_src_pte); + pte_unmap(&orig_dst_pte); + src_pte = dst_pte = NULL; + migration_entry_wait(mm, src_pmd, src_addr); + err = -EAGAIN; + } else + err = -EFAULT; + goto out; + } + + err = move_swap_pte(mm, dst_addr, src_addr, + dst_pte, src_pte, + orig_dst_pte, orig_src_pte, + dst_ptl, src_ptl); + } + +out: + if (src_anon_vma) { + anon_vma_unlock_write(src_anon_vma); + put_anon_vma(src_anon_vma); + } + if (src_folio) { + folio_unlock(src_folio); + folio_put(src_folio); + } + if (dst_pte) + pte_unmap(dst_pte); + if (src_pte) + pte_unmap(src_pte); + mmu_notifier_invalidate_range_end(&range); + + return err; +} + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static inline bool move_splits_huge_pmd(unsigned long dst_addr, + unsigned long src_addr, + unsigned long src_end) +{ + return (src_addr & ~HPAGE_PMD_MASK) || (dst_addr & ~HPAGE_PMD_MASK) || + src_end - src_addr < HPAGE_PMD_SIZE; +} +#else +static inline bool move_splits_huge_pmd(unsigned long dst_addr, + unsigned long src_addr, + unsigned long src_end) +{ + /* This is unreachable anyway, just to avoid warnings when HPAGE_PMD_SIZE==0 */ + return false; +} +#endif + +static inline bool vma_move_compatible(struct vm_area_struct *vma) +{ + return !(vma->vm_flags & (VM_PFNMAP | VM_IO | VM_HUGETLB | + VM_MIXEDMAP | VM_SHADOW_STACK)); +} + +static int validate_move_areas(struct userfaultfd_ctx *ctx, + struct vm_area_struct *src_vma, + struct vm_area_struct *dst_vma) +{ + /* Only allow moving if both have the same access and protection */ + if ((src_vma->vm_flags & VM_ACCESS_FLAGS) != (dst_vma->vm_flags & VM_ACCESS_FLAGS) || + pgprot_val(src_vma->vm_page_prot) != pgprot_val(dst_vma->vm_page_prot)) + return -EINVAL; + + /* Only allow moving if both are mlocked or both aren't */ + if ((src_vma->vm_flags & VM_LOCKED) != (dst_vma->vm_flags & VM_LOCKED)) + return -EINVAL; + + /* + * For now, we keep it simple and only move between writable VMAs. + * Access flags are equal, therefore cheching only the source is enough. + */ + if (!(src_vma->vm_flags & VM_WRITE)) + return -EINVAL; + + /* Check if vma flags indicate content which can be moved */ + if (!vma_move_compatible(src_vma) || !vma_move_compatible(dst_vma)) + return -EINVAL; + + /* Ensure dst_vma is registered in uffd we are operating on */ + if (!dst_vma->vm_userfaultfd_ctx.ctx || + dst_vma->vm_userfaultfd_ctx.ctx != ctx) + return -EINVAL; + + /* Only allow moving across anonymous vmas */ + if (!vma_is_anonymous(src_vma) || !vma_is_anonymous(dst_vma)) + return -EINVAL; + + /* + * Ensure the dst_vma has a anon_vma or this page + * would get a NULL anon_vma when moved in the + * dst_vma. + */ + if (unlikely(anon_vma_prepare(dst_vma))) + return -ENOMEM; + + return 0; +} + +/** + * move_pages - move arbitrary anonymous pages of an existing vma + * @ctx: pointer to the userfaultfd context + * @mm: the address space to move pages + * @dst_start: start of the destination virtual memory range + * @src_start: start of the source virtual memory range + * @len: length of the virtual memory range + * @mode: flags from uffdio_move.mode + * + * Must be called with mmap_lock held for read. + * + * move_pages() remaps arbitrary anonymous pages atomically in zero + * copy. It only works on non shared anonymous pages because those can + * be relocated without generating non linear anon_vmas in the rmap + * code. + * + * It provides a zero copy mechanism to handle userspace page faults. + * The source vma pages should have mapcount == 1, which can be + * enforced by using madvise(MADV_DONTFORK) on src vma. + * + * The thread receiving the page during the userland page fault + * will receive the faulting page in the source vma through the network, + * storage or any other I/O device (MADV_DONTFORK in the source vma + * avoids move_pages() to fail with -EBUSY if the process forks before + * move_pages() is called), then it will call move_pages() to map the + * page in the faulting address in the destination vma. + * + * This userfaultfd command works purely via pagetables, so it's the + * most efficient way to move physical non shared anonymous pages + * across different virtual addresses. Unlike mremap()/mmap()/munmap() + * it does not create any new vmas. The mapping in the destination + * address is atomic. + * + * It only works if the vma protection bits are identical from the + * source and destination vma. + * + * It can remap non shared anonymous pages within the same vma too. + * + * If the source virtual memory range has any unmapped holes, or if + * the destination virtual memory range is not a whole unmapped hole, + * move_pages() will fail respectively with -ENOENT or -EEXIST. This + * provides a very strict behavior to avoid any chance of memory + * corruption going unnoticed if there are userland race conditions. + * Only one thread should resolve the userland page fault at any given + * time for any given faulting address. This means that if two threads + * try to both call move_pages() on the same destination address at the + * same time, the second thread will get an explicit error from this + * command. + * + * The command retval will return "len" is successful. The command + * however can be interrupted by fatal signals or errors. If + * interrupted it will return the number of bytes successfully + * remapped before the interruption if any, or the negative error if + * none. It will never return zero. Either it will return an error or + * an amount of bytes successfully moved. If the retval reports a + * "short" remap, the move_pages() command should be repeated by + * userland with src+retval, dst+reval, len-retval if it wants to know + * about the error that interrupted it. + * + * The UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES flag can be specified to + * prevent -ENOENT errors to materialize if there are holes in the + * source virtual range that is being remapped. The holes will be + * accounted as successfully remapped in the retval of the + * command. This is mostly useful to remap hugepage naturally aligned + * virtual regions without knowing if there are transparent hugepage + * in the regions or not, but preventing the risk of having to split + * the hugepmd during the remap. + * + * If there's any rmap walk that is taking the anon_vma locks without + * first obtaining the folio lock (the only current instance is + * folio_referenced), they will have to verify if the folio->mapping + * has changed after taking the anon_vma lock. If it changed they + * should release the lock and retry obtaining a new anon_vma, because + * it means the anon_vma was changed by move_pages() before the lock + * could be obtained. This is the only additional complexity added to + * the rmap code to provide this anonymous page remapping functionality. + */ +ssize_t move_pages(struct userfaultfd_ctx *ctx, struct mm_struct *mm, + unsigned long dst_start, unsigned long src_start, + unsigned long len, __u64 mode) +{ + struct vm_area_struct *src_vma, *dst_vma; + unsigned long src_addr, dst_addr; + pmd_t *src_pmd, *dst_pmd; + long err = -EINVAL; + ssize_t moved = 0; + + /* Sanitize the command parameters. */ + if (WARN_ON_ONCE(src_start & ~PAGE_MASK) || + WARN_ON_ONCE(dst_start & ~PAGE_MASK) || + WARN_ON_ONCE(len & ~PAGE_MASK)) + goto out; + + /* Does the address range wrap, or is the span zero-sized? */ + if (WARN_ON_ONCE(src_start + len <= src_start) || + WARN_ON_ONCE(dst_start + len <= dst_start)) + goto out; + + /* + * Make sure the vma is not shared, that the src and dst remap + * ranges are both valid and fully within a single existing + * vma. + */ + src_vma = find_vma(mm, src_start); + if (!src_vma || (src_vma->vm_flags & VM_SHARED)) + goto out; + if (src_start < src_vma->vm_start || + src_start + len > src_vma->vm_end) + goto out; + + dst_vma = find_vma(mm, dst_start); + if (!dst_vma || (dst_vma->vm_flags & VM_SHARED)) + goto out; + if (dst_start < dst_vma->vm_start || + dst_start + len > dst_vma->vm_end) + goto out; + + err = validate_move_areas(ctx, src_vma, dst_vma); + if (err) + goto out; + + for (src_addr = src_start, dst_addr = dst_start; + src_addr < src_start + len;) { + spinlock_t *ptl; + pmd_t dst_pmdval; + unsigned long step_size; + + /* + * Below works because anonymous area would not have a + * transparent huge PUD. If file-backed support is added, + * that case would need to be handled here. + */ + src_pmd = mm_find_pmd(mm, src_addr); + if (unlikely(!src_pmd)) { + if (!(mode & UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES)) { + err = -ENOENT; + break; + } + src_pmd = mm_alloc_pmd(mm, src_addr); + if (unlikely(!src_pmd)) { + err = -ENOMEM; + break; + } + } + dst_pmd = mm_alloc_pmd(mm, dst_addr); + if (unlikely(!dst_pmd)) { + err = -ENOMEM; + break; + } + + dst_pmdval = pmdp_get_lockless(dst_pmd); + /* + * If the dst_pmd is mapped as THP don't override it and just + * be strict. If dst_pmd changes into TPH after this check, the + * move_pages_huge_pmd() will detect the change and retry + * while move_pages_pte() will detect the change and fail. + */ + if (unlikely(pmd_trans_huge(dst_pmdval))) { + err = -EEXIST; + break; + } + + ptl = pmd_trans_huge_lock(src_pmd, src_vma); + if (ptl) { + if (pmd_devmap(*src_pmd)) { + spin_unlock(ptl); + err = -ENOENT; + break; + } + + /* Check if we can move the pmd without splitting it. */ + if (move_splits_huge_pmd(dst_addr, src_addr, src_start + len) || + !pmd_none(dst_pmdval)) { + struct folio *folio = pfn_folio(pmd_pfn(*src_pmd)); + + if (!folio || !PageAnonExclusive(&folio->page)) { + spin_unlock(ptl); + err = -EBUSY; + break; + } + + spin_unlock(ptl); + split_huge_pmd(src_vma, src_pmd, src_addr); + /* The folio will be split by move_pages_pte() */ + continue; + } + + err = move_pages_huge_pmd(mm, dst_pmd, src_pmd, + dst_pmdval, dst_vma, src_vma, + dst_addr, src_addr); + step_size = HPAGE_PMD_SIZE; + } else { + if (pmd_none(*src_pmd)) { + if (!(mode & UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES)) { + err = -ENOENT; + break; + } + if (unlikely(__pte_alloc(mm, src_pmd))) { + err = -ENOMEM; + break; + } + } + + if (unlikely(pte_alloc(mm, dst_pmd))) { + err = -ENOMEM; + break; + } + + err = move_pages_pte(mm, dst_pmd, src_pmd, + dst_vma, src_vma, + dst_addr, src_addr, mode); + step_size = PAGE_SIZE; + } + + cond_resched(); + + if (fatal_signal_pending(current)) { + /* Do not override an error */ + if (!err || err == -EAGAIN) + err = -EINTR; + break; + } + + if (err) { + if (err == -EAGAIN) + continue; + break; + } + + /* Proceed to the next page */ + dst_addr += step_size; + src_addr += step_size; + moved += step_size; + } + +out: + VM_WARN_ON(moved < 0); + VM_WARN_ON(err > 0); + VM_WARN_ON(!moved && !err); + return moved ? moved : err; +} From patchwork Wed Dec 6 10:36:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suren Baghdasaryan X-Patchwork-Id: 13481429 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 30523C10F07 for ; Wed, 6 Dec 2023 10:37:16 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 2EBB86B00A5; Wed, 6 Dec 2023 05:37:15 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 29B246B00A6; Wed, 6 Dec 2023 05:37:15 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 116806B00A7; Wed, 6 Dec 2023 05:37:15 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0013.hostedemail.com [216.40.44.13]) by kanga.kvack.org (Postfix) with ESMTP id F24FB6B00A5 for ; Wed, 6 Dec 2023 05:37:14 -0500 (EST) Received: from smtpin04.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id C8EFFA0174 for ; Wed, 6 Dec 2023 10:37:14 +0000 (UTC) X-FDA: 81536041188.04.1F59178 Received: from mail-yb1-f202.google.com (mail-yb1-f202.google.com [209.85.219.202]) by imf30.hostedemail.com (Postfix) with ESMTP id 1370B80002 for ; Wed, 6 Dec 2023 10:37:12 +0000 (UTC) Authentication-Results: imf30.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=IxgfOk0j; spf=pass (imf30.hostedemail.com: domain of 32E5wZQYKCGkZbYLUINVVNSL.JVTSPUbe-TTRcHJR.VYN@flex--surenb.bounces.google.com designates 209.85.219.202 as permitted sender) smtp.mailfrom=32E5wZQYKCGkZbYLUINVVNSL.JVTSPUbe-TTRcHJR.VYN@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1701859033; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=Puo0/IOkGZzeDNo6LANVKcztB/uZ2FwQ4rTVo9jmukU=; b=0ie1EihS030vLh6qoyqh121UzfKl10vl8aMedaMsu3QUYm5oBLK8usULdXgvOskdYIe9We TvQCd7Xxn+/8TUIUB2jaNvLz5OuzKXVyBioNyjCC+70a7H+DyDFCXhuS7kRJeGACTuujgU F3otIU7MMvo9HDzD8QoWc0sT/omIFMo= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1701859033; a=rsa-sha256; cv=none; b=y9hJtlie9D/wgy3YfmtBvXNj9eIMgDFac3A0Z9ebUA+5oZix8ugoxfGrNf/pH2huTixBqS k8A6OOL+4QeextPOQII6I4y3luQDx4T7uY04/7u32e4o5XfyC/2HYLN2C9tMCR+fbwzQRX XssYtfStyu7DtlrE9ZmaLVmjRtz/5T4= ARC-Authentication-Results: i=1; imf30.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=IxgfOk0j; spf=pass (imf30.hostedemail.com: domain of 32E5wZQYKCGkZbYLUINVVNSL.JVTSPUbe-TTRcHJR.VYN@flex--surenb.bounces.google.com designates 209.85.219.202 as permitted sender) smtp.mailfrom=32E5wZQYKCGkZbYLUINVVNSL.JVTSPUbe-TTRcHJR.VYN@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com Received: by mail-yb1-f202.google.com with SMTP id 3f1490d57ef6-db54a19c7d6so5703555276.3 for ; Wed, 06 Dec 2023 02:37:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1701859032; x=1702463832; darn=kvack.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Puo0/IOkGZzeDNo6LANVKcztB/uZ2FwQ4rTVo9jmukU=; b=IxgfOk0jZs5V0JXdxIsdkEpFEqcFAxngELMcJBxwrY/dyBLiHANpbD5BEJ7SgB5F5u bBet5VaJ5f8xgRpB094yPpGN7wEnPwqWacmsO5LQ//9zCCtdxBV6Kc0cS7CFcxq3DCrI baj+nrHDmxzeJdsezETAWPOuVwwm7G+cjW9MwfUyz2Ddw1ob0SNAiAlyExqcQjCsncqC k+jGrgPQKfIYUkFgt8BSuOAWSplz3oc/+Rdrxj8Fj4diKyIKUvyVJRrRiVCNkf+vuw6R v3Zhld2yQTQ9ey1KKFR2irIIVuZ2wMTzcL+L7hKQ32mcpfge/5TT8jlffhre00T6pvw8 EtLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701859032; x=1702463832; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Puo0/IOkGZzeDNo6LANVKcztB/uZ2FwQ4rTVo9jmukU=; b=nXHrdwRNbL7vn+G81zHqAsKYbqCmJjILPCWU9LtnwYQrWUn3Ks6WZWw5c+GePICvMc 4GDFE2Uwz2oZl2abWfneiueJRCSLY2dQuU3S1XJSI3whbxcYaBgEVKwOXzo55sqIdpuZ B6YconlsdL/5T74JBYbQhlNOOG72EOZ8OeCvyIPlxLnHzcCHAekrkPmXaODsG7SWCJhB WgMOgWmcUQWRmUkOwYphtrCVrxOOObkITy7bCJFnWP+MHH2wuxt/hc+ccClwgLGg73dl IHMolFTKlQOaL4ECQiFWbJ4uw+eXk9+VoECGCkCDY5gyK47ybQHyHvSG8XU33dqlcS33 tDTw== X-Gm-Message-State: AOJu0YzaNdlLR90GDhsxAj23PB1ZE+bf6rpiKqiT4E29aMcApxZ3DK/5 t91o9nSe9i4k4j6pvXRjBa9ULbS1E/g= X-Google-Smtp-Source: AGHT+IHA1Y29L+NkSe0tx6k2aoEfMY/lNB6ALySjHtUB1ExXnuX9TN8ZY2Jn+/kFOMbKEKZSCPu3KGAmWc0= X-Received: from surenb-desktop.mtv.corp.google.com ([2620:15c:211:201:73f6:b5e2:415:6ba5]) (user=surenb job=sendgmr) by 2002:a25:3144:0:b0:da0:5452:29e4 with SMTP id x65-20020a253144000000b00da0545229e4mr5930ybx.0.1701859032195; Wed, 06 Dec 2023 02:37:12 -0800 (PST) Date: Wed, 6 Dec 2023 02:36:57 -0800 In-Reply-To: <20231206103702.3873743-1-surenb@google.com> Mime-Version: 1.0 References: <20231206103702.3873743-1-surenb@google.com> X-Mailer: git-send-email 2.43.0.rc2.451.g8631bc7472-goog Message-ID: <20231206103702.3873743-4-surenb@google.com> Subject: [PATCH v6 3/5] selftests/mm: call uffd_test_ctx_clear at the end of the test From: Suren Baghdasaryan To: akpm@linux-foundation.org Cc: viro@zeniv.linux.org.uk, brauner@kernel.org, shuah@kernel.org, aarcange@redhat.com, lokeshgidra@google.com, peterx@redhat.com, david@redhat.com, ryan.roberts@arm.com, hughd@google.com, mhocko@suse.com, axelrasmussen@google.com, rppt@kernel.org, willy@infradead.org, Liam.Howlett@oracle.com, jannh@google.com, zhangpeng362@huawei.com, bgeffon@google.com, kaleshsingh@google.com, ngeoffray@google.com, jdduke@google.com, surenb@google.com, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-team@android.com X-Rspamd-Queue-Id: 1370B80002 X-Rspam-User: X-Rspamd-Server: rspam11 X-Stat-Signature: 95b95awhcuz33c57wqqrptzs76jk4ro7 X-HE-Tag: 1701859032-49558 X-HE-Meta: U2FsdGVkX1+17DcXXBZVrCGyM+rtYjGmQFauvmLHZm3gnqwnFYFvGmmAJGbfdorS09Z2XAHR2zYq8rYeFOiMPY67cOrT0mwQtZeBioEU30GZDdaKApzsyq6zxVyVjJ+Sd74dvS3olKYwpKc/w2F4Qwg/jan4hWOEur0gnbRu9lZM5RSrWrpkPdfQzmdpr+qgKzZTB+1m8uujXkjvNuO1yK/WAaAM4e131rz2PL2/QdQnqIz6H7DU/LIcPnxbiLOl6wdXE8rchWWKjMY72qHBQirdpo4UB6Op5lF6tmAN3ePXJZi85IJdvCob5tA3G5nctqTC4RlnAvHs5KPFYp1rl+N2RbrieehyQnvH3g53auQQZKOpAWByEYa5jzFe9hgTxqyAvG7zoogs/q2srsLQQhDhjzMuH5Ywsie/XroXKJRHXz+J/DDWwxDH5HU96Mxw9uDIO7wBlsiN1tE0eTUyimfAaafv3QjoPsHgKqzhaQ+GGb4PX/+ZDMKpzMAft4xFIAhnIcqhmcfiKFU/mGqVSbQ4tjV1Ky1TJGSCWLXuveKncdMXadX8FZN/wlTjDS2n+k5p3RwG5eLg2jtiG9WaD6G9U4Nhfm2zna+tGz37UKAhNq+qUTVGH2hiKikB90YGmn23tAImisJ/jy/yfXjDo/ht5oBC3ecc+pZBjAGrLRHjd6TLo1UK9wZKGUBpgcPXV5r5t4AVYt/RW7P/Q8bQLO2SN0vg8Eqa4fKJvKWIMUqJbt4nK3FlROlNqFCOm97MoDMPGJpS4Y/mTBsCjl7s8r5Xw/mHc+nN4H9ZlHv/eEuXJAJLenGY3tSavHJftAVS84Fg3N5IbScEP8ueTy5MbBFGPOdvf+vbP3IJxuZOYPlczhKX/oEwG3/O27pOzjLEs694vEZ5PRrRatFCcZ/PZDVJM5OgFbcfteT5rN17D4HIIBEBbQs4ecLE7859yM/n5+ijsrAE46dtipnjsYi CZn1COVz fNiLmnF0Q+IYfbCnY0GRy3vFoBRNFp1ojQa6wcxA11wtjltI+FP1NHwwvEISQ4fglyYQUjH59aZJBYnZzG+zypWoo0uBDTxLwPNBmlQvliGF27inVT6MKlRpuuQazjETdULyN5hw+JCArWyD5aYCkDQ/4/XnPfH2qDgEw8ykyxBHxmBNLZmcDkO5+lGxFXDvQ3iOUZicx8zEGcvHmwQqky1DMY8W88fhoCAv5jJR2M6rEwrYnFCkUi0/VXqtuEyhvQrl6PBjX0SZqyl62i/6mbBU1JV6n3x81M4ISl47Yo1PNtC0gfh/jsMfnqy9NURdQeyKYDvEsD81s1JUt8QdwQRZ79gXfT/LJjXBJPUU7IANFtvDKifpEOCqi5a+Q822yjstCWShCFooayc8k2aYUpFnXRr4GkUJgfacQdODN0oi0C8vEq57RjeT6l1cp7UImezPw6SQRot3R8CiTnmZKUJ2zs1XjTpOhssSNNhItgj25o6qUmzoMWGgtkdMuBMFrLRSv6RvmwidiZwGfecfRtwRuC7W8mkBiISi95K1equkxe+LGsY8GloNfwk+g5alzCZzg45lgFQtFSR5zqhuHgQnDBLJpTWXBJvRPB0Ck55wDWdspcmV5v7kvE6R6+PxUjdgjg+tuzHus4N5A3Ky72zk/S3TPpjiTMawa8Z/evBrAHcm8hWrBkcBQ4OULTnxtMzasjVzDCcIqG8yFGa5qKnoCAg== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: uffd_test_ctx_clear() is being called from uffd_test_ctx_init() to unmap areas used in the previous test run. This approach is problematic because while unmapping areas uffd_test_ctx_clear() uses page_size and nr_pages which might differ from one test run to another. Fix this by calling uffd_test_ctx_clear() after each test is done. Signed-off-by: Suren Baghdasaryan Reviewed-by: Peter Xu Reviewed-by: Axel Rasmussen --- tools/testing/selftests/mm/uffd-common.c | 4 +--- tools/testing/selftests/mm/uffd-common.h | 1 + tools/testing/selftests/mm/uffd-stress.c | 5 ++++- tools/testing/selftests/mm/uffd-unit-tests.c | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/mm/uffd-common.c b/tools/testing/selftests/mm/uffd-common.c index 02b89860e193..583e5a4cc0fd 100644 --- a/tools/testing/selftests/mm/uffd-common.c +++ b/tools/testing/selftests/mm/uffd-common.c @@ -262,7 +262,7 @@ static inline void munmap_area(void **area) *area = NULL; } -static void uffd_test_ctx_clear(void) +void uffd_test_ctx_clear(void) { size_t i; @@ -298,8 +298,6 @@ int uffd_test_ctx_init(uint64_t features, const char **errmsg) unsigned long nr, cpu; int ret; - uffd_test_ctx_clear(); - ret = uffd_test_ops->allocate_area((void **)&area_src, true); ret |= uffd_test_ops->allocate_area((void **)&area_dst, false); if (ret) { diff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selftests/mm/uffd-common.h index 7c4fa964c3b0..870776b5a323 100644 --- a/tools/testing/selftests/mm/uffd-common.h +++ b/tools/testing/selftests/mm/uffd-common.h @@ -105,6 +105,7 @@ extern uffd_test_ops_t *uffd_test_ops; void uffd_stats_report(struct uffd_args *args, int n_cpus); int uffd_test_ctx_init(uint64_t features, const char **errmsg); +void uffd_test_ctx_clear(void); int userfaultfd_open(uint64_t *features); int uffd_read_msg(int ufd, struct uffd_msg *msg); void wp_range(int ufd, __u64 start, __u64 len, bool wp); diff --git a/tools/testing/selftests/mm/uffd-stress.c b/tools/testing/selftests/mm/uffd-stress.c index 469e0476af26..7e83829bbb33 100644 --- a/tools/testing/selftests/mm/uffd-stress.c +++ b/tools/testing/selftests/mm/uffd-stress.c @@ -323,8 +323,10 @@ static int userfaultfd_stress(void) uffd_stats_reset(args, nr_cpus); /* bounce pass */ - if (stress(args)) + if (stress(args)) { + uffd_test_ctx_clear(); return 1; + } /* Clear all the write protections if there is any */ if (test_uffdio_wp) @@ -354,6 +356,7 @@ static int userfaultfd_stress(void) uffd_stats_report(args, nr_cpus); } + uffd_test_ctx_clear(); return 0; } diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c index 2709a34a39c5..e7d43c198041 100644 --- a/tools/testing/selftests/mm/uffd-unit-tests.c +++ b/tools/testing/selftests/mm/uffd-unit-tests.c @@ -1319,6 +1319,7 @@ int main(int argc, char *argv[]) continue; } test->uffd_fn(&args); + uffd_test_ctx_clear(); } } From patchwork Wed Dec 6 10:36:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suren Baghdasaryan X-Patchwork-Id: 13481430 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id DB63BC10F13 for ; Wed, 6 Dec 2023 10:37:18 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 8439F6B00A6; Wed, 6 Dec 2023 05:37:17 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 7F3E16B00A7; Wed, 6 Dec 2023 05:37:17 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 5F6176B00A8; Wed, 6 Dec 2023 05:37:17 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 4C12B6B00A6 for ; Wed, 6 Dec 2023 05:37:17 -0500 (EST) Received: from smtpin14.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 1DB8D1A0165 for ; Wed, 6 Dec 2023 10:37:17 +0000 (UTC) X-FDA: 81536041314.14.58CD8DB Received: from mail-yb1-f201.google.com (mail-yb1-f201.google.com [209.85.219.201]) by imf17.hostedemail.com (Postfix) with ESMTP id 5E41A40015 for ; Wed, 6 Dec 2023 10:37:15 +0000 (UTC) Authentication-Results: imf17.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=PMIod3NW; spf=pass (imf17.hostedemail.com: domain of 32k5wZQYKCGsbdaNWKPXXPUN.LXVURWdg-VVTeJLT.XaP@flex--surenb.bounces.google.com designates 209.85.219.201 as permitted sender) smtp.mailfrom=32k5wZQYKCGsbdaNWKPXXPUN.LXVURWdg-VVTeJLT.XaP@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1701859035; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=LKRfVsFKiKRj/bBn07n7V+AeCZxk2uFtLWEya65cVnY=; b=H/TOcg8/qW9wU5lrJGKJvkSoAe6XEJo+yg4wOONqrXjsuS1ZxP9K92nh+3yOG8lyx7OCbu ZbIyfo2kATPbALM11Djqodj85tOdadk0bkA2qkxoDtXBWPPdUX2JdKZfx1uXR5SqMvAtli y69xz+OVlMuzdaaTmj6o3MyAwtkmXuc= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1701859035; a=rsa-sha256; cv=none; b=bdqqsJ8zgBGysFbCjB2NMGXzav79MlFbz/B2M6/Xj9iPUYtVI80m7vwyd7fXEdBII3D4pb npf5jLaCMYpZDFGVQFOLup0lPyOOhCB7y/GZfgF5lhL+Vsbf5ZDHy8PvKl5svCEhwvQT3t if9NKRbGKAAyQJ/jg32/TU8ZqfsCVcY= ARC-Authentication-Results: i=1; imf17.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=PMIod3NW; spf=pass (imf17.hostedemail.com: domain of 32k5wZQYKCGsbdaNWKPXXPUN.LXVURWdg-VVTeJLT.XaP@flex--surenb.bounces.google.com designates 209.85.219.201 as permitted sender) smtp.mailfrom=32k5wZQYKCGsbdaNWKPXXPUN.LXVURWdg-VVTeJLT.XaP@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com Received: by mail-yb1-f201.google.com with SMTP id 3f1490d57ef6-db547281f5dso5863038276.2 for ; Wed, 06 Dec 2023 02:37:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1701859034; x=1702463834; darn=kvack.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=LKRfVsFKiKRj/bBn07n7V+AeCZxk2uFtLWEya65cVnY=; b=PMIod3NWPib74TVLoQZGE+olG4Ip240uKYDDs8GWYpz74xFFxpdvgR5yukhwRTtHfy TIiHVyO8bTXZ/7yHy2f6KqvOw9qxJvqNKvuCFO0FWRJDgt9deoF52fi3Hu3mvvuZx+1H +3WUGZ4m8uWeHNqwHyTIGBoI7dqPWw+KRvRWBjeSR4wLQYxEJ+xHqwOfqARSmgjlK5+8 GdAuh11odd63nKq8nBwp+y0ihSD9GmPF6XVzPMFur6vbvqHTjWWPJQIuPYf0NjQHql8t O4f4+lQVBa96TgRuaRVmpzSgZ4lXYNUB55KcTWTNHw8ovR/1cfCf6ZS+qFxjhlXTEgWJ Jcwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701859034; x=1702463834; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=LKRfVsFKiKRj/bBn07n7V+AeCZxk2uFtLWEya65cVnY=; b=mMJhSNtgfbQQX8cjoTud1CATmA3ytJjeGB55/DF8l2MfXTnv97awZad3Kuayg0kHo8 oJwxaNZyauVVfFl8Aq6zK/I970DLHV+z7vic6rtEwJHhwVjNOFvp/nZDdT65McHtC99H EE5Nikl+JsgaEOhdDBWgOtDAZHtkHPR/RI6LU3eeX6Z8fnvOY9/svEzxO/uHkWhJGMC3 ffr5WvcpTbiPHdOVPMXxvX10F9QmgCoJji043yoE3JjnN/MYmI8eJGAZTXfIcDzSmYf1 2K/w4tNxCbXFG2qBWsycHuAk1P/FPc6t0A54NIfasmS1zG9hyYB0J19i8hubQshTP88N GSlw== X-Gm-Message-State: AOJu0YyBaRdbmME4Dg45NplPau4PBWREuu81tkQeb9xacdLLNlvPhW7D wTq3C2urdPutWvrqvKfrIA65k7hZtBY= X-Google-Smtp-Source: AGHT+IHftIhmpWTuhBJ4KgQdy7Iz+ajmipBw3xyDTOe9qFzmSjg8LtWMwYZC/utheufnhCJo9BaLVXYt0+s= X-Received: from surenb-desktop.mtv.corp.google.com ([2620:15c:211:201:73f6:b5e2:415:6ba5]) (user=surenb job=sendgmr) by 2002:a25:d095:0:b0:db5:4766:e365 with SMTP id h143-20020a25d095000000b00db54766e365mr5227ybg.8.1701859034586; Wed, 06 Dec 2023 02:37:14 -0800 (PST) Date: Wed, 6 Dec 2023 02:36:58 -0800 In-Reply-To: <20231206103702.3873743-1-surenb@google.com> Mime-Version: 1.0 References: <20231206103702.3873743-1-surenb@google.com> X-Mailer: git-send-email 2.43.0.rc2.451.g8631bc7472-goog Message-ID: <20231206103702.3873743-5-surenb@google.com> Subject: [PATCH v6 4/5] selftests/mm: add uffd_test_case_ops to allow test case-specific operations From: Suren Baghdasaryan To: akpm@linux-foundation.org Cc: viro@zeniv.linux.org.uk, brauner@kernel.org, shuah@kernel.org, aarcange@redhat.com, lokeshgidra@google.com, peterx@redhat.com, david@redhat.com, ryan.roberts@arm.com, hughd@google.com, mhocko@suse.com, axelrasmussen@google.com, rppt@kernel.org, willy@infradead.org, Liam.Howlett@oracle.com, jannh@google.com, zhangpeng362@huawei.com, bgeffon@google.com, kaleshsingh@google.com, ngeoffray@google.com, jdduke@google.com, surenb@google.com, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-team@android.com X-Stat-Signature: piet1hx463deee1ip3jg199eqrgcdzau X-Rspamd-Server: rspam10 X-Rspamd-Queue-Id: 5E41A40015 X-Rspam-User: X-HE-Tag: 1701859035-671647 X-HE-Meta: U2FsdGVkX1+nUNmCqc9XqSsc1U/e62e/yexBlk0vBGYpRbzKlhmOHh/mPE8NlMVXTAHnRVPjTi1K917d2hBBak1s4tVfTdL8RRiVXS/7hs3WHq5wYnS7D31bWNaBWCzV91SR8et0k4a74fvXY+Tj5oHfHACz79Z1IZpbFUPLbN/Mf4IMkRSxVp19dNt5D75mrGDs305V9IErssurjYzs1v5m+L/Vt8AB8xQoVuqGC9aSbya+A2xquwZS+7fnI59QC5Ei+eR6GV+xtWGluSqX+X+xFMyRUa3NomMzdicaIopZsADoYp4+g1wAwH9IU2NvUrzutHRpZXeTe5zaSnPWb3PUDNq2PDMtsUYshIOAWO632dMIr3uBkoujC6deMpoT1I4RuTE9gjQiiIP8olb/vDIoTjigqTc3IfDTrSXk8Z/cY1FonhKQnIhWDj5kuLuaPiflT/ph8Uf98pBmK5caM9K/aSnuCA0Hbhch7ArkvxeqzCGKSdFwzFmGiJAVx6qgvEAEgthN+5Rgx8eXcsCOZrqCplM0UA92VLVw9aPw5p9Z7uWyLv758QJYK8TIP9PQZJmi2A5PWLBFqN7eS7Rx3OGU16DLmO31LpzaEplUtJlDKoqkS8zKkZ/W43HujUadpYtmziMTiVwS8MGhBmABX4dX6WNyt2T0E8N2BgGqILYTXR7NtqY3Meda5CBP18jmtJ7HI6lsj83aA7jFVWibCGre+yaOt8o/zRVJWzWla7KhprzVaKpmTYX/p8kYyQX7Tk/cwUu1HuAXNRj6cxw0glvIMLU4ee+61UpbIf80H0zz7mD9gkp/FLwlG0SJw/e8YvGs04IQmC8jSlFcHZJUw760CzZk6GhAlkvQ9qtZw/KfsNwugEJtvDV4pP0O4ZFQrpTeJgdENtukDgff11LdX6PlQRZvSEfkYLouFqUPqVZQGlXZAhIZ0SHL8XNNnZaWGS8MNHsmnA8BN9PUsGD g6Xea0Sg AAd0u3RqsqlJ5Wc1Me4EFlmpJtyHymoxFLeu3Nes7yEfbG+lKxUjyrAboTnFPNQ/7puYgPVI532TJeO/LXKFZS76EPRzc7adNJNze4+LSzotRyI2NnEKHHm3QPzJvRr1+w/qjw4PnXKhlv0rQocOBCS7q45BKk1mnFPF1clhHr+cEDiGkJkOR7p2ixIcJJjbo1wf7hhYZI8+RVhWG6dNROKPtaloZGgGvF91XT3H7w82lXmI/+diUVCHwEF+KjGpS36/FRSWwq6QLkM2Rwfdi4wDv7+w3a0P3q3WiWraIs/c5uvPbew83+9tFAdEB/dxiqEYqIVXKMEPdhX1LvV7UtMgcrIQMgrnY/xHGqehZaCLgYbFt42Mq4T/5vAScecwoWJfEi7CkfHXE5mAk18KPQVKHBZCs6fd/1z0oJkyTT5vdTsFSX9mpe+YEfdjodrPtU465fUD1DDVrohPHRuueTgR30WAPz3nFpHYVGZB9dHKpU1X7gxfV8AxTwNun/sfq6uDIKjdKG4yj9XYcRF23wKKcIYG79NoX2z/6mjMEBvn0O7hKEXPj37IpWe9dMiTTNfhqRlRgszHYg8Z0YeBYJA5hainqp9k9GkCXeSMNnCnpYCGTRKDH3G2iFYQw4m1nkpzwz69kA9FZQqV2GVCefWdjVw== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Currently each test can specify unique operations using uffd_test_ops, however these operations are per-memory type and not per-test. Add uffd_test_case_ops which each test case can customize for its own needs regardless of the memory type being used. Pre- and post-allocation operations are added, some of which will be used in the next patch to implement test-specific operations like madvise after memory is allocated but before it is accessed. Signed-off-by: Suren Baghdasaryan --- tools/testing/selftests/mm/uffd-common.c | 13 +++++++++++++ tools/testing/selftests/mm/uffd-common.h | 7 +++++++ tools/testing/selftests/mm/uffd-unit-tests.c | 2 ++ 3 files changed, 22 insertions(+) diff --git a/tools/testing/selftests/mm/uffd-common.c b/tools/testing/selftests/mm/uffd-common.c index 583e5a4cc0fd..fb3bbc77fd00 100644 --- a/tools/testing/selftests/mm/uffd-common.c +++ b/tools/testing/selftests/mm/uffd-common.c @@ -17,6 +17,7 @@ bool map_shared; bool test_uffdio_wp = true; unsigned long long *count_verify; uffd_test_ops_t *uffd_test_ops; +uffd_test_case_ops_t *uffd_test_case_ops; static int uffd_mem_fd_create(off_t mem_size, bool hugetlb) { @@ -298,6 +299,12 @@ int uffd_test_ctx_init(uint64_t features, const char **errmsg) unsigned long nr, cpu; int ret; + if (uffd_test_case_ops && uffd_test_case_ops->pre_alloc) { + ret = uffd_test_case_ops->pre_alloc(errmsg); + if (ret) + return ret; + } + ret = uffd_test_ops->allocate_area((void **)&area_src, true); ret |= uffd_test_ops->allocate_area((void **)&area_dst, false); if (ret) { @@ -306,6 +313,12 @@ int uffd_test_ctx_init(uint64_t features, const char **errmsg) return ret; } + if (uffd_test_case_ops && uffd_test_case_ops->post_alloc) { + ret = uffd_test_case_ops->post_alloc(errmsg); + if (ret) + return ret; + } + ret = userfaultfd_open(&features); if (ret) { if (errmsg) diff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selftests/mm/uffd-common.h index 870776b5a323..774595ee629e 100644 --- a/tools/testing/selftests/mm/uffd-common.h +++ b/tools/testing/selftests/mm/uffd-common.h @@ -90,6 +90,12 @@ struct uffd_test_ops { }; typedef struct uffd_test_ops uffd_test_ops_t; +struct uffd_test_case_ops { + int (*pre_alloc)(const char **errmsg); + int (*post_alloc)(const char **errmsg); +}; +typedef struct uffd_test_case_ops uffd_test_case_ops_t; + extern unsigned long nr_cpus, nr_pages, nr_pages_per_cpu, page_size; extern char *area_src, *area_src_alias, *area_dst, *area_dst_alias, *area_remap; extern int uffd, uffd_flags, finished, *pipefd, test_type; @@ -102,6 +108,7 @@ extern uffd_test_ops_t anon_uffd_test_ops; extern uffd_test_ops_t shmem_uffd_test_ops; extern uffd_test_ops_t hugetlb_uffd_test_ops; extern uffd_test_ops_t *uffd_test_ops; +extern uffd_test_case_ops_t *uffd_test_case_ops; void uffd_stats_report(struct uffd_args *args, int n_cpus); int uffd_test_ctx_init(uint64_t features, const char **errmsg); diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c index e7d43c198041..debc423bdbf4 100644 --- a/tools/testing/selftests/mm/uffd-unit-tests.c +++ b/tools/testing/selftests/mm/uffd-unit-tests.c @@ -78,6 +78,7 @@ typedef struct { uffd_test_fn uffd_fn; unsigned int mem_targets; uint64_t uffd_feature_required; + uffd_test_case_ops_t *test_case_ops; } uffd_test_case_t; static void uffd_test_report(void) @@ -185,6 +186,7 @@ uffd_setup_environment(uffd_test_args_t *args, uffd_test_case_t *test, { map_shared = mem_type->shared; uffd_test_ops = mem_type->mem_ops; + uffd_test_case_ops = test->test_case_ops; if (mem_type->mem_flag & (MEM_HUGETLB_PRIVATE | MEM_HUGETLB)) page_size = default_huge_page_size(); From patchwork Wed Dec 6 10:36:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suren Baghdasaryan X-Patchwork-Id: 13481431 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50353C4167B for ; Wed, 6 Dec 2023 10:37:21 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 052DC6B00A8; Wed, 6 Dec 2023 05:37:20 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 0029D6B00A9; Wed, 6 Dec 2023 05:37:19 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id DE7006B00AA; Wed, 6 Dec 2023 05:37:19 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id CDDA86B00A8 for ; Wed, 6 Dec 2023 05:37:19 -0500 (EST) Received: from smtpin23.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id AD54340113 for ; Wed, 6 Dec 2023 10:37:19 +0000 (UTC) X-FDA: 81536041398.23.7BE9C34 Received: from mail-yb1-f202.google.com (mail-yb1-f202.google.com [209.85.219.202]) by imf29.hostedemail.com (Postfix) with ESMTP id C5F88120021 for ; Wed, 6 Dec 2023 10:37:17 +0000 (UTC) Authentication-Results: imf29.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=evVJpV1S; spf=pass (imf29.hostedemail.com: domain of 33E5wZQYKCG0dfcPYMRZZRWP.NZXWTYfi-XXVgLNV.ZcR@flex--surenb.bounces.google.com designates 209.85.219.202 as permitted sender) smtp.mailfrom=33E5wZQYKCG0dfcPYMRZZRWP.NZXWTYfi-XXVgLNV.ZcR@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1701859037; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=iVIa5cg328sO4f63WvwXvkSZbx/mUmzDkh+gAL5+Ahc=; b=7qe09Yw5W2JJfoj/T9kVIqtqL9n2pqIc5kIJcEweCNWXuqPXoGyRH50h+s29kNM2WZmuu9 kyQysTfz/JKOTDD18wq48gSdG3j6Pf4regqf3JcOW2Yx314c/Jfn16NukC8p8oEp5bUR2o +cOVJE9VA0649g2ufIUyIUo+Nhm+yhw= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1701859037; a=rsa-sha256; cv=none; b=ymh79eRQY7Q/aPW5F0ayGFRgxGOBEUIyz5iBM37fmV+uKaaA6ESSZpVYYEZKERb093lmAK vv3tOO5OnHejTp8AkrgG3Z5Elaq4TEqCQmj8oUE8Tx9E0GZXA0mlWdDgjd2sM8ALnI5ymr 10SxEJMxw70r6kTM+CE911t4jwyAOvg= ARC-Authentication-Results: i=1; imf29.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=evVJpV1S; spf=pass (imf29.hostedemail.com: domain of 33E5wZQYKCG0dfcPYMRZZRWP.NZXWTYfi-XXVgLNV.ZcR@flex--surenb.bounces.google.com designates 209.85.219.202 as permitted sender) smtp.mailfrom=33E5wZQYKCG0dfcPYMRZZRWP.NZXWTYfi-XXVgLNV.ZcR@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com Received: by mail-yb1-f202.google.com with SMTP id 3f1490d57ef6-db584b8fb9cso5977223276.2 for ; Wed, 06 Dec 2023 02:37:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1701859037; x=1702463837; darn=kvack.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=iVIa5cg328sO4f63WvwXvkSZbx/mUmzDkh+gAL5+Ahc=; b=evVJpV1SysitSaTmYuY4FMCadOmJxpYWc1vli967VQium+1ZlLGdnQyKJmciRW7jes 2TyzT/ZczwSewN1nzff18NtLUnEPbwv3UZcIB810TU1cSSrvob/mjZl5wcrtqFGzXbdq YupKvoSk4GL06+2XwQ8C9Z/lDlOp2eAfhmyzpDNdma96BjsjHDPy8/SEX02i8P8pp3qH cTzMYQuWyK/4MtfSbbNKOW7DWQ7aDr+Kq6mgw08dJgN5i7NuQlqf8BGI7y77qs9K+MII mVnBx/9tuLyZuGY5SKHskn60vcZ5P7xkcECNLrfZ1Pvz24CvAgkx5isM/X3eHvUpD696 PjTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701859037; x=1702463837; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=iVIa5cg328sO4f63WvwXvkSZbx/mUmzDkh+gAL5+Ahc=; b=EGGJ5DSehFj2WH0OiiwKeYivx4vHKkiSAI+6F9FSWgjptiWGwDai3/hah+zEGDrt+s MuIaY5UtedBxyVZ0niku9dyDgchqXHmv/GF8GYteVcnre+6WXFNaCJT9V/OQzBtzNGhD YjEmEtmVRcilx9DmwPf/TgCYj3oaLbq1ii2hp5TX/FyQOsEmsHVKUZf3oSVPniW6ioVf hKnug/mQj9HNAlQ/hee1e1raALzDdQc+kfMUis2Pgaz13FsXjTbGDyc/MYJxSP0EEop9 pgUVxD9aOrBZZvGoOS0SFCu2LnMWQ7B9UlVnH9UE0LepOwrt0g7I5P6OhJozuKMAQi6B 3BsA== X-Gm-Message-State: AOJu0YxXLcFZ4YlqIGXGL7LcSAN6tUl55dHwWF5L0gMnSwl+AzOSiqCH dRnQRTwbOQ6n6FMgruWP/sySZIdJIC0= X-Google-Smtp-Source: AGHT+IGkgKbxoygTMvEFVetsgh/4I8+posq2zTqpEUJ0xsC7qcK0racQMhZFneM9yrLm1+Uko2/h58wIowE= X-Received: from surenb-desktop.mtv.corp.google.com ([2620:15c:211:201:73f6:b5e2:415:6ba5]) (user=surenb job=sendgmr) by 2002:a25:e097:0:b0:db3:fa34:50b0 with SMTP id x145-20020a25e097000000b00db3fa3450b0mr4837ybg.4.1701859036922; Wed, 06 Dec 2023 02:37:16 -0800 (PST) Date: Wed, 6 Dec 2023 02:36:59 -0800 In-Reply-To: <20231206103702.3873743-1-surenb@google.com> Mime-Version: 1.0 References: <20231206103702.3873743-1-surenb@google.com> X-Mailer: git-send-email 2.43.0.rc2.451.g8631bc7472-goog Message-ID: <20231206103702.3873743-6-surenb@google.com> Subject: [PATCH v6 5/5] selftests/mm: add UFFDIO_MOVE ioctl test From: Suren Baghdasaryan To: akpm@linux-foundation.org Cc: viro@zeniv.linux.org.uk, brauner@kernel.org, shuah@kernel.org, aarcange@redhat.com, lokeshgidra@google.com, peterx@redhat.com, david@redhat.com, ryan.roberts@arm.com, hughd@google.com, mhocko@suse.com, axelrasmussen@google.com, rppt@kernel.org, willy@infradead.org, Liam.Howlett@oracle.com, jannh@google.com, zhangpeng362@huawei.com, bgeffon@google.com, kaleshsingh@google.com, ngeoffray@google.com, jdduke@google.com, surenb@google.com, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-team@android.com X-Stat-Signature: sh76gtiai3mtbsgzsky8bqgr4oekihxu X-Rspamd-Server: rspam10 X-Rspamd-Queue-Id: C5F88120021 X-Rspam-User: X-HE-Tag: 1701859037-804871 X-HE-Meta: U2FsdGVkX18dR9135r70frw9OK/oEi9KEjgFFJmCefZvi16H2gkABKXMWGgU6RzJwTU1Q4LTJO+Q7TGym10IfL3gUn2eTr6odHqSkPDR1BclhOxM6nooKVraIMmFN2sd30FihBjYwOMM9xDmXAFSXr0lEiQs36AQGLbhwMl1saDtRd8eErnfDjvZ8Y0dGTCogaA0GVF/0qMO+1mJiFbNnQzJngT+bdb+vqC1JBTk5aRlP9EjOVtEcKiPbXHmAep62SXofJdNa4fYzy0cjTOVhgPkRC0RIoqklCnKXogjikwFiIVA9XmAVV5bpTRM6RXdD/fMmUXoATAO9E/FAEjA8j3QFd1NrssLj8njfaxmwkwS4a3zMkxCqx9/W1ttTVfU+g/vrUavttYYxAm+f2O/n+Ey79OYjTE3uTR6tNqOsuCZcuUJF+VG0BFPw9grUXgWhPBZioxwmQwK0gzzxP2Zuljn1EzqAhZskQf2uILq9UmdAXnWeeE3bWLIOsU3kF15+7kYqE62OMvHa5Nuq2dp8VEQUx3ov6ERZFr0A4+Sz5YTtlzzCMDwv86d1+FQj/TUQ6PCXfHrFDSdHvPoFJ2SUgRnQzNMG2M3ap8cAlTEkx+ytmFUHYAY8ai+Txwka9lNDPL+lZjm6mVqDd4Xy+GxecesNc4drUPtCX4c0kIBdbD/lu79RQygIyBUr311VhpgLGvGlOAGToJq2xecfY31RBxCyXHtUS7ra3YP6dlQ5LXIMUl+gcBk5pvlCcXPgespdoAFTqUfEMJX0Cc0ETtRSeV9nuH5Kt+wlUHwuyRy7UWyd6aMJ08F2NYxSCyPG1lesqfjMD/19MjeJeGWC7FWA/9XhUE68Ti68BJnvvZrM9l4yQt9n5jxdzU3xdkOCSOARgTpEmFVL9Pf+Ns25Et6scFdfqxOhUlrA5jPDF4UGPc4TlncVNilUMTIOP3AfUefCnWlRHZ5jQCwbyHHzC2 6+mk5B8z a4s9QPLz05hgW0AjEPgSWdVj4d9QVyMF9E8omHLcRJumRqNHXzUorVctnTjmBtnLe9ZJhmehvTDnb01Z2RbRTOr1y3GlzVqXd8jzCiv7znwthPvtS+RxBJYkIO7mp11z67pBmPhucbI72jr2H520WcOFVMs0hBfP5LbH4Z7mEkXU9P1OWVn38mB4m5uxYUu0dS7af/V80c0kKCcAcAJciL64RXOf8HFTnz6LP4NH23MV0901hJIgREyPFBDAjgqGC4Ydh0qHHoJ4d3r+aBh5D7HyznSGX7SMq/gi9MiwjQ/qC81VaNHAxr0Po3ozUk19FY0GXAfjlUic3DrrQkL6gpra8Fw+VtKGKqH7EgLcE9xS6rAmG06+sKZRvxTRsraxo6JQ00BFY94v88gYpA0kM0rMqHumRqSbJy9/5fJEaLWp18HtPZQYU6v9nIKkaFDBKrQaqwL98TKmywX1l0bYcpMW212F1H3BE3SAbCtrbLAcQu6a2X9zRHGF3/GFu2TfeuNKdu7bbCwntPhtfM401lZ5spWLCgq/NRVqIxR9QD5sU0ootLk2OVsRsGUA853Or5+NZZB3Hll3QtAoHt2FOMo8SYQVDz1EszWih7EuNQEi6e69HUd0ac3M4GvpNi9sASk3MudN3wBddHLKh5Db+6QJ1xS75IcFpPijy X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Add tests for new UFFDIO_MOVE ioctl which uses uffd to move source into destination buffer while checking the contents of both after the move. After the operation the content of the destination buffer should match the original source buffer's content while the source buffer should be zeroed. Separate tests are designed for PMD aligned and unaligned cases because they utilize different code paths in the kernel. Signed-off-by: Suren Baghdasaryan --- tools/testing/selftests/mm/uffd-common.c | 24 +++ tools/testing/selftests/mm/uffd-common.h | 1 + tools/testing/selftests/mm/uffd-unit-tests.c | 189 +++++++++++++++++++ 3 files changed, 214 insertions(+) diff --git a/tools/testing/selftests/mm/uffd-common.c b/tools/testing/selftests/mm/uffd-common.c index fb3bbc77fd00..b0ac0ec2356d 100644 --- a/tools/testing/selftests/mm/uffd-common.c +++ b/tools/testing/selftests/mm/uffd-common.c @@ -631,6 +631,30 @@ int copy_page(int ufd, unsigned long offset, bool wp) return __copy_page(ufd, offset, false, wp); } +int move_page(int ufd, unsigned long offset, unsigned long len) +{ + struct uffdio_move uffdio_move; + + if (offset + len > nr_pages * page_size) + err("unexpected offset %lu and length %lu\n", offset, len); + uffdio_move.dst = (unsigned long) area_dst + offset; + uffdio_move.src = (unsigned long) area_src + offset; + uffdio_move.len = len; + uffdio_move.mode = UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES; + uffdio_move.move = 0; + if (ioctl(ufd, UFFDIO_MOVE, &uffdio_move)) { + /* real retval in uffdio_move.move */ + if (uffdio_move.move != -EEXIST) + err("UFFDIO_MOVE error: %"PRId64, + (int64_t)uffdio_move.move); + wake_range(ufd, uffdio_move.dst, len); + } else if (uffdio_move.move != len) { + err("UFFDIO_MOVE error: %"PRId64, (int64_t)uffdio_move.move); + } else + return 1; + return 0; +} + int uffd_open_dev(unsigned int flags) { int fd, uffd; diff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selftests/mm/uffd-common.h index 774595ee629e..cb055282c89c 100644 --- a/tools/testing/selftests/mm/uffd-common.h +++ b/tools/testing/selftests/mm/uffd-common.h @@ -119,6 +119,7 @@ void wp_range(int ufd, __u64 start, __u64 len, bool wp); void uffd_handle_page_fault(struct uffd_msg *msg, struct uffd_args *args); int __copy_page(int ufd, unsigned long offset, bool retry, bool wp); int copy_page(int ufd, unsigned long offset, bool wp); +int move_page(int ufd, unsigned long offset, unsigned long len); void *uffd_poll_thread(void *arg); int uffd_open_dev(unsigned int flags); diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c index debc423bdbf4..d8091523c2df 100644 --- a/tools/testing/selftests/mm/uffd-unit-tests.c +++ b/tools/testing/selftests/mm/uffd-unit-tests.c @@ -23,6 +23,9 @@ #define MEM_ALL (MEM_ANON | MEM_SHMEM | MEM_SHMEM_PRIVATE | \ MEM_HUGETLB | MEM_HUGETLB_PRIVATE) +#define ALIGN_UP(x, align_to) \ + ((__typeof__(x))((((unsigned long)(x)) + ((align_to)-1)) & ~((align_to)-1))) + struct mem_type { const char *name; unsigned int mem_flag; @@ -1064,6 +1067,178 @@ static void uffd_poison_test(uffd_test_args_t *targs) uffd_test_pass(); } +static void +uffd_move_handle_fault_common(struct uffd_msg *msg, struct uffd_args *args, + unsigned long len) +{ + unsigned long offset; + + if (msg->event != UFFD_EVENT_PAGEFAULT) + err("unexpected msg event %u", msg->event); + + if (msg->arg.pagefault.flags & + (UFFD_PAGEFAULT_FLAG_WP | UFFD_PAGEFAULT_FLAG_MINOR | UFFD_PAGEFAULT_FLAG_WRITE)) + err("unexpected fault type %llu", msg->arg.pagefault.flags); + + offset = (char *)(unsigned long)msg->arg.pagefault.address - area_dst; + offset &= ~(len-1); + + if (move_page(uffd, offset, len)) + args->missing_faults++; +} + +static void uffd_move_handle_fault(struct uffd_msg *msg, + struct uffd_args *args) +{ + uffd_move_handle_fault_common(msg, args, page_size); +} + +static void uffd_move_pmd_handle_fault(struct uffd_msg *msg, + struct uffd_args *args) +{ + uffd_move_handle_fault_common(msg, args, read_pmd_pagesize()); +} + +static void +uffd_move_test_common(uffd_test_args_t *targs, unsigned long chunk_size, + void (*handle_fault)(struct uffd_msg *msg, struct uffd_args *args)) +{ + unsigned long nr; + pthread_t uffd_mon; + char c; + unsigned long long count; + struct uffd_args args = { 0 }; + char *orig_area_src, *orig_area_dst; + unsigned long step_size, step_count; + unsigned long src_offs = 0; + unsigned long dst_offs = 0; + + /* Prevent source pages from being mapped more than once */ + if (madvise(area_src, nr_pages * page_size, MADV_DONTFORK)) + err("madvise(MADV_DONTFORK) failure"); + + if (uffd_register(uffd, area_dst, nr_pages * page_size, + true, false, false)) + err("register failure"); + + args.handle_fault = handle_fault; + if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args)) + err("uffd_poll_thread create"); + + step_size = chunk_size / page_size; + step_count = nr_pages / step_size; + + if (chunk_size > page_size) { + char *aligned_src = ALIGN_UP(area_src, chunk_size); + char *aligned_dst = ALIGN_UP(area_dst, chunk_size); + + if (aligned_src != area_src || aligned_dst != area_dst) { + src_offs = (aligned_src - area_src) / page_size; + dst_offs = (aligned_dst - area_dst) / page_size; + step_count--; + } + orig_area_src = area_src; + orig_area_dst = area_dst; + area_src = aligned_src; + area_dst = aligned_dst; + } + + /* + * Read each of the pages back using the UFFD-registered mapping. We + * expect that the first time we touch a page, it will result in a missing + * fault. uffd_poll_thread will resolve the fault by moving source + * page to destination. + */ + for (nr = 0; nr < step_count * step_size; nr += step_size) { + unsigned long i; + + /* Check area_src content */ + for (i = 0; i < step_size; i++) { + count = *area_count(area_src, nr + i); + if (count != count_verify[src_offs + nr + i]) + err("nr %lu source memory invalid %llu %llu\n", + nr + i, count, count_verify[src_offs + nr + i]); + } + + /* Faulting into area_dst should move the page or the huge page */ + for (i = 0; i < step_size; i++) { + count = *area_count(area_dst, nr + i); + if (count != count_verify[dst_offs + nr + i]) + err("nr %lu memory corruption %llu %llu\n", + nr, count, count_verify[dst_offs + nr + i]); + } + + /* Re-check area_src content which should be empty */ + for (i = 0; i < step_size; i++) { + count = *area_count(area_src, nr + i); + if (count != 0) + err("nr %lu move failed %llu %llu\n", + nr, count, count_verify[src_offs + nr + i]); + } + } + if (step_size > page_size) { + area_src = orig_area_src; + area_dst = orig_area_dst; + } + + if (write(pipefd[1], &c, sizeof(c)) != sizeof(c)) + err("pipe write"); + if (pthread_join(uffd_mon, NULL)) + err("join() failed"); + + if (args.missing_faults != step_count || args.minor_faults != 0) + uffd_test_fail("stats check error"); + else + uffd_test_pass(); +} + +static void uffd_move_test(uffd_test_args_t *targs) +{ + uffd_move_test_common(targs, page_size, uffd_move_handle_fault); +} + +static void uffd_move_pmd_test(uffd_test_args_t *targs) +{ + uffd_move_test_common(targs, read_pmd_pagesize(), + uffd_move_pmd_handle_fault); +} + +static int prevent_hugepages(const char **errmsg) +{ + /* This should be done before source area is populated */ + if (madvise(area_src, nr_pages * page_size, MADV_NOHUGEPAGE)) { + /* Ignore only if CONFIG_TRANSPARENT_HUGEPAGE=n */ + if (errno != EINVAL) { + if (errmsg) + *errmsg = "madvise(MADV_NOHUGEPAGE) failed"; + return -errno; + } + } + return 0; +} + +static int request_hugepages(const char **errmsg) +{ + /* This should be done before source area is populated */ + if (madvise(area_src, nr_pages * page_size, MADV_HUGEPAGE)) { + if (errmsg) { + *errmsg = (errno == EINVAL) ? + "CONFIG_TRANSPARENT_HUGEPAGE is not set" : + "madvise(MADV_HUGEPAGE) failed"; + } + return -errno; + } + return 0; +} + +struct uffd_test_case_ops uffd_move_test_case_ops = { + .post_alloc = prevent_hugepages, +}; + +struct uffd_test_case_ops uffd_move_test_pmd_case_ops = { + .post_alloc = request_hugepages, +}; + /* * Test the returned uffdio_register.ioctls with different register modes. * Note that _UFFDIO_ZEROPAGE is tested separately in the zeropage test. @@ -1141,6 +1316,20 @@ uffd_test_case_t uffd_tests[] = { .mem_targets = MEM_ALL, .uffd_feature_required = 0, }, + { + .name = "move", + .uffd_fn = uffd_move_test, + .mem_targets = MEM_ANON, + .uffd_feature_required = UFFD_FEATURE_MOVE, + .test_case_ops = &uffd_move_test_case_ops, + }, + { + .name = "move-pmd", + .uffd_fn = uffd_move_pmd_test, + .mem_targets = MEM_ANON, + .uffd_feature_required = UFFD_FEATURE_MOVE, + .test_case_ops = &uffd_move_test_pmd_case_ops, + }, { .name = "wp-fork", .uffd_fn = uffd_wp_fork_test,