From 54de0c023cf3b0d1b1b4477d4d852b5a52fa236f Mon Sep 17 00:00:00 2001 From: Dhairya Parmar Date: Wed, 9 Jul 2025 02:55:36 +0530 Subject: [PATCH] client: check client config and snaprealm flag before snapdir lookup this commit adds a new client config client_respect_subvolume_snapshot_visibility which acts as knob to have a per-client control over the snapshot visibility and checks it along with the snaprealm flag while looking up a subvolume inode. Fixes: https://tracker.ceph.com/issues/71740 Signed-off-by: Dhairya Parmar --- src/client/Client.cc | 34 +++++++++++++++++++++++---- src/client/Client.h | 1 + src/client/ClientSnapRealm.h | 2 ++ src/common/options/mds-client.yaml.in | 11 +++++++++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 4d802fa5d60..e81ffbcadcd 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -431,6 +431,9 @@ Client::Client(Messenger *m, MonClient *mc, Objecter *objecter_) injected_write_delay_secs = std::chrono::duration( cct->_conf.get_val("client_inject_write_delay_secs")).count(); + respect_subvolume_snapshot_visibility = cct->_conf.get_val( + "client_respect_subvolume_snapshot_visibility"); + if (cct->_conf->client_acl_type == "posix_acl") acl_type = POSIX_ACL; @@ -5314,13 +5317,16 @@ static bool has_new_snaps(const SnapContext& old_snapc, } struct SnapRealmInfoMeta { - SnapRealmInfoMeta(utime_t last_modified, uint64_t change_attr) + SnapRealmInfoMeta(utime_t last_modified, + uint64_t change_attr, + bool is_snapdir_visible) : last_modified(last_modified), - change_attr(change_attr) { - } + change_attr(change_attr), + is_snapdir_visible(is_snapdir_visible) {} utime_t last_modified; uint64_t change_attr; + bool is_snapdir_visible; }; static std::pair> get_snap_realm_info( @@ -5328,7 +5334,8 @@ static std::pair> get_snap_realm if (session->mds_features.test(CEPHFS_FEATURE_NEW_SNAPREALM_INFO)) { SnapRealmInfoNew ninfo; decode(ninfo, p); - return std::make_pair(ninfo.info, SnapRealmInfoMeta(ninfo.last_modified, ninfo.change_attr)); + return std::make_pair(ninfo.info, SnapRealmInfoMeta(ninfo.last_modified, + ninfo.change_attr, ninfo.flags & SnapRealmInfoNew::SNAPDIR_VISIBILITY)); } else { SnapRealmInfo info; decode(info, p); @@ -5386,6 +5393,7 @@ void Client::update_snap_trace(MetaSession *session, const bufferlist& bl, SnapR if (realm_info_meta) { realm->last_modified = (*realm_info_meta).last_modified; realm->change_attr = (*realm_info_meta).change_attr; + realm->is_snapdir_visible = (*realm_info_meta).is_snapdir_visible; } realm->my_snaps = info.my_snaps; invalidate = true; @@ -7602,6 +7610,11 @@ int Client::_lookup(const InodeRef& dir, const std::string& name, std::string& a if (dname == cct->_conf->client_snapdir && dir->snapid == CEPH_NOSNAP) { + if (respect_subvolume_snapshot_visibility && + !dir->snaprealm->is_snapdir_visible) { + r = -EPERM; + goto done; + } *target = open_snapdir(dir); goto done; } @@ -13336,6 +13349,10 @@ int Client::mksnap(const char *relpath, const char *name, const UserPerm& perm, if (int rc = path_walk(cwd, filepath(relpath), &wdr, perm, {}); rc < 0) { return rc; } + if (respect_subvolume_snapshot_visibility && + !wdr.target->snaprealm->is_snapdir_visible) { + return -EPERM; + } auto snapdir = open_snapdir(wdr.target); if (int rc = path_walk(std::move(snapdir), filepath(name), &wdr, perm, {.require_target = false}); rc < 0) { return rc; @@ -13354,6 +13371,10 @@ int Client::rmsnap(const char *relpath, const char *name, const UserPerm& perms, if (int rc = path_walk(cwd, filepath(relpath), &in, perms, {}); rc < 0) { return rc; } + if (respect_subvolume_snapshot_visibility && + !in->snaprealm->is_snapdir_visible) { + return -EPERM; + } auto snapdir = open_snapdir(in.get()); return _rmdir(snapdir.get(), name, perms, check_perms); } @@ -17659,6 +17680,7 @@ std::vector Client::get_tracked_keys() const noexcept "client_oc_size", "client_oc_target_dirty", "client_permissions", + "client_respect_subvolume_snapshot_visibility", "fuse_default_permissions" }); static_assert(std::is_sorted(begin(as_sv), end(as_sv))); @@ -17717,6 +17739,10 @@ void Client::handle_conf_change(const ConfigProxy& conf, injected_write_delay_secs = std::chrono::duration( cct->_conf.get_val("client_inject_write_delay_secs")).count(); } + if (changed.count("client_respect_subvolume_snapshot_visibility")) { + respect_subvolume_snapshot_visibility = cct->_conf.get_val( + "client_respect_subvolume_snapshot_visibility"); + } } void intrusive_ptr_add_ref(Inode *in) diff --git a/src/client/Client.h b/src/client/Client.h index 0847ea5c69e..bc7386a5ed9 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -2058,6 +2058,7 @@ private: bool is_fuse = false; bool client_permissions; bool fuse_default_permissions; + bool respect_subvolume_snapshot_visibility; std::locale m_locale; }; diff --git a/src/client/ClientSnapRealm.h b/src/client/ClientSnapRealm.h index 4b7eabff572..3f5da9a8ed5 100644 --- a/src/client/ClientSnapRealm.h +++ b/src/client/ClientSnapRealm.h @@ -29,6 +29,7 @@ struct SnapRealm { std::set pchildren; utime_t last_modified; uint64_t change_attr; + bool is_snapdir_visible = true; private: SnapContext cached_snap_context; // my_snaps + parent snaps + past_parent_snaps @@ -62,6 +63,7 @@ inline std::ostream& operator<<(std::ostream& out, const SnapRealm& r) { << " cached_snapc=" << r.cached_snap_context << " last_modified=" << r.last_modified << " change_attr=" << r.change_attr + << " is_snapdir_visible=" << r.is_snapdir_visible << ")"; } diff --git a/src/common/options/mds-client.yaml.in b/src/common/options/mds-client.yaml.in index f80562d08c0..cb77a0c91ff 100644 --- a/src/common/options/mds-client.yaml.in +++ b/src/common/options/mds-client.yaml.in @@ -589,6 +589,17 @@ options: - mds_client flags: - runtime +- name: client_respect_subvolume_snapshot_visibility + type: bool + level: advanced + desc: Respect subvolume snapshot visibility + long_desc: Option to decide whether to respect the is_snapdir_visible flag + set in each subvolume's snaprealm + default: false + services: + - mds_client + flags: + - runtime - name: client_file_blockdiff_max_concurrent_object_scans type: uint level: advanced -- 2.39.5