]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
tests: add a test for doing a getattr while caps are recalled but before returned
authorJeff Layton <jlayton@redhat.com>
Fri, 16 Feb 2018 20:01:26 +0000 (15:01 -0500)
committerJeff Layton <jlayton@redhat.com>
Sat, 3 Mar 2018 13:32:19 +0000 (08:32 -0500)
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 <jlayton@redhat.com>
src/test/libcephfs/deleg.cc

index 46b52385b8bf91b5690e59258bdb5608f6092206..7ac0d60cb1df8ae211440d4dedbac5296c922d47 100644 (file)
@@ -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);
+}