From: Jeff Layton Date: Fri, 16 Feb 2018 20:01:26 +0000 (-0500) Subject: tests: add a test for doing a getattr while caps are recalled but before returned X-Git-Tag: v13.0.2~73^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=91e5bfa2406dd64e6ed3e168d4cf47dee60ffff0;p=ceph.git tests: add a test for doing a getattr while caps are recalled but before returned Add a testcase to reproduce the deadlock I was seeing with delegations in ganesha. Tracker: http://tracker.ceph.com/issues/23028 Signed-off-by: Jeff Layton --- diff --git a/src/test/libcephfs/deleg.cc b/src/test/libcephfs/deleg.cc index 46b52385b8b..7ac0d60cb1d 100644 --- a/src/test/libcephfs/deleg.cc +++ b/src/test/libcephfs/deleg.cc @@ -59,9 +59,10 @@ static void open_breaker_func(struct ceph_mount_info *cmount, const char *filena struct ceph_statx stx; UserPerm *perms = ceph_mount_perms(cmount); - ASSERT_EQ(ceph_ll_lookup(cmount, root, filename, &file, &stx, 0, 0, perms), 0); + ASSERT_EQ(ceph_ll_lookup(cmount, root, filename, &file, &stx, CEPH_STATX_ALL_STATS, 0, perms), 0); int ret; for (;;) { + ASSERT_EQ(ceph_ll_getattr(cmount, file, &stx, CEPH_STATX_ALL_STATS, 0, perms), 0); ret = ceph_ll_open(cmount, file, flags, &fh, perms); if (ret != -EAGAIN) break; @@ -302,3 +303,66 @@ TEST(LibCephFS, DelegTimeout) { ASSERT_EQ(ceph_ll_getattr(cmount, root, &stx, 0, 0, perms), -ENOTCONN); ceph_release(cmount); } + +TEST(LibCephFS, RecalledGetattr) { + struct ceph_mount_info *cmount1; + ASSERT_EQ(ceph_create(&cmount1, NULL), 0); + ASSERT_EQ(ceph_conf_read_file(cmount1, NULL), 0); + ASSERT_EQ(0, ceph_conf_parse_env(cmount1, NULL)); + ASSERT_EQ(ceph_mount(cmount1, "/"), 0); + ASSERT_EQ(set_default_deleg_timeout(cmount1), 0); + + Inode *root, *file; + ASSERT_EQ(ceph_ll_lookup_root(cmount1, &root), 0); + + char filename[32]; + sprintf(filename, "recalledgetattr%x", getpid()); + + Fh *fh; + struct ceph_statx stx; + UserPerm *perms = ceph_mount_perms(cmount1); + + ASSERT_EQ(ceph_ll_create(cmount1, root, filename, 0666, + O_RDWR|O_CREAT|O_EXCL, &file, &fh, &stx, 0, 0, perms), 0); + ASSERT_EQ(ceph_ll_write(cmount1, fh, 0, sizeof(filename), filename), sizeof(filename)); + ASSERT_EQ(ceph_ll_close(cmount1, fh), 0); + + /* New mount for read delegation */ + struct ceph_mount_info *cmount2; + ASSERT_EQ(ceph_create(&cmount2, NULL), 0); + ASSERT_EQ(ceph_conf_read_file(cmount2, NULL), 0); + ASSERT_EQ(0, ceph_conf_parse_env(cmount2, NULL)); + ASSERT_EQ(ceph_mount(cmount2, "/"), 0); + ASSERT_EQ(set_default_deleg_timeout(cmount2), 0); + + ASSERT_EQ(ceph_ll_lookup_root(cmount2, &root), 0); + perms = ceph_mount_perms(cmount2); + ASSERT_EQ(ceph_ll_lookup(cmount2, root, filename, &file, &stx, 0, 0, perms), 0); + + ASSERT_EQ(ceph_ll_open(cmount2, file, O_WRONLY, &fh, perms), 0); + ASSERT_EQ(ceph_ll_write(cmount2, fh, 0, sizeof(filename), filename), sizeof(filename)); + ASSERT_EQ(ceph_ll_close(cmount2, fh), 0); + + ASSERT_EQ(ceph_ll_open(cmount2, file, O_RDONLY, &fh, perms), 0); + + /* Break delegation */ + std::atomic_bool recalled(false); + ASSERT_EQ(ceph_ll_delegation(cmount2, fh, CEPH_DELEGATION_RD, dummy_deleg_cb, &recalled), 0); + ASSERT_EQ(ceph_ll_read(cmount2, fh, 0, sizeof(filename), filename), sizeof(filename)); + ASSERT_EQ(ceph_ll_getattr(cmount2, file, &stx, CEPH_STATX_ALL_STATS, 0, perms), 0); + std::atomic_bool opened(false); + std::thread breaker1(open_breaker_func, cmount1, filename, O_WRONLY, &opened); + do { + ASSERT_EQ(ceph_ll_getattr(cmount2, file, &stx, CEPH_STATX_ALL_STATS, 0, perms), 0); + usleep(1000); + } while (!recalled.load()); + ASSERT_EQ(opened.load(), false); + ASSERT_EQ(ceph_ll_getattr(cmount2, file, &stx, CEPH_STATX_ALL_STATS, 0, perms), 0); + ASSERT_EQ(ceph_ll_delegation(cmount2, fh, CEPH_DELEGATION_NONE, dummy_deleg_cb, nullptr), 0); + breaker1.join(); + ASSERT_EQ(ceph_ll_close(cmount2, fh), 0); + ceph_unmount(cmount2); + ceph_release(cmount2); + ceph_unmount(cmount1); + ceph_release(cmount1); +}