summaryrefslogtreecommitdiffstats
path: root/src/test/libcephfs/vxattr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/libcephfs/vxattr.cc')
-rw-r--r--src/test/libcephfs/vxattr.cc385
1 files changed, 385 insertions, 0 deletions
diff --git a/src/test/libcephfs/vxattr.cc b/src/test/libcephfs/vxattr.cc
new file mode 100644
index 000000000..2a5ad70e4
--- /dev/null
+++ b/src/test/libcephfs/vxattr.cc
@@ -0,0 +1,385 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2021 Red Hat Inc.
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include "include/compat.h"
+#include "gtest/gtest.h"
+#include "include/cephfs/libcephfs.h"
+#include "mds/mdstypes.h"
+#include "include/stat.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <string.h>
+
+#include "common/Clock.h"
+#include "common/ceph_json.h"
+
+#ifdef __linux__
+#include <limits.h>
+#include <sys/xattr.h>
+#endif
+
+#include <fmt/format.h>
+#include <map>
+#include <vector>
+#include <thread>
+#include <regex>
+#include <string>
+
+#ifndef ALLPERMS
+#define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
+#endif
+
+using namespace std;
+
+TEST(LibCephFS, LayoutVerifyDefaultLayout) {
+
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(0, ceph_create(&cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(0, ceph_mount(cmount, "/"));
+
+ ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777));
+
+ {
+ char value[1024] = "";
+ int r = 0;
+
+ // check for default layout
+ r = ceph_getxattr(cmount, "/", "ceph.dir.layout.json", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+ std::clog << "layout:" << value << std::endl;
+ ASSERT_STRNE((char*)NULL, strstr(value, "\"inheritance\": \"@default\""));
+ }
+
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test"));
+
+ ceph_shutdown(cmount);
+}
+
+TEST(LibCephFS, LayoutSetAndVerifyNewAndInheritedLayout) {
+
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(0, ceph_create(&cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(0, ceph_mount(cmount, "/"));
+
+ ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777));
+
+ std::string pool_name_set;
+
+ {
+ char value[1024] = "";
+ int r = 0;
+
+ r = ceph_getxattr(cmount, "/", "ceph.dir.layout.json", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+
+ JSONParser json_parser;
+ ASSERT_EQ(json_parser.parse(value, r), 1);
+ ASSERT_EQ(json_parser.is_object(), 1);
+
+ std::string pool_name;
+
+ JSONDecoder::decode_json("pool_name", pool_name, &json_parser, true);
+
+ pool_name_set = pool_name;
+
+ // set a new layout
+ std::string new_layout;
+ new_layout += "{";
+ new_layout += "\"stripe_unit\": 65536, ";
+ new_layout += "\"stripe_count\": 1, ";
+ new_layout += "\"object_size\": 65536, ";
+ new_layout += "\"pool_name\": \"" + pool_name + "\"";
+ new_layout += "}";
+
+ ASSERT_EQ(0, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.json", (void*)new_layout.c_str(), new_layout.length(), XATTR_CREATE));
+ }
+
+ {
+ char value[1024] = "";
+ int r = 0;
+
+ r = ceph_getxattr(cmount, "test/d0", "ceph.dir.layout.json", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+ std::clog << "layout:" << value << std::endl;
+
+ JSONParser json_parser;
+ ASSERT_EQ(json_parser.parse(value, r), 1);
+ ASSERT_EQ(json_parser.is_object(), 1);
+
+ int64_t object_size;
+ int64_t stripe_unit;
+ int64_t stripe_count;
+ std::string pool_name;
+ std::string inheritance;
+
+ JSONDecoder::decode_json("pool_name", pool_name, &json_parser, true);
+ JSONDecoder::decode_json("object_size", object_size, &json_parser, true);
+ JSONDecoder::decode_json("stripe_unit", stripe_unit, &json_parser, true);
+ JSONDecoder::decode_json("stripe_count", stripe_count, &json_parser, true);
+ JSONDecoder::decode_json("inheritance", inheritance, &json_parser, true);
+
+ // now verify the layout
+ ASSERT_EQ(pool_name.compare(pool_name_set), 0);
+ ASSERT_EQ(object_size, 65536);
+ ASSERT_EQ(stripe_unit, 65536);
+ ASSERT_EQ(stripe_count, 1);
+ ASSERT_EQ(inheritance.compare("@set"), 0);
+ }
+
+ {
+ char value[1024] = "";
+ int r = 0;
+
+ JSONParser json_parser;
+ std::string inheritance;
+
+ // now check that the subdir layout is inherited
+ r = ceph_getxattr(cmount, "test/d0/subdir", "ceph.dir.layout.json", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+ std::clog << "layout:" << value << std::endl;
+ ASSERT_EQ(json_parser.parse(value, r), 1);
+ ASSERT_EQ(json_parser.is_object(), 1);
+ JSONDecoder::decode_json("inheritance", inheritance, &json_parser, true);
+ ASSERT_EQ(inheritance.compare("@inherited"), 0);
+ }
+
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test"));
+
+ ceph_shutdown(cmount);
+}
+
+TEST(LibCephFS, LayoutSetBadJSON) {
+
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(0, ceph_create(&cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(0, ceph_mount(cmount, "/"));
+
+ ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777));
+
+ {
+ // set a new layout and verify the same
+ const char *new_layout = "" // bad json without starting brace
+ "\"stripe_unit\": 65536, "
+ "\"stripe_count\": 1, "
+ "\"object_size\": 65536, "
+ "\"pool_name\": \"cephfs.a.data\", "
+ "}";
+ // try to set a malformed JSON, eg. without an open brace
+ ASSERT_EQ(-EINVAL, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.json", (void*)new_layout, strlen(new_layout), XATTR_CREATE));
+ }
+
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test"));
+
+ ceph_shutdown(cmount);
+}
+
+TEST(LibCephFS, LayoutSetBadPoolName) {
+
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(0, ceph_create(&cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(0, ceph_mount(cmount, "/"));
+
+ ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777));
+
+ {
+ // try setting a bad pool name
+ ASSERT_EQ(-EINVAL, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.pool_name", (void*)"UglyPoolName", 12, XATTR_CREATE));
+ }
+
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test"));
+
+ ceph_shutdown(cmount);
+}
+
+TEST(LibCephFS, LayoutSetBadPoolId) {
+
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(0, ceph_create(&cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(0, ceph_mount(cmount, "/"));
+
+ ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777));
+
+ {
+ // try setting a bad pool id
+ ASSERT_EQ(-EINVAL, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.pool_id", (void*)"300", 3, XATTR_CREATE));
+ }
+
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test"));
+
+ ceph_shutdown(cmount);
+}
+
+TEST(LibCephFS, LayoutSetInvalidFieldName) {
+
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(0, ceph_create(&cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(0, ceph_mount(cmount, "/"));
+
+ ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777));
+
+ {
+ // try to set in invalid field
+ ASSERT_EQ(-ENODATA, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.bad_field", (void*)"300", 3, XATTR_CREATE));
+ }
+
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test"));
+
+ ceph_shutdown(cmount);
+}
+
+TEST(LibCephFS, GetAndSetDirPin) {
+
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(0, ceph_create(&cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(0, ceph_mount(cmount, "/"));
+
+ ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d1", 0777));
+
+ {
+ char value[1024] = "";
+ int r = ceph_getxattr(cmount, "test/d1", "ceph.dir.pin", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+ ASSERT_STREQ("-1", value);
+ }
+
+ {
+ char value[1024] = "";
+ int r = -1;
+
+ ASSERT_EQ(0, ceph_setxattr(cmount, "test/d1", "ceph.dir.pin", (void*)"1", 1, XATTR_CREATE));
+
+ r = ceph_getxattr(cmount, "test/d1", "ceph.dir.pin", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+ ASSERT_STREQ("1", value);
+ }
+
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d1"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test"));
+
+ ceph_shutdown(cmount);
+}
+
+TEST(LibCephFS, GetAndSetDirDistribution) {
+
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(0, ceph_create(&cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(0, ceph_mount(cmount, "/"));
+
+ ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d2", 0777));
+
+ {
+ char value[1024] = "";
+ int r = ceph_getxattr(cmount, "test/d2", "ceph.dir.pin.distributed", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+ ASSERT_STREQ("0", value);
+ }
+
+ {
+ char value[1024] = "";
+ int r = -1;
+
+ ASSERT_EQ(0, ceph_setxattr(cmount, "test/d2", "ceph.dir.pin.distributed", (void*)"1", 1, XATTR_CREATE));
+
+ r = ceph_getxattr(cmount, "test/d2", "ceph.dir.pin.distributed", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+ ASSERT_STREQ("1", value);
+ }
+
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d2"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test"));
+
+ ceph_shutdown(cmount);
+}
+
+TEST(LibCephFS, GetAndSetDirRandom) {
+
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(0, ceph_create(&cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(0, ceph_mount(cmount, "/"));
+
+ ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d3", 0777));
+
+ {
+ char value[1024] = "";
+ int r = ceph_getxattr(cmount, "test/d3", "ceph.dir.pin.random", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+ ASSERT_STREQ("0", value);
+ }
+
+ {
+ double val = (double)1.0/(double)128.0;
+ std::stringstream ss;
+ ss << val;
+ ASSERT_EQ(0, ceph_setxattr(cmount, "test/d3", "ceph.dir.pin.random", (void*)ss.str().c_str(), strlen(ss.str().c_str()), XATTR_CREATE));
+
+ char value[1024] = "";
+ int r = -1;
+
+ r = ceph_getxattr(cmount, "test/d3", "ceph.dir.pin.random", (void*)value, sizeof(value));
+ ASSERT_GT(r, 0);
+ ASSERT_LT(r, sizeof value);
+ ASSERT_STREQ(ss.str().c_str(), value);
+ }
+
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test/d3"));
+ ASSERT_EQ(0, ceph_rmdir(cmount, "test"));
+
+ ceph_shutdown(cmount);
+}