From c39aaf90ed1b23343eba2b341bb8ee6a50a4ea74 Mon Sep 17 00:00:00 2001 From: John Spray Date: Mon, 27 Mar 2017 12:56:31 +0100 Subject: [PATCH] mds: validate prealloc_inos on sessions after load Mitigates http://tracker.ceph.com/issues/16842 Signed-off-by: John Spray --- src/mds/InoTable.cc | 11 +++++++++++ src/mds/InoTable.h | 3 +++ src/mds/MDSRank.cc | 34 ++++++++++++++++++++++++++++++++++ src/mds/MDSRank.h | 2 ++ 4 files changed, 50 insertions(+) diff --git a/src/mds/InoTable.cc b/src/mds/InoTable.cc index f192b12ac05..fc1faa87642 100644 --- a/src/mds/InoTable.cc +++ b/src/mds/InoTable.cc @@ -198,6 +198,17 @@ bool InoTable::is_marked_free(inodeno_t id) const return free.contains(id) || projected_free.contains(id); } +bool InoTable::intersects_free( + const interval_set &other, + interval_set *intersection) +{ + interval_set i; + i.intersection_of(free, other); + if (intersection != nullptr) { + *intersection = i; + } + return !(i.empty()); +} bool InoTable::repair(inodeno_t id) { diff --git a/src/mds/InoTable.h b/src/mds/InoTable.h index a787d348a32..5f6a0b385ac 100644 --- a/src/mds/InoTable.h +++ b/src/mds/InoTable.h @@ -43,6 +43,9 @@ class InoTable : public MDSTable { void replay_reset(); bool repair(inodeno_t id); bool is_marked_free(inodeno_t id) const; + bool intersects_free( + const interval_set &other, + interval_set *intersection); void reset_state() override; void encode_state(bufferlist& bl) const override { diff --git a/src/mds/MDSRank.cc b/src/mds/MDSRank.cc index eb538f9c849..3eeba37d471 100644 --- a/src/mds/MDSRank.cc +++ b/src/mds/MDSRank.cc @@ -1036,11 +1036,45 @@ void MDSRank::boot_start(BootStep step, int r) break; case MDS_BOOT_REPLAY_DONE: assert(is_any_replay()); + + // Sessiontable and inotable should be in sync after replay, validate + // that they are consistent. + validate_sessions(); + replay_done(); break; } } +void MDSRank::validate_sessions() +{ + assert(mds_lock.is_locked_by_me()); + std::vector victims; + + // Identify any sessions which have state inconsistent with other, + // after they have been loaded from rados during startup. + // Mitigate bugs like: http://tracker.ceph.com/issues/16842 + const auto &sessions = sessionmap.get_sessions(); + for (const auto &i : sessions) { + Session *session = i.second; + interval_set badones; + if (inotable->intersects_free(session->info.prealloc_inos, &badones)) { + clog->error() << "Client session loaded with invalid preallocated " + "inodes, evicting session " << *session; + + // Make the session consistent with inotable so that it can + // be cleanly torn down + session->info.prealloc_inos.subtract(badones); + + victims.push_back(session); + } + } + + for (const auto &session: victims) { + server->kill_session(session, nullptr); + } +} + void MDSRank::starting_done() { dout(3) << "starting_done" << dendl; diff --git a/src/mds/MDSRank.h b/src/mds/MDSRank.h index 8c0802561b6..5fc6376b6b8 100644 --- a/src/mds/MDSRank.h +++ b/src/mds/MDSRank.h @@ -480,6 +480,8 @@ class MDSRank { void active_start(); void stopping_start(); void stopping_done(); + + void validate_sessions(); // <<< // >>> -- 2.39.5