Merge PR #28456 into master

* refs/pull/28456/head:
	mds: ignore sessionmap version mismatch if mds_wipe_sessions is set
	mds: fix corner case of replaying open sessions

Reviewed-by: Patrick Donnelly <pdonnell@redhat.com>
This commit is contained in:
Patrick Donnelly 2019-06-13 12:22:05 -07:00
commit c735b901da
No known key found for this signature in database
GPG Key ID: 3A2A7E25BEA8AADB
4 changed files with 74 additions and 44 deletions

View File

@ -3221,7 +3221,7 @@ void Server::apply_allocated_inos(MDRequestRef& mdr, Session *session)
ceph_assert(session);
session->pending_prealloc_inos.subtract(mdr->prealloc_inos);
session->info.prealloc_inos.insert(mdr->prealloc_inos);
mds->sessionmap.mark_dirty(session);
mds->sessionmap.mark_dirty(session, !mdr->used_prealloc_ino);
mds->inotable->apply_alloc_ids(mdr->prealloc_inos);
}
if (mdr->used_prealloc_ino) {

View File

@ -669,12 +669,13 @@ void SessionMap::touch_session(Session *session)
session->last_cap_renew = clock::now();
}
void SessionMap::_mark_dirty(Session *s)
void SessionMap::_mark_dirty(Session *s, bool may_save)
{
if (dirty_sessions.count(s->info.inst.name))
return;
if (dirty_sessions.size() >= g_conf()->mds_sessionmap_keys_per_op) {
if (may_save &&
dirty_sessions.size() >= g_conf()->mds_sessionmap_keys_per_op) {
// Pre-empt the usual save() call from journal segment trim, in
// order to avoid building up an oversized OMAP update operation
// from too many sessions modified at once
@ -685,12 +686,12 @@ void SessionMap::_mark_dirty(Session *s)
dirty_sessions.insert(s->info.inst.name);
}
void SessionMap::mark_dirty(Session *s)
void SessionMap::mark_dirty(Session *s, bool may_save)
{
dout(20) << __func__ << " s=" << s << " name=" << s->info.inst.name
<< " v=" << version << dendl;
_mark_dirty(s);
_mark_dirty(s, may_save);
version++;
s->pop_pv(version);
}
@ -700,7 +701,7 @@ void SessionMap::replay_dirty_session(Session *s)
dout(20) << __func__ << " s=" << s << " name=" << s->info.inst.name
<< " v=" << version << dendl;
_mark_dirty(s);
_mark_dirty(s, false);
replay_advance_version();
}
@ -711,6 +712,46 @@ void SessionMap::replay_advance_version()
projected = version;
}
void SessionMap::replay_open_sessions(version_t event_cmapv,
map<client_t,entity_inst_t>& client_map,
map<client_t,client_metadata_t>& client_metadata_map)
{
unsigned already_saved;
if (version + client_map.size() < event_cmapv)
goto bad;
// Server::finish_force_open_sessions() marks sessions dirty one by one.
// Marking a session dirty may flush all existing dirty sessions. So it's
// possible that some sessions are already saved in sessionmap.
already_saved = client_map.size() - (event_cmapv - version);
for (const auto& p : client_map) {
Session *s = get_or_add_session(p.second);
auto q = client_metadata_map.find(p.first);
if (q != client_metadata_map.end())
s->info.client_metadata.merge(q->second);
if (already_saved > 0) {
if (s->is_closed())
goto bad;
--already_saved;
continue;
}
set_state(s, Session::STATE_OPEN);
replay_dirty_session(s);
}
return;
bad:
mds->clog->error() << "error replaying open sessions(" << client_map.size()
<< ") sessionmap v " << event_cmapv << " table " << version;
ceph_assert(g_conf()->mds_wipe_sessions);
mds->sessionmap.wipe();
mds->sessionmap.set_version(event_cmapv);
}
version_t SessionMap::mark_projected(Session *s)
{
dout(20) << __func__ << " s=" << s << " name=" << s->info.inst.name

View File

@ -662,21 +662,6 @@ public:
get_client_sessions(f);
}
void replay_open_sessions(map<client_t,entity_inst_t>& client_map,
map<client_t,client_metadata_t>& client_metadata_map) {
for (map<client_t,entity_inst_t>::iterator p = client_map.begin();
p != client_map.end();
++p) {
Session *s = get_or_add_session(p->second);
auto q = client_metadata_map.find(p->first);
if (q != client_metadata_map.end())
s->info.client_metadata.merge(q->second);
set_state(s, Session::STATE_OPEN);
replay_dirty_session(s);
}
}
// helpers
entity_inst_t& get_inst(entity_name_t w) {
ceph_assert(session_map.count(w));
@ -724,7 +709,7 @@ protected:
std::set<entity_name_t> dirty_sessions;
std::set<entity_name_t> null_sessions;
bool loaded_legacy = false;
void _mark_dirty(Session *session);
void _mark_dirty(Session *session, bool may_save);
public:
/**
@ -735,7 +720,7 @@ public:
* to the backing store. Must have called
* mark_projected previously for this session.
*/
void mark_dirty(Session *session);
void mark_dirty(Session *session, bool may_save=true);
/**
* Advance the projected version, and mark this
@ -763,6 +748,14 @@ public:
*/
void replay_advance_version();
/**
* During replay, open sessions, advance versions and
* mark these sessions as dirty.
*/
void replay_open_sessions(version_t event_cmapv,
map<client_t,entity_inst_t>& client_map,
map<client_t,client_metadata_t>& client_metadata_map);
/**
* For these session IDs, if a session exists with this ID, and it has
* dirty completed_requests, then persist it immediately

View File

@ -1481,12 +1481,13 @@ void EMetaBlob::replay(MDSRank *mds, LogSegment *logseg, MDSlaveUpdate *slaveup)
}
}
if (sessionmapv) {
unsigned diff = (used_preallocated_ino && !preallocated_inos.empty()) ? 2 : 1;
if (mds->sessionmap.get_version() >= sessionmapv) {
dout(10) << "EMetaBlob.replay sessionmap v " << sessionmapv
<< " <= table " << mds->sessionmap.get_version() << dendl;
} else if (mds->sessionmap.get_version() + 2 >= sessionmapv) {
} else if (mds->sessionmap.get_version() + diff == sessionmapv) {
dout(10) << "EMetaBlob.replay sessionmap v " << sessionmapv
<< " -(1|2) == table " << mds->sessionmap.get_version()
<< " - " << diff << " == table " << mds->sessionmap.get_version()
<< " prealloc " << preallocated_inos
<< " used " << used_preallocated_ino
<< dendl;
@ -1512,16 +1513,16 @@ void EMetaBlob::replay(MDSRank *mds, LogSegment *logseg, MDSlaveUpdate *slaveup)
} else {
dout(10) << "EMetaBlob.replay no session for " << client_name << dendl;
if (used_preallocated_ino) {
if (used_preallocated_ino)
mds->sessionmap.replay_advance_version();
}
if (!preallocated_inos.empty())
mds->sessionmap.replay_advance_version();
}
ceph_assert(sessionmapv == mds->sessionmap.get_version());
} else {
mds->clog->error() << "journal replay sessionmap v " << sessionmapv
<< " -(1|2) > table " << mds->sessionmap.get_version();
mds->clog->error() << "EMetaBlob.replay sessionmap v " << sessionmapv
<< " - " << diff << " > table " << mds->sessionmap.get_version();
ceph_assert(g_conf()->mds_wipe_sessions);
mds->sessionmap.wipe();
mds->sessionmap.set_version(sessionmapv);
@ -1615,7 +1616,7 @@ void ESession::replay(MDSRank *mds)
if (mds->sessionmap.get_version() >= cmapv) {
dout(10) << "ESession.replay sessionmap " << mds->sessionmap.get_version()
<< " >= " << cmapv << ", noop" << dendl;
} else {
} else if (mds->sessionmap.get_version() + 1 == cmapv) {
dout(10) << "ESession.replay sessionmap " << mds->sessionmap.get_version()
<< " < " << cmapv << " " << (open ? "open":"close") << " " << client_inst << dendl;
Session *session;
@ -1646,6 +1647,12 @@ void ESession::replay(MDSRank *mds)
mds->sessionmap.replay_advance_version();
}
ceph_assert(mds->sessionmap.get_version() == cmapv);
} else {
mds->clog->error() << "ESession.replay sessionmap v " << cmapv
<< " - 1 > table " << mds->sessionmap.get_version();
ceph_assert(g_conf()->mds_wipe_sessions);
mds->sessionmap.wipe();
mds->sessionmap.set_version(cmapv);
}
if (inos.size() && inotablev) {
@ -1778,8 +1785,7 @@ void ESessions::replay(MDSRank *mds)
} else {
dout(10) << "ESessions.replay sessionmap " << mds->sessionmap.get_version()
<< " < " << cmapv << dendl;
mds->sessionmap.replay_open_sessions(client_map, client_metadata_map);
ceph_assert(mds->sessionmap.get_version() == cmapv);
mds->sessionmap.replay_open_sessions(cmapv, client_map, client_metadata_map);
}
update_segment();
}
@ -2062,9 +2068,7 @@ void EUpdate::replay(MDSRank *mds)
decode(cm, blp);
if (!blp.end())
decode(cmm, blp);
mds->sessionmap.replay_open_sessions(cm, cmm);
ceph_assert(mds->sessionmap.get_version() == cmapv);
mds->sessionmap.replay_open_sessions(cmapv, cm, cmm);
}
}
update_segment();
@ -2910,15 +2914,7 @@ void EImportStart::replay(MDSRank *mds)
decode(cm, blp);
if (!blp.end())
decode(cmm, blp);
mds->sessionmap.replay_open_sessions(cm, cmm);
if (mds->sessionmap.get_version() != cmapv) {
derr << "sessionmap version " << mds->sessionmap.get_version()
<< " != cmapv " << cmapv << dendl;
mds->clog->error() << "failure replaying journal (EImportStart)";
mds->damaged();
ceph_abort(); // Should be unreachable because damaged() calls respawn()
}
mds->sessionmap.replay_open_sessions(cmapv, cm, cmm);
}
update_segment();
}