From nobody Mon Dec 1 23:04:00 2025 Received: from mail-pf1-f182.google.com (mail-pf1-f182.google.com [209.85.210.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 95BDD274B5F for ; Sat, 29 Nov 2025 09:15:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764407737; cv=none; b=QSMM4Cg6JuCcvQIHND6zi0zToG0V3ISeXDpiEYOvt8kjYwrnbokGvDfIvUuMOd8HQ3O4J9GiOxpLL+L/3ZUL8d555N2xaN6FivHYtUQiAQd07AnNp5aj98Hnp2d03XczwMpRMv9AUf3XDnfkWdgqvssgjmaKYejFEHBtlR18AiA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764407737; c=relaxed/simple; bh=g44NCATS1TCM4N3MVgj2aM+W4i89Z9A+wULVk7cS86E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=thhpOXEEb/jeoxcvDJFlNEWOkVqdndDBbEMd5ZgjV7f2xw20GzuhWUEwwhPGBRevlryOYdrCHRZuDf+ypRdB3oJSalPQPJUBwKXL4k5liqhxnjLQZfvw2DjonrZHlIWNFgGGN9E5pz4ZItYZ+VpLsgN1zPLAjXJkmKkmLJjt7Jk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=GtCGuny0; arc=none smtp.client-ip=209.85.210.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GtCGuny0" Received: by mail-pf1-f182.google.com with SMTP id d2e1a72fcca58-7ba49f92362so1561847b3a.1 for ; Sat, 29 Nov 2025 01:15:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1764407734; x=1765012534; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8dR6VknWnQZF4bSIzafZo2V382x8cKwTyyx/xFmReEY=; b=GtCGuny0JKPxy1lgupIwYdq780gZdI1gIqBA7ZYsW5vGohRQ2yxZlxtwfPvKUPRVUe aG5RfvHUe/kXgLzRTHTT6Z5OqoxrjmZEfjQZODiqj1Ll4da6XglLyXg+A69kl+QcMk1p nE52RahsgFr1vKAPZkAVjeEZpF0gN1zgDiZNd4blvcA2WG+Qy6Ap/pk/Mu5h1HB8JG3o 4doO5lZl23X3wo9DxleVnYu0F92ee4UHKd5CQwAOTHqpW1iFOg2nlWbxV5w1r4hyFlVU fqG/bCdqHNSqnE557D8QNiaWRi3+B2gxlpXazwKHHlH7OQNf/z9N8DNYcxHFJo2OzAjx BYvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764407734; x=1765012534; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8dR6VknWnQZF4bSIzafZo2V382x8cKwTyyx/xFmReEY=; b=s6E2cew0/+tAzj2j+nxhq8LpbNoZemq7NykyaWk5/rq2K6jRMc6QUVFjI5zZNAi7Y4 z79bbZz9fyTR6+mOwtQZLaGaYV8H5Jki5EYM8feA5PUU6Ahf0dF1I7N7WmckgdR8r3vx z4NzIj76WF+Fz+41Rhs3CYkMS8Wf3ikEYf8rBalzZ6tTccDjKh2aJpZNDLRXcIVeMWMG NX9hKpRMKrMNorOQenMh+ivmHDrbXXjciaw4zu+C3mLpW826rj2WXGs9hPqseosPPsT3 oEZNLqpc/0187lF8jpc/EHBwo286vs9jQ2gcKtzklgLB1Sx44TyHilCgh5y7JrmowIU4 pY3g== X-Forwarded-Encrypted: i=1; AJvYcCX6Tm77Y+pBiUrvMchIxCljMLv94IPFY+qPbVtrGj1n37zN6t3/hfgDSC5g1yfo3nQPBi++uYWdV6KFlgc=@vger.kernel.org X-Gm-Message-State: AOJu0YzoMgUpaz0UOhRY3SuJaE9GfLEqPHI4bwHnNpgOZ9t3ORzaHWYZ J6JB7x24GtC5jOvzNakj1fgkIXdfBz6Z7ixyqI4iXY9LXe+IktXwDoSY X-Gm-Gg: ASbGnct+MxMDdl1CxT4foHr1Tq8uoNglV20ySTJ85rueirKSH0kggKWXmhOehddae+x jRtlZ+JvWi7O1ChfZxz68d9O8jeUgLDT+VerYU22Y8w4WUsKnGmowEfqFXJFwlASPz96QTpReds HfkLo8mWcRRNd3Gw0J/fL9Q3i8GRZgtTWWW/ER1Q5kdOSS7CcccxIcX/ajnvJo+4ZRvEyds7kGa 0Y5IuxtWC1k1vDjyCCo+XiUNjRW6cSM9M88dOMELFhuqGpwYvnh316inVuaX7ABrO8qUU1sHxaR TgDD/g+fTg64zevN2/jJ0pnoFfcV3uC92qONwMNIhut8ELEVCTNLWFU08opwaCaBJGkz9k4+3kg zSzNURLpcsggMz1IPiAkfymZVLGbTcZtJTwcHOV9h9++e7c82p/kMUGVbxCw1KpvFGAByXw4pMn RV6Ti1r+rqPDo= X-Google-Smtp-Source: AGHT+IHruZIAOHm6EMOKF1APwodVcDGXlfmCY/BJnPMVAX/ATWPHaJ22ObFNln7/rm4RyHPip0Lemg== X-Received: by 2002:a05:6a00:cc8:b0:77d:98ee:e1c5 with SMTP id d2e1a72fcca58-7c42066e5f7mr37864729b3a.15.1764407733645; Sat, 29 Nov 2025 01:15:33 -0800 (PST) Received: from fedora ([2405:201:3017:184:2d1c:8c4c:2945:3f7c]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7d15e7db416sm7300563b3a.41.2025.11.29.01.15.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 29 Nov 2025 01:15:33 -0800 (PST) From: Bhavik Sachdev To: Alexander Viro , Christian Brauner , Shuah Khan Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, criu@lists.linux.dev, Jan Kara , Jeff Layton , Aleksa Sarai , Miklos Szeredi , Bhavik Sachdev , Pavel Tikhomirov , Andrei Vagin , Alexander Mikhalitsyn , John Hubbard , Amir Goldstein , "Martin K . Petersen" , Andrew Donnellan Subject: [PATCH v7 3/3] selftests: statmount: tests for STATMOUNT_BY_FD Date: Sat, 29 Nov 2025 14:41:22 +0530 Message-ID: <20251129091455.757724-4-b.sachdev1904@gmail.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20251129091455.757724-1-b.sachdev1904@gmail.com> References: <20251129091455.757724-1-b.sachdev1904@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add tests for STATMOUNT_BY_FD flag, which adds support for passing a file descriptors to statmount(). The fd can also be on a "unmounted" mount (mount unmounted with MNT_DETACH), we also include tests for that. Co-developed-by: Andrei Vagin Signed-off-by: Andrei Vagin Signed-off-by: Bhavik Sachdev --- .../filesystems/statmount/statmount.h | 15 +- .../filesystems/statmount/statmount_test.c | 261 +++++++++++++++++- .../filesystems/statmount/statmount_test_ns.c | 101 ++++++- 3 files changed, 354 insertions(+), 23 deletions(-) diff --git a/tools/testing/selftests/filesystems/statmount/statmount.h b/to= ols/testing/selftests/filesystems/statmount/statmount.h index 99e5ad082fb1..e1cba4bfd8d9 100644 --- a/tools/testing/selftests/filesystems/statmount/statmount.h +++ b/tools/testing/selftests/filesystems/statmount/statmount.h @@ -43,19 +43,24 @@ #endif #endif =20 -static inline int statmount(uint64_t mnt_id, uint64_t mnt_ns_id, uint64_t = mask, - struct statmount *buf, size_t bufsize, +static inline int statmount(uint64_t mnt_id, uint64_t mnt_ns_id, uint32_t = fd, + uint64_t mask, struct statmount *buf, size_t bufsize, unsigned int flags) { struct mnt_id_req req =3D { .size =3D MNT_ID_REQ_SIZE_VER0, - .mnt_id =3D mnt_id, .param =3D mask, }; =20 - if (mnt_ns_id) { + if (flags & STATMOUNT_BY_FD) { req.size =3D MNT_ID_REQ_SIZE_VER1; - req.mnt_ns_id =3D mnt_ns_id; + req.mnt_fd =3D fd; + } else { + req.mnt_id =3D mnt_id; + if (mnt_ns_id) { + req.size =3D MNT_ID_REQ_SIZE_VER1; + req.mnt_ns_id =3D mnt_ns_id; + } } =20 return syscall(__NR_statmount, &req, buf, bufsize, flags); diff --git a/tools/testing/selftests/filesystems/statmount/statmount_test.c= b/tools/testing/selftests/filesystems/statmount/statmount_test.c index f048042e53e9..4790a349806e 100644 --- a/tools/testing/selftests/filesystems/statmount/statmount_test.c +++ b/tools/testing/selftests/filesystems/statmount/statmount_test.c @@ -33,15 +33,24 @@ static const char *const known_fs[] =3D { "sysv", "tmpfs", "tracefs", "ubifs", "udf", "ufs", "v7", "vboxsf", "vfat", "virtiofs", "vxfs", "xenfs", "xfs", "zonefs", NULL }; =20 -static struct statmount *statmount_alloc(uint64_t mnt_id, uint64_t mask, u= nsigned int flags) +static struct statmount *statmount_alloc(uint64_t mnt_id, int fd, uint64_t= mask, unsigned int flags) { size_t bufsize =3D 1 << 15; - struct statmount *buf =3D NULL, *tmp =3D alloca(bufsize); + struct statmount *buf =3D NULL, *tmp =3D NULL; int tofree =3D 0; int ret; =20 + if (flags & STATMOUNT_BY_FD && fd < 0) + return NULL; + + tmp =3D alloca(bufsize); + for (;;) { - ret =3D statmount(mnt_id, 0, mask, tmp, bufsize, flags); + if (flags & STATMOUNT_BY_FD) + ret =3D statmount(0, 0, (uint32_t) fd, mask, tmp, bufsize, flags); + else + ret =3D statmount(mnt_id, 0, 0, mask, tmp, bufsize, flags); + if (ret !=3D -1) break; if (tofree) @@ -237,7 +246,7 @@ static void test_statmount_zero_mask(void) struct statmount sm; int ret; =20 - ret =3D statmount(root_id, 0, 0, &sm, sizeof(sm), 0); + ret =3D statmount(root_id, 0, 0, 0, &sm, sizeof(sm), 0); if (ret =3D=3D -1) { ksft_test_result_fail("statmount zero mask: %s\n", strerror(errno)); @@ -263,7 +272,7 @@ static void test_statmount_mnt_basic(void) int ret; uint64_t mask =3D STATMOUNT_MNT_BASIC; =20 - ret =3D statmount(root_id, 0, mask, &sm, sizeof(sm), 0); + ret =3D statmount(root_id, 0, 0, mask, &sm, sizeof(sm), 0); if (ret =3D=3D -1) { ksft_test_result_fail("statmount mnt basic: %s\n", strerror(errno)); @@ -323,7 +332,7 @@ static void test_statmount_sb_basic(void) struct statx sx; struct statfs sf; =20 - ret =3D statmount(root_id, 0, mask, &sm, sizeof(sm), 0); + ret =3D statmount(root_id, 0, 0, mask, &sm, sizeof(sm), 0); if (ret =3D=3D -1) { ksft_test_result_fail("statmount sb basic: %s\n", strerror(errno)); @@ -375,7 +384,7 @@ static void test_statmount_mnt_point(void) { struct statmount *sm; =20 - sm =3D statmount_alloc(root_id, STATMOUNT_MNT_POINT, 0); + sm =3D statmount_alloc(root_id, 0, STATMOUNT_MNT_POINT, 0); if (!sm) { ksft_test_result_fail("statmount mount point: %s\n", strerror(errno)); @@ -405,7 +414,7 @@ static void test_statmount_mnt_root(void) assert(last_dir); last_dir++; =20 - sm =3D statmount_alloc(root_id, STATMOUNT_MNT_ROOT, 0); + sm =3D statmount_alloc(root_id, 0, STATMOUNT_MNT_ROOT, 0); if (!sm) { ksft_test_result_fail("statmount mount root: %s\n", strerror(errno)); @@ -438,7 +447,7 @@ static void test_statmount_fs_type(void) const char *fs_type; const char *const *s; =20 - sm =3D statmount_alloc(root_id, STATMOUNT_FS_TYPE, 0); + sm =3D statmount_alloc(root_id, 0, STATMOUNT_FS_TYPE, 0); if (!sm) { ksft_test_result_fail("statmount fs type: %s\n", strerror(errno)); @@ -467,7 +476,7 @@ static void test_statmount_mnt_opts(void) char *line =3D NULL; size_t len =3D 0; =20 - sm =3D statmount_alloc(root_id, STATMOUNT_MNT_BASIC | STATMOUNT_MNT_OPTS, + sm =3D statmount_alloc(root_id, 0, STATMOUNT_MNT_BASIC | STATMOUNT_MNT_OP= TS, 0); if (!sm) { ksft_test_result_fail("statmount mnt opts: %s\n", @@ -557,7 +566,7 @@ static void test_statmount_string(uint64_t mask, size_t= off, const char *name) uint32_t start, i; int ret; =20 - sm =3D statmount_alloc(root_id, mask, 0); + sm =3D statmount_alloc(root_id, 0, mask, 0); if (!sm) { ksft_test_result_fail("statmount %s: %s\n", name, strerror(errno)); @@ -586,14 +595,14 @@ static void test_statmount_string(uint64_t mask, size= _t off, const char *name) exactsize =3D sm->size; shortsize =3D sizeof(*sm) + i; =20 - ret =3D statmount(root_id, 0, mask, sm, exactsize, 0); + ret =3D statmount(root_id, 0, 0, mask, sm, exactsize, 0); if (ret =3D=3D -1) { ksft_test_result_fail("statmount exact size: %s\n", strerror(errno)); goto out; } errno =3D 0; - ret =3D statmount(root_id, 0, mask, sm, shortsize, 0); + ret =3D statmount(root_id, 0, 0, mask, sm, shortsize, 0); if (ret !=3D -1 || errno !=3D EOVERFLOW) { ksft_test_result_fail("should have failed with EOVERFLOW: %s\n", strerror(errno)); @@ -658,6 +667,226 @@ static void test_listmount_tree(void) ksft_test_result_pass("listmount tree\n"); } =20 +static void test_statmount_by_fd(void) +{ + struct statmount *sm =3D NULL; + char tmpdir[] =3D "/statmount.fd.XXXXXX"; + const char root[] =3D "/test"; + char subdir[PATH_MAX], tmproot[PATH_MAX]; + int fd; + + if (!mkdtemp(tmpdir)) { + ksft_perror("mkdtemp"); + return; + } + + if (mount("statmount.test", tmpdir, "tmpfs", 0, NULL)) { + ksft_perror("mount"); + rmdir(tmpdir); + return; + } + + snprintf(subdir, PATH_MAX, "%s%s", tmpdir, root); + snprintf(tmproot, PATH_MAX, "%s/%s", tmpdir, "chroot"); + + if (mkdir(subdir, 0755)) { + ksft_perror("mkdir"); + goto err_tmpdir; + } + + if (mount(subdir, subdir, NULL, MS_BIND, 0)) { + ksft_perror("mount"); + goto err_subdir; + } + + if (mkdir(tmproot, 0755)) { + ksft_perror("mkdir"); + goto err_subdir; + } + + fd =3D open(subdir, O_PATH); + if (fd < 0) { + ksft_perror("open"); + goto err_tmproot; + } + + if (chroot(tmproot)) { + ksft_perror("chroot"); + goto err_fd; + } + + sm =3D statmount_alloc(0, fd, STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT, S= TATMOUNT_BY_FD); + if (!sm) { + ksft_test_result_fail("statmount by fd failed: %s\n", strerror(errno)); + goto err_chroot; + } + + if (sm->size < sizeof(*sm)) { + ksft_test_result_fail("unexpected size: %u < %u\n", + sm->size, (uint32_t) sizeof(*sm)); + goto err_chroot; + } + + if (sm->mask & STATMOUNT_MNT_POINT) { + ksft_test_result_fail("STATMOUNT_MNT_POINT unexpectedly set in statmount= \n"); + goto err_chroot; + } + + if (!(sm->mask & STATMOUNT_MNT_ROOT)) { + ksft_test_result_fail("STATMOUNT_MNT_ROOT not set in statmount\n"); + goto err_chroot; + } + + if (strcmp(root, sm->str + sm->mnt_root) !=3D 0) { + ksft_test_result_fail("statmount returned incorrect mnt_root," + "statmount mnt_root: %s !=3D %s\n", + sm->str + sm->mnt_root, root); + goto err_chroot; + } + + if (chroot(".")) { + ksft_perror("chroot"); + goto out; + } + + free(sm); + sm =3D statmount_alloc(0, fd, STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT, S= TATMOUNT_BY_FD); + if (!sm) { + ksft_test_result_fail("statmount by fd failed: %s\n", strerror(errno)); + goto err_fd; + } + + if (sm->size < sizeof(*sm)) { + ksft_test_result_fail("unexpected size: %u < %u\n", + sm->size, (uint32_t) sizeof(*sm)); + goto out; + } + + if (!(sm->mask & STATMOUNT_MNT_POINT)) { + ksft_test_result_fail("STATMOUNT_MNT_POINT not set in statmount\n"); + goto out; + } + + if (!(sm->mask & STATMOUNT_MNT_ROOT)) { + ksft_test_result_fail("STATMOUNT_MNT_ROOT not set in statmount\n"); + goto out; + } + + if (strcmp(subdir, sm->str + sm->mnt_point) !=3D 0) { + ksft_test_result_fail("statmount returned incorrect mnt_point," + "statmount mnt_point: %s !=3D %s\n", sm->str + sm->mnt_point, subdir); + goto out; + } + + if (strcmp(root, sm->str + sm->mnt_root) !=3D 0) { + ksft_test_result_fail("statmount returned incorrect mnt_root," + "statmount mnt_root: %s !=3D %s\n", sm->str + sm->mnt_root, root); + goto out; + } + + ksft_test_result_pass("statmount by fd\n"); + goto out; +err_chroot: + chroot("."); +out: + free(sm); +err_fd: + close(fd); +err_tmproot: + rmdir(tmproot); +err_subdir: + umount2(subdir, MNT_DETACH); + rmdir(subdir); +err_tmpdir: + umount2(tmpdir, MNT_DETACH); + rmdir(tmpdir); +} + +static void test_statmount_by_fd_unmounted(void) +{ + const char root[] =3D "/test.unmounted"; + char tmpdir[] =3D "/statmount.fd.XXXXXX"; + char subdir[PATH_MAX]; + int fd; + struct statmount *sm =3D NULL; + + if (!mkdtemp(tmpdir)) { + ksft_perror("mkdtemp"); + return; + } + + if (mount("statmount.test", tmpdir, "tmpfs", 0, NULL)) { + ksft_perror("mount"); + rmdir(tmpdir); + return; + } + + snprintf(subdir, PATH_MAX, "%s%s", tmpdir, root); + + if (mkdir(subdir, 0755)) { + ksft_perror("mkdir"); + goto err_tmpdir; + } + + if (mount(subdir, subdir, 0, MS_BIND, NULL)) { + ksft_perror("mount"); + goto err_subdir; + } + + fd =3D open(subdir, O_PATH); + if (fd < 0) { + ksft_perror("open"); + goto err_subdir; + } + + if (umount2(tmpdir, MNT_DETACH)) { + ksft_perror("umount2"); + goto err_fd; + } + + sm =3D statmount_alloc(0, fd, STATMOUNT_MNT_POINT | STATMOUNT_MNT_ROOT, S= TATMOUNT_BY_FD); + if (!sm) { + ksft_test_result_fail("statmount by fd unmounted: %s\n", + strerror(errno)); + goto err_sm; + } + + if (sm->size < sizeof(*sm)) { + ksft_test_result_fail("unexpected size: %u < %u\n", + sm->size, (uint32_t) sizeof(*sm)); + goto err_sm; + } + + if (sm->mask & STATMOUNT_MNT_POINT) { + ksft_test_result_fail("STATMOUNT_MNT_POINT unexpectedly set in mask\n"); + goto err_sm; + } + + if (!(sm->mask & STATMOUNT_MNT_ROOT)) { + ksft_test_result_fail("STATMOUNT_MNT_ROOT not set in mask\n"); + goto err_sm; + } + + if (strcmp(sm->str + sm->mnt_root, root) !=3D 0) { + ksft_test_result_fail("statmount returned incorrect mnt_root," + "statmount mnt_root: %s !=3D %s\n", + sm->str + sm->mnt_root, root); + goto err_sm; + } + + ksft_test_result_pass("statmount by fd on unmounted mount\n"); +err_sm: + free(sm); +err_fd: + close(fd); +err_subdir: + umount2(subdir, MNT_DETACH); + rmdir(subdir); +err_tmpdir: + umount2(tmpdir, MNT_DETACH); + rmdir(tmpdir); +} + #define str_off(memb) (offsetof(struct statmount, memb) / sizeof(uint32_t)) =20 int main(void) @@ -669,14 +898,14 @@ int main(void) =20 ksft_print_header(); =20 - ret =3D statmount(0, 0, 0, NULL, 0, 0); + ret =3D statmount(0, 0, 0, 0, NULL, 0, 0); assert(ret =3D=3D -1); if (errno =3D=3D ENOSYS) ksft_exit_skip("statmount() syscall not supported\n"); =20 setup_namespace(); =20 - ksft_set_plan(15); + ksft_set_plan(17); test_listmount_empty_root(); test_statmount_zero_mask(); test_statmount_mnt_basic(); @@ -693,6 +922,8 @@ int main(void) test_statmount_string(all_mask, str_off(fs_type), "fs type & all"); =20 test_listmount_tree(); + test_statmount_by_fd_unmounted(); + test_statmount_by_fd(); =20 =20 if (ksft_get_fail_cnt() + ksft_get_error_cnt() > 0) diff --git a/tools/testing/selftests/filesystems/statmount/statmount_test_n= s.c b/tools/testing/selftests/filesystems/statmount/statmount_test_ns.c index 605a3fa16bf7..6449b50dde0c 100644 --- a/tools/testing/selftests/filesystems/statmount/statmount_test_ns.c +++ b/tools/testing/selftests/filesystems/statmount/statmount_test_ns.c @@ -102,7 +102,7 @@ static int _test_statmount_mnt_ns_id(void) if (!root_id) return NSID_ERROR; =20 - ret =3D statmount(root_id, 0, STATMOUNT_MNT_NS_ID, &sm, sizeof(sm), 0); + ret =3D statmount(root_id, 0, 0, STATMOUNT_MNT_NS_ID, &sm, sizeof(sm), 0); if (ret =3D=3D -1) { ksft_print_msg("statmount mnt ns id: %s\n", strerror(errno)); return NSID_ERROR; @@ -128,6 +128,98 @@ static int _test_statmount_mnt_ns_id(void) return NSID_PASS; } =20 +static int _test_statmount_mnt_ns_id_by_fd(void) +{ + struct statmount sm; + uint64_t mnt_ns_id; + int ret, fd, mounted =3D 1, status =3D NSID_ERROR; + char mnt[] =3D "/statmount.fd.XXXXXX"; + + ret =3D get_mnt_ns_id("/proc/self/ns/mnt", &mnt_ns_id); + if (ret !=3D NSID_PASS) + return ret; + + if (!mkdtemp(mnt)) { + ksft_print_msg("statmount by fd mnt ns id mkdtemp: %s\n", strerror(errno= )); + return NSID_ERROR; + } + + if (mount(mnt, mnt, NULL, MS_BIND, 0)) { + ksft_print_msg("statmount by fd mnt ns id mount: %s\n", strerror(errno)); + status =3D NSID_ERROR; + goto err; + } + + fd =3D open(mnt, O_PATH); + if (fd < 0) { + ksft_print_msg("statmount by fd mnt ns id open: %s\n", strerror(errno)); + goto err; + } + + ret =3D statmount(0, 0, fd, STATMOUNT_MNT_NS_ID, &sm, sizeof(sm), STATMOU= NT_BY_FD); + if (ret =3D=3D -1) { + ksft_print_msg("statmount mnt ns id statmount: %s\n", strerror(errno)); + status =3D NSID_ERROR; + goto out; + } + + if (sm.size !=3D sizeof(sm)) { + ksft_print_msg("unexpected size: %u !=3D %u\n", sm.size, + (uint32_t)sizeof(sm)); + status =3D NSID_FAIL; + goto out; + } + if (sm.mask !=3D STATMOUNT_MNT_NS_ID) { + ksft_print_msg("statmount mnt ns id unavailable\n"); + status =3D NSID_SKIP; + goto out; + } + + if (sm.mnt_ns_id !=3D mnt_ns_id) { + ksft_print_msg("unexpected mnt ns ID: 0x%llx !=3D 0x%llx\n", + (unsigned long long)sm.mnt_ns_id, + (unsigned long long)mnt_ns_id); + status =3D NSID_FAIL; + goto out; + } + + mounted =3D 0; + if (umount2(mnt, MNT_DETACH)) { + ksft_print_msg("statmount by fd mnt ns id umount2: %s\n", strerror(errno= )); + goto out; + } + + ret =3D statmount(0, 0, fd, STATMOUNT_MNT_NS_ID, &sm, sizeof(sm), STATMOU= NT_BY_FD); + if (ret =3D=3D -1) { + ksft_print_msg("statmount mnt ns id statmount: %s\n", strerror(errno)); + status =3D NSID_ERROR; + goto out; + } + + if (sm.size !=3D sizeof(sm)) { + ksft_print_msg("unexpected size: %u !=3D %u\n", sm.size, + (uint32_t)sizeof(sm)); + status =3D NSID_FAIL; + goto out; + } + + if (sm.mask =3D=3D STATMOUNT_MNT_NS_ID) { + ksft_print_msg("unexpected STATMOUNT_MNT_NS_ID in mask\n"); + status =3D NSID_FAIL; + goto out; + } + + status =3D NSID_PASS; +out: + close(fd); + if (mounted) + umount2(mnt, MNT_DETACH); +err: + rmdir(mnt); + return status; +} + + static void test_statmount_mnt_ns_id(void) { pid_t pid; @@ -148,6 +240,9 @@ static void test_statmount_mnt_ns_id(void) if (ret !=3D NSID_PASS) exit(ret); ret =3D _test_statmount_mnt_ns_id(); + if (ret !=3D NSID_PASS) + exit(ret); + ret =3D _test_statmount_mnt_ns_id_by_fd(); exit(ret); } =20 @@ -179,7 +274,7 @@ static int validate_external_listmount(pid_t pid, uint6= 4_t child_nr_mounts) for (int i =3D 0; i < nr_mounts; i++) { struct statmount sm; =20 - ret =3D statmount(list[i], mnt_ns_id, STATMOUNT_MNT_NS_ID, &sm, + ret =3D statmount(list[i], mnt_ns_id, 0, STATMOUNT_MNT_NS_ID, &sm, sizeof(sm), 0); if (ret < 0) { ksft_print_msg("statmount mnt ns id: %s\n", strerror(errno)); @@ -275,7 +370,7 @@ int main(void) int ret; =20 ksft_print_header(); - ret =3D statmount(0, 0, 0, NULL, 0, 0); + ret =3D statmount(0, 0, 0, 0, NULL, 0, 0); assert(ret =3D=3D -1); if (errno =3D=3D ENOSYS) ksft_exit_skip("statmount() syscall not supported\n"); --=20 2.52.0