From nobody Tue Aug 23 20:46:57 2022 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4MC1Vn3l40z4ZFbf; Tue, 23 Aug 2022 20:46:57 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4MC1Vn3CbXz3ZNB; Tue, 23 Aug 2022 20:46:57 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1661287617; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=7DmaeEYn8evYRcSOEYyDcgFq/VnXrdHXqq7XDO2p5ns=; b=oN/3Zsp+5xbcJnSEc/bLvx8LGmBKTac6F/je05PMYYo0h9wV46ualV4uXWNxzxfu74Jy6M 7LcWlKvHbrKg03leUShzxY/6cFSB/WSNaSQRQ9ksAFpleAG76WhS2MdjTWZmy0Jv02aNqt nWzUcGAfZqAk4PKnnuv9Xwa2s/Zzq9UULFQ6mnpiNzQBrafMnTvD3HAiTgu8NY4R6RNYke ue5Z15l2B23ifEWDZw0BaTiXvGV0LCKdBcSutjMiAHHT/3P3OZ/unbEQ3RkXO+NehKc6qH j8fvfG0rh+NQVGl162Axs/dScyxoyCbdBgl+RlnP8Xis8FfXgiSMWuq4dkfO4Q== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4MC1Vn2KLTzjlR; Tue, 23 Aug 2022 20:46:57 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 27NKkvPs049344; Tue, 23 Aug 2022 20:46:57 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 27NKkvHs049343; Tue, 23 Aug 2022 20:46:57 GMT (envelope-from git) Date: Tue, 23 Aug 2022 20:46:57 GMT Message-Id: <202208232046.27NKkvHs049343@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mark Johnston Subject: git: fdb52057a4a0 - stable/13 - tests: Add more shared shadow regression tests List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: fdb52057a4a085ebd73f98abcb8c6f80da8bcdcf Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1661287617; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=7DmaeEYn8evYRcSOEYyDcgFq/VnXrdHXqq7XDO2p5ns=; b=bbiKaUktBqcZ6kdzDXMQ+OdilUBt3R8sjFThcBiNU8mux4FSMplHdCdVwRmuYXnrN9C1mu IShaJqdvov5UtPMiSGBwkOdHeGldVaOTy0lJt0tR/+QJdNA7WeEl+/FBDxKyTNutaw9HD7 ND+x44Rwxftm52s9OoXFVVtujL8cu5EO0St+5o3jF2zLXJpQ1Im9kSNuGixz2XyeGU3xEi TLbzetRMNvtXF37LeppejJV1IVa7mCxxCPWDl5TCnWB25MbxTVsFc4MId1enLiBXCvZ1pg 1xfPF1vvi9a3wcw++WaEMTZq+TZBThsppQrDFo2xgoHciSpctJ2N8h1TeUeXzg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1661287617; a=rsa-sha256; cv=none; b=wBPbkvXZiEAd9uO+xuGq69NUGQw1etjHWlvBfApccGi84Ib6dda7Xf5WtQKv7guaN2HM4U BByATlgIaOKTQfVX1IIuYoRji2dqdvsNZ/scqBKGALiniOBg9ubFK3Ci0IHqLTiPxQIF4e AFwGdjn7W8IdrOOSno/1JzWq6FxGypVjK/KrPQjEbdfJgN8E5pUsvpxPUmVGdd/D/U2sAd FF+uRBW0POGcjzVYzoXxOgXR8sDoKE9NIaJ1nHtdJY88RNf5tmk+XIDA5xZNynP5BFnW29 FOLag0I+0pngGdoDeAnmSSu2gM+sItNKiTlr4bJ+bmhsfhJWFMWfkhLp0jzXeg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=fdb52057a4a085ebd73f98abcb8c6f80da8bcdcf commit fdb52057a4a085ebd73f98abcb8c6f80da8bcdcf Author: Mark Johnston AuthorDate: 2022-08-09 20:17:56 +0000 Commit: Mark Johnston CommitDate: 2022-08-23 20:15:40 +0000 tests: Add more shared shadow regression tests The new tests exercise simulated COW that occurs when the protections on a wired, copy-on-write mapping are changed from read-only to read-write. Sponsored by: The FreeBSD Foundation (cherry picked from commit 1dfa8b73f6a68b5ec202a51021a8ec7ab4b94b8e) --- tests/sys/vm/shared_shadow_inval_test.c | 182 ++++++++++++++++++++++---------- 1 file changed, 128 insertions(+), 54 deletions(-) diff --git a/tests/sys/vm/shared_shadow_inval_test.c b/tests/sys/vm/shared_shadow_inval_test.c index 75e3655e3bd8..6a1e693d3455 100644 --- a/tests/sys/vm/shared_shadow_inval_test.c +++ b/tests/sys/vm/shared_shadow_inval_test.c @@ -1,5 +1,9 @@ /* * Copyright (c) 2021 Dell Inc. or its subsidiaries. All Rights Reserved. + * Copyright (c) 2022 The FreeBSD Foundation + * + * Portions of this software were developed by Mark Johnston under sponsorship + * from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,7 +29,13 @@ /* * Test behavior when a mapping of a shared shadow vm object is - * invalidated by COW from another mapping. + * invalidated by COW from another mapping. In particular, when + * minherit(INHERT_SHARE) is applied to a COW mapping, a subsequently + * forked child process will share the parent's shadow object. Thus, + * pages already mapped into one sharing process may be written from + * another, triggering a copy into the shadow object. The VM system + * expects that a fully shadowed page is unmapped, but at one point the + * use of a shared shadow object could break this invariant. * * This is a regression test for an issue isolated by rlibby@FreeBSD.org * from an issue detected by stress2's collapse.sh by jeff@FreeBSD.org. @@ -35,10 +45,13 @@ * standalone program with -DSTANDALONE (and optionally -DDEBUG). */ -#include +#include #include #include +#include +#include #include + #include #include @@ -49,7 +62,7 @@ #include #include -#ifdef STANDALONE +#ifdef STANDALONE #define ATF_REQUIRE(x) do { \ if (!(x)) \ errx(1, "%s", #x); \ @@ -58,7 +71,7 @@ #include #endif -#ifdef DEBUG +#ifdef DEBUG #define dprintf(...) printf(__VA_ARGS__) #else #define dprintf(...) @@ -66,20 +79,25 @@ #define DEPTH 5 +#define FLAG_COLLAPSE 0x1 +#define FLAG_BLOCK_XFER 0x2 +#define FLAG_FULLMOD 0x4 +#define FLAG_MASK (FLAG_COLLAPSE | FLAG_BLOCK_XFER | FLAG_FULLMOD) + struct shared_state { void *p; size_t len; size_t modlen; + size_t pagesize; bool collapse; bool block_xfer; + bool lazy_cow; bool okay; volatile bool exiting[DEPTH]; volatile bool exit; volatile bool p3_did_write; }; -static long g_pagesize; - /* * Program flow. There are three or four processes that are descendants * of the process running the test (P0), where arrows go from parents to @@ -123,7 +141,7 @@ child_fault(struct shared_state *ss) { size_t i; - for (i = 0; i < ss->len; i += g_pagesize) + for (i = 0; i < ss->len; i += ss->pagesize) (void)((volatile char *)ss->p)[i]; } @@ -132,7 +150,7 @@ child_write(struct shared_state *ss, int val, size_t len) { size_t i; - for (i = 0; i < len; i += g_pagesize) + for (i = 0; i < len; i += ss->pagesize) ((int *)ss->p)[i / sizeof(int)] = val; atomic_thread_fence_rel(); } @@ -154,7 +172,7 @@ child_verify(struct shared_state *ss, int depth, int newval, int oldval) size_t i; int expectval, foundval; - for (i = 0; i < ss->len; i += g_pagesize) { + for (i = 0; i < ss->len; i += ss->pagesize) { expectval = i < ss->modlen ? newval : oldval; foundval = ((int *)ss->p)[i / sizeof(int)]; if (foundval == expectval) @@ -180,8 +198,15 @@ child(struct shared_state *ss, int depth) MAP_SHARED | MAP_ANON, -1, 0); if (ss->p == MAP_FAILED) child_err("mmap"); + /* P1 stamps the shared memory. */ child_write(ss, mypid, ss->len); + if (!ss->lazy_cow) { + if (mlock(ss->p, ss->len) == -1) + child_err("mprotect"); + if (mprotect(ss->p, ss->len, PROT_READ) == -1) + child_err("mprotect"); + } if (ss->block_xfer) { /* * P4 is forked so that its existence blocks a page COW @@ -216,12 +241,16 @@ child(struct shared_state *ss, int depth) */ if (minherit(ss->p, ss->len, INHERIT_SHARE) != 0) child_err("minherit"); + /* * P2 faults a page in P1's object before P1 exits and the - * shadow chain is collapsed. + * shadow chain is collapsed. This may be redundant if the + * (read-only) mappings were copied by fork(), but it doesn't + * hurt. */ child_fault(ss); oldval = atomic_load_acq_int(ss->p); + /* Fork P3. */ pid = child_fork(ss, depth + 1); if (ss->collapse) { @@ -242,6 +271,19 @@ child(struct shared_state *ss, int depth) ss->exit = true; break; case 3: + /* + * Use mlock()+mprotect() to trigger the COW. This + * exercises a different COW handler than the one used + * for lazy faults. + */ + if (!ss->lazy_cow) { + if (mlock(ss->p, ss->len) == -1) + child_err("mlock"); + if (mprotect(ss->p, ss->len, PROT_READ | PROT_WRITE) == + -1) + child_err("mprotect"); + } + /* * P3 writes the memory. A page is faulted into the shared * P2/P3 shadow object. P2's mapping of the page in P1's @@ -268,19 +310,18 @@ child(struct shared_state *ss, int depth) } static void -do_shared_shadow_inval(bool collapse, bool block_xfer, bool full_mod) +do_one_shared_shadow_inval(bool lazy_cow, size_t pagesize, size_t len, + unsigned int flags) { struct shared_state *ss; pid_t pid; + int status; pid = getpid(); dprintf("P0 (pid %d) %s(collapse=%d, block_xfer=%d, full_mod=%d)\n", pid, __func__, (int)collapse, (int)block_xfer, (int)full_mod); - g_pagesize = sysconf(_SC_PAGESIZE); - ATF_REQUIRE(g_pagesize > 0); - ATF_REQUIRE(procctl(P_PID, pid, PROC_REAP_ACQUIRE, NULL) == 0); /* Shared memory for coordination. */ @@ -288,10 +329,12 @@ do_shared_shadow_inval(bool collapse, bool block_xfer, bool full_mod) MAP_SHARED | MAP_ANON, -1, 0); ATF_REQUIRE(ss != MAP_FAILED); - ss->len = 2 * 1024 * 1024 + g_pagesize; /* 2 MB + page size */ - ss->modlen = full_mod ? ss->len : ss->len / 2; - ss->collapse = collapse; - ss->block_xfer = block_xfer; + ss->len = len; + ss->modlen = (flags & FLAG_FULLMOD) ? ss->len : ss->len / 2; + ss->pagesize = pagesize; + ss->collapse = (flags & FLAG_COLLAPSE) != 0; + ss->block_xfer = (flags & FLAG_BLOCK_XFER) != 0; + ss->lazy_cow = lazy_cow; pid = fork(); ATF_REQUIRE(pid != -1); @@ -300,7 +343,8 @@ do_shared_shadow_inval(bool collapse, bool block_xfer, bool full_mod) /* Wait for all descendants to exit. */ do { - pid = wait(NULL); + pid = wait(&status); + ATF_REQUIRE(WIFEXITED(status)); } while (pid != -1 || errno != ECHILD); atomic_thread_fence_acq(); @@ -310,51 +354,81 @@ do_shared_shadow_inval(bool collapse, bool block_xfer, bool full_mod) ATF_REQUIRE(procctl(P_PID, getpid(), PROC_REAP_RELEASE, NULL) == 0); } +static void +do_shared_shadow_inval(bool lazy_cow) +{ + size_t largepagesize, pagesize, pagesizes[MAXPAGESIZES], sysctllen; + + sysctllen = sizeof(pagesizes); + ATF_REQUIRE(sysctlbyname("hw.pagesizes", pagesizes, &sysctllen, NULL, + 0) == 0); + ATF_REQUIRE(sysctllen >= sizeof(size_t)); + + pagesize = pagesizes[0]; + largepagesize = sysctllen >= 2 * sizeof(size_t) ? + pagesizes[1] : 2 * 1024 * 1024; + + for (unsigned int i = 0; i <= FLAG_MASK; i++) { + do_one_shared_shadow_inval(lazy_cow, pagesize, + pagesize, i); + do_one_shared_shadow_inval(lazy_cow, pagesize, + 2 * pagesize, i); + do_one_shared_shadow_inval(lazy_cow, pagesize, + largepagesize - pagesize, i); + do_one_shared_shadow_inval(lazy_cow, pagesize, + largepagesize, i); + do_one_shared_shadow_inval(lazy_cow, pagesize, + largepagesize + pagesize, i); + } +} + +static void +do_shared_shadow_inval_eager(void) +{ + struct rlimit rl; + + rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; + ATF_REQUIRE(setrlimit(RLIMIT_MEMLOCK, &rl) == 0); + + do_shared_shadow_inval(false); +} + +static void +do_shared_shadow_inval_lazy(void) +{ + do_shared_shadow_inval(true); +} + #ifdef STANDALONE int main(void) { - - do_shared_shadow_inval(false, false, false); - do_shared_shadow_inval(false, false, true); - do_shared_shadow_inval(false, true, false); - do_shared_shadow_inval(false, true, true); - do_shared_shadow_inval(true, false, false); - do_shared_shadow_inval(true, false, true); - do_shared_shadow_inval(true, true, false); - do_shared_shadow_inval(true, true, true); + do_shared_shadow_inval_lazy(); + do_shared_shadow_inval_eager(); printf("pass\n"); } #else - -#define SHARED_SHADOW_INVAL_TC(suffix, collapse, block_xfer, full_mod) \ -ATF_TC_WITHOUT_HEAD(shared_shadow_inval__##suffix); \ -ATF_TC_BODY(shared_shadow_inval__##suffix, tc) \ -{ \ - do_shared_shadow_inval(collapse, block_xfer, full_mod); \ +ATF_TC_WITHOUT_HEAD(shared_shadow_inval__lazy_cow); +ATF_TC_BODY(shared_shadow_inval__lazy_cow, tc) +{ + do_shared_shadow_inval_lazy(); } -SHARED_SHADOW_INVAL_TC(nocollapse_noblockxfer_nofullmod, false, false, false); -SHARED_SHADOW_INVAL_TC(nocollapse_noblockxfer_fullmod, false, false, true); -SHARED_SHADOW_INVAL_TC(nocollapse_blockxfer_nofullmod, false, true, false); -SHARED_SHADOW_INVAL_TC(nocollapse_blockxfer_fullmod, false, true, true); -SHARED_SHADOW_INVAL_TC(collapse_noblockxfer_nofullmod, true, false, false); -SHARED_SHADOW_INVAL_TC(collapse_noblockxfer_fullmod, true, false, true); -SHARED_SHADOW_INVAL_TC(collapse_blockxfer_nofullmod, true, true, false); -SHARED_SHADOW_INVAL_TC(collapse_blockxfer_fullmod, true, true, true); +ATF_TC(shared_shadow_inval__eager_cow); +ATF_TC_HEAD(shared_shadow_inval__eager_cow, tc) +{ + /* Needed to raise the mlock() limit. */ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(shared_shadow_inval__eager_cow, tc) +{ + do_shared_shadow_inval_eager(); +} ATF_TP_ADD_TCS(tp) { - ATF_TP_ADD_TC(tp, - shared_shadow_inval__nocollapse_noblockxfer_nofullmod); - ATF_TP_ADD_TC(tp, shared_shadow_inval__nocollapse_noblockxfer_fullmod); - ATF_TP_ADD_TC(tp, shared_shadow_inval__nocollapse_blockxfer_nofullmod); - ATF_TP_ADD_TC(tp, shared_shadow_inval__nocollapse_blockxfer_fullmod); - ATF_TP_ADD_TC(tp, shared_shadow_inval__collapse_noblockxfer_nofullmod); - ATF_TP_ADD_TC(tp, shared_shadow_inval__collapse_noblockxfer_fullmod); - ATF_TP_ADD_TC(tp, shared_shadow_inval__collapse_blockxfer_nofullmod); - ATF_TP_ADD_TC(tp, shared_shadow_inval__collapse_blockxfer_fullmod); - - return atf_no_error(); + ATF_TP_ADD_TC(tp, shared_shadow_inval__lazy_cow); + ATF_TP_ADD_TC(tp, shared_shadow_inval__eager_cow); + return (atf_no_error()); } -#endif +#endif /* !STANDALONE */