• NeilBrown's avatar
    md: avoid deadlock when dirty buffers during md_stop. · 260fa034
    NeilBrown authored
    When the last process closes /dev/mdX sync_blockdev will be called so
    that all buffers get flushed.
    So if it is then opened for the STOP_ARRAY ioctl to be sent there will
    be nothing to flush.
    
    However if we open /dev/mdX in order to send the STOP_ARRAY ioctl just
    moments before some other process which was writing closes their file
    descriptor, then there won't be a 'last close' and the buffers might
    not get flushed.
    
    So do_md_stop() calls sync_blockdev().  However at this point it is
    holding ->reconfig_mutex.  So if the array is currently 'clean' then
    the writes from sync_blockdev() will not complete until the array
    can be marked dirty and that won't happen until some other thread
    can get ->reconfig_mutex.  So we deadlock.
    
    We need to move the sync_blockdev() call to before we take
    ->reconfig_mutex.
    However then some other thread could open /dev/mdX and write to it
    after we call sync_blockdev() and before we actually stop the array.
    This can leave dirty data in the page cache which is awkward.
    
    So introduce new flag MD_STILL_CLOSED.  Set it before calling
    sync_blockdev(), clear it if anyone does open the file, and abort the
    STOP_ARRAY attempt if it gets set before we lock against further
    opens.
    
    It is still possible to get problems if you open /dev/mdX, write to
    it, then issue the STOP_ARRAY ioctl.  Just don't do that.
    Signed-off-by: default avatarNeilBrown <neilb@suse.de>
    260fa034
md.h 21.2 KB