bool allows_snaps() const { return test_flag(CEPH_MDSMAP_ALLOW_SNAPS); }
bool was_snaps_ever_allowed() const { return ever_allowed_features & CEPH_MDSMAP_ALLOW_SNAPS; }
+ void set_multimds_snaps_allowed() {
+ set_flag(CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS);
+ ever_allowed_features |= CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS;
+ explicitly_allowed_features |= CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS;
+ }
+ void clear_multimds_snaps_allowed() { clear_flag(CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS); }
bool allows_multimds_snaps() const { return test_flag(CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS); }
epoch_t get_epoch() const { return epoch; }
em.first->second.hit(now, amount);
}
+class C_MDS_MonCommand : public MDSInternalContext {
+ std::string cmd;
+public:
+ std::string outs;
+ C_MDS_MonCommand(MDSRank *m, std::string_view c)
+ : MDSInternalContext(m), cmd(c) {}
+ void finish(int r) override {
+ mds->_mon_command_finish(r, cmd, outs);
+ }
+};
+
+void MDSRank::_mon_command_finish(int r, std::string_view cmd, std::string_view outs)
+{
+ if (r < 0) {
+ dout(0) << __func__ << ": mon command " << cmd << " failed with errno " << r
+ << " (" << outs << ")" << dendl;
+ } else {
+ dout(1) << __func__ << ": mon command " << cmd << " succeed" << dendl;
+ }
+}
+
+void MDSRank::set_mdsmap_multimds_snaps_allowed()
+{
+ static bool already_sent = false;
+ if (already_sent)
+ return;
+
+ stringstream ss;
+ ss << "{\"prefix\":\"fs set\", \"fs_name\":\"" << mdsmap->get_fs_name() << "\", ";
+ ss << "\"var\":\"allow_multimds_snaps\", \"val\":\"true\", ";
+ ss << "\"confirm\":\"--yes-i-am-really-a-mds\"}";
+ std::vector<std::string> cmd = {ss.str()};
+
+ dout(0) << __func__ << ": sending mon command: " << cmd[0] << dendl;
+
+ C_MDS_MonCommand *fin = new C_MDS_MonCommand(this, cmd[0]);
+ monc->start_mon_command(cmd, {}, nullptr, &fin->outs, new C_IO_Wrapper(this, fin));
+
+ already_sent = true;
+}
+
void MDSRankDispatcher::tick()
{
heartbeat_reset();
balancer->tick();
mdcache->find_stale_fragment_freeze();
mdcache->migrator->find_stale_export_freeze();
- if (snapserver)
+
+ if (mdsmap->get_tableserver() == whoami) {
snapserver->check_osd_map(false);
+ // Filesystem was created by pre-mimic mds. Allow multi-active mds after
+ // all old snapshots are deleted.
+ if (!mdsmap->allows_multimds_snaps() &&
+ snapserver->can_allow_multimds_snaps()) {
+ set_mdsmap_multimds_snaps_allowed();
+ }
+ }
}
if (is_active() || is_stopping()) {
void MDSRankDispatcher::handle_osd_map()
{
- if (is_active() && snapserver) {
+ if (is_active() &&
+ mdsmap->get_tableserver() == whoami) {
snapserver->check_osd_map(true);
}
bool is_any_replay() const { return (is_replay() || is_standby_replay()); }
bool is_stopped() const { return mdsmap->is_stopped(whoami); }
bool is_cluster_degraded() const { return cluster_degraded; }
+ bool allows_multimds_snaps() const { return mdsmap->allows_multimds_snaps(); }
void handle_write_error(int err);
/* Update MDSMap export_targets for this rank. Called on ::tick(). */
void update_targets(utime_t now);
+ friend class C_MDS_MonCommand;
+ void _mon_command_finish(int r, std::string_view cmd, std::string_view outs);
+ void set_mdsmap_multimds_snaps_allowed();
private:
mono_time starttime = mono_clock::zero();
};
if (!srnode.past_parent_snaps.empty())
assert(mdcache->mds->snapclient->get_cached_version() > 0);
+ if (!srnode.past_parents.empty() &&
+ mdcache->mds->allows_multimds_snaps()) {
+ dout(10) << " skip non-empty past_parents since multimds_snaps is allowed" << dendl;
+ open = true;
+ return true;
+ }
+
// and my past parents too!
assert(srnode.past_parents.size() >= num_open_past_parents);
if (srnode.past_parents.size() > num_open_past_parents) {
if (!srnode.past_parent_snaps.empty())
assert(mdcache->mds->snapclient->get_cached_version() > 0);
+ if (!srnode.past_parents.empty() &&
+ mdcache->mds->allows_multimds_snaps()) {
+ dout(10) << " skip non-empty past_parents since multimds_snaps is allowed" << dendl;
+ open = true;
+ return true;
+ }
+
for (auto p = srnode.past_parents.lower_bound(first);
p != srnode.past_parents.end();
++p) {
}
last_created = last_snap;
last_destroyed = last_snap;
+ snaprealm_v2_since = last_snap + 1;
version++;
}
MonClient *mon_client = nullptr;
snapid_t last_snap;
snapid_t last_created, last_destroyed;
+ snapid_t snaprealm_v2_since;
map<snapid_t, SnapInfo> snaps;
map<int, set<snapid_t> > need_to_purge;
version_t last_checked_osdmap;
void encode_server_state(bufferlist& bl) const override {
- ENCODE_START(4, 3, bl);
+ ENCODE_START(5, 3, bl);
encode(last_snap, bl);
encode(snaps, bl);
encode(need_to_purge, bl);
encode(pending_noop, bl);
encode(last_created, bl);
encode(last_destroyed, bl);
+ encode(snaprealm_v2_since, bl);
ENCODE_FINISH(bl);
}
void decode_server_state(bufferlist::iterator& bl) override {
- DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl);
+ DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl);
decode(last_snap, bl);
decode(snaps, bl);
decode(need_to_purge, bl);
last_created = last_snap;
last_destroyed = last_snap;
}
+ if (struct_v >= 5)
+ decode(snaprealm_v2_since, bl);
+ else
+ snaprealm_v2_since = last_snap + 1;
+
DECODE_FINISH(bl);
}
void check_osd_map(bool force);
+ bool can_allow_multimds_snaps() const {
+ return snaps.empty() || snaps.begin()->first >= snaprealm_v2_since;
+ }
+
void encode(bufferlist& bl) const {
encode_server_state(bl);
}
<< " parameter to control the number of active MDSs"
<< " allowed. This command is DEPRECATED and will be"
<< " REMOVED from future releases.";
+ } else if (var == "allow_multimds_snaps") {
+ bool enable = false;
+ int r = parse_bool(val, &enable, ss);
+ if (r != 0) {
+ return r;
+ }
+
+ string confirm;
+ if (!cmd_getval(g_ceph_context, cmdmap, "confirm", confirm) ||
+ confirm != "--yes-i-am-really-a-mds") {
+ ss << "Warning! This command is for MDS only. Do not run it manually";
+ return -EPERM;
+ }
+
+ if (enable) {
+ ss << "enabled multimds with snapshot";
+ fsmap.modify_filesystem(
+ fs->fscid,
+ [](std::shared_ptr<Filesystem> fs)
+ {
+ fs->mds_map.set_multimds_snaps_allowed();
+ });
+ } else {
+ ss << "disabled multimds with snapshot";
+ fsmap.modify_filesystem(
+ fs->fscid,
+ [](std::shared_ptr<Filesystem> fs)
+ {
+ fs->mds_map.clear_multimds_snaps_allowed();
+ });
+ }
} else if (var == "allow_dirfrags") {
ss << "Directory fragmentation is now permanently enabled."
<< " This command is DEPRECATED and will be REMOVED from future releases.";
"name=maxmds,type=CephInt,range=0", \
"set max MDS index", "mds", "rw", "cli,rest", FLAG(OBSOLETE))
COMMAND_WITH_FLAG("mds set " \
- "name=var,type=CephChoices,strings=max_mds|max_file_size"
- "|allow_new_snaps|inline_data|allow_multimds|allow_dirfrags " \
+ "name=var,type=CephChoices,strings=max_mds|max_file_size|inline_data|"
+ "allow_new_snaps|allow_multimds|allow_multimds_snaps|allow_dirfrags " \
"name=val,type=CephString " \
"name=confirm,type=CephString,req=false", \
"set mds parameter <var> to <val>", "mds", "rw", "cli,rest", FLAG(OBSOLETE))