From eb4c36bf23f32cf9117d62660a4919dcfe80baa5 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Fri, 4 May 2018 11:11:35 +0800 Subject: [PATCH] mds: allow client to specify its session timeout This is for ganesha client (it is expected to be reclaimed if it dies) The default session timeout may be too short to reliably get ganesha back up. Signed-off-by: "Yan, Zheng" --- src/client/Client.cc | 9 +++ src/client/Client.h | 1 + src/include/cephfs/libcephfs.h | 9 +++ src/libcephfs.cc | 5 ++ src/mds/Server.cc | 103 +++++++++++++++++++++------------ 5 files changed, 90 insertions(+), 37 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index a8534663ad2..173df17ab42 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -14206,6 +14206,15 @@ void Client::set_uuid(const std::string& uuid) _close_sessions(); } +// called before mount. 0 means infinite +void Client::set_session_timeout(unsigned timeout) +{ + Mutex::Locker l(client_lock); + assert(initialized); + + metadata["timeout"] = stringify(timeout); +} + // called before mount int Client::start_reclaim(const std::string& uuid, unsigned flags, const std::string& fs_name) diff --git a/src/client/Client.h b/src/client/Client.h index b8c4d7cc044..3aa3a03d8a2 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -298,6 +298,7 @@ public: void abort_conn(); void set_uuid(const std::string& uuid); + void set_session_timeout(unsigned timeout); int start_reclaim(const std::string& uuid, unsigned flags, const std::string& fs_name); void finish_reclaim(); diff --git a/src/include/cephfs/libcephfs.h b/src/include/cephfs/libcephfs.h index 4573fa5ce84..31e31950973 100644 --- a/src/include/cephfs/libcephfs.h +++ b/src/include/cephfs/libcephfs.h @@ -1784,6 +1784,15 @@ mode_t ceph_umask(struct ceph_mount_info *cmount, mode_t mode); */ void ceph_set_uuid(struct ceph_mount_info *cmount, const char *uuid); +/** + * Set ceph client session timeout + * @param cmount the ceph mount handle to use. + * @param timeout the timeout to set + * + * Must be called before mount. + */ +void ceph_set_session_timeout(struct ceph_mount_info *cmount, unsigned timeout); + /** * Start to reclaim states of other client * @param cmount the ceph mount handle to use. diff --git a/src/libcephfs.cc b/src/libcephfs.cc index 9d27e23984a..0d8ad43f9f5 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -1918,6 +1918,11 @@ extern "C" int ceph_set_deleg_timeout(class ceph_mount_info *cmount, uint32_t ti return cmount->get_client()->set_deleg_timeout(timeout); } +extern "C" void ceph_set_session_timeout(class ceph_mount_info *cmount, unsigned timeout) +{ + cmount->get_client()->set_session_timeout(timeout); +} + extern "C" void ceph_set_uuid(class ceph_mount_info *cmount, const char *uuid) { cmount->get_client()->set_uuid(std::string(uuid)); diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 8ba4d7fa6f9..956a2adbe65 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -891,21 +891,53 @@ void Server::find_idle_sessions() // (caps go stale, lease die) double queue_max_age = mds->get_dispatch_queue_max_age(ceph_clock_now()); double cutoff = queue_max_age + mds->mdsmap->get_session_timeout(); - while (1) { - Session *session = mds->sessionmap.get_oldest_session(Session::STATE_OPEN); - if (!session) break; - auto last_cap_renew_span = std::chrono::duration(now-session->last_cap_renew).count(); - if (last_cap_renew_span < cutoff) { - dout(20) << "laggiest active session is " << session->info.inst << " and renewed caps recently (" << last_cap_renew_span << "s ago)" << dendl; - break; + + std::vector to_evict; + + const auto sessions_p1 = mds->sessionmap.by_state.find(Session::STATE_OPEN); + if (sessions_p1 != mds->sessionmap.by_state.end() && !sessions_p1->second->empty()) { + std::vector new_stale; + + for (auto session : *(sessions_p1->second)) { + auto last_cap_renew_span = std::chrono::duration(now - session->last_cap_renew).count(); + if (last_cap_renew_span < cutoff) { + dout(20) << "laggiest active session is " << session->info.inst + << " and renewed caps recently (" << last_cap_renew_span << "s ago)" << dendl; + continue; + } + + auto it = session->info.client_metadata.find("timeout"); + if (it != session->info.client_metadata.end()) { + unsigned timeout = strtoul(it->second.c_str(), nullptr, 0); + if (timeout == 0) { + dout(10) << "skipping session " << session->info.inst + << ", infinite timeout specified" << dendl; + continue; + } + double cutoff = queue_max_age + timeout; + if (last_cap_renew_span < cutoff) { + dout(10) << "skipping session " << session->info.inst + << ", timeout (" << timeout << ") specified" + << " and renewed caps recently (" << last_cap_renew_span << "s ago)" << dendl; + continue; + } + + // do not go through stale, evict it directly. + to_evict.push_back(session); + } else { + dout(10) << "new stale session " << session->info.inst + << " last renewed caps " << last_cap_renew_span << "s ago" << dendl; + new_stale.push_back(session); + } } - dout(10) << "new stale session " << session->info.inst << " last renewed caps " << last_cap_renew_span << "s ago" << dendl; - mds->sessionmap.set_state(session, Session::STATE_STALE); - mds->locker->revoke_stale_caps(session); - mds->locker->remove_stale_leases(session); - mds->send_message_client(MClientSession::create(CEPH_SESSION_STALE, session->get_push_seq()), session); - finish_flush_session(session, session->get_push_seq()); + for (auto session : new_stale) { + mds->sessionmap.set_state(session, Session::STATE_STALE); + mds->locker->revoke_stale_caps(session); + mds->locker->remove_stale_leases(session); + mds->send_message_client(MClientSession::create(CEPH_SESSION_STALE, session->get_push_seq()), session); + finish_flush_session(session, session->get_push_seq()); + } } // autoclose @@ -924,38 +956,35 @@ void Server::find_idle_sessions() } // Collect a list of sessions exceeding the autoclose threshold - std::vector to_evict; - const auto sessions_p = mds->sessionmap.by_state.find(Session::STATE_STALE); - if (sessions_p == mds->sessionmap.by_state.end() || sessions_p->second->empty()) { - return; + const auto sessions_p2 = mds->sessionmap.by_state.find(Session::STATE_STALE); + if (sessions_p2 != mds->sessionmap.by_state.end() && !sessions_p2->second->empty()) { + for (auto session : *(sessions_p2->second)) { + assert(session->is_stale()); + auto last_cap_renew_span = std::chrono::duration(now - session->last_cap_renew).count(); + if (last_cap_renew_span < cutoff) { + dout(20) << "oldest stale session is " << session->info.inst + << " and recently renewed caps " << last_cap_renew_span << "s ago" << dendl; + break; + } + to_evict.push_back(session); + } } - const auto &stale_sessions = sessions_p->second; - ceph_assert(stale_sessions != nullptr); - for (const auto &session: *stale_sessions) { - auto last_cap_renew_span = std::chrono::duration(now-session->last_cap_renew).count(); + for (auto session: to_evict) { if (session->is_importing()) { - dout(10) << "stopping at importing session " << session->info.inst << dendl; - break; - } - ceph_assert(session->is_stale()); - if (last_cap_renew_span < cutoff) { - dout(20) << "oldest stale session is " << session->info.inst << " and recently renewed caps " << last_cap_renew_span << "s ago" << dendl; - break; + dout(10) << "skipping session " << session->info.inst << ", it's being imported" << dendl; + continue; } - to_evict.push_back(session); - } - - for (const auto &session: to_evict) { - auto last_cap_renew_span = std::chrono::duration(now-session->last_cap_renew).count(); - mds->clog->warn() << "evicting unresponsive client " << *session << ", after " << last_cap_renew_span << " seconds"; - dout(10) << "autoclosing stale session " << session->info.inst << " last renewed caps " << last_cap_renew_span << "s ago" << dendl; + auto last_cap_renew_span = std::chrono::duration(now - session->last_cap_renew).count(); + mds->clog->warn() << "evicting unresponsive client " << *session + << ", after " << last_cap_renew_span << " seconds"; + dout(10) << "autoclosing stale session " << session->info.inst + << " last renewed caps " << last_cap_renew_span << "s ago" << dendl; if (g_conf()->mds_session_blacklist_on_timeout) { std::stringstream ss; - mds->evict_client(session->get_client().v, false, true, - ss, nullptr); + mds->evict_client(session->get_client().v, false, true, ss, nullptr); } else { kill_session(session, NULL); } -- 2.39.5