[Drbd-dev] Possible synchronization problems in 8.0.6

Graham, Simon Simon.Graham at stratus.com
Sun Nov 25 22:03:29 CET 2007


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 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.

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.

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.

Thoughts/comments?
/simgr


More information about the drbd-dev mailing list