mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 08:15:07 -04:00
md/md-llbitmap: only end fully synced chunks
llbitmap_cond_end_sync() is called with the sync thread's current sector. That value is an exclusive progress boundary: sectors below it have completed, but the llbitmap chunk containing it can still be in progress. The old code converted that sector directly to the last bit passed to BitmapActionEndsync. If resync had only advanced part-way into a large llbitmap chunk, the in-progress chunk was marked synced and flushed before the rest of the chunk was repaired. A later bitmap-assisted RAID1 resync could then skip the remainder of that chunk and leave stale mirror data behind. This can be reproduced without editing bitmap metadata by creating a large RAID1 with a lockless bitmap so llbitmap naturally selects a 524288-sector chunk (with the default 128 KiB bitmap area, an array just over 16 TiB is enough), making one mirror stale through the normal degraded write/re-add path, and throttling resync so the daemon checkpoint runs while resync is still inside the first chunk. On the bad kernel, bit 0 is ended early and a stale sector later in the same chunk is skipped. With this fix, bit 0 remains Syncing until resync reaches the next chunk boundary. Round the exclusive progress sector down to the nearest llbitmap chunk boundary and end only chunks strictly below that boundary. Also honor the force argument so callers that need an immediate checkpoint are not suppressed by daemon_sleep. Tested-by: Mykola Marzhan <mykola@meshstor.io> Link: https://patch.msgid.link/20260802195038.164272-4-yukuai@kernel.org Signed-off-by: Yu Kuai <yukuai@fygo.io>
This commit is contained in:
@@ -1450,22 +1450,27 @@ static void llbitmap_cond_end_sync(struct mddev *mddev, sector_t sector,
|
||||
bool force)
|
||||
{
|
||||
struct llbitmap *llbitmap = mddev->bitmap;
|
||||
sector_t complete;
|
||||
|
||||
if (sector == 0) {
|
||||
llbitmap->last_end_sync = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time_before(jiffies, llbitmap->last_end_sync +
|
||||
HZ * mddev->bitmap_info.daemon_sleep))
|
||||
if (!force && time_before(jiffies, llbitmap->last_end_sync +
|
||||
HZ * mddev->bitmap_info.daemon_sleep))
|
||||
return;
|
||||
|
||||
wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active));
|
||||
|
||||
mddev->curr_resync_completed = sector;
|
||||
set_bit(MD_SB_CHANGE_CLEAN, &mddev->sb_flags);
|
||||
llbitmap_state_machine(llbitmap, 0, sector >> llbitmap->chunkshift,
|
||||
BitmapActionEndsync);
|
||||
|
||||
complete = round_down(sector, llbitmap->chunksize);
|
||||
if (complete)
|
||||
llbitmap_state_machine(llbitmap, 0,
|
||||
(complete >> llbitmap->chunkshift) - 1,
|
||||
BitmapActionEndsync);
|
||||
__llbitmap_flush(mddev);
|
||||
|
||||
llbitmap->last_end_sync = jiffies;
|
||||
|
||||
Reference in New Issue
Block a user