diff options
Diffstat (limited to 'drivers/md/dm-integrity.c')
| -rw-r--r-- | drivers/md/dm-integrity.c | 85 | 
1 files changed, 55 insertions, 30 deletions
| diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 46b5d542b8fe..781942aeddd1 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -35,7 +35,7 @@  #define MIN_LOG2_INTERLEAVE_SECTORS	3  #define MAX_LOG2_INTERLEAVE_SECTORS	31  #define METADATA_WORKQUEUE_MAX_ACTIVE	16 -#define RECALC_SECTORS			8192 +#define RECALC_SECTORS			32768  #define RECALC_WRITE_SUPER		16  #define BITMAP_BLOCK_SIZE		4096	/* don't change it */  #define BITMAP_FLUSH_INTERVAL		(10 * HZ) @@ -262,6 +262,7 @@ struct dm_integrity_c {  	bool journal_uptodate;  	bool just_formatted;  	bool recalculate_flag; +	bool reset_recalculate_flag;  	bool discard;  	bool fix_padding;  	bool fix_hmac; @@ -1428,8 +1429,10 @@ static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, se  		if (op == TAG_READ) {  			memcpy(tag, dp, to_copy);  		} else if (op == TAG_WRITE) { -			memcpy(dp, tag, to_copy); -			dm_bufio_mark_partial_buffer_dirty(b, *metadata_offset, *metadata_offset + to_copy); +			if (memcmp(dp, tag, to_copy)) { +				memcpy(dp, tag, to_copy); +				dm_bufio_mark_partial_buffer_dirty(b, *metadata_offset, *metadata_offset + to_copy); +			}  		} else {  			/* e.g.: op == TAG_CMP */ @@ -2686,26 +2689,30 @@ next_chunk:  	if (unlikely(dm_integrity_failed(ic)))  		goto err; -	io_req.bi_op = REQ_OP_READ; -	io_req.bi_op_flags = 0; -	io_req.mem.type = DM_IO_VMA; -	io_req.mem.ptr.addr = ic->recalc_buffer; -	io_req.notify.fn = NULL; -	io_req.client = ic->io; -	io_loc.bdev = ic->dev->bdev; -	io_loc.sector = get_data_sector(ic, area, offset); -	io_loc.count = n_sectors; +	if (!ic->discard) { +		io_req.bi_op = REQ_OP_READ; +		io_req.bi_op_flags = 0; +		io_req.mem.type = DM_IO_VMA; +		io_req.mem.ptr.addr = ic->recalc_buffer; +		io_req.notify.fn = NULL; +		io_req.client = ic->io; +		io_loc.bdev = ic->dev->bdev; +		io_loc.sector = get_data_sector(ic, area, offset); +		io_loc.count = n_sectors; -	r = dm_io(&io_req, 1, &io_loc, NULL); -	if (unlikely(r)) { -		dm_integrity_io_error(ic, "reading data", r); -		goto err; -	} +		r = dm_io(&io_req, 1, &io_loc, NULL); +		if (unlikely(r)) { +			dm_integrity_io_error(ic, "reading data", r); +			goto err; +		} -	t = ic->recalc_tags; -	for (i = 0; i < n_sectors; i += ic->sectors_per_block) { -		integrity_sector_checksum(ic, logical_sector + i, ic->recalc_buffer + (i << SECTOR_SHIFT), t); -		t += ic->tag_size; +		t = ic->recalc_tags; +		for (i = 0; i < n_sectors; i += ic->sectors_per_block) { +			integrity_sector_checksum(ic, logical_sector + i, ic->recalc_buffer + (i << SECTOR_SHIFT), t); +			t += ic->tag_size; +		} +	} else { +		t = ic->recalc_tags + (n_sectors >> ic->sb->log2_sectors_per_block) * ic->tag_size;  	}  	metadata_block = get_metadata_sector_and_offset(ic, area, offset, &metadata_offset); @@ -3134,7 +3141,8 @@ static void dm_integrity_resume(struct dm_target *ti)  		rw_journal_sectors(ic, REQ_OP_READ, 0, 0,  				   ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);  		if (ic->mode == 'B') { -			if (ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit) { +			if (ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit && +			    !ic->reset_recalculate_flag) {  				block_bitmap_copy(ic, ic->recalc_bitmap, ic->journal);  				block_bitmap_copy(ic, ic->may_write_bitmap, ic->journal);  				if (!block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, @@ -3156,7 +3164,8 @@ static void dm_integrity_resume(struct dm_target *ti)  			}  		} else {  			if (!(ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit && -			      block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_TEST_ALL_CLEAR))) { +			      block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_TEST_ALL_CLEAR)) || +			    ic->reset_recalculate_flag) {  				ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING);  				ic->sb->recalc_sector = cpu_to_le64(0);  			} @@ -3169,6 +3178,10 @@ static void dm_integrity_resume(struct dm_target *ti)  			dm_integrity_io_error(ic, "writing superblock", r);  	} else {  		replay_journal(ic); +		if (ic->reset_recalculate_flag) { +			ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING); +			ic->sb->recalc_sector = cpu_to_le64(0); +		}  		if (ic->mode == 'B') {  			ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP);  			ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit; @@ -3242,6 +3255,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,  		arg_count += !!ic->meta_dev;  		arg_count += ic->sectors_per_block != 1;  		arg_count += !!(ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)); +		arg_count += ic->reset_recalculate_flag;  		arg_count += ic->discard;  		arg_count += ic->mode == 'J';  		arg_count += ic->mode == 'J'; @@ -3261,6 +3275,8 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,  			DMEMIT(" block_size:%u", ic->sectors_per_block << SECTOR_SHIFT);  		if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))  			DMEMIT(" recalculate"); +		if (ic->reset_recalculate_flag) +			DMEMIT(" reset_recalculate");  		if (ic->discard)  			DMEMIT(" allow_discards");  		DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS); @@ -3914,7 +3930,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)  	unsigned extra_args;  	struct dm_arg_set as;  	static const struct dm_arg _args[] = { -		{0, 17, "Invalid number of feature args"}, +		{0, 18, "Invalid number of feature args"},  	};  	unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;  	bool should_write_sb; @@ -4039,6 +4055,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)  			if (val >= (uint64_t)UINT_MAX * 1000 / HZ) {  				r = -EINVAL;  				ti->error = "Invalid bitmap_flush_interval argument"; +				goto bad;  			}  			ic->bitmap_flush_interval = msecs_to_jiffies(val);  		} else if (!strncmp(opt_string, "internal_hash:", strlen("internal_hash:"))) { @@ -4058,6 +4075,9 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)  				goto bad;  		} else if (!strcmp(opt_string, "recalculate")) {  			ic->recalculate_flag = true; +		} else if (!strcmp(opt_string, "reset_recalculate")) { +			ic->recalculate_flag = true; +			ic->reset_recalculate_flag = true;  		} else if (!strcmp(opt_string, "allow_discards")) {  			ic->discard = true;  		} else if (!strcmp(opt_string, "fix_padding")) { @@ -4348,11 +4368,13 @@ try_smaller_buffer:  			goto bad;  		}  		INIT_WORK(&ic->recalc_work, integrity_recalc); -		ic->recalc_buffer = vmalloc(RECALC_SECTORS << SECTOR_SHIFT); -		if (!ic->recalc_buffer) { -			ti->error = "Cannot allocate buffer for recalculating"; -			r = -ENOMEM; -			goto bad; +		if (!ic->discard) { +			ic->recalc_buffer = vmalloc(RECALC_SECTORS << SECTOR_SHIFT); +			if (!ic->recalc_buffer) { +				ti->error = "Cannot allocate buffer for recalculating"; +				r = -ENOMEM; +				goto bad; +			}  		}  		ic->recalc_tags = kvmalloc_array(RECALC_SECTORS >> ic->sb->log2_sectors_per_block,  						 ic->tag_size, GFP_KERNEL); @@ -4361,6 +4383,9 @@ try_smaller_buffer:  			r = -ENOMEM;  			goto bad;  		} +		if (ic->discard) +			memset(ic->recalc_tags, DISCARD_FILLER, +			       (RECALC_SECTORS >> ic->sb->log2_sectors_per_block) * ic->tag_size);  	} else {  		if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {  			ti->error = "Recalculate can only be specified with internal_hash"; @@ -4554,7 +4579,7 @@ static void dm_integrity_dtr(struct dm_target *ti)  static struct target_type integrity_target = {  	.name			= "integrity", -	.version		= {1, 7, 0}, +	.version		= {1, 9, 0},  	.module			= THIS_MODULE,  	.features		= DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,  	.ctr			= dm_integrity_ctr, | 
