Re: [PATCH 0/8] md/raid5: scalability and rebuild-path improvements
From: Hiroshi Nishida
Date: Fri Jul 10 2026 - 09:13:38 EST
Hi Yu Kuai,
Thanks again for the review, and in particular for:
> I can accept make those values configurable, but not direct
> modifications.
I've reworked the tunables along exactly those lines and will send them as
a separate, self-contained series, "md/raid5: size stripe-cache and worker
tuning from the hardware".
Rather than raising any fixed constant, each value now derives a default
from the hardware and stays overridable:
- the stripe-cache hash lock count (was a fixed 8) is sized from the CPU
count, clamped to 8..32;
- the stripe_cache_size ceiling (was a fixed 32768) scales with memory,
but never drops below 32768;
- the initial stripe_cache_size (was a fixed 256) scales gently with
memory, 256..4096;
- the default group_thread_cnt (was 0, i.e. single-threaded) is derived
from the CPU count (half the online CPUs per NUMA node, capped);
- the stripe batch size (was a fixed 8) is exposed as a parameter.
Ahead of those, the series opens with a one-line prerequisite fix:
alloc_thread_groups() sizes the per-node worker_groups[] array by
num_possible_nodes() but indexes it by cpu_to_node(), so a sparse NUMA node
map can index off the end -- reachable once the worker-group default (the
last patch) is on. It is Fixes:-tagged and can be taken on its own.
The key point for the consumer-NAS concern you raised: each default only
rises on hardware that can back it -- the lock and worker counts scale with
the core count, the cache sizes with RAM -- so a genuinely small system (a
few cores and a few GB) keeps today's values and footprint. And each one is
overridable via a module parameter (group_thread_cnt also via its existing
sysfs attribute), including all the way back to today's behaviour. So nothing is
imposed; the default simply tracks the machine instead of a constant, and
a wide array on a large host no longer needs a recompile or manual
per-array tuning to use the memory and cores it has.
And on performance -- on real NVMe this time, not a ramdisk: on a 16-disk
raid6 array (a 32-vCPU / 16-core host, steady state, interleaved runs) the
hardware-derived defaults run 2.1-3.2x the stock defaults (4K random write
~39k -> ~100k IOPS), essentially all of it from patch 6 turning on the
worker groups. Patches 2-5 (the cache and lock sizing) are
throughput-neutral on real SSD, as you'd expect -- they earn their place as
configurability and sane defaults, not a speed claim. And there is no
regression at the small end: a 4-CPU box derives 2 workers and is never
slower on any workload, and a box with two or fewer CPUs derives 0 and is
byte-for-byte unchanged.
It has been through KASAN + lockdep + DEBUG_LIST on RAID5
(create/rebuild/scrub, plus the bitmap add/remove that drives the
lock-all-hash-locks quiesce path), at both the derived defaults and pinned
values including nr_stripe_hash_locks=32.
The two unrelated parts of the original series -- the type-widening /
correctness fixes and the resync/recovery dispatch changes -- I'll send as
their own small series, as discussed.
Thanks,
2026年7月5日(日) 19:56 yu kuai <yukuai@xxxxxxx>:
>
> Hi,
>
> 在 2026/6/24 23:54, Hiroshi Nishida 写道:
> > This series collects small, individually low-risk md/raid5 changes for
> > large, many-core, many-disk arrays. Their common theme is reducing
> > per-stripe and stripe-cache contention, so the benefit appears mainly
> > when the raid5 stripe-handling worker threads are in use
> > (group_thread_cnt > 0); at the default group_thread_cnt = 0 (a single
> > handling thread) the series is essentially neutral.
> >
> > - patches 1-3 remove signed arithmetic from a hot-path divisor, lift an
> > arbitrary stripe-cache size cap, and widen a badblock length argument
> > that currently truncates large ranges;
> > - patch 4 raises NR_STRIPE_HASH_LOCKS (8 -> 32) to spread stripe-hash
> > contention on high core-count systems;
> > - patches 5 and 8 reduce per-stripe overhead in the resync/recovery
> > path and bound the share of the stripe cache a rebuild may hold while
> > user I/O is competing;
> > - patch 6 allocates each worker group's array on its own NUMA node;
> > - patch 7 raises MAX_STRIPE_BATCH (8 -> 32).
> >
> > Measured effect, treatment vs baseline, % change in mean IOPS (N=3),
> > swept over group_thread_cnt (RAID6 4+2, 22-core host, ramdisk members):
>
> Testing with ramdisk does serve as a useful reference, but it does not reflect
> real world usage.
>
> >
> > workload gtc=0 gtc=2 gtc=4 gtc=8
> > random 4K write (RMW) +4.2% +8.1% +17.4% +6.5%
> > DB mixed 75/25 8K +0.4% +4.2% +10.3% +4.7%
> > high-concurrency 70/30 4K +3.9% +1.2% +10.0% +0.2%
> > OLTP 70/30 16K -0.3% +4.7% +10.1% +9.3%
> > partial-stripe write 8K +1.1% +4.8% +11.2% +14.2%
>
> With a quick review I saw many static configurations is changed, I agree
> these changes can improve arrays with ssd/nvme and a system with large
> memory available. However, we already tested with hdd and about 8G memory
> available, these changes will not improve performance at all, with the
> extra memory overhead.
>
> I can accept make those values configurable, but not direct modifications.
> As validation is required for numerous scenarios. Memory resources are precious
> especially for most consumer NAS devices.
>
> >
> > At the default single handling thread (group_thread_cnt = 0) the series is
> > neutral (no regression). As worker threads are added the gain grows,
> > peaking broadly around group_thread_cnt = 4 at roughly +10-17% across the
> > whole mix; at gtc = 8 the write-heavy workloads keep gaining while the
> > read-heavy high-concurrency case has saturated. (Per-run cv was <1%
> > except the random-write test, ~5-9%, from a cold first run.)
> >
> > These numbers are on a ramdisk, which removes device latency and so
> > overstates the CPU-side contention effect relative to a real device;
> > they show the direction and the group_thread_cnt dependence, not an
> > absolute speedup. The stripe-hash/batch patches (4, 7) and the cache cap
> > (2) drive this; patch 6 only matters on multi-socket systems (not
> > exercised above) and patches 5/8 act on the resync/recovery path rather
> > than this steady-state workload.
> >
> > Reproduction (stock mdadm + fio):
> > mdadm --create /dev/md0 --level=6 --raid-devices=6 --chunk=512 \
> > --assume-clean <6 members>
> > echo 16384 > /sys/block/md0/md/stripe_cache_size
> > echo N > /sys/block/md0/md/group_thread_cnt # N = 0,2,4,8
> > fio --filename=/dev/md0 --direct=1 --ioengine=libaio --group_reporting \
> > --time_based --runtime=15 --name=w <per-workload opts>:
> > random write : --rw=randwrite --bs=4k --numjobs=4 --iodepth=32
> > DB mixed : --rw=randrw --rwmixread=75 --bs=8k --numjobs=8 --iodepth=16
> > high-concur. : --rw=randrw --rwmixread=70 --bs=4k --numjobs=16 --iodepth=8
> > OLTP : --rw=randrw --rwmixread=70 --bs=16k --numjobs=6 --iodepth=16
> > partial-stripe : --rw=randwrite --bs=8k --numjobs=4 --iodepth=32
> >
> > Each patch stands on its own; I am happy to drop or defer any that is not
> > justified on its own merit.
> >
> > Functional testing on RAID5 and RAID6: create, fail a member, rebuild
> > onto a spare / re-add, full data read-back verified, and scrub
> > ("check") reporting mismatch_cnt == 0. The series was also exercised
> > with KASAN and lockdep enabled -- including heavy group_thread_cnt
> > churn on a multi-node setup to stress the per-NUMA-node worker
> > allocation and the raid5_quiesce hash-lock-all path -- with no reports.
> >
> > Hiroshi Nishida (8):
> > md: change chunk_sectors and stripe cache counts to unsigned int
> > md/raid5: raise stripe cache limit from 32768 to 262144
> > md: widen badblock sectors param from int to sector_t
> > md/raid5: raise NR_STRIPE_HASH_LOCKS from 8 to 32
> > md/raid5: submit a window of stripes during resync/recovery
> > md/raid5: allocate worker groups per NUMA node
> > md/raid5: raise MAX_STRIPE_BATCH from 8 to 32
> > md/raid5: reserve stripe cache for user I/O during rebuild
> >
> > drivers/md/md.c | 4 +-
> > drivers/md/md.h | 10 ++--
> > drivers/md/raid5.c | 129 ++++++++++++++++++++++++++++++++-------------
> > drivers/md/raid5.h | 33 ++++++++----
> > 4 files changed, 121 insertions(+), 55 deletions(-)
> >
> > base-commit: 55b77337bdd088c77461588e5ec094421b89911b
> >
> --
> Thanks,
> Kuai
--
Hiroshi Nishida
nishidafmly@xxxxxxxxx