From c899d3da8f0c1d2fd81596ef6fe8c36a92511d2e Mon Sep 17 00:00:00 2001 From: Dhairya Parmar Date: Thu, 3 Jul 2025 17:22:38 +0530 Subject: [PATCH] mds: add ceph.dir.subvolume.snaps.visible vxattr using SNAPDIR_VISIBILITY flag added in sr_t Fixes: https://tracker.ceph.com/issues/71740 Signed-off-by: Dhairya Parmar --- src/mds/Server.cc | 103 +++++++++++++++++++++++++++++++++++++++++++ src/mds/Server.h | 6 ++- src/mds/SnapRealm.cc | 3 +- src/mds/snap.cc | 9 ++++ src/mds/snap.h | 9 +++- 5 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/mds/Server.cc b/src/mds/Server.cc index fdfd5d3e08a..c8f7997ea64 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -6518,6 +6518,96 @@ void Server::handle_client_setvxattr(const MDRequestRef& mdr, CInode *cur) mdr->no_early_reply = true; pip = pi.inode.get(); adjust_realm = true; + } else if (name == "ceph.dir.subvolume.snaps.visible"sv) { + if (!cur->is_dir()) { + respond_to_request(mdr, -EINVAL); + return; + } + + bool val = true; + try { + std::string errstr; + val = strict_strtob(value, &errstr); + if (!errstr.empty()) { + dout(10) << "bad vxattr value, unable to parse bool for " << name + << ": " << errstr << dendl; + respond_to_request(mdr, -EINVAL); + return; + } + } catch (boost::bad_lexical_cast const& e) { + dout(10) << "bad vxattr value, unable to parse bool for " << name + << ": " << e.what() << dendl; + respond_to_request(mdr, -EINVAL); + return; + } + + // perform few checks with lightweight rdlock + if (!mdr->more()->rdonly_checks) { + lov.add_rdlock(&cur->snaplock); + if (!mds->locker->acquire_locks(mdr, lov)) { + dout(20) << "handle_client_getvxattr could not acquire rdlock on " + << *cur << dendl; + return; + } + + const auto srnode = cur->get_projected_srnode(); + if (!srnode) { + dout(10) << "no-op since no snaprealm node found for " + << req->get_filepath() << dendl; + respond_to_request(mdr, 0); + return; + } + // check if visibility already matches the desired value + if (val == srnode->is_snapdir_visible()) { + dout(20) << "snapdir visibility for " << req->get_filepath() + << " is already set to " << std::boolalpha << val << dendl; + respond_to_request(mdr, 0); + return; + } + + mdr->more()->rdonly_checks = true; + dout(20) << "dropping rdlock on " << *cur << dendl; + mds->locker->drop_locks(mdr.get()); + } + + if (!xlock_policylock(mdr, cur, false, true)) { + return; + } + + /* Repeat rdlocks checks to see if anything changed b/w rdlock release and + * xlock policylock acquisition + */ + { + const auto srnode = cur->get_projected_srnode(); + if (!srnode) { + dout(10) << "no-op since no snaprealm node found for " + << req->get_filepath() << dendl; + respond_to_request(mdr, 0); + return; + } + + if (val == srnode->is_snapdir_visible()) { + dout(20) << "snapdir visibility for " << req->get_filepath() + << " is already set to " << std::boolalpha << val << dendl; + respond_to_request(mdr, 0); + return; + } + } + + adjust_realm = true; + auto pi = cur->project_inode(mdr, false, adjust_realm); + dout(20) << "setting snapdir visibility to " << std::boolalpha + << val << " for " << req->get_filepath() << dendl; + if (val) { + pi.snapnode->set_snapdir_visibility(); + } else { + pi.snapnode->unset_snapdir_visibility(); + } + pi.snapnode->last_modified = mdr->get_op_stamp(); + pi.snapnode->change_attr++; + + mdr->no_early_reply = true; + pip = pi.inode.get(); } else if (name == "ceph.dir.pin"sv) { if (!cur->is_dir() || cur->is_root()) { respond_to_request(mdr, -EINVAL); @@ -7284,6 +7374,19 @@ void Server::handle_client_getvxattr(const MDRequestRef& mdr) // since we only handle ceph vxattrs here r = -ENODATA; // no such attribute } + } else if (xattr_name == "ceph.dir.subvolume.snaps.visible"sv) { + if (!cur->is_dir()) { + r = -ENOTDIR; + } else { + const auto srnode = cur->get_projected_srnode(); + if (!srnode) { + dout(10) << "no-op since no snaprealm node found for " + << mdr->client_request->get_filepath() << dendl; + r = 0; + } else { + *css << srnode->is_snapdir_visible(); + } + } } else { // otherwise respond as invalid request // since we only handle ceph vxattrs here diff --git a/src/mds/Server.h b/src/mds/Server.h index 234afe0f533..51de128d59d 100644 --- a/src/mds/Server.h +++ b/src/mds/Server.h @@ -500,7 +500,8 @@ private: xattr_name == "ceph.dir.charmap"sv || xattr_name == "ceph.dir.normalization"sv || xattr_name == "ceph.dir.encoding"sv || - xattr_name == "ceph.dir.casesensitive"sv; + xattr_name == "ceph.dir.casesensitive"sv || + xattr_name == "ceph.dir.subvolume.snaps.visible"sv; } static bool is_ceph_dir_vxattr(std::string_view xattr_name) { @@ -519,7 +520,8 @@ private: xattr_name == "ceph.dir.charmap"sv || xattr_name == "ceph.dir.normalization"sv || xattr_name == "ceph.dir.encoding"sv || - xattr_name == "ceph.dir.casesensitive"sv; + xattr_name == "ceph.dir.casesensitive"sv || + xattr_name == "ceph.dir.subvolume.snaps.visible"sv; } static bool is_ceph_file_vxattr(std::string_view xattr_name) { diff --git a/src/mds/SnapRealm.cc b/src/mds/SnapRealm.cc index f4de37e3422..0ed4cb8fae9 100644 --- a/src/mds/SnapRealm.cc +++ b/src/mds/SnapRealm.cc @@ -57,7 +57,8 @@ ostream& operator<<(ostream& out, const SnapRealm& realm) if (realm.srnode.is_parent_global()) out << " global "; out << " last_modified " << realm.srnode.last_modified - << " change_attr " << realm.srnode.change_attr; + << " change_attr " << realm.srnode.change_attr + << " is_snapdir_visible " << realm.srnode.is_snapdir_visible(); out << " " << &realm << ")"; return out; } diff --git a/src/mds/snap.cc b/src/mds/snap.cc index ca316d084a2..b3cd1fc3d0d 100644 --- a/src/mds/snap.cc +++ b/src/mds/snap.cc @@ -194,6 +194,7 @@ void sr_t::dump(Formatter *f) const f->dump_unsigned("last_destroyed", last_destroyed); f->dump_stream("last_modified") << last_modified; f->dump_unsigned("change_attr", change_attr); + f->dump_unsigned("is_snapdir_visible", is_snapdir_visible()); f->dump_unsigned("current_parent_since", current_parent_since); f->open_array_section("snaps"); @@ -247,3 +248,11 @@ std::list sr_t::generate_test_instances() return ls; } +void sr_t::print(std::ostream& out) const { + out << "sr_t(seq=" << seq + << " created=" << created + << " last_created=" << last_created + << " last_destroyed=" << last_destroyed + << " flags=" << flags << ")"; +} + diff --git a/src/mds/snap.h b/src/mds/snap.h index 539e20c6839..73980611fd2 100644 --- a/src/mds/snap.h +++ b/src/mds/snap.h @@ -88,10 +88,15 @@ struct sr_t { void clear_subvolume() { flags &= ~SUBVOLUME; } bool is_subvolume() const { return flags & SUBVOLUME; } + void set_snapdir_visibility() { flags |= SNAPDIR_VISIBILITY; } + void unset_snapdir_visibility() { flags &= ~SNAPDIR_VISIBILITY; } + bool is_snapdir_visible() const { return flags & SNAPDIR_VISIBILITY; } + void encode(ceph::buffer::list &bl) const; void decode(ceph::buffer::list::const_iterator &bl); void dump(ceph::Formatter *f) const; static std::list generate_test_instances(); + void print(std::ostream&) const; snapid_t seq = 0; // basically, a version/seq # for changes to _this_ realm. snapid_t created = 0; // when this realm was created. @@ -106,11 +111,13 @@ struct sr_t { uint64_t change_attr = 0; // tracks changes to snap // realm attrs. - __u32 flags = 0; enum { PARENT_GLOBAL = 1 << 0, SUBVOLUME = 1 << 1, + SNAPDIR_VISIBILITY = 1 << 2, }; + + __u32 flags = SNAPDIR_VISIBILITY; // snapdir visibility is always on by default }; WRITE_CLASS_ENCODER(sr_t) -- 2.39.5