session->con.reset(NULL); // break con <-> session ref cycle
// note that we break session->con *before* the session_handle_reset
// cleanup below. this avoids a race between us and
- // PG::add_backoff, split_backoff, etc.
+ // PG::add_backoff, Session::check_backoff, etc.
session_handle_reset(session);
session->put();
return true;
session->put(); // get_priv takes a ref, and so does the SessionRef
if (op->get_req()->get_type() == CEPH_MSG_OSD_OP) {
- BackoffRef b(session->have_backoff(info.pgid,
- info.pgid.pgid.get_hobj_start()));
- if (b) {
- dout(10) << " have backoff " << *b << " " << *m << dendl;
- assert(!b->is_acked() || !g_conf->osd_debug_crash_on_ignored_backoff);
+ if (session->check_backoff(cct, info.pgid,
+ info.pgid.pgid.get_hobj_start(), m)) {
return;
}
}
session->put(); // get_priv() takes a ref, and so does the intrusive_ptr
- BackoffRef b(session->have_backoff(info.pgid, head));
- if (b) {
- dout(10) << __func__ << " have backoff " << *b << " " << *m << dendl;
- assert(!b->is_acked() || !g_conf->osd_debug_crash_on_ignored_backoff);
+ if (session->check_backoff(cct, info.pgid, head, m)) {
return;
}
}
}
assert(!backoff_count == backoffs.empty());
}
+
+bool Session::check_backoff(
+ CephContext *cct, spg_t pgid, const hobject_t& oid, Message *m)
+{
+ BackoffRef b(have_backoff(pgid, oid));
+ if (b) {
+ dout(10) << __func__ << " session " << this << " has backoff " << *b
+ << " for " << *m << dendl;
+ assert(!b->is_acked() || !g_conf->osd_debug_crash_on_ignored_backoff);
+ return true;
+ }
+ // we may race with ms_handle_reset. it clears session->con before removing
+ // backoffs, so if we see con is cleared here we have to abort this
+ // request.
+ if (!con) {
+ dout(10) << __func__ << " session " << this << " disconnected" << dendl;
+ return true;
+ }
+ return false;
+}
return nullptr;
}
+ bool check_backoff(
+ CephContext *cct, spg_t pgid, const hobject_t& oid, Message *m);
+
void add_backoff(BackoffRef b) {
Mutex::Locker l(backoff_lock);
assert(!backoff_count == backoffs.empty());