]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
test/libcephfs: add test case for revoking caps
authorXiubo Li <xiubli@redhat.com>
Tue, 11 Oct 2022 04:53:17 +0000 (12:53 +0800)
committerXiubo Li <xiubli@redhat.com>
Wed, 23 Aug 2023 09:28:30 +0000 (17:28 +0800)
When writing to a file and the max_size is approaching the client
will try to trigger to call check_caps() and flush the caps to MDS.
But just in case the MDS is revoking Fsxrw caps, since the client
keeps writing and holding the Fw caps it may only release part of
the caps but the Fw.

Fixes: https://tracker.ceph.com/issues/57244
Signed-off-by: Xiubo Li <xiubli@redhat.com>
(cherry picked from commit 3c63980b9d38aa935cf920512e129968c15b5aa9)

src/test/libcephfs/multiclient.cc

index 465bbd8f77246f0362d55b5a16ed8ba5b8fc37a4..f8806a50aa71b04fea6731f3753857dc3f515e90 100644 (file)
 
 #include "gtest/gtest.h"
 #include "include/cephfs/libcephfs.h"
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <dirent.h>
+#include <thread>
 #ifdef __linux__
 #include <sys/xattr.h>
 #endif
@@ -97,3 +98,82 @@ TEST(LibCephFS, MulticlientHoleEOF) {
   ceph_shutdown(ca);
   ceph_shutdown(cb);
 }
+
+static void write_func(bool *stop)
+{
+  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(ceph_mount(cmount, "/"), 0);
+
+  char name[20];
+  snprintf(name, sizeof(name), "foo.%d", getpid());
+  int fd = ceph_open(cmount, name, O_CREAT|O_RDWR, 0644);
+  ASSERT_LE(0, fd);
+
+  int buf_size = 4096;
+  char *buf = (char *)malloc(buf_size);
+  if (!buf) {
+    *stop = true;
+    printf("write_func failed to allocate buffer!");
+    return;
+  }
+  memset(buf, 1, buf_size);
+
+  while (!(*stop)) {
+    int i;
+
+    // truncate the file size to 4096 will set the max_size to 4MB.
+    ASSERT_EQ(0, ceph_ftruncate(cmount, fd, 4096));
+
+    // write 4MB + extra 64KB data will make client to trigger to
+    // call check_cap() to report new size. And if MDS is revoking
+    // the Fsxrw caps and we are still holding the Fw caps and will
+    // trigger tracker#57244.
+    for (i = 0; i < 1040; i++) {
+      ASSERT_EQ(ceph_write(cmount, fd, buf, buf_size, 0), buf_size);
+    }
+  }
+
+  ceph_shutdown(cmount);
+}
+
+static void setattr_func(bool *stop)
+{
+  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(ceph_mount(cmount, "/"), 0);
+
+  char name[20];
+  snprintf(name, sizeof(name), "foo.%d", getpid());
+  int fd = ceph_open(cmount, name, O_CREAT|O_RDWR, 0644);
+  ASSERT_LE(0, fd);
+
+  while (!(*stop)) {
+    // setattr will make the MDS to acquire xlock for the filelock and
+    // force to revoke caps from clients
+    struct ceph_statx stx = {.stx_size = 0};
+    ASSERT_EQ(ceph_fsetattrx(cmount, fd, &stx, CEPH_SETATTR_SIZE), 0);
+  }
+
+  ceph_shutdown(cmount);
+}
+
+TEST(LibCephFS, MulticlientRevokeCaps) {
+  std::thread thread1, thread2;
+  bool stop = false;
+  int wait = 60; // in second
+
+  thread1 = std::thread(write_func, &stop);
+  thread2 = std::thread(setattr_func, &stop);
+
+  printf(" Will run test for %d seconds!\n", wait);
+  sleep(wait);
+  stop = true;
+
+  thread1.join();
+  thread2.join();
+}