[DRBD-user] strange drbd bug

Lars Ellenberg lars.ellenberg at linbit.com
Tue Oct 14 22:37:13 CEST 2014

Note: "permalinks" may not be as permanent as we would like,
direct links of old sources may well be a few messages off.


On Tue, Oct 14, 2014 at 06:07:21PM +0200, Bart Van Assche wrote:
> On 10/14/14 17:08, Lars Ellenberg wrote:
> >On Tue, Oct 14, 2014 at 03:27:56PM +0200, Matteo Tescione wrote:
> >>Discussed this topic with Bart from SCST, he suggested:
> >>"To me this looks like a DRBD bug. If a timeout of a DRBD request occurs
> >>the DRBD timeout handler (request_timer_fn()) is called, that function
> >>grabs a spinlock and next calls kthread_create_on_node() with that
> >>spinlock held.
> >
> >Well, no, our request_timer_fn does nothing like that.
> >At least it is not supposed to, and I don't see a code path
> >leading to anything like that.
> 
> Hello Lars,
> 
> Matteo reported that this occurred with DRBD version 8.4.4 (see also
> http://sourceforge.net/p/scst/mailman/message/32928699/). My
> conclusion from the stack trace posted by Matteo is that the call
> chain was as follows:

Yes, I've seen the stack trace. But:

> -> run_timer_softirq()
> -> call_timer_fn
> -> request_timer_fn()
> -> _drbd_set_state()
> -> __drbd_set_state()
> -> _drbd_thread_stop() (locks the &thi->t_lock spinlock)
> -> drbd_thread_start()
> -> kthread_create_on_node()
> -> wait_for_completion()
> 
> In other words, wait_for_completion() is not only called from
> soft-IRQ context but also with a spinlock held. Does this make sense
> to you ?

Absolutely not.

But wait....

_drbd_thread_stop takes a "wait" parameter.
It's a helper function for drbd_thread_stop()
and for drbd_thread_stop_nowait().
It is possible that "somewhere" we call drbd_thread_stop()
where we should call drbd_thread_stop_nowait().
But I don't see where that would be.

Same helper function is called for drbd_thread_restart_nowait().
I'd say that's what happens here.

So from the state change triggered by the request_timer_fn
in softirq context ("current" is "swapper" as seen from the other mail),
we trigger a drbd_thread_restart_nowait().

Which calls kthread_create -> drbd_thread_setup

And *there* it bombs out.

Yes, I see it happening now.

I just wonder why it does not happen *always* then, *every* time that
request timer expires and causes the peer to be kicked out?

maybe something changed around kthread_create as well.

Or maybe we just have been lucky for the last few years,
and the "wake_up_process(); wait_on_completion()" in kthread_run
just so happened to never need to call schedule,
because it always took the fast path.

workaround for now: don't use that request timer...
(ko-count=0)

Or chose to *disconnect* (Go "StandAlone"), instead of trying to reconnect,
once that timer expires.
(see below).

We'll have to think about how to fix it best.

	Lars


diff --git a/drbd/drbd_state.c b/drbd/drbd_state.c
index e3f6569..aca4210 100644
--- a/drbd/drbd_state.c
+++ b/drbd/drbd_state.c
@@ -1433,7 +1433,7 @@ _drbd_set_state(struct drbd_device *device, union drbd_state ns,
        /* Upon network failure, we need to restart the receiver. */
        if (os.conn > C_WF_CONNECTION &&
            ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT)
-               drbd_thread_restart_nowait(&connection->receiver);
+               drbd_thread_stop_nowait(&connection->receiver);

        /* Resume AL writing if we get a connection */
        if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) {




More information about the drbd-user mailing list