msgr: queue reset exactly once on any connection

Use the atomic pipe link removal as a signal that we are the one failing
the con and use that to queue the reset event.

This fixes the case where we have an open, the session gets set up via the
handle_accept callback, and then race with another connection and go into
wait + close, or just close.  In that case, fault() needs to queue a reset
event to match the accept.

Signed-off-by: Sage Weil <sage@inktank.com>
This commit is contained in:
Sage Weil 2013-06-11 16:44:05 -07:00
parent 26e16c008d
commit de64bc50f2
2 changed files with 7 additions and 4 deletions

View File

@ -231,13 +231,15 @@ public:
}
return !failed;
}
void clear_pipe(RefCountedObject *old_p) {
bool clear_pipe(RefCountedObject *old_p) {
if (old_p == pipe) {
Mutex::Locker l(lock);
pipe->put();
pipe = NULL;
failed = true;
return true;
}
return false;
}
void reset_pipe(RefCountedObject *p) {
Mutex::Locker l(lock);

View File

@ -1171,6 +1171,8 @@ void Pipe::fault(bool onread)
if (state == STATE_CLOSED ||
state == STATE_CLOSING) {
ldout(msgr->cct,10) << "fault already closed|closing" << dendl;
if (connection_state->clear_pipe(this))
msgr->dispatch_queue.queue_reset(connection_state.get());
return;
}
@ -1206,9 +1208,8 @@ void Pipe::fault(bool onread)
// disconnect from Connection, and mark it failed. future messages
// will be dropped.
assert(connection_state);
connection_state->clear_pipe(this);
msgr->dispatch_queue.queue_reset(connection_state.get());
if (connection_state->clear_pipe(this))
msgr->dispatch_queue.queue_reset(connection_state.get());
return;
}