#include <thread>
#include <atomic>
+/* in ms -- 1 minute */
+#define MAX_WAIT (60 * 1000)
+
+static void wait_for_atomic_bool(std::atomic_bool &recalled)
+{
+ int i = 0;
+
+ while (!recalled.load()) {
+ ASSERT_LT(i++, MAX_WAIT);
+ usleep(1000);
+ }
+}
+
static int set_default_deleg_timeout(struct ceph_mount_info *cmount)
{
uint32_t session_timeout = ceph_get_cap_return_timeout(cmount);
struct ceph_statx stx;
UserPerm *perms = ceph_mount_perms(cmount);
- ASSERT_EQ(ceph_ll_lookup(cmount, root, filename, &file, &stx, 0, 0, perms), 0);
- int ret;
+ ASSERT_EQ(ceph_ll_lookup(cmount, root, filename, &file, &stx, CEPH_STATX_ALL_STATS, 0, perms), 0);
+ int ret, i = 0;
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;
+ ASSERT_LT(i++, MAX_WAIT);
usleep(1000);
}
ASSERT_EQ(ret, 0);
struct ceph_statx stx;
UserPerm *perms = ceph_mount_perms(cmount);
- int ret;
+ int ret, i = 0;
for (;;) {
switch (cmd) {
case DelegTestRename:
}
if (ret != -EAGAIN)
break;
+ ASSERT_LT(i++, MAX_WAIT);
usleep(1000);
}
ASSERT_EQ(ret, 0);
O_RDWR|O_CREAT|O_EXCL, &file, &fh, &stx, 0, 0, perms), 0);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_WR, dummy_deleg_cb, &recalled), 0);
std::thread breaker1(open_breaker_func, tcmount, filename, O_RDWR, &opened);
- while (!recalled.load())
- usleep(1000);
+
+ wait_for_atomic_bool(recalled);
ASSERT_EQ(opened.load(), false);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_NONE, dummy_deleg_cb, &recalled), 0);
breaker1.join();
O_RDWR|O_CREAT|O_EXCL, &file, &fh, &stx, 0, 0, perms), 0);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_WR, dummy_deleg_cb, &recalled), 0);
std::thread breaker2(open_breaker_func, tcmount, filename, O_RDONLY, &opened);
- while (!recalled.load())
- usleep(1000);
+ wait_for_atomic_bool(recalled);
ASSERT_EQ(opened.load(), false);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_NONE, dummy_deleg_cb, &recalled), 0);
breaker2.join();
// ensure that r/w open breaks r/o delegation
opened.store(false);
std::thread breaker4(open_breaker_func, tcmount, filename, O_WRONLY, &opened);
- while (!recalled.load())
- usleep(1000);
+ wait_for_atomic_bool(recalled);
usleep(1000);
ASSERT_EQ(opened.load(), false);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_NONE, dummy_deleg_cb, &recalled), 0);
O_RDWR|O_CREAT|O_EXCL, &file, &fh, &stx, 0, 0, perms), 0);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_WR, dummy_deleg_cb, &recalled), 0);
std::thread breaker5(namespace_breaker_func, tcmount, DelegTestLink, filename, newname);
- while (!recalled.load())
- usleep(1000);
+ wait_for_atomic_bool(recalled);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_NONE, dummy_deleg_cb, &recalled), 0);
breaker5.join();
ASSERT_EQ(ceph_ll_close(cmount, fh), 0);
O_RDWR|O_CREAT|O_EXCL, &file, &fh, &stx, 0, 0, perms), 0);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_WR, dummy_deleg_cb, &recalled), 0);
std::thread breaker6(namespace_breaker_func, tcmount, DelegTestRename, filename, newname);
- while (!recalled.load())
- usleep(1000);
+ wait_for_atomic_bool(recalled);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_NONE, dummy_deleg_cb, &recalled), 0);
breaker6.join();
ASSERT_EQ(ceph_ll_close(cmount, fh), 0);
O_RDWR|O_CREAT|O_EXCL, &file, &fh, &stx, 0, 0, perms), 0);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_WR, dummy_deleg_cb, &recalled), 0);
std::thread breaker7(namespace_breaker_func, tcmount, DelegTestUnlink, filename, nullptr);
- while (!recalled.load())
- usleep(1000);
+ wait_for_atomic_bool(recalled);
ASSERT_EQ(ceph_ll_delegation(cmount, fh, CEPH_DELEGATION_NONE, dummy_deleg_cb, &recalled), 0);
breaker7.join();
ASSERT_EQ(ceph_ll_close(cmount, fh), 0);
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);
+ int i = 0;
+ do {
+ ASSERT_EQ(ceph_ll_getattr(cmount2, file, &stx, CEPH_STATX_ALL_STATS, 0, perms), 0);
+ ASSERT_LT(i++, MAX_WAIT);
+ 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);
+}