From 10223a2588c3159770903e91748963b407434cfa Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Feb 2018 15:01:26 -0500 Subject: [PATCH] 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 (cherry picked from commit 91e5bfa2406dd64e6ed3e168d4cf47dee60ffff0) --- src/test/libcephfs/deleg.cc | 66 ++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/src/test/libcephfs/deleg.cc b/src/test/libcephfs/deleg.cc index 46b52385b8bf..7ac0d60cb1df 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); +} -- 2.47.3