Skip to content

Commit

Permalink
Merge pull request ceph#30843 from smithfarm/wip-41853-nautilus
Browse files Browse the repository at this point in the history
nautilus: mds: reject sessionless messages

Reviewed-by: Ramana Raja <rraja@redhat.com>
  • Loading branch information
yuriw committed Feb 11, 2020
2 parents 3f8a4c0 + e7afc57 commit ae181f7
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 8 deletions.
5 changes: 5 additions & 0 deletions src/common/options.cc
Expand Up @@ -7786,6 +7786,11 @@ std::vector<Option> get_mds_options() {
.set_default(true)
.set_description("additional reply to clients that metadata requests are complete but not yet durable"),

Option("mds_replay_unsafe_with_closed_session", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
.set_default(false)
.set_flag(Option::FLAG_RUNTIME)
.set_description("complete all the replay request when mds is restarted, no matter the session is closed or not"),

Option("mds_default_dir_hash", Option::TYPE_INT, Option::LEVEL_ADVANCED)
.set_default(CEPH_STR_HASH_RJENKINS)
.set_description("hash function to select directory fragment for dentry name"),
Expand Down
2 changes: 1 addition & 1 deletion src/mds/Locker.cc
Expand Up @@ -1831,7 +1831,7 @@ void Locker::file_update_finish(CInode *in, MutationRef& mut, unsigned flags,

if (ack) {
Session *session = mds->get_session(client);
if (session) {
if (session && !session->is_closed()) {
// "oldest flush tid" > 0 means client uses unique TID for each flush
if (ack->get_oldest_flush_tid() > 0)
session->add_completed_flush(ack->get_client_tid());
Expand Down
1 change: 1 addition & 0 deletions src/mds/MDSRank.cc
Expand Up @@ -3679,6 +3679,7 @@ const char** MDSRankDispatcher::get_tracked_conf_keys() const
"mds_recall_warning_decay_rate",
"mds_request_load_average_decay_rate",
"mds_session_cache_liveness_decay_rate",
"mds_replay_unsafe_with_closed_session",
NULL
};
return KEYS;
Expand Down
47 changes: 40 additions & 7 deletions src/mds/Server.cc
Expand Up @@ -193,6 +193,7 @@ Server::Server(MDSRank *m) :
terminating_sessions(false),
recall_throttle(g_conf().get_val<double>("mds_recall_max_decay_rate"))
{
replay_unsafe_with_closed_session = g_conf().get_val<bool>("mds_replay_unsafe_with_closed_session");
cap_revoke_eviction_timeout = g_conf().get_val<double>("mds_cap_revoke_eviction_timeout");
supported_features = feature_bitset_t(CEPHFS_FEATURES_MDS_SUPPORTED);
}
Expand All @@ -205,13 +206,23 @@ void Server::dispatch(const Message::const_ref &m)
return;
}

/*
*In reconnect phase, client sent unsafe requests to mds before reconnect msg. Seting sessionclosed_isok will handle scenario like this:

1. In reconnect phase, client sent unsafe requests to mds.
2. It reached reconnect timeout. All sessions without sending reconnect msg in time, some of which may had sent unsafe requests, are marked as closed.
(Another situation is #31668, which will deny all client reconnect msg to speed up reboot).
3.So these unsafe request from session without sending reconnect msg in time or being denied could be handled in clientreplay phase.

*/
bool sessionclosed_isok = replay_unsafe_with_closed_session;
// active?
// handle_slave_request()/handle_client_session() will wait if necessary
if (m->get_type() == CEPH_MSG_CLIENT_REQUEST && !mds->is_active()) {
const auto &req = MClientRequest::msgref_cast(m);
if (mds->is_reconnect() || mds->get_want_state() == CEPH_MDS_STATE_RECONNECT) {
Session *session = mds->get_session(req);
if (!session || session->is_closed()) {
if (!session || (!session->is_open() && !sessionclosed_isok)) {
dout(5) << "session is closed, dropping " << req->get_reqid() << dendl;
return;
}
Expand Down Expand Up @@ -442,6 +453,9 @@ void Server::handle_client_session(const MClientSession::const_ref &m)

if (!session) {
dout(0) << " ignoring sessionless msg " << *m << dendl;
auto reply = MClientSession::create(CEPH_SESSION_REJECT);
reply->metadata["error_string"] = "sessionless";
mds->send_message(reply, m->get_connection());
return;
}

Expand Down Expand Up @@ -776,8 +790,9 @@ void Server::_session_logged(Session *session, uint64_t state_seq, bool open, ve
} else if (session->is_killing()) {
// destroy session, close connection
if (session->get_connection()) {
session->get_connection()->mark_down();
session->get_connection()->set_priv(NULL);
session->get_connection()->mark_down();
mds->sessionmap.set_state(session, Session::STATE_CLOSED);
session->set_connection(nullptr);
}
mds->sessionmap.remove_session(session);
} else {
Expand Down Expand Up @@ -1083,6 +1098,9 @@ void Server::evict_cap_revoke_non_responders() {
}

void Server::handle_conf_change(const std::set<std::string>& changed) {
if (changed.count("mds_replay_unsafe_with_closed_session")) {
replay_unsafe_with_closed_session = g_conf().get_val<bool>("mds_replay_unsafe_with_closed_session");
}
if (changed.count("mds_cap_revoke_eviction_timeout")) {
cap_revoke_eviction_timeout = g_conf().get_val<double>("mds_cap_revoke_eviction_timeout");
dout(20) << __func__ << " cap revoke eviction timeout changed to "
Expand Down Expand Up @@ -1232,8 +1250,20 @@ void Server::handle_client_reconnect(const MClientReconnect::const_ref &m)
<< (m->has_more() ? " (more)" : "") << dendl;
client_t from = m->get_source().num();
Session *session = mds->get_session(m);
if (!session)
if (!session) {
dout(0) << " ignoring sessionless msg " << *m << dendl;
auto reply = MClientSession::create(CEPH_SESSION_REJECT);
reply->metadata["error_string"] = "sessionless";
mds->send_message(reply, m->get_connection());
return;
}

if (!session->is_open()) {
dout(0) << " ignoring msg from not-open session" << *m << dendl;
auto reply = MClientSession::create(CEPH_SESSION_CLOSE);
mds->send_message(reply, m->get_connection());
return;
}

if (!mds->is_reconnect() && mds->get_want_state() == CEPH_MDS_STATE_RECONNECT) {
dout(10) << " we're almost in reconnect state (mdsmap delivery race?); waiting" << dendl;
Expand Down Expand Up @@ -2140,13 +2170,14 @@ void Server::handle_client_request(const MClientRequest::const_ref &req)
return;
}

bool sessionclosed_isok = replay_unsafe_with_closed_session;
// active session?
Session *session = 0;
if (req->get_source().is_client()) {
session = mds->get_session(req);
if (!session) {
dout(5) << "no session for " << req->get_source() << ", dropping" << dendl;
} else if (session->is_closed() ||
} else if ((session->is_closed() && (!mds->is_clientreplay() || !sessionclosed_isok)) ||
session->is_closing() ||
session->is_killing()) {
dout(5) << "session closed|closing|killing, dropping" << dendl;
Expand All @@ -2172,6 +2203,8 @@ void Server::handle_client_request(const MClientRequest::const_ref &req)
inodeno_t created;
if (session->have_completed_request(req->get_reqid().tid, &created)) {
has_completed = true;
if (!session->is_open())
return;
// Don't send traceless reply if the completed request has created
// new inode. Treat the request as lookup request instead.
if (req->is_replay() ||
Expand Down Expand Up @@ -3095,7 +3128,7 @@ CInode* Server::prepare_new_inode(MDRequestRef& mdr, CDir *dir, inodeno_t useino
// state. In that corner case, session's prealloc_inos are being freed.
// To simplify the code, we disallow using/refilling session's prealloc_ino
// while session is opening.
bool allow_prealloc_inos = !mdr->session->is_opening();
bool allow_prealloc_inos = mdr->session->is_open();

// assign ino
if (allow_prealloc_inos &&
Expand All @@ -3110,7 +3143,7 @@ CInode* Server::prepare_new_inode(MDRequestRef& mdr, CDir *dir, inodeno_t useino
<< dendl;
} else {
mdr->alloc_ino =
in->inode.ino = mds->inotable->project_alloc_id();
in->inode.ino = mds->inotable->project_alloc_id(useino);
dout(10) << "prepare_new_inode alloc " << mdr->alloc_ino << dendl;
}

Expand Down
1 change: 1 addition & 0 deletions src/mds/Server.h
Expand Up @@ -105,6 +105,7 @@ class Server {
feature_bitset_t supported_features;
feature_bitset_t required_client_features;

bool replay_unsafe_with_closed_session = false;
double cap_revoke_eviction_timeout = 0;

friend class MDSContinuation;
Expand Down

0 comments on commit ae181f7

Please sign in to comment.