Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm integrity: implement synchronous mode for reboot handling

Unfortunatelly, there may be bios coming even after the reboot notifier
was called. We don't want these bios to make the bitmap dirty again.

To address this, implement a synchronous mode - when a bio is about to
be terminated, we clean the bitmap and terminate the bio after the clean
operation succeeds. This obviously slows down bio processing, but it
makes sure that when all bios are finished, the bitmap will be clean.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>

authored by

Mikulas Patocka and committed by
Mike Snitzer
48271493 1f5a7759

+38 -5
+38 -5
drivers/md/dm-integrity.c
··· 171 171 struct page_list *may_write_bitmap; 172 172 struct bitmap_block_status *bbs; 173 173 unsigned bitmap_flush_interval; 174 + int synchronous_mode; 175 + struct bio_list synchronous_bios; 174 176 struct delayed_work bitmap_flush_work; 175 177 176 178 struct crypto_skcipher *journal_crypt; ··· 1384 1382 int r = dm_integrity_failed(ic); 1385 1383 if (unlikely(r) && !bio->bi_status) 1386 1384 bio->bi_status = errno_to_blk_status(r); 1385 + if (unlikely(ic->synchronous_mode) && bio_op(bio) == REQ_OP_WRITE) { 1386 + unsigned long flags; 1387 + spin_lock_irqsave(&ic->endio_wait.lock, flags); 1388 + bio_list_add(&ic->synchronous_bios, bio); 1389 + queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0); 1390 + spin_unlock_irqrestore(&ic->endio_wait.lock, flags); 1391 + return; 1392 + } 1387 1393 bio_endio(bio); 1388 1394 } 1389 1395 ··· 2504 2494 struct dm_integrity_c *ic = container_of(work, struct dm_integrity_c, bitmap_flush_work.work); 2505 2495 struct dm_integrity_range range; 2506 2496 unsigned long limit; 2497 + struct bio *bio; 2507 2498 2508 2499 dm_integrity_flush_buffers(ic); 2509 2500 ··· 2525 2514 >> (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit) 2526 2515 << (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit); 2527 2516 } 2528 - DEBUG_print("zeroing journal\n"); 2517 + /*DEBUG_print("zeroing journal\n");*/ 2529 2518 block_bitmap_op(ic, ic->journal, 0, limit, BITMAP_OP_CLEAR); 2530 2519 block_bitmap_op(ic, ic->may_write_bitmap, 0, limit, BITMAP_OP_CLEAR); 2531 2520 2532 2521 rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0, ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL); 2533 2522 2534 - remove_range(ic, &range); 2523 + spin_lock_irq(&ic->endio_wait.lock); 2524 + remove_range_unlocked(ic, &range); 2525 + while (unlikely((bio = bio_list_pop(&ic->synchronous_bios)) != NULL)) { 2526 + bio_endio(bio); 2527 + spin_unlock_irq(&ic->endio_wait.lock); 2528 + spin_lock_irq(&ic->endio_wait.lock); 2529 + } 2530 + spin_unlock_irq(&ic->endio_wait.lock); 2535 2531 } 2536 2532 2537 2533 ··· 2738 2720 init_journal_node(&ic->journal_tree[i]); 2739 2721 } 2740 2722 2741 - static int dm_integrity_reboot(struct notifier_block *n, unsigned long code, void *x) 2723 + static void dm_integrity_enter_synchronous_mode(struct dm_integrity_c *ic) 2742 2724 { 2743 - struct dm_integrity_c *ic = container_of(n, struct dm_integrity_c, reboot_notifier); 2725 + DEBUG_print("dm_integrity_enter_synchronous_mode\n"); 2744 2726 2745 2727 if (ic->mode == 'B') { 2746 - DEBUG_print("dm_integrity_reboot\n"); 2728 + ic->bitmap_flush_interval = msecs_to_jiffies(10) + 1; 2729 + ic->synchronous_mode = 1; 2730 + 2747 2731 cancel_delayed_work_sync(&ic->bitmap_flush_work); 2748 2732 queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0); 2749 2733 flush_workqueue(ic->commit_wq); 2750 2734 } 2735 + } 2736 + 2737 + static int dm_integrity_reboot(struct notifier_block *n, unsigned long code, void *x) 2738 + { 2739 + struct dm_integrity_c *ic = container_of(n, struct dm_integrity_c, reboot_notifier); 2740 + 2741 + DEBUG_print("dm_integrity_reboot\n"); 2742 + 2743 + dm_integrity_enter_synchronous_mode(ic); 2751 2744 2752 2745 return NOTIFY_DONE; 2753 2746 } ··· 2882 2853 ic->reboot_notifier.next = NULL; 2883 2854 ic->reboot_notifier.priority = INT_MAX - 1; /* be notified after md and before hardware drivers */ 2884 2855 WARN_ON(register_reboot_notifier(&ic->reboot_notifier)); 2856 + 2857 + #if 0 2858 + dm_integrity_enter_synchronous_mode(ic); 2859 + #endif 2885 2860 } 2886 2861 2887 2862 static void dm_integrity_status(struct dm_target *ti, status_type_t type,