From 0f2abc9bc9390de3951e2494b5ed41ca9111cc50 Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Mon, 24 Feb 2025 09:46:15 -0500 Subject: [PATCH] test/libcephfs: add test for lookup failure after readdir That we do not get unexpected ENOENT following readdirs (particularly thinking of cap_shared_gen differences). Test-case-for: https://tracker.ceph.com/issues/70100 Signed-off-by: Patrick Donnelly --- src/test/libcephfs/test.cc | 145 +++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/src/test/libcephfs/test.cc b/src/test/libcephfs/test.cc index de9dd53a7bd5d..a5793620d1f00 100644 --- a/src/test/libcephfs/test.cc +++ b/src/test/libcephfs/test.cc @@ -41,10 +41,23 @@ #include #include #include +#include #include using namespace std; +static std::string generate_random_string(int length = 20) { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> distrib('a', 'z'); + + std::string str; + for (int i = 0; i < length; ++i) { + str += static_cast(distrib(gen)); + } + return str; +} + TEST(LibCephFS, OpenEmptyComponent) { pid_t mypid = getpid(); @@ -3638,6 +3651,94 @@ TEST(LibCephFS, SnapdirAttrs) { ceph_shutdown(cmount); } +TEST(LibCephFS, SnapDirLookup) { + struct ceph_mount_info *cmount; + ASSERT_EQ(ceph_create(&cmount, NULL), 0); + ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0); + ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); + ASSERT_EQ(0, ceph_mount(cmount, NULL)); + + auto top = generate_random_string(); + ASSERT_EQ(ceph_mkdir(cmount, top.c_str(), 0777), 0); + ASSERT_EQ(0, ceph_chdir(cmount, top.c_str())); + + ASSERT_EQ(ceph_mkdir(cmount, "foo", 0777), 0); + ASSERT_EQ(ceph_mkdir(cmount, "foo/bar", 0777), 0); + ASSERT_EQ(ceph_mkdir(cmount, "foo/.snap/snap", 0777), 0); + + ASSERT_EQ(0, ceph_unmount(cmount)); + ASSERT_EQ(0, ceph_mount(cmount, NULL)); + ASSERT_EQ(0, ceph_chdir(cmount, top.c_str())); + ASSERT_EQ(0, ceph_chdir(cmount, "foo/")); + + { + struct ceph_dir_result *cdr = NULL; + struct dirent* de = nullptr; + ASSERT_EQ(0, ceph_opendir(cmount, ".", &cdr)); + while((de = ceph_readdir(cmount, cdr))) { + continue; + } + ASSERT_EQ(0, ceph_closedir(cmount, cdr)); + } + + { + struct stat buf; + ASSERT_EQ(0, ceph_stat(cmount, "bar", &buf)); + } + + ASSERT_EQ(0, ceph_unmount(cmount)); + ASSERT_EQ(0, ceph_mount(cmount, NULL)); + ASSERT_EQ(0, ceph_chdir(cmount, top.c_str())); + ASSERT_EQ(0, ceph_chdir(cmount, "foo/")); + + { + struct ceph_dir_result *cdr = NULL; + struct dirent* de = nullptr; + ASSERT_EQ(0, ceph_opendir(cmount, ".snap/", &cdr)); + while((de = ceph_readdir(cmount, cdr))) { + continue; + } + ASSERT_EQ(0, ceph_closedir(cmount, cdr)); + } + + + { + struct stat buf; + ASSERT_EQ(0, ceph_stat(cmount, ".snap/snap/bar", &buf)); + } + + ASSERT_EQ(0, ceph_unmount(cmount)); + ASSERT_EQ(0, ceph_mount(cmount, NULL)); + ASSERT_EQ(0, ceph_chdir(cmount, top.c_str())); + ASSERT_EQ(0, ceph_chdir(cmount, "foo/")); + + { + struct ceph_dir_result *cdr = NULL; + struct dirent* de = nullptr; + ASSERT_EQ(0, ceph_opendir(cmount, ".snap/snap/", &cdr)); + while((de = ceph_readdir(cmount, cdr))) { + continue; + } + ASSERT_EQ(0, ceph_closedir(cmount, cdr)); + } + + { + struct stat buf; + ASSERT_EQ(0, ceph_stat(cmount, ".snap/snap/bar", &buf)); + } + + ASSERT_EQ(0, ceph_unmount(cmount)); + ASSERT_EQ(0, ceph_mount(cmount, NULL)); + ASSERT_EQ(0, ceph_chdir(cmount, top.c_str())); + + ASSERT_EQ(ceph_rmdir(cmount, "foo/.snap/snap"), 0); + ASSERT_EQ(ceph_rmdir(cmount, "foo/bar"), 0); + ASSERT_EQ(ceph_rmdir(cmount, "foo"), 0); + + ASSERT_EQ(0, ceph_unmount(cmount)); + ceph_shutdown(cmount); +} + TEST(LibCephFS, SnapdirAttrsOnSnapCreate) { struct ceph_mount_info *cmount; ASSERT_EQ(ceph_create(&cmount, NULL), 0); @@ -3793,3 +3894,47 @@ TEST(LibCephFS, SnapdirAttrsOnSnapRename) { ASSERT_EQ(0, ceph_unmount(cmount)); ceph_shutdown(cmount); } + +TEST(LibCephFS, SubdirLookupAfterReaddir_ll) { + struct ceph_mount_info *cmount; + Inode *root, *subdir = NULL; + struct ceph_statx stx; + + ASSERT_EQ(ceph_create(&cmount, NULL), 0); + ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0); + ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); + ASSERT_EQ(0, ceph_mount(cmount, NULL)); + + ceph_rmdir(cmount, "foo/bar"); + ceph_rmdir(cmount, "foo"); + + ASSERT_EQ(ceph_mkdir(cmount, "foo", 0777), 0); + ASSERT_EQ(ceph_mkdir(cmount, "foo/bar", 0777), 0); + + ASSERT_EQ(0, ceph_unmount(cmount)); + ASSERT_EQ(0, ceph_mount(cmount, NULL)); + + UserPerm *perms = ceph_mount_perms(cmount); + + { + ASSERT_EQ(0, ceph_ll_walk(cmount, ".", &root, &stx, CEPH_STATX_INO, 0, perms)); + ASSERT_EQ(0, ceph_ll_lookup(cmount, root, "foo/bar", &subdir, &stx, CEPH_STATX_INO, 0, perms)); + } + + { + struct ceph_dir_result *cdr = NULL; + struct dirent *de = NULL; + ASSERT_EQ(0, ceph_ll_opendir(cmount, root, &cdr, perms)); + while((de = ceph_readdir(cmount, cdr))) { + continue; + } + ASSERT_EQ(0, ceph_ll_releasedir(cmount, cdr)); + } + + { + ASSERT_EQ(0, ceph_ll_lookup(cmount, root, "foo/bar", &subdir, &stx, CEPH_STATX_INO, 0, perms)); + } + + ASSERT_EQ(0, ceph_unmount(cmount)); + ceph_shutdown(cmount); +} -- 2.39.5