Hi Kuai,

On Tue, Oct 20, 2026 at 8:57 AM yu kuai <[email protected]> wrote:
>
> Hi,
>
> 在 2026/9/10 16:11, Jack Wang 写道:
> > From: Jack Wang <[email protected]>
> >
> > Writing to a queue limits attribute of an md array while a spare is
> > being re-added deadlocks the array.  I reported this earlier here:
> >
> >    
> > https://lore.kernel.org/linux-raid/CAMGffE=heGA3y8FjQ0Sm1jj-kd-=h9y54wozkassezhc9un...@mail.gmail.com/
> >
> > Four tasks, one array:
> >
> >    udev-worker    queue_attr_store() holds q->limits_lock, waits in
> >                   blk_mq_freeze_queue() for q_usage_counter to drain
>
> Sorry for the delay, usually blk_mq_freeze_queue() is useless for bio-based
> disks, because it can't guarantee inflight BIOs to drain. So this looks like
> a long term problem since queue_attr_store() can still update limits while
> there can still be bios inflight.
>
> >    fio            holds a q_usage_counter reference, parked in
> >                   md_handle_request()'s is_suspended() loop
> >    mdadm          suspended the array, waits for reconfig_mutex
> >    md_start_sync  holds reconfig_mutex, waits for q->limits_lock
>
> And this deadlock looks related to blk_mq_freeze_queue() concurrent with
> mddev_suspend(), hence there can be bio blocked between. So I think there
> can be a simpler solution for this deadlock.
>
> 1) either remove the blk_mq_freeze_queue() from limits update for mdraid, or
> 2) also add blk_mq_freeze_queue() to mddev_suspend().
>
> If this is a mdraid specific problem, I'll suggest 2). If there are other
> bio-based drivers have the same problem, we might what to replace
> blk_mq_freeze_queue() with driver's bio suspend to fix that limits can
> update with inflight bios as well.
Thanks for the suggestion, will look into it back from vacation. Yes,
it's a MDraid specific problem.
>
> >
> > The last leg is mddev_stack_new_rdev() from ->hot_add_disk().  Since
> > commit c99f66e4084a ("block: fix queue freeze vs limits lock order in
> > sysfs store methods") the sysfs store holds q->limits_lock across the
> > freeze, so md must not block on that lock while it is holding back the
> > I/O the freeze waits for.  That is the same hazard mddev_suspend()
> > already documents for reconfig_mutex.
> >
> > v1 kept q->limits_lock outermost where it could and used a trylock
> > everywhere else.  Christoph asked for the lock ordering to be fixed
> > instead, so v2 drops the trylock and the block patch that added it.
> >
> > The rule v2 applies is that q->limits_lock nests outside reconfig_mutex
> > and the suspend everywhere, with no exceptions to paper over.  The two
> > callers that cannot own an update do not need one: check_sb_changes()
> > and md_check_recovery() only ever re-add a device that is already a
> > member, so its limits are stacked and the update is a refresh, and they
> > now take the no-stack path unconditionally.  mddev_update_io_opt() is
> > not an add and does need the update, so patch 4 defers it to a work
> > item that takes the lock with nothing held.
> >
> > Making the hoists unconditional exposed a second cycle that the trylock
> > had been hiding, which Nilay hit with lockdep on v1:
> >
> >    q->limits_lock -> reconfig_mutex        added by this series
> >    reconfig_mutex -> disk->open_mutex      pre-existing, md opens legs
> >                                            under reconfig_mutex
> >    disk->open_mutex -> q->limits_lock      pre-existing, sd_open() ->
> >                                            sd_revalidate_disk()
> >
> > Only the middle edge can go, so legs are now opened before any md lock
> > is taken.  Patch 7 does the opens and patch 8 the holder links, which
> > take disk->open_mutex too and were easy to miss because the release
> > side only takes blk_holder_mutex.  Opening without reconfig_mutex means
> > the superblock format fields have to be snapshotted and rechecked once
> > the array is locked.
> >
> > Patches 1, 3 and 6 are plumbing with no functional change.
> >
> > Two callers still take q->limits_lock inside reconfig_mutex, both with
> > the array suspended, and patch 5 says why: ->start_reshape() from
> > action_store(), which suspends before flushing sync_work, and
> > raid*_run() -> queue_limits_set() from level_store(), which already
> > hangs on its own because it freezes the queue while suspended.  Both
> > need more restructuring than belongs here.
> >
> > The patches are based on v7.3-rc2.
> >
> > v1: https://lore.kernel.org/linux-raid/[email protected]/T/#t
> >
> > Changes since v1:
> >   - Drop the trylock and the block patch adding
> >     queue_limits_start_update_trylock(), per Christoph.
> >   - check_sb_changes() and md_check_recovery() take the no-stack path
> >     unconditionally instead of trying the lock first.
> >   - Defer the io_opt update to a work item rather than skipping it on a
> >     contended pass (patch 4, was "md: don't wait for q->limits_lock in
> >     mddev_update_io_opt()").
> >   - New patches 6-8 to close the reconfig_mutex -> disk->open_mutex
> >     edge that lockdep reported on v1: pass a queue_limits through
> >     ->run(), open new legs before locking the array, and link their
> >     holders there too.
> >   - Rebased on v7.3-rc2.
> >
> > Testing, on v7.3-rc2 with lockdep (PROVE_LOCKING, DEBUG_LOCK_ALLOC):
> >
> >   - the reproducer below, 20 fail/remove/add cycles with fio in flight
> >     and a loop writing queue/max_sectors_kb, where the same test wedges
> >     the array before the series
> >   - array start at raid0, raid1, raid5, raid10 and linear, spare add,
> >     fail and remove, the rdev sysfs stores, ADD_NEW_DISK, array_state
> >     transitions, a level change and a raid5 3 -> 4 reshape to
> >     completion, which is what exercises patch 4's work item: io_opt
> >     goes from 1048576 to 1572864 once end_reshape() runs
> >   - HOT_ADD_DISK of an undersized leg, so bind_rdev_to_array() fails
> >     and patch 8's release path runs
> >
> > No lockdep reports, and debug_locks stayed 1 throughout.  Every patch
> > builds on its own.
> >
> > A blktests case covering this deadlock will be sent separately.
> >
> > The reproducer, for anyone who wants it:
> >
> >    mdadm -C /dev/md111 --force -e 1.2 --assume-clean -l 1 \
> >          --bitmap=internal -n 2 /dev/ram0 /dev/ram1
> >
> >    fio --direct=1 --rw=randrw --ioengine=libaio --iodepth=32 --numjobs=4 \
> >        --time_based=1 --runtime=180 --filename=/dev/md111 --name=repro &
> >
> >    while :; do
> >        echo 128 > /sys/block/md111/queue/max_sectors_kb 2>/dev/null
> >    done &
> >
> >    for i in $(seq 20); do
> >        mdadm /dev/md111 --fail /dev/ram0
> >        mdadm /dev/md111 --remove /dev/ram0
> >        mdadm /dev/md111 --add /dev/ram0
> >        mdadm --wait /dev/md111
> >    done
> >
> > Jack Wang (8):
> >    md: pass a queue_limits down to ->hot_add_disk()
> >    md: don't wait for q->limits_lock in check_sb_changes()
> >    md: pass a queue_limits through the rdev sysfs stores
> >    md: defer the io_opt update out of the sync thread
> >    md: take q->limits_lock before locking and suspending the array
> >    md: pass a queue_limits through ->run()
> >    md: open new legs before locking the array
> >    md: link a new leg's holder before locking the array
> >
> >   drivers/md/dm-raid.c       |   4 +-
> >   drivers/md/md-autodetect.c |  38 ++-
> >   drivers/md/md-linear.c     |  30 +-
> >   drivers/md/md.c            | 661 +++++++++++++++++++++++++++++--------
> >   drivers/md/md.h            |  56 +++-
> >   drivers/md/raid0.c         |  16 +-
> >   drivers/md/raid1.c         |  26 +-
> >   drivers/md/raid10.c        |  37 ++-
> >   drivers/md/raid5.c         |  54 ++-
> >   9 files changed, 741 insertions(+), 181 deletions(-)
> >
> --
> Thanks,
> Kuai

Reply via email to