diff options
Diffstat (limited to 'drivers/md/dm-integrity.c')
| -rw-r--r-- | drivers/md/dm-integrity.c | 84 | 
1 files changed, 43 insertions, 41 deletions
| diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index b225b3e445fa..2f03fecd312d 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -6,6 +6,8 @@   * This file is released under the GPL.   */ +#include "dm-bio-record.h" +  #include <linux/compiler.h>  #include <linux/module.h>  #include <linux/device-mapper.h> @@ -201,17 +203,19 @@ struct dm_integrity_c {  	__u8 log2_blocks_per_bitmap_bit;  	unsigned char mode; -	int suspending;  	int failed;  	struct crypto_shash *internal_hash; +	struct dm_target *ti; +  	/* these variables are locked with endio_wait.lock */  	struct rb_root in_progress;  	struct list_head wait_list;  	wait_queue_head_t endio_wait;  	struct workqueue_struct *wait_wq; +	struct workqueue_struct *offload_wq;  	unsigned char commit_seq;  	commit_id_t commit_ids[N_COMMIT_IDS]; @@ -293,11 +297,7 @@ struct dm_integrity_io {  	struct completion *completion; -	struct gendisk *orig_bi_disk; -	u8 orig_bi_partno; -	bio_end_io_t *orig_bi_end_io; -	struct bio_integrity_payload *orig_bi_integrity; -	struct bvec_iter orig_bi_iter; +	struct dm_bio_details bio_details;  };  struct journal_completion { @@ -1439,7 +1439,7 @@ static void dec_in_flight(struct dm_integrity_io *dio)  			dio->range.logical_sector += dio->range.n_sectors;  			bio_advance(bio, dio->range.n_sectors << SECTOR_SHIFT);  			INIT_WORK(&dio->work, integrity_bio_wait); -			queue_work(ic->wait_wq, &dio->work); +			queue_work(ic->offload_wq, &dio->work);  			return;  		}  		do_endio_flush(ic, dio); @@ -1450,14 +1450,9 @@ static void integrity_end_io(struct bio *bio)  {  	struct dm_integrity_io *dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io)); -	bio->bi_iter = dio->orig_bi_iter; -	bio->bi_disk = dio->orig_bi_disk; -	bio->bi_partno = dio->orig_bi_partno; -	if (dio->orig_bi_integrity) { -		bio->bi_integrity = dio->orig_bi_integrity; +	dm_bio_restore(&dio->bio_details, bio); +	if (bio->bi_integrity)  		bio->bi_opf |= REQ_INTEGRITY; -	} -	bio->bi_end_io = dio->orig_bi_end_io;  	if (dio->completion)  		complete(dio->completion); @@ -1542,7 +1537,7 @@ static void integrity_metadata(struct work_struct *w)  			}  		} -		__bio_for_each_segment(bv, bio, iter, dio->orig_bi_iter) { +		__bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) {  			unsigned pos;  			char *mem, *checksums_ptr; @@ -1586,7 +1581,7 @@ again:  		if (likely(checksums != checksums_onstack))  			kfree(checksums);  	} else { -		struct bio_integrity_payload *bip = dio->orig_bi_integrity; +		struct bio_integrity_payload *bip = dio->bio_details.bi_integrity;  		if (bip) {  			struct bio_vec biv; @@ -1865,7 +1860,7 @@ static void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map  	if (need_sync_io && from_map) {  		INIT_WORK(&dio->work, integrity_bio_wait); -		queue_work(ic->metadata_wq, &dio->work); +		queue_work(ic->offload_wq, &dio->work);  		return;  	} @@ -2005,20 +2000,13 @@ offload_to_thread:  	} else  		dio->completion = NULL; -	dio->orig_bi_iter = bio->bi_iter; - -	dio->orig_bi_disk = bio->bi_disk; -	dio->orig_bi_partno = bio->bi_partno; +	dm_bio_record(&dio->bio_details, bio);  	bio_set_dev(bio, ic->dev->bdev); - -	dio->orig_bi_integrity = bio_integrity(bio);  	bio->bi_integrity = NULL;  	bio->bi_opf &= ~REQ_INTEGRITY; - -	dio->orig_bi_end_io = bio->bi_end_io;  	bio->bi_end_io = integrity_end_io; -  	bio->bi_iter.bi_size = dio->range.n_sectors << SECTOR_SHIFT; +  	generic_make_request(bio);  	if (need_sync_io) { @@ -2315,7 +2303,7 @@ static void integrity_writer(struct work_struct *w)  	unsigned prev_free_sectors;  	/* the following test is not needed, but it tests the replay code */ -	if (READ_ONCE(ic->suspending) && !ic->meta_dev) +	if (unlikely(dm_suspended(ic->ti)) && !ic->meta_dev)  		return;  	spin_lock_irq(&ic->endio_wait.lock); @@ -2376,7 +2364,7 @@ static void integrity_recalc(struct work_struct *w)  next_chunk: -	if (unlikely(READ_ONCE(ic->suspending))) +	if (unlikely(dm_suspended(ic->ti)))  		goto unlock_ret;  	range.logical_sector = le64_to_cpu(ic->sb->recalc_sector); @@ -2501,7 +2489,7 @@ static void bitmap_block_work(struct work_struct *w)  				    dio->range.n_sectors, BITMAP_OP_TEST_ALL_SET)) {  			remove_range(ic, &dio->range);  			INIT_WORK(&dio->work, integrity_bio_wait); -			queue_work(ic->wait_wq, &dio->work); +			queue_work(ic->offload_wq, &dio->work);  		} else {  			block_bitmap_op(ic, ic->journal, dio->range.logical_sector,  					dio->range.n_sectors, BITMAP_OP_SET); @@ -2524,7 +2512,7 @@ static void bitmap_block_work(struct work_struct *w)  		remove_range(ic, &dio->range);  		INIT_WORK(&dio->work, integrity_bio_wait); -		queue_work(ic->wait_wq, &dio->work); +		queue_work(ic->offload_wq, &dio->work);  	}  	queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval); @@ -2804,8 +2792,6 @@ static void dm_integrity_postsuspend(struct dm_target *ti)  	del_timer_sync(&ic->autocommit_timer); -	WRITE_ONCE(ic->suspending, 1); -  	if (ic->recalc_wq)  		drain_workqueue(ic->recalc_wq); @@ -2834,8 +2820,6 @@ static void dm_integrity_postsuspend(struct dm_target *ti)  #endif  	} -	WRITE_ONCE(ic->suspending, 0); -  	BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress));  	ic->journal_uptodate = true; @@ -2888,17 +2872,24 @@ static void dm_integrity_resume(struct dm_target *ti)  	} else {  		replay_journal(ic);  		if (ic->mode == 'B') { -			int mode;  			ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP);  			ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit;  			r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);  			if (unlikely(r))  				dm_integrity_io_error(ic, "writing superblock", r); -			mode = ic->recalculate_flag ? BITMAP_OP_SET : BITMAP_OP_CLEAR; -			block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, mode); -			block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, mode); -			block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, mode); +			block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); +			block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); +			block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); +			if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) && +			    le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors) { +				block_bitmap_op(ic, ic->journal, le64_to_cpu(ic->sb->recalc_sector), +						ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET); +				block_bitmap_op(ic, ic->recalc_bitmap, le64_to_cpu(ic->sb->recalc_sector), +						ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET); +				block_bitmap_op(ic, ic->may_write_bitmap, le64_to_cpu(ic->sb->recalc_sector), +						ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET); +			}  			rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,  					   ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);  		} @@ -2967,7 +2958,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,  			DMEMIT(" meta_device:%s", ic->meta_dev->name);  		if (ic->sectors_per_block != 1)  			DMEMIT(" block_size:%u", ic->sectors_per_block << SECTOR_SHIFT); -		if (ic->recalculate_flag) +		if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))  			DMEMIT(" recalculate");  		DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS);  		DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors); @@ -3623,6 +3614,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)  	}  	ti->private = ic;  	ti->per_io_data_size = sizeof(struct dm_integrity_io); +	ic->ti = ti;  	ic->in_progress = RB_ROOT;  	INIT_LIST_HEAD(&ic->wait_list); @@ -3836,6 +3828,14 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)  		goto bad;  	} +	ic->offload_wq = alloc_workqueue("dm-integrity-offload", WQ_MEM_RECLAIM, +					  METADATA_WORKQUEUE_MAX_ACTIVE); +	if (!ic->offload_wq) { +		ti->error = "Cannot allocate workqueue"; +		r = -ENOMEM; +		goto bad; +	} +  	ic->commit_wq = alloc_workqueue("dm-integrity-commit", WQ_MEM_RECLAIM, 1);  	if (!ic->commit_wq) {  		ti->error = "Cannot allocate workqueue"; @@ -4140,6 +4140,8 @@ static void dm_integrity_dtr(struct dm_target *ti)  		destroy_workqueue(ic->metadata_wq);  	if (ic->wait_wq)  		destroy_workqueue(ic->wait_wq); +	if (ic->offload_wq) +		destroy_workqueue(ic->offload_wq);  	if (ic->commit_wq)  		destroy_workqueue(ic->commit_wq);  	if (ic->writer_wq) @@ -4200,7 +4202,7 @@ static void dm_integrity_dtr(struct dm_target *ti)  static struct target_type integrity_target = {  	.name			= "integrity", -	.version		= {1, 4, 0}, +	.version		= {1, 5, 0},  	.module			= THIS_MODULE,  	.features		= DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,  	.ctr			= dm_integrity_ctr, |