From c4a335d7c619cfda9b019e45df22cb55ef53caec Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 9 Mar 2020 21:14:30 +0800 Subject: [PATCH] mon: add 'ceph fs required_client_feature add/rm' command Fixes: https://tracker.ceph.com/issues/43817 Signed-off-by: "Yan, Zheng" --- PendingReleaseNotes | 6 ++ doc/cephfs/administration.rst | 91 +++++++++++++++++++ .../tasks/3-compat_client/pacific.yaml | 2 +- .../tasks/4-compat_client.yaml | 2 +- qa/tasks/cephfs/test_admin.py | 34 +++++++ qa/tasks/mgr/dashboard/test_health.py | 2 +- src/CMakeLists.txt | 3 +- src/crimson/CMakeLists.txt | 1 + src/mds/MDSMap.cc | 61 ++++++++++--- src/mds/MDSMap.h | 16 +++- src/mds/MDSRank.cc | 3 +- src/mds/Server.cc | 22 +---- src/mds/cephfs_features.cc | 72 +++++++++++++++ src/mds/cephfs_features.h | 11 +++ src/mds/mdstypes.h | 22 +++++ src/mon/FSCommands.cc | 75 +++++++++++++++ src/mon/MDSMonitor.cc | 17 ++++ src/mon/MonCommands.h | 11 +++ 18 files changed, 407 insertions(+), 44 deletions(-) create mode 100644 src/mds/cephfs_features.cc diff --git a/PendingReleaseNotes b/PendingReleaseNotes index a68499e0484..e9b580ba38b 100644 --- a/PendingReleaseNotes +++ b/PendingReleaseNotes @@ -86,3 +86,9 @@ * Monitors now have a config option ``mon_osd_warn_num_repaired``, 10 by default. If any OSD has repaired more than this many I/O errors in stored data a ``OSD_TOO_MANY_REPAIRS`` health warning is generated. + +* Introduce commands that manipulate required client features of a file system:: + + ceph fs required_client_features add + ceph fs required_client_features rm + ceph fs feature ls diff --git a/doc/cephfs/administration.rst b/doc/cephfs/administration.rst index 605864431c2..4261e9480ee 100644 --- a/doc/cephfs/administration.rst +++ b/doc/cephfs/administration.rst @@ -237,6 +237,97 @@ For example, to only allow Nautilus clients, use: Clients running an older version will be automatically evicted. +Enforcing minimum version of CephFS client is achieved by setting required +client features. Commands to manipulate required client features of a file +system: + +:: + + fs required_client_features add reply_encoding + fs required_client_features rm reply_encoding + +To list all CephFS features + +:: + + fs feature ls + + +CephFS features and first release they came out. + ++------------------+--------------+-----------------+ +| Feature | Ceph release | Upstream Kernel | ++==================+==============+=================+ +| jewel | jewel | 4.5 | ++------------------+--------------+-----------------+ +| kraken | kraken | 4.13 | ++------------------+--------------+-----------------+ +| luminous | luminous | 4.13 | ++------------------+--------------+-----------------+ +| mimic | mimic | 4.19 | ++------------------+--------------+-----------------+ +| reply_encoding | nautilus | 5.1 | ++------------------+--------------+-----------------+ +| reclaim_client | nautilus | N/A | ++------------------+--------------+-----------------+ +| lazy_caps_wanted | nautilus | 5.1 | ++------------------+--------------+-----------------+ +| multi_reconnect | nautilus | 5.1 | ++------------------+--------------+-----------------+ +| deleg_ino | octopus | 5.6 | ++------------------+--------------+-----------------+ +| metric_collect | pacific | N/A | ++------------------+--------------+-----------------+ + +CephFS Feature Descriptions + + +:: + + reply_encoding + +MDS encodes request reply in extensible format if client supports this feature. + + +:: + + reclaim_client + +MDS allows new client to reclaim another (dead) client's states. This feature +is used by NFS-Ganesha. + + +:: + + lazy_caps_wanted + +When a stale client resumes, if the client supports this feature, mds only needs +to re-issue caps that are explictly wanted. + + +:: + + multi_reconnect + +When mds failover, client sends reconnect messages to mds, to reestablish cache +states. If MDS supports this feature, client can split large reconnect message +into multiple ones. + + +:: + + deleg_ino + +MDS delegate inode numbers to client if client supports this feature. Having +delegated inode numbers is a prerequisite for client to do async file creation. + + +:: + + metric_collect + +Clients can send performance metric to MDS if MDS support this feature. + Global settings --------------- diff --git a/qa/suites/fs/upgrade/featureful_client/old_client/tasks/3-compat_client/pacific.yaml b/qa/suites/fs/upgrade/featureful_client/old_client/tasks/3-compat_client/pacific.yaml index d8761e9bd29..56f8ebde9fd 100644 --- a/qa/suites/fs/upgrade/featureful_client/old_client/tasks/3-compat_client/pacific.yaml +++ b/qa/suites/fs/upgrade/featureful_client/old_client/tasks/3-compat_client/pacific.yaml @@ -6,5 +6,5 @@ tasks: - exec: mon.a: - ceph fs dump --format=json-pretty - - ceph fs set cephfs min_compat_client pacific + - ceph fs required_client_features cephfs add metric_collect - fs.clients_evicted: diff --git a/qa/suites/fs/upgrade/featureful_client/upgraded_client/tasks/4-compat_client.yaml b/qa/suites/fs/upgrade/featureful_client/upgraded_client/tasks/4-compat_client.yaml index a553f31d50e..be282706818 100644 --- a/qa/suites/fs/upgrade/featureful_client/upgraded_client/tasks/4-compat_client.yaml +++ b/qa/suites/fs/upgrade/featureful_client/upgraded_client/tasks/4-compat_client.yaml @@ -6,7 +6,7 @@ tasks: - exec: mon.a: - ceph fs dump --format=json-pretty - - ceph fs set cephfs min_compat_client octopus + - ceph fs required_client_features cephfs add metric_collect - fs.clients_evicted: clients: client.0: False diff --git a/qa/tasks/cephfs/test_admin.py b/qa/tasks/cephfs/test_admin.py index 393146fa285..661547e733f 100644 --- a/qa/tasks/cephfs/test_admin.py +++ b/qa/tasks/cephfs/test_admin.py @@ -164,6 +164,40 @@ class TestAdminCommands(CephFSTestCase): self._check_pool_application_metadata_key_value( pool_names[i], 'cephfs', keys[i], fs_name) + def test_required_client_features(self): + """ + That `ceph fs required_client_features` command functions. + """ + + def is_required(index): + out = self.fs.mon_manager.raw_cluster_cmd('fs', 'get', self.fs.name, '--format=json-pretty') + features = json.loads(out)['mdsmap']['required_client_features'] + if "feature_{0}".format(index) in features: + return True; + return False; + + features = json.loads(self.fs.mon_manager.raw_cluster_cmd('fs', 'feature', 'ls', '--format=json-pretty')) + self.assertGreater(len(features), 0); + + for f in features: + self.fs.mon_manager.raw_cluster_cmd('fs', 'required_client_features', self.fs.name, 'rm', str(f['index'])) + + for f in features: + index = f['index'] + feature = f['name'] + if feature == 'reserved': + feature = str(index) + + if index % 3 == 0: + continue; + self.fs.mon_manager.raw_cluster_cmd('fs', 'required_client_features', self.fs.name, 'add', feature) + self.assertTrue(is_required(index)) + + if index % 2 == 0: + continue; + self.fs.mon_manager.raw_cluster_cmd('fs', 'required_client_features', self.fs.name, 'rm', feature) + self.assertFalse(is_required(index)) + class TestConfigCommands(CephFSTestCase): """ diff --git a/qa/tasks/mgr/dashboard/test_health.py b/qa/tasks/mgr/dashboard/test_health.py index 08551e488ab..73028494d85 100644 --- a/qa/tasks/mgr/dashboard/test_health.py +++ b/qa/tasks/mgr/dashboard/test_health.py @@ -40,7 +40,7 @@ class HealthTest(DashboardTestCase): 'ro_compat': JObj({}, allow_unknown=True), 'incompat': JObj({}, allow_unknown=True) }), - 'min_compat_client': str, + 'required_client_features': JObj({}, allow_unknown=True), 'data_pools': JList(int), 'info': JObj({}, allow_unknown=True), 'fs_name': str, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 054eab5a9be..e243f0cd945 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -294,7 +294,8 @@ list(APPEND mds_files mds/FSMapUser.cc mds/inode_backtrace.cc mds/mdstypes.cc - mds/flock.cc) + mds/flock.cc + mds/cephfs_features.cc) add_subdirectory(json_spirit) diff --git a/src/crimson/CMakeLists.txt b/src/crimson/CMakeLists.txt index 0d267288f15..f5dc80800c1 100644 --- a/src/crimson/CMakeLists.txt +++ b/src/crimson/CMakeLists.txt @@ -100,6 +100,7 @@ add_library(crimson-common STATIC ${PROJECT_SOURCE_DIR}/src/mgr/ServiceMap.cc ${PROJECT_SOURCE_DIR}/src/mds/inode_backtrace.cc ${PROJECT_SOURCE_DIR}/src/mds/mdstypes.cc + ${PROJECT_SOURCE_DIR}/src/mds/cephfs_features.cc ${PROJECT_SOURCE_DIR}/src/mds/FSMap.cc ${PROJECT_SOURCE_DIR}/src/mds/FSMapUser.cc ${PROJECT_SOURCE_DIR}/src/mds/MDSMap.cc diff --git a/src/mds/MDSMap.cc b/src/mds/MDSMap.cc index f1ff7c36f7f..b359573b90f 100644 --- a/src/mds/MDSMap.cc +++ b/src/mds/MDSMap.cc @@ -150,8 +150,9 @@ void MDSMap::dump(Formatter *f) const f->dump_int("root", root); f->dump_int("session_timeout", session_timeout); f->dump_int("session_autoclose", session_autoclose); - f->dump_stream("min_compat_client") << to_integer(min_compat_client) << " (" - << min_compat_client << ")"; + f->open_object_section("required_client_features"); + cephfs_dump_features(f, required_client_features); + f->close_section(); f->dump_int("max_file_size", max_file_size); f->dump_int("last_failure", last_failure); f->dump_int("last_failure_osd_epoch", last_failure_osd_epoch); @@ -230,8 +231,7 @@ void MDSMap::print(ostream& out) const out << "session_timeout\t" << session_timeout << "\n" << "session_autoclose\t" << session_autoclose << "\n"; out << "max_file_size\t" << max_file_size << "\n"; - out << "min_compat_client\t" << to_integer(min_compat_client) << " (" - << min_compat_client << ")\n"; + out << "required_client_features\t" << cephfs_stringify_features(required_client_features) << "\n"; out << "last_failure\t" << last_failure << "\n" << "last_failure_osd_epoch\t" << last_failure_osd_epoch << "\n"; out << "compat\t" << compat << "\n"; @@ -702,7 +702,7 @@ void MDSMap::encode(bufferlist& bl, uint64_t features) const encode(data_pools, bl); encode(cas_pool, bl); - __u16 ev = 15; + __u16 ev = 16; encode(ev, bl); encode(compat, bl); encode(metadata_pool, bl); @@ -724,7 +724,11 @@ void MDSMap::encode(bufferlist& bl, uint64_t features) const encode(balancer, bl); encode(standby_count_wanted, bl); encode(old_max_mds, bl); - encode(min_compat_client, bl); + { + ceph_release_t min_compat_client = ceph_release_t::unknown; + encode(min_compat_client, bl); + } + encode(required_client_features, bl); ENCODE_FINISH(bl); } @@ -852,16 +856,24 @@ void MDSMap::decode(bufferlist::const_iterator& p) decode(old_max_mds, p); } - if (ev == 14) { - int8_t r; - decode(r, p); - if (r < 0) { - min_compat_client = ceph_release_t::unknown; + if (ev >= 14) { + ceph_release_t min_compat_client; + if (ev == 14) { + int8_t r; + decode(r, p); + if (r < 0) { + min_compat_client = ceph_release_t::unknown; + } else { + min_compat_client = ceph_release_t{static_cast(r)}; + } + } else if (ev >= 15) { + decode(min_compat_client, p); + } + if (ev >= 16) { + decode(required_client_features, p); } else { - min_compat_client = ceph_release_t{static_cast(r)}; + set_min_compat_client(min_compat_client); } - } else if (ev > 14) { - decode(min_compat_client, p); } DECODE_FINISH(p); @@ -1048,3 +1060,24 @@ bool MDSMap::is_degraded() const { } return false; } + +void MDSMap::set_min_compat_client(ceph_release_t version) +{ + vector bits = CEPHFS_FEATURES_MDS_REQUIRED; + + if (version >= ceph_release_t::octopus) + bits.push_back(CEPHFS_FEATURE_OCTOPUS); + else if (version >= ceph_release_t::nautilus) + bits.push_back(CEPHFS_FEATURE_NAUTILUS); + else if (version >= ceph_release_t::mimic) + bits.push_back(CEPHFS_FEATURE_MIMIC); + else if (version >= ceph_release_t::luminous) + bits.push_back(CEPHFS_FEATURE_LUMINOUS); + else if (version >= ceph_release_t::kraken) + bits.push_back(CEPHFS_FEATURE_KRAKEN); + else if (version >= ceph_release_t::jewel) + bits.push_back(CEPHFS_FEATURE_JEWEL); + + std::sort(bits.begin(), bits.end()); + required_client_features = feature_bitset_t(bits); +} diff --git a/src/mds/MDSMap.h b/src/mds/MDSMap.h index 2c3b3221146..4efd32f472d 100644 --- a/src/mds/MDSMap.h +++ b/src/mds/MDSMap.h @@ -35,6 +35,7 @@ #include "common/config.h" #include "mds/mdstypes.h" +#include "mds/cephfs_features.h" #define MDS_FEATURE_INCOMPAT_BASE CompatSet::Feature(1, "base v0.20") #define MDS_FEATURE_INCOMPAT_CLIENTRANGES CompatSet::Feature(2, "client writeable ranges") @@ -186,8 +187,17 @@ public: uint64_t get_max_filesize() const { return max_file_size; } void set_max_filesize(uint64_t m) { max_file_size = m; } - ceph_release_t get_min_compat_client() const { return min_compat_client; } - void set_min_compat_client(ceph_release_t version) { min_compat_client = version; } + void set_min_compat_client(ceph_release_t version); + + void add_required_client_feature(size_t bit) { + required_client_features.insert(bit); + } + void remove_required_client_feature(size_t bit) { + required_client_features.erase(bit); + } + const auto& get_required_client_features() const { + return required_client_features; + } int get_flags() const { return flags; } bool test_flag(int f) const { return flags & f; } @@ -561,7 +571,7 @@ protected: __u32 session_autoclose = 300; uint64_t max_file_size = 1ULL<<40; /* 1TB */ - ceph_release_t min_compat_client{ceph_release_t::unknown}; + feature_bitset_t required_client_features; std::vector data_pools; // file data pools available to clients (via an ioctl). first is the default. int64_t cas_pool = -1; // where CAS objects go diff --git a/src/mds/MDSRank.cc b/src/mds/MDSRank.cc index 1ab7f3a67ce..161adeb4d74 100644 --- a/src/mds/MDSRank.cc +++ b/src/mds/MDSRank.cc @@ -2238,8 +2238,7 @@ void MDSRankDispatcher::handle_mds_map( if (objecter->get_client_incarnation() != incarnation) objecter->set_client_incarnation(incarnation); - if (mdsmap->get_min_compat_client() < ceph_release_t::max && - oldmap.get_min_compat_client() != mdsmap->get_min_compat_client()) + if (mdsmap->get_required_client_features() != oldmap.get_required_client_features()) server->update_required_client_features(); // for debug diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 1b8a2ac0311..41da5d19ade 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -1516,27 +1516,7 @@ void Server::infer_supported_features(Session *session, client_metadata_t& clien void Server::update_required_client_features() { - vector bits = CEPHFS_FEATURES_MDS_REQUIRED; - - /* If this blows up on you, you added a release without adding a new release bit to cephfs_features.h */ - static_assert(CEPHFS_CURRENT_RELEASE == CEPH_RELEASE_MAX-1); - - ceph_release_t min_compat = mds->mdsmap->get_min_compat_client(); - if (min_compat >= ceph_release_t::octopus) - bits.push_back(CEPHFS_FEATURE_OCTOPUS); - else if (min_compat >= ceph_release_t::nautilus) - bits.push_back(CEPHFS_FEATURE_NAUTILUS); - else if (min_compat >= ceph_release_t::mimic) - bits.push_back(CEPHFS_FEATURE_MIMIC); - else if (min_compat >= ceph_release_t::luminous) - bits.push_back(CEPHFS_FEATURE_LUMINOUS); - else if (min_compat >= ceph_release_t::kraken) - bits.push_back(CEPHFS_FEATURE_KRAKEN); - else if (min_compat >= ceph_release_t::jewel) - bits.push_back(CEPHFS_FEATURE_JEWEL); - - std::sort(bits.begin(), bits.end()); - required_client_features = feature_bitset_t(bits); + required_client_features = mds->mdsmap->get_required_client_features(); dout(7) << "required_client_features: " << required_client_features << dendl; if (mds->get_state() >= MDSMap::STATE_RECONNECT) { diff --git a/src/mds/cephfs_features.cc b/src/mds/cephfs_features.cc new file mode 100644 index 00000000000..dcec2c46aa3 --- /dev/null +++ b/src/mds/cephfs_features.cc @@ -0,0 +1,72 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include +#include +#include "cephfs_features.h" +#include "mdstypes.h" + +static const std::array feature_names +{ + "reserved", + "reserved", + "reserved", + "reserved", + "reserved", + "jewel", + "kraken", + "luminous", + "mimic", + "reply_encoding", + "reclaim_client", + "lazy_caps_wanted", + "multi_reconnect", + "deleg_ino", + "metric_collect", +}; +static_assert(feature_names.size() == CEPHFS_FEATURE_MAX + 1); + +std::string_view cephfs_feature_name(size_t id) +{ + if (id > feature_names.size()) + return "unknown"; + return feature_names[id]; +} + +int cephfs_feature_from_name(std::string_view name) +{ + for (size_t i = 0; i < feature_names.size(); ++i) { + if (name == feature_names[i]) + return i; + } + return -1; +} + +std::string cephfs_stringify_features(const feature_bitset_t& features) +{ + std::ostringstream ss; + bool first = true; + ss << "{"; + for (size_t i = 0; i < feature_names.size(); ++i) { + if (!features.test(i)) + continue; + if (!first) + ss << ","; + ss << i << "=" << cephfs_feature_name(i); + first = false; + } + ss << "}"; + return ss.str(); +} + +void cephfs_dump_features(ceph::Formatter *f, const feature_bitset_t& features) +{ + for (size_t i = 0; i < feature_names.size(); ++i) { + if (!features.test(i)) + continue; + char s[18]; + snprintf(s, sizeof(s), "feature_%lu", i); + f->dump_string(s, cephfs_feature_name(i)); + } +} + diff --git a/src/mds/cephfs_features.h b/src/mds/cephfs_features.h index 37b0ba6d9ed..75309ef5da8 100644 --- a/src/mds/cephfs_features.h +++ b/src/mds/cephfs_features.h @@ -15,6 +15,11 @@ #ifndef CEPHFS_FEATURES_H #define CEPHFS_FEATURES_H +class feature_bitset_t; +namespace ceph { + class Formatter; +} + // When adding a new release, please update the "current" release below, add a // feature bit for that release, add that feature bit to CEPHFS_FEATURES_ALL, // and update Server::update_required_client_features(). This feature bit @@ -35,6 +40,7 @@ #define CEPHFS_FEATURE_DELEG_INO 13 #define CEPHFS_FEATURE_OCTOPUS 13 #define CEPHFS_FEATURE_METRIC_COLLECT 14 +#define CEPHFS_FEATURE_MAX 14 #define CEPHFS_FEATURES_ALL { \ 0, 1, 2, 3, 4, \ @@ -58,4 +64,9 @@ #define CEPHFS_FEATURES_CLIENT_SUPPORTED CEPHFS_FEATURES_ALL #define CEPHFS_FEATURES_CLIENT_REQUIRED {} +extern std::string_view cephfs_feature_name(size_t id); +extern int cephfs_feature_from_name(std::string_view name); +std::string cephfs_stringify_features(const feature_bitset_t& features); +void cephfs_dump_features(ceph::Formatter *f, const feature_bitset_t& features); + #endif diff --git a/src/mds/mdstypes.h b/src/mds/mdstypes.h index a0b689c37a5..4eeb3311c6d 100644 --- a/src/mds/mdstypes.h +++ b/src/mds/mdstypes.h @@ -1171,9 +1171,31 @@ public: return false; return _vec[bit / bits_per_block] & ((block_type)1 << (bit % bits_per_block)); } + void insert(size_t bit) { + size_t n = bit / bits_per_block; + if (n >= _vec.size()) + _vec.resize(n + 1); + _vec[n] |= ((block_type)1 << (bit % bits_per_block)); + } + void erase(size_t bit) { + size_t n = bit / bits_per_block; + if (n >= _vec.size()) + return; + _vec[n] &= ~((block_type)1 << (bit % bits_per_block)); + if (n + 1 == _vec.size()) { + while (!_vec.empty() && _vec.back() == 0) + _vec.pop_back(); + } + } void clear() { _vec.clear(); } + bool operator==(const feature_bitset_t& other) const { + return _vec == other._vec; + } + bool operator!=(const feature_bitset_t& other) const { + return _vec != other._vec; + } void encode(ceph::buffer::list& bl) const; void decode(ceph::buffer::list::const_iterator &p); void dump(ceph::Formatter *f) const; diff --git a/src/mon/FSCommands.cc b/src/mon/FSCommands.cc index fa65213e52b..86efed8e64e 100644 --- a/src/mon/FSCommands.cc +++ b/src/mon/FSCommands.cc @@ -18,6 +18,7 @@ #include "FSCommands.h" #include "MDSMonitor.h" #include "MgrStatMonitor.h" +#include "mds/cephfs_features.h" using TOPNSPC::common::cmd_getval; @@ -651,6 +652,79 @@ public: } }; +class RequiredClientFeaturesHandler : public FileSystemCommandHandler +{ + public: + RequiredClientFeaturesHandler() + : FileSystemCommandHandler("fs required_client_features") + { + } + + int handle( + Monitor *mon, + FSMap &fsmap, + MonOpRequestRef op, + const cmdmap_t& cmdmap, + std::stringstream &ss) override + { + std::string fs_name; + if (!cmd_getval(cmdmap, "fs_name", fs_name) || fs_name.empty()) { + ss << "Missing filesystem name"; + return -EINVAL; + } + auto fs = fsmap.get_filesystem(fs_name); + if (fs == nullptr) { + ss << "Not found: '" << fs_name << "'"; + return -ENOENT; + } + string subop; + if (!cmd_getval(cmdmap, "subop", subop) || + (subop != "add" && subop != "rm")) { + ss << "Must either add or rm a feature; " << subop << " is not recognized"; + return -EINVAL; + } + string val; + if (!cmd_getval(cmdmap, "val", val) || val.empty()) { + ss << "Missing feature id/name"; + return -EINVAL; + } + + int feature = cephfs_feature_from_name(val); + if (feature < 0) { + string err; + feature = strict_strtol(val.c_str(), 10, &err); + if (err.length()) { + ss << "Invalid feature name: " << val; + return -EINVAL; + } + if (feature < 0 || feature > CEPHFS_FEATURE_MAX) { + ss << "Invalid feature id: " << feature; + return -EINVAL; + } + } + + if (subop == "add") { + fsmap.modify_filesystem( + fs->fscid, + [feature](std::shared_ptr fs) + { + fs->mds_map.add_required_client_feature(feature); + }); + ss << "added feature '" << cephfs_feature_name(feature) << "' to required_client_features"; + } else { + fsmap.modify_filesystem( + fs->fscid, + [feature](std::shared_ptr fs) + { + fs->mds_map.remove_required_client_feature(feature); + }); + ss << "removed feature '" << cephfs_feature_name(feature) << "' to required_client_features"; + } + return 0; + } +}; + + class AddDataPoolHandler : public FileSystemCommandHandler { public: @@ -988,6 +1062,7 @@ FileSystemCommandHandler::load(Paxos *paxos) handlers.push_back(std::make_shared()); handlers.push_back(std::make_shared()); handlers.push_back(std::make_shared()); + handlers.push_back(std::make_shared()); handlers.push_back(std::make_shared(paxos)); handlers.push_back(std::make_shared()); handlers.push_back(std::make_shared(paxos)); diff --git a/src/mon/MDSMonitor.cc b/src/mon/MDSMonitor.cc index 738b490d9fc..9415ad814c7 100644 --- a/src/mon/MDSMonitor.cc +++ b/src/mon/MDSMonitor.cc @@ -1190,6 +1190,23 @@ bool MDSMonitor::preprocess_command(MonOpRequestRef op) } } r = 0; + } else if (prefix == "fs feature ls") { + if (f) { + f->open_array_section("cephfs_features"); + for (size_t i = 0; i <= CEPHFS_FEATURE_MAX; ++i) { + f->open_object_section("feature"); + f->dump_int("index", i); + f->dump_string("name", cephfs_feature_name(i)); + f->close_section(); + } + f->close_section(); + f->flush(ds); + } else { + for (size_t i = 0; i <= CEPHFS_FEATURE_MAX; ++i) { + ds << i << " " << cephfs_feature_name(i) << std::endl; + } + } + r = 0; } out: diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index 125b16bab28..f1e429aef23 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -405,6 +405,17 @@ COMMAND("fs flag set name=flag_name,type=CephChoices,strings=enable_multiple " "name=yes_i_really_mean_it,type=CephBool,req=false", "Set a global CephFS flag", "fs", "rw") + +COMMAND("fs feature ls", + "list available cephfs features to be set/unset", + "mds", "r") + +COMMAND("fs required_client_features " + "name=fs_name,type=CephString " + "name=subop,type=CephChoices,strings=add|rm " + "name=val,type=CephString ", + "add/remove required features of clients", "mds", "rw") + COMMAND("fs add_data_pool name=fs_name,type=CephString " "name=pool,type=CephString", "add data pool ", "mds", "rw") -- 2.39.5