[Drbd-dev] Possible synchronization problems in 8.0.6

Lars Ellenberg lars.ellenberg at linbit.com
Sun Nov 25 22:36:46 CET 2007


On Sun, Nov 25, 2007 at 04:03:29PM -0500, Graham, Simon wrote:
> We've been seeing some odd problems lately with the syncer not being
> resumed and netlink state change events being delivered out of order and
> I think I've tracked this down to the following synchronization issues:
> 
> 1. When suspending/resuming sync for other devices, the code currently
> does NOT acquire the lock 
>    for the target device whose aftr_isp is being modified - instead, the
> code acquires the 
>    'drbd_global_lock' which is just the DRBD0 lock plus disabling
> interrupts

this is not true.

STATIC void drbd_global_lock(void)
{
	drbd_dev *mdev;
	int i;

	local_irq_disable();
	for (i=0; i < minor_count; i++) {
		if(!(mdev = minor_to_mdev(i))) continue;
		spin_lock(&mdev->req_lock);
	}
}

this disables irq,
then aquires _all_ reqest locks of all (allocated) devices _in order_.

ugly assignment inside the if condition.
should be cleaned up.

> - this is fine on a 
>    UP system but not on SMP where another processor might be executing
>    _drbd_set_state() for the target device at the same time. I think
>    this can cause two problems:
>    a. First, when setting/clearing bit fields in mdev->flags, you might
>       corrupt the value if both processor access flags at the same time
>    b. Second, the order that after_state_ch worker items are put on the
>       queue can be inverted resulting in out of order netlink events

> 2. The way the resync timer is handled when pausing and resuming sync
> has a hole I think IF you get pause followed immediately by resume
> (which seems to happen occasionally) as follows:
>    a. The pause code sets the STOP_SYNC_TIMER bit and updates the
>       timer so that the resync_timer_fn should run immediately
>    b. The resume code updates the timer so that the function runs
>       immediately UNLESS the STOP_SYNC_TIMER bit is set
>    c. When the resync_timer_fn runs, it clears the flag if set and
>       terminates.
> 
>    So if we pause and immediately resume, it's possible that the flag
>    is still set and we end up never scheduling the timer to run again,
>    leading to stalled resync - this was a recent change added by Phil
>    I think - previously it would just clear the bit and call mod_timer
>    in the resume case.

hm. so this needs to be revised.

> I think the key thing about problem 1 above is that there is an
> unwritten rule that when calling _drbd_set_state() you MUST first
> qcquire the mdev lock for the device being modified. I've looked at this
> a little and would propose:
> 
> 1. Do away with drbd_global_lock
> 2. Change _drbd_pause_after and _dbd_resume_next to acquire the target
> device lock before checking may_sync_now and calling _drbd_set_state.
> 3. Change drbd_start_sync to acquire the tartget devices lock before
> calling _drbd_set_state and releasing it before checking that the sync
> will go ahead.

hm...  still thinking.

> Lastly, I'd like to propose doing the netlink broadcast inside
> _drbd_set_state instead of delaying it to the after_state_ch processing
> - this will ensure that netlink events wont get reordered. I originally
> thought that simply ensuring we always call _drbd_set_state with the
> device lock held would be enough, but that doesn't handle the cases
> where we do the after_state_change inline instead of from the worker
> thread.

I don't think we can do netlink broadcasts
from what is potentially irq context.

phil has some thoughts about this already,
aparently we need to always queue the after_state_change to the worker.

-- 
: Lars Ellenberg                            Tel +43-1-8178292-55 :
: LINBIT Information Technologies GmbH      Fax +43-1-8178292-82 :
: Vivenotgasse 48, A-1120 Vienna/Europe    http://www.linbit.com :


More information about the drbd-dev mailing list