]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: introduce ceph.mirror.info virtual xattr
authorVenky Shankar <vshankar@redhat.com>
Wed, 26 Aug 2020 12:55:51 +0000 (08:55 -0400)
committerVenky Shankar <vshankar@redhat.com>
Tue, 13 Oct 2020 04:29:38 +0000 (00:29 -0400)
This is a compound xattr with the xattr value being fixed in
format. MDS stores this xattr as two (since the xattr value
right now just has two components or compounds) separate entries
in the xattr_map. This is done to avoid bloating the xattr value
if more "compounds" are added.

You may ask, why do it this way rather having the application
(cephfs-mirror daemon in this case) just set each xattr one
after the other? Well, we loose xattr consistency (from the
application point-of-view) -- an application crash (bug!) or
an ENOSPC in the server could leave M out of N xattrs (M < N)
on-disk.

With the compound xattr operation done on the server side,
journaling ensure that either all (N) xattrs are available or
none are available after recovering from a crash.

Signed-off-by: Venky Shankar <vshankar@redhat.com>
src/mds/Server.cc
src/mds/Server.h

index 37c14bf4de140e836d9e2c10271d88614263b0cf..91598f173f0f0cb889e6f0ba9b785016bb3a1f02 100644 (file)
@@ -56,6 +56,7 @@
 
 #include <list>
 #include <iostream>
+#include <regex>
 #include <string_view>
 #include <functional>
 
@@ -5825,6 +5826,13 @@ const Server::XattrHandler Server::xattr_handlers[] = {
     setxattr: &Server::default_setxattr_handler,
     removexattr: &Server::default_removexattr_handler,
   },
+  {
+    xattr_name: "ceph.mirror.info",
+    description: "mirror info xattr handler",
+    validate: &Server::mirror_info_xattr_validate,
+    setxattr: &Server::mirror_info_setxattr_handler,
+    removexattr: &Server::mirror_info_removexattr_handler
+  },
 };
 
 const Server::XattrHandler* Server::get_xattr_or_default_handler(std::string_view xattr_name) {
@@ -5910,6 +5918,84 @@ void Server::default_removexattr_handler(CInode *cur, InodeStoreBase::xattr_map_
   xattr_rm(xattrs, xattr_op.xattr_name);
 }
 
+// mirror info xattr handlers
+const std::string Server::MirrorXattrInfo::MIRROR_INFO_REGEX = "^cluster_id=([a-f0-9]{8}-" \
+                                                               "[a-f0-9]{4}-[a-f0-9]{4}-" \
+                                                               "[a-f0-9]{4}-[a-f0-9]{12})" \
+                                                               " fs_id=(\\d+)$";
+const std::string Server::MirrorXattrInfo::CLUSTER_ID = "ceph.mirror.info.cluster_id";
+const std::string Server::MirrorXattrInfo::FS_ID = "ceph.mirror.info.fs_id";
+int Server::parse_mirror_info_xattr(const std::string &name, const std::string &value,
+                                    std::string &cluster_id, std::string &fs_id) {
+  dout(20) << "parsing name=" << name << ", value=" << value << dendl;
+
+  static const std::regex regex(Server::MirrorXattrInfo::MIRROR_INFO_REGEX);
+  std::smatch match;
+
+  std::regex_search(value, match, regex);
+  if (match.size() != 3) {
+    derr << "mirror info parse error" << dendl;
+    return -EINVAL;
+  }
+
+  cluster_id = match[1];
+  fs_id = match[2];
+  dout(20) << " parsed cluster_id=" << cluster_id << ", fs_id=" << fs_id << dendl;
+  return 0;
+}
+
+int Server::mirror_info_xattr_validate(CInode *cur, const InodeStoreBase::xattr_map_const_ptr xattrs,
+                                       XattrOp *xattr_op) {
+  if (!cur->is_root()) {
+    return -EINVAL;
+  }
+
+  int v1 = xattr_validate(cur, xattrs, Server::MirrorXattrInfo::CLUSTER_ID, xattr_op->op, xattr_op->flags);
+  int v2 = xattr_validate(cur, xattrs, Server::MirrorXattrInfo::FS_ID, xattr_op->op, xattr_op->flags);
+  if (v1 != v2) {
+    derr << "inconsistent mirror info state (" << v1 << "," << v2 << ")" << dendl;
+    return -EINVAL;
+  }
+
+  if (v1 < 0) {
+    return v1;
+  }
+
+  if (xattr_op->op == CEPH_MDS_OP_RMXATTR) {
+    return 0;
+  }
+
+  std::string cluster_id;
+  std::string fs_id;
+  int r = parse_mirror_info_xattr(xattr_op->xattr_name, xattr_op->xattr_value.to_str(),
+                                  cluster_id, fs_id);
+  if (r < 0) {
+    return r;
+  }
+
+  xattr_op->xinfo = std::make_unique<MirrorXattrInfo>(cluster_id, fs_id);
+  return 0;
+}
+
+void Server::mirror_info_setxattr_handler(CInode *cur, InodeStoreBase::xattr_map_ptr xattrs,
+                                          const XattrOp &xattr_op) {
+  auto mirror_info = dynamic_cast<MirrorXattrInfo&>(*(xattr_op.xinfo));
+
+  bufferlist bl;
+  bl.append(mirror_info.cluster_id.c_str(), mirror_info.cluster_id.length());
+  xattr_set(xattrs, Server::MirrorXattrInfo::CLUSTER_ID, bl);
+
+  bl.clear();
+  bl.append(mirror_info.fs_id.c_str(), mirror_info.fs_id.length());
+  xattr_set(xattrs, Server::MirrorXattrInfo::FS_ID, bl);
+}
+
+void Server::mirror_info_removexattr_handler(CInode *cur, InodeStoreBase::xattr_map_ptr xattrs,
+                                             const XattrOp &xattr_op) {
+  xattr_rm(xattrs, Server::MirrorXattrInfo::CLUSTER_ID);
+  xattr_rm(xattrs, Server::MirrorXattrInfo::FS_ID);
+}
+
 void Server::handle_client_setxattr(MDRequestRef& mdr)
 {
   const cref_t<MClientRequest> &req = mdr->client_request;
index ed58d7ad94ebfa7ce7db49b4c546f87dd7eea9bd..10c9df553f07d4fe5b9dc2c131fe6be882c5758b 100644 (file)
@@ -326,6 +326,21 @@ private:
     }
   };
 
+  struct MirrorXattrInfo : XattrInfo {
+    std::string cluster_id;
+    std::string fs_id;
+
+    static const std::string MIRROR_INFO_REGEX;
+    static const std::string CLUSTER_ID;
+    static const std::string FS_ID;
+
+    MirrorXattrInfo(std::string_view cluster_id,
+                    std::string_view fs_id)
+      : cluster_id(cluster_id),
+        fs_id(fs_id) {
+    }
+  };
+
   struct XattrOp {
     int op;
     std::string xattr_name;
@@ -382,6 +397,16 @@ private:
   void default_removexattr_handler(CInode *cur, InodeStoreBase::xattr_map_ptr xattrs,
                                    const XattrOp &xattr_op);
 
+  // mirror info xattr handler
+  int parse_mirror_info_xattr(const std::string &name, const std::string &value,
+                              std::string &cluster_id, std::string &fs_id);
+  int mirror_info_xattr_validate(CInode *cur, const InodeStoreBase::xattr_map_const_ptr xattrs,
+                                 XattrOp *xattr_op);
+  void mirror_info_setxattr_handler(CInode *cur, InodeStoreBase::xattr_map_ptr xattrs,
+                                    const XattrOp &xattr_op);
+  void mirror_info_removexattr_handler(CInode *cur, InodeStoreBase::xattr_map_ptr xattrs,
+                                       const XattrOp &xattr_op);
+
   static bool is_ceph_vxattr(std::string_view xattr_name) {
     return xattr_name.rfind("ceph.dir.layout", 0) == 0 ||
            xattr_name.rfind("ceph.file.layout", 0) == 0 ||