From: Venky Shankar Date: Wed, 26 Aug 2020 12:55:51 +0000 (-0400) Subject: mds: introduce ceph.mirror.info virtual xattr X-Git-Tag: v16.1.0~827^2~6 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a631febb2c170002accb7d0a87348ed524fba59c;p=ceph.git mds: introduce ceph.mirror.info virtual xattr 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 --- diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 37c14bf4de1..91598f173f0 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -56,6 +56,7 @@ #include #include +#include #include #include @@ -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(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(*(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 &req = mdr->client_request; diff --git a/src/mds/Server.h b/src/mds/Server.h index ed58d7ad94e..10c9df553f0 100644 --- a/src/mds/Server.h +++ b/src/mds/Server.h @@ -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 ||