Skip to content

Commit 4403023

Browse files
committed
md/md-llbitmap: add CleanUnwritten state for RAID-5 proactive parity building
Add new states to the llbitmap state machine to support proactive XOR parity building for RAID-5 arrays. This allows users to pre-build parity data for unwritten regions before any user data is written. New states added: - BitNeedSyncUnwritten: Transitional state when proactive sync is triggered via sysfs on Unwritten regions. - BitSyncingUnwritten: Proactive sync in progress for unwritten region. - BitCleanUnwritten: XOR parity has been pre-built, but no user data written yet. When user writes to this region, it transitions to BitDirty. New actions added: - BitmapActionProactiveSync: Trigger for proactive XOR parity building. - BitmapActionClearUnwritten: Convert CleanUnwritten/NeedSyncUnwritten/ SyncingUnwritten states back to Unwritten before recovery starts. State flows: - Current (lazy): Unwritten -> (write) -> NeedSync -> (sync) -> Dirty -> Clean - New (proactive): Unwritten -> (sysfs) -> NeedSyncUnwritten -> (sync) -> CleanUnwritten - On write to CleanUnwritten: CleanUnwritten -> (write) -> Dirty -> Clean - On disk replacement: CleanUnwritten regions are converted to Unwritten before recovery starts, so recovery only rebuilds regions with user data A new sysfs interface is added at /sys/block/mdX/md/llbitmap/proactive_sync (write-only) to trigger proactive sync. This only works for RAID-456 arrays. Link: https://lore.kernel.org/linux-raid/20260323054644.3351791-3-yukuai@fnnas.com/ Signed-off-by: Yu Kuai <yukuai@fnnas.com>
1 parent 09af773 commit 4403023

1 file changed

Lines changed: 128 additions & 12 deletions

File tree

drivers/md/md-llbitmap.c

Lines changed: 128 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,20 @@ enum llbitmap_state {
208208
BitNeedSync,
209209
/* data is synchronizing */
210210
BitSyncing,
211+
/*
212+
* Proactive sync requested for unwritten region (raid456 only).
213+
* Triggered via sysfs when user wants to pre-build XOR parity
214+
* for regions that have never been written.
215+
*/
216+
BitNeedSyncUnwritten,
217+
/* Proactive sync in progress for unwritten region */
218+
BitSyncingUnwritten,
219+
/*
220+
* XOR parity has been pre-built for a region that has never had
221+
* user data written. When user writes to this region, it transitions
222+
* to BitDirty.
223+
*/
224+
BitCleanUnwritten,
211225
BitStateCount,
212226
BitNone = 0xff,
213227
};
@@ -232,6 +246,12 @@ enum llbitmap_action {
232246
* BitNeedSync.
233247
*/
234248
BitmapActionStale,
249+
/*
250+
* Proactive sync trigger for raid456 - builds XOR parity for
251+
* Unwritten regions without requiring user data write first.
252+
*/
253+
BitmapActionProactiveSync,
254+
BitmapActionClearUnwritten,
235255
BitmapActionCount,
236256
/* Init state is BitUnwritten */
237257
BitmapActionInit,
@@ -304,6 +324,8 @@ static char state_machine[BitStateCount][BitmapActionCount] = {
304324
[BitmapActionDaemon] = BitNone,
305325
[BitmapActionDiscard] = BitNone,
306326
[BitmapActionStale] = BitNone,
327+
[BitmapActionProactiveSync] = BitNeedSyncUnwritten,
328+
[BitmapActionClearUnwritten] = BitNone,
307329
},
308330
[BitClean] = {
309331
[BitmapActionStartwrite] = BitDirty,
@@ -314,6 +336,8 @@ static char state_machine[BitStateCount][BitmapActionCount] = {
314336
[BitmapActionDaemon] = BitNone,
315337
[BitmapActionDiscard] = BitUnwritten,
316338
[BitmapActionStale] = BitNeedSync,
339+
[BitmapActionProactiveSync] = BitNone,
340+
[BitmapActionClearUnwritten] = BitNone,
317341
},
318342
[BitDirty] = {
319343
[BitmapActionStartwrite] = BitNone,
@@ -324,6 +348,8 @@ static char state_machine[BitStateCount][BitmapActionCount] = {
324348
[BitmapActionDaemon] = BitClean,
325349
[BitmapActionDiscard] = BitUnwritten,
326350
[BitmapActionStale] = BitNeedSync,
351+
[BitmapActionProactiveSync] = BitNone,
352+
[BitmapActionClearUnwritten] = BitNone,
327353
},
328354
[BitNeedSync] = {
329355
[BitmapActionStartwrite] = BitNone,
@@ -334,6 +360,8 @@ static char state_machine[BitStateCount][BitmapActionCount] = {
334360
[BitmapActionDaemon] = BitNone,
335361
[BitmapActionDiscard] = BitUnwritten,
336362
[BitmapActionStale] = BitNone,
363+
[BitmapActionProactiveSync] = BitNone,
364+
[BitmapActionClearUnwritten] = BitNone,
337365
},
338366
[BitSyncing] = {
339367
[BitmapActionStartwrite] = BitNone,
@@ -344,6 +372,44 @@ static char state_machine[BitStateCount][BitmapActionCount] = {
344372
[BitmapActionDaemon] = BitNone,
345373
[BitmapActionDiscard] = BitUnwritten,
346374
[BitmapActionStale] = BitNeedSync,
375+
[BitmapActionProactiveSync] = BitNone,
376+
[BitmapActionClearUnwritten] = BitNone,
377+
},
378+
[BitNeedSyncUnwritten] = {
379+
[BitmapActionStartwrite] = BitNeedSync,
380+
[BitmapActionStartsync] = BitSyncingUnwritten,
381+
[BitmapActionEndsync] = BitNone,
382+
[BitmapActionAbortsync] = BitUnwritten,
383+
[BitmapActionReload] = BitUnwritten,
384+
[BitmapActionDaemon] = BitNone,
385+
[BitmapActionDiscard] = BitUnwritten,
386+
[BitmapActionStale] = BitUnwritten,
387+
[BitmapActionProactiveSync] = BitNone,
388+
[BitmapActionClearUnwritten] = BitUnwritten,
389+
},
390+
[BitSyncingUnwritten] = {
391+
[BitmapActionStartwrite] = BitSyncing,
392+
[BitmapActionStartsync] = BitSyncingUnwritten,
393+
[BitmapActionEndsync] = BitCleanUnwritten,
394+
[BitmapActionAbortsync] = BitUnwritten,
395+
[BitmapActionReload] = BitUnwritten,
396+
[BitmapActionDaemon] = BitNone,
397+
[BitmapActionDiscard] = BitUnwritten,
398+
[BitmapActionStale] = BitUnwritten,
399+
[BitmapActionProactiveSync] = BitNone,
400+
[BitmapActionClearUnwritten] = BitUnwritten,
401+
},
402+
[BitCleanUnwritten] = {
403+
[BitmapActionStartwrite] = BitDirty,
404+
[BitmapActionStartsync] = BitNone,
405+
[BitmapActionEndsync] = BitNone,
406+
[BitmapActionAbortsync] = BitNone,
407+
[BitmapActionReload] = BitNone,
408+
[BitmapActionDaemon] = BitNone,
409+
[BitmapActionDiscard] = BitUnwritten,
410+
[BitmapActionStale] = BitUnwritten,
411+
[BitmapActionProactiveSync] = BitNone,
412+
[BitmapActionClearUnwritten] = BitUnwritten,
347413
},
348414
};
349415

@@ -376,14 +442,15 @@ static void llbitmap_infect_dirty_bits(struct llbitmap *llbitmap,
376442
pctl->state[pos] = level_456 ? BitNeedSync : BitDirty;
377443
break;
378444
case BitClean:
445+
case BitCleanUnwritten:
379446
pctl->state[pos] = BitDirty;
380447
break;
381448
}
382449
}
383450
}
384451

385452
static void llbitmap_set_page_dirty(struct llbitmap *llbitmap, int idx,
386-
int offset)
453+
int offset, bool infect)
387454
{
388455
struct llbitmap_page_ctl *pctl = llbitmap->pctl[idx];
389456
unsigned int io_size = llbitmap->io_size;
@@ -398,7 +465,7 @@ static void llbitmap_set_page_dirty(struct llbitmap *llbitmap, int idx,
398465
* resync all the dirty bits, hence skip infect new dirty bits to
399466
* prevent resync unnecessary data.
400467
*/
401-
if (llbitmap->mddev->degraded) {
468+
if (llbitmap->mddev->degraded || !infect) {
402469
set_bit(block, pctl->dirty);
403470
return;
404471
}
@@ -438,7 +505,9 @@ static void llbitmap_write(struct llbitmap *llbitmap, enum llbitmap_state state,
438505

439506
llbitmap->pctl[idx]->state[bit] = state;
440507
if (state == BitDirty || state == BitNeedSync)
441-
llbitmap_set_page_dirty(llbitmap, idx, bit);
508+
llbitmap_set_page_dirty(llbitmap, idx, bit, true);
509+
else if (state == BitNeedSyncUnwritten)
510+
llbitmap_set_page_dirty(llbitmap, idx, bit, false);
442511
}
443512

444513
static struct page *llbitmap_read_page(struct llbitmap *llbitmap, int idx)
@@ -627,11 +696,10 @@ static enum llbitmap_state llbitmap_state_machine(struct llbitmap *llbitmap,
627696
goto write_bitmap;
628697
}
629698

630-
if (c == BitNeedSync)
699+
if (c == BitNeedSync || c == BitNeedSyncUnwritten)
631700
need_resync = !mddev->degraded;
632701

633702
state = state_machine[c][action];
634-
635703
write_bitmap:
636704
if (unlikely(mddev->degraded)) {
637705
/* For degraded array, mark new data as need sync. */
@@ -658,8 +726,7 @@ static enum llbitmap_state llbitmap_state_machine(struct llbitmap *llbitmap,
658726
}
659727

660728
llbitmap_write(llbitmap, state, start);
661-
662-
if (state == BitNeedSync)
729+
if (state == BitNeedSync || state == BitNeedSyncUnwritten)
663730
need_resync = !mddev->degraded;
664731
else if (state == BitDirty &&
665732
!timer_pending(&llbitmap->pending_timer))
@@ -1229,7 +1296,7 @@ static bool llbitmap_blocks_synced(struct mddev *mddev, sector_t offset)
12291296
unsigned long p = offset >> llbitmap->chunkshift;
12301297
enum llbitmap_state c = llbitmap_read(llbitmap, p);
12311298

1232-
return c == BitClean || c == BitDirty;
1299+
return c == BitClean || c == BitDirty || c == BitCleanUnwritten;
12331300
}
12341301

12351302
static sector_t llbitmap_skip_sync_blocks(struct mddev *mddev, sector_t offset)
@@ -1243,6 +1310,10 @@ static sector_t llbitmap_skip_sync_blocks(struct mddev *mddev, sector_t offset)
12431310
if (c == BitUnwritten)
12441311
return blocks;
12451312

1313+
/* Skip CleanUnwritten - no user data, will be reset after recovery */
1314+
if (c == BitCleanUnwritten)
1315+
return blocks;
1316+
12461317
/* For degraded array, don't skip */
12471318
if (mddev->degraded)
12481319
return 0;
@@ -1261,14 +1332,25 @@ static bool llbitmap_start_sync(struct mddev *mddev, sector_t offset,
12611332
{
12621333
struct llbitmap *llbitmap = mddev->bitmap;
12631334
unsigned long p = offset >> llbitmap->chunkshift;
1335+
enum llbitmap_state state;
1336+
1337+
/*
1338+
* Before recovery starts, convert CleanUnwritten to Unwritten.
1339+
* This ensures the new disk won't have stale parity data.
1340+
*/
1341+
if (offset == 0 && test_bit(MD_RECOVERY_RECOVER, &mddev->recovery) &&
1342+
!test_bit(MD_RECOVERY_LAZY_RECOVER, &mddev->recovery))
1343+
llbitmap_state_machine(llbitmap, 0, llbitmap->chunks - 1,
1344+
BitmapActionClearUnwritten);
1345+
12641346

12651347
/*
12661348
* Handle one bit at a time, this is much simpler. And it doesn't matter
12671349
* if md_do_sync() loop more times.
12681350
*/
12691351
*blocks = llbitmap->chunksize - (offset & (llbitmap->chunksize - 1));
1270-
return llbitmap_state_machine(llbitmap, p, p,
1271-
BitmapActionStartsync) == BitSyncing;
1352+
state = llbitmap_state_machine(llbitmap, p, p, BitmapActionStartsync);
1353+
return state == BitSyncing || state == BitSyncingUnwritten;
12721354
}
12731355

12741356
/* Something is wrong, sync_thread stop at @offset */
@@ -1474,9 +1556,15 @@ static ssize_t bits_show(struct mddev *mddev, char *page)
14741556
}
14751557

14761558
mutex_unlock(&mddev->bitmap_info.mutex);
1477-
return sprintf(page, "unwritten %d\nclean %d\ndirty %d\nneed sync %d\nsyncing %d\n",
1559+
return sprintf(page,
1560+
"unwritten %d\nclean %d\ndirty %d\n"
1561+
"need sync %d\nsyncing %d\n"
1562+
"need sync unwritten %d\nsyncing unwritten %d\n"
1563+
"clean unwritten %d\n",
14781564
bits[BitUnwritten], bits[BitClean], bits[BitDirty],
1479-
bits[BitNeedSync], bits[BitSyncing]);
1565+
bits[BitNeedSync], bits[BitSyncing],
1566+
bits[BitNeedSyncUnwritten], bits[BitSyncingUnwritten],
1567+
bits[BitCleanUnwritten]);
14801568
}
14811569

14821570
static struct md_sysfs_entry llbitmap_bits = __ATTR_RO(bits);
@@ -1549,11 +1637,39 @@ barrier_idle_store(struct mddev *mddev, const char *buf, size_t len)
15491637

15501638
static struct md_sysfs_entry llbitmap_barrier_idle = __ATTR_RW(barrier_idle);
15511639

1640+
static ssize_t
1641+
proactive_sync_store(struct mddev *mddev, const char *buf, size_t len)
1642+
{
1643+
struct llbitmap *llbitmap;
1644+
1645+
/* Only for RAID-456 */
1646+
if (!raid_is_456(mddev))
1647+
return -EINVAL;
1648+
1649+
mutex_lock(&mddev->bitmap_info.mutex);
1650+
llbitmap = mddev->bitmap;
1651+
if (!llbitmap || !llbitmap->pctl) {
1652+
mutex_unlock(&mddev->bitmap_info.mutex);
1653+
return -ENODEV;
1654+
}
1655+
1656+
/* Trigger proactive sync on all Unwritten regions */
1657+
llbitmap_state_machine(llbitmap, 0, llbitmap->chunks - 1,
1658+
BitmapActionProactiveSync);
1659+
1660+
mutex_unlock(&mddev->bitmap_info.mutex);
1661+
return len;
1662+
}
1663+
1664+
static struct md_sysfs_entry llbitmap_proactive_sync =
1665+
__ATTR(proactive_sync, 0200, NULL, proactive_sync_store);
1666+
15521667
static struct attribute *md_llbitmap_attrs[] = {
15531668
&llbitmap_bits.attr,
15541669
&llbitmap_metadata.attr,
15551670
&llbitmap_daemon_sleep.attr,
15561671
&llbitmap_barrier_idle.attr,
1672+
&llbitmap_proactive_sync.attr,
15571673
NULL
15581674
};
15591675

0 commit comments

Comments
 (0)