• Joel Becker's avatar
    ocfs2: Remove CANCELGRANT from the view of dlmglue. · de551246
    Joel Becker authored
    o2dlm has the non-standard behavior of providing a cancel callback
    (unlock_ast) even when the cancel has failed (the locking operation
    succeeded without canceling).  This is called CANCELGRANT after the
    status code sent to the callback.  fs/dlm does not provide this
    callback, so dlmglue must be changed to live without it.
    o2dlm_unlock_ast_wrapper() in stackglue now ignores CANCELGRANT calls.
    
    Because dlmglue no longer sees CANCELGRANT, ocfs2_unlock_ast() no longer
    needs to check for it.  ocfs2_locking_ast() must catch that a cancel was
    tried and clear the cancel state.
    
    Making these changes opens up a locking race.  dlmglue uses the the
    OCFS2_LOCK_BUSY flag to ensure only one thread is calling the dlm at any
    one time.  But dlmglue must unlock the lockres before calling into the
    dlm.  In the small window of time between unlocking the lockres and
    calling the dlm, the downconvert thread can try to cancel the lock.  The
    downconvert thread is checking the OCFS2_LOCK_BUSY flag - it doesn't
    know that ocfs2_dlm_lock() has not yet been called.
    
    Because ocfs2_dlm_lock() has not yet been called, the cancel operation
    will just be a no-op.  There's nothing to cancel.  With CANCELGRANT,
    dlmglue uses the CANCELGRANT callback to clear up the cancel state.
    When it comes around again, it will retry the cancel.  Eventually, the
    first thread will have called into ocfs2_dlm_lock(), and either the
    lock or the cancel will succeed.  The downconvert thread can then do its
    downconvert.
    
    Without CANCELGRANT, there is nothing to clean up the cancellation
    state.  The downconvert thread does not know to retry its operations.
    More importantly, the original lock may be blocking on the other node
    that is trying to cancel us.  With neither able to make progress, the
    ast is never called and the cancellation state is never cleaned up that
    way.  dlmglue is deadlocked.
    
    The OCFS2_LOCK_PENDING flag is introduced to remedy this window.  It is
    set at the same time OCFS2_LOCK_BUSY is.  Thus, the downconvert thread
    can check whether the lock is cancelable.  If not, it just loops around
    to try again.  Once ocfs2_dlm_lock() is called, the thread then clears
    OCFS2_LOCK_PENDING and wakes the downconvert thread.  Now, if the
    downconvert thread finds the lock BUSY, it can safely try to cancel it.
    Whether the cancel works or not, the state will be properly set and the
    lock processing can continue.
    Signed-off-by: default avatarJoel Becker <joel.becker@oracle.com>
    Signed-off-by: default avatarMark Fasheh <mfasheh@suse.com>
    de551246
dlmglue.c 95.1 KB