From 32c0abfe53b676a8ffbdefd5c7fce5b30e1d8c0f Mon Sep 17 00:00:00 2001 From: Milind Changire Date: Mon, 24 Jan 2022 13:44:17 +0530 Subject: [PATCH] mds: add new getvxattr op This new op fetches ceph namespace specific extended attributes i.e. attributes "ceph.dir.layout.json", "ceph.file.layout.json" and "ceph.dir.pin*" For layout attributes, value of the .json xattrs provide the following features: 1. output in json format 2. resolves layout from the most closest ancestor inode, starting at self 3. adds an 'inheritance' field to show the layout inheritance where: @default - implies default system-wide layout @inherited - implies layout has been inherited from an ancestor @set - implies layout has been set for that specific inode 4. adds two fields: pool_name and pool_id to differentiate between the two values; especially for the situations where users have chosen to use purely digit sequences to name pools; since pool_id is system generated and its output is a decimal number as well, users cannot distinguish the value in the field named 'pool' Fixes: https://tracker.ceph.com/issues/51062 Signed-off-by: Milind Changire (cherry picked from commit b96c01da85315f52811d3ff81949dd7daefdefb5) --- src/include/ceph_fs.h | 1 + src/mds/Server.cc | 161 ++++++++++++++++++++++++++++++++++++++++++ src/mds/Server.h | 29 ++++++++ 3 files changed, 191 insertions(+) diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index eb73efa036630..aed669a7f4506 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -387,6 +387,7 @@ enum { CEPH_MDS_OP_LOOKUPPARENT = 0x00103, CEPH_MDS_OP_LOOKUPINO = 0x00104, CEPH_MDS_OP_LOOKUPNAME = 0x00105, + CEPH_MDS_OP_GETVXATTR = 0x00106, CEPH_MDS_OP_SETXATTR = 0x01105, CEPH_MDS_OP_RMXATTR = 0x01106, diff --git a/src/mds/Server.cc b/src/mds/Server.cc index aa80a03b4af2d..759d80c245949 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -198,6 +198,8 @@ void Server::create_logger() "Request type set file layout latency"); plb.add_time_avg(l_mdss_req_setdirlayout_latency, "req_setdirlayout_latency", "Request type set directory layout latency"); + plb.add_time_avg(l_mdss_req_getvxattr_latency, "req_getvxattr_latency", + "Request type get virtual extended attribute latency"); plb.add_time_avg(l_mdss_req_setxattr_latency, "req_setxattr_latency", "Request type set extended attribute latency"); plb.add_time_avg(l_mdss_req_rmxattr_latency, "req_rmxattr_latency", @@ -2001,6 +2003,9 @@ void Server::perf_gather_op_latency(const cref_t &req, utime_t l case CEPH_MDS_OP_SETDIRLAYOUT: code = l_mdss_req_setdirlayout_latency; break; + case CEPH_MDS_OP_GETVXATTR: + code = l_mdss_req_getvxattr_latency; + break; case CEPH_MDS_OP_SETXATTR: code = l_mdss_req_setxattr_latency; break; @@ -2573,6 +2578,9 @@ void Server::dispatch_client_request(MDRequestRef& mdr) case CEPH_MDS_OP_GETATTR: handle_client_getattr(mdr, false); break; + case CEPH_MDS_OP_GETVXATTR: + handle_client_getvxattr(mdr); + break; case CEPH_MDS_OP_SETATTR: handle_client_setattr(mdr); @@ -6275,6 +6283,159 @@ void Server::handle_client_removexattr(MDRequestRef& mdr) journal_and_reply(mdr, cur, 0, le, new C_MDS_inode_update_finish(this, mdr, cur)); } +void Server::handle_client_getvxattr(MDRequestRef& mdr) +{ + const auto& req = mdr->client_request; + string xattr_name{req->get_path2()}; + + // is a ceph virtual xattr? + if (!is_ceph_vxattr(xattr_name)) { + respond_to_request(mdr, -CEPHFS_ENODATA); + return; + } + + CInode *cur = rdlock_path_pin_ref(mdr, true, false); + if (!cur) { + return; + } + + if (is_ceph_dir_vxattr(xattr_name)) { + if (!cur->is_dir()) { + respond_to_request(mdr, -CEPHFS_ENODATA); + return; + } + } else if (is_ceph_file_vxattr(xattr_name)) { + if (cur->is_dir()) { + respond_to_request(mdr, -CEPHFS_ENODATA); + return; + } + } + + CachedStackStringStream css; + int r = 0; + ceph::bufferlist bl; + // handle these vxattrs + if ((xattr_name.substr(0, 15) == "ceph.dir.layout"sv) || + (xattr_name.substr(0, 16) == "ceph.file.layout"sv)) { + std::string layout_field; + + struct layout_xattr_info_t { + enum class InheritanceStatus : uint32_t { + DEFAULT = 0, + SET = 1, + INHERITED = 2 + }; + + const file_layout_t layout; + const InheritanceStatus status; + + layout_xattr_info_t(const file_layout_t& l, InheritanceStatus inh) + : layout(l), status(inh) { } + + static std::string status_to_string(InheritanceStatus status) { + switch (status) { + case InheritanceStatus::DEFAULT: return "default"s; + case InheritanceStatus::SET: return "set"s; + case InheritanceStatus::INHERITED: return "inherited"s; + default: return "unknown"s; + } + } + }; + + auto is_default_layout = [&](const file_layout_t& layout) -> bool { + return (layout == mdcache->default_file_layout); + }; + auto get_inherited_layout = [&](CInode *cur) -> layout_xattr_info_t { + auto orig_in = cur; + + while (cur) { + if (cur->get_projected_inode()->has_layout()) { + auto& curr_layout = cur->get_projected_inode()->layout; + if (is_default_layout(curr_layout)) { + return {curr_layout, layout_xattr_info_t::InheritanceStatus::DEFAULT}; + } + if (cur == orig_in) { + // we've found a new layout at this inode + return {curr_layout, layout_xattr_info_t::InheritanceStatus::SET}; + } else { + return {curr_layout, layout_xattr_info_t::InheritanceStatus::INHERITED}; + } + } + + if (cur->is_root()) { + break; + } + + cur = cur->get_projected_parent_dir()->get_inode(); + } + mds->clog->error() << "no layout found at root dir!"; + ceph_abort("no layout found at root dir! something is really messed up with layouts!"); + }; + + if (xattr_name == "ceph.dir.layout.json"sv || + xattr_name == "ceph.file.layout.json"sv) { + // fetch layout only for valid xattr_name + const auto lxi = get_inherited_layout(cur); + + *css << "{\"stripe_unit\": " << lxi.layout.stripe_unit + << ", \"stripe_count\": " << lxi.layout.stripe_count + << ", \"object_size\": " << lxi.layout.object_size + << ", \"pool_name\": "; + mds->objecter->with_osdmap([lxi, &css](const OSDMap& o) { + *css << "\""; + if (o.have_pg_pool(lxi.layout.pool_id)) { + *css << o.get_pool_name(lxi.layout.pool_id); + } + *css << "\""; + }); + *css << ", \"pool_id\": " << (uint64_t)lxi.layout.pool_id; + *css << ", \"pool_namespace\": \"" << lxi.layout.pool_ns << "\""; + *css << ", \"inheritance\": \"@" + << layout_xattr_info_t::status_to_string(lxi.status) << "\"}"; + } else if ((xattr_name == "ceph.dir.layout.pool_name"sv) || + (xattr_name == "ceph.file.layout.pool_name"sv)) { + // fetch layout only for valid xattr_name + const auto lxi = get_inherited_layout(cur); + mds->objecter->with_osdmap([lxi, &css](const OSDMap& o) { + if (o.have_pg_pool(lxi.layout.pool_id)) { + *css << o.get_pool_name(lxi.layout.pool_id); + } + }); + } else if ((xattr_name == "ceph.dir.layout.pool_id"sv) || + (xattr_name == "ceph.file.layout.pool_id"sv)) { + // fetch layout only for valid xattr_name + const auto lxi = get_inherited_layout(cur); + *css << (uint64_t)lxi.layout.pool_id; + } else { + r = -CEPHFS_ENODATA; // no such attribute + } + } else if (xattr_name.substr(0, 12) == "ceph.dir.pin"sv) { + if (xattr_name == "ceph.dir.pin"sv) { + *css << cur->get_projected_inode()->export_pin; + } else if (xattr_name == "ceph.dir.pin.random"sv) { + *css << cur->get_projected_inode()->export_ephemeral_random_pin; + } else if (xattr_name == "ceph.dir.pin.distributed"sv) { + *css << cur->get_projected_inode()->export_ephemeral_distributed_pin; + } else { + // otherwise respond as invalid request + // since we only handle ceph vxattrs here + r = -CEPHFS_ENODATA; // no such attribute + } + } else { + // otherwise respond as invalid request + // since we only handle ceph vxattrs here + r = -CEPHFS_ENODATA; // no such attribute + } + + if (r == 0) { + ENCODE_START(1, 1, bl); + encode(css->strv(), bl); + ENCODE_FINISH(bl); + mdr->reply_extra_bl = bl; + } + + respond_to_request(mdr, r); +} // ================================================================= // DIRECTORY and NAMESPACE OPS diff --git a/src/mds/Server.h b/src/mds/Server.h index e378959c180e3..265bc9cf6da7a 100644 --- a/src/mds/Server.h +++ b/src/mds/Server.h @@ -80,6 +80,7 @@ enum { l_mdss_req_unlink_latency, l_mdss_cap_revoke_eviction, l_mdss_cap_acquisition_throttle, + l_mdss_req_getvxattr_latency, l_mdss_last, }; @@ -221,6 +222,7 @@ public: file_layout_t *layout); void handle_set_vxattr(MDRequestRef& mdr, CInode *cur); void handle_remove_vxattr(MDRequestRef& mdr, CInode *cur); + void handle_client_getvxattr(MDRequestRef& mdr); void handle_client_setxattr(MDRequestRef& mdr); void handle_client_removexattr(MDRequestRef& mdr); @@ -421,6 +423,33 @@ private: xattr_name == "ceph.dir.pin.distributed"sv; } + static bool is_ceph_dir_vxattr(std::string_view xattr_name) { + return (xattr_name == "ceph.dir.layout" || + xattr_name == "ceph.dir.layout.json" || + xattr_name == "ceph.dir.layout.object_size" || + xattr_name == "ceph.dir.layout.stripe_unit" || + xattr_name == "ceph.dir.layout.stripe_count" || + xattr_name == "ceph.dir.layout.pool" || + xattr_name == "ceph.dir.layout.pool_name" || + xattr_name == "ceph.dir.layout.pool_id" || + xattr_name == "ceph.dir.layout.pool_namespace" || + xattr_name == "ceph.dir.pin" || + xattr_name == "ceph.dir.pin.random" || + xattr_name == "ceph.dir.pin.distributed"); + } + + static bool is_ceph_file_vxattr(std::string_view xattr_name) { + return (xattr_name == "ceph.file.layout" || + xattr_name == "ceph.file.layout.json" || + xattr_name == "ceph.file.layout.object_size" || + xattr_name == "ceph.file.layout.stripe_unit" || + xattr_name == "ceph.file.layout.stripe_count" || + xattr_name == "ceph.file.layout.pool" || + xattr_name == "ceph.file.layout.pool_name" || + xattr_name == "ceph.file.layout.pool_id" || + xattr_name == "ceph.file.layout.pool_namespace"); + } + static bool is_allowed_ceph_xattr(std::string_view xattr_name) { // not a ceph xattr -- allow! if (xattr_name.rfind("ceph.", 0) != 0) { -- 2.39.5