From: Yan, Zheng Date: Sat, 8 Jun 2019 05:08:21 +0000 (+0800) Subject: mds: fix corner case of replaying open sessions X-Git-Tag: v15.1.0~2469^2~1 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=8e0ddc9808bf2d21180f9f4f78eafafdb4670262;p=ceph-ci.git mds: fix corner case of replaying open sessions Marking a session dirty may flush all existing dirty sessions. MDS calls Server::finish_force_open_sessions() for log event that opens multiple sessions. The function marks sessions dirty one by one. So sessions opened by a log event may get flushed partially. When replaying a log event that opens multiple sessions, mds need to check if some of these sessions have already been flushed. Fixes: https://tracker.ceph.com/issues/40211 Signed-off-by: "Yan, Zheng" --- diff --git a/src/mds/Server.cc b/src/mds/Server.cc index d4392d1b604..deaf69a8a32 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -3200,7 +3200,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) { diff --git a/src/mds/SessionMap.cc b/src/mds/SessionMap.cc index 144b2607484..3a9f465418f 100644 --- a/src/mds/SessionMap.cc +++ b/src/mds/SessionMap.cc @@ -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(); } diff --git a/src/mds/SessionMap.h b/src/mds/SessionMap.h index abcaab679d0..add18631049 100644 --- a/src/mds/SessionMap.h +++ b/src/mds/SessionMap.h @@ -656,8 +656,14 @@ public: get_client_sessions(f); } - void replay_open_sessions(map& client_map, + void replay_open_sessions(version_t event_cmapv, + map& client_map, map& client_metadata_map) { + // 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. + ceph_assert(version + client_map.size() >= event_cmapv); + unsigned already_saved = client_map.size() - (event_cmapv - version); for (map::iterator p = client_map.begin(); p != client_map.end(); ++p) { @@ -666,6 +672,12 @@ public: if (q != client_metadata_map.end()) s->info.client_metadata.merge(q->second); + if (already_saved > 0) { + ceph_assert(s->is_open()); + --already_saved; + continue; + } + set_state(s, Session::STATE_OPEN); replay_dirty_session(s); } @@ -718,7 +730,7 @@ protected: std::set dirty_sessions; std::set null_sessions; bool loaded_legacy = false; - void _mark_dirty(Session *session); + void _mark_dirty(Session *session, bool may_save); public: /** @@ -729,7 +741,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 diff --git a/src/mds/journal.cc b/src/mds/journal.cc index d44c4ab1949..0888725985e 100644 --- a/src/mds/journal.cc +++ b/src/mds/journal.cc @@ -1778,8 +1778,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 +2061,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 +2907,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(); }