Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18593088 authored by Martin K. Petersen's avatar Martin K. Petersen Committed by Jens Axboe
Browse files

block: Clean up the code used to generate and verify integrity metadata



Instead of the "operate" parameter we pass in a seed value and a pointer
to a function that can be used to process the integrity metadata. The
generation function is changed to have a return value to fit into this
scheme.

Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: default avatarSagi Grimberg <sagig@mellanox.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent 5a2aa873
Loading
Loading
Loading
Loading
+22 −60
Original line number Original line Diff line number Diff line
@@ -207,69 +207,43 @@ static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
}
}


/**
/**
 * bio_integrity_generate_verify - Generate/verify integrity metadata for a bio
 * bio_integrity_process - Process integrity metadata for a bio
 * @bio:	bio to generate/verify integrity metadata for
 * @bio:	bio to generate/verify integrity metadata for
 * @operate:	operate number, 1 for generate, 0 for verify
 * @proc_fn:	Pointer to the relevant processing function
 */
 */
static int bio_integrity_generate_verify(struct bio *bio, int operate)
static int bio_integrity_process(struct bio *bio,
				 integrity_processing_fn *proc_fn)
{
{
	struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
	struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
	struct blk_integrity_exchg bix;
	struct blk_integrity_iter iter;
	struct bio_vec *bv;
	struct bio_vec *bv;
	struct bio_integrity_payload *bip = bio_integrity(bio);
	struct bio_integrity_payload *bip = bio_integrity(bio);
	sector_t seed;
	unsigned int i, ret = 0;
	unsigned int intervals, ret = 0, i;
	void *prot_buf = page_address(bip->bip_vec->bv_page) +
	void *prot_buf = page_address(bip->bip_vec->bv_page) +
		bip->bip_vec->bv_offset;
		bip->bip_vec->bv_offset;


	if (operate)
	iter.disk_name = bio->bi_bdev->bd_disk->disk_name;
		seed = bio->bi_iter.bi_sector;
	iter.interval = bi->interval;
	else
	iter.seed = bip_get_seed(bip);
		seed = bip->bip_iter.bi_sector;
	iter.prot_buf = prot_buf;

	bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
	bix.interval = bi->interval;


	bio_for_each_segment_all(bv, bio, i) {
	bio_for_each_segment_all(bv, bio, i) {
		void *kaddr = kmap_atomic(bv->bv_page);
		void *kaddr = kmap_atomic(bv->bv_page);
		bix.data_buf = kaddr + bv->bv_offset;

		bix.data_size = bv->bv_len;
		iter.data_buf = kaddr + bv->bv_offset;
		bix.prot_buf = prot_buf;
		iter.data_size = bv->bv_len;
		bix.seed = seed;


		ret = proc_fn(&iter);
		if (operate)
			bi->generate_fn(&bix);
		else {
			ret = bi->verify_fn(&bix);
		if (ret) {
		if (ret) {
			kunmap_atomic(kaddr);
			kunmap_atomic(kaddr);
			return ret;
			return ret;
		}
		}
		}

		intervals = bv->bv_len / bi->interval;
		seed += intervals;
		prot_buf += intervals * bi->tuple_size;


		kunmap_atomic(kaddr);
		kunmap_atomic(kaddr);
	}
	}
	return ret;
	return ret;
}
}


/**
 * bio_integrity_generate - Generate integrity metadata for a bio
 * @bio:	bio to generate integrity metadata for
 *
 * Description: Generates integrity metadata for a bio by calling the
 * block device's generation callback function.  The bio must have a
 * bip attached with enough room to accommodate the generated
 * integrity metadata.
 */
static void bio_integrity_generate(struct bio *bio)
{
	bio_integrity_generate_verify(bio, 1);
}

/**
/**
 * bio_integrity_prep - Prepare bio for integrity I/O
 * bio_integrity_prep - Prepare bio for integrity I/O
 * @bio:	bio to prepare
 * @bio:	bio to prepare
@@ -321,7 +295,7 @@ int bio_integrity_prep(struct bio *bio)


	bip->bip_owns_buf = 1;
	bip->bip_owns_buf = 1;
	bip->bip_iter.bi_size = len;
	bip->bip_iter.bi_size = len;
	bip->bip_iter.bi_sector = bio->bi_iter.bi_sector;
	bip_set_seed(bip, bio->bi_iter.bi_sector);


	/* Map it */
	/* Map it */
	offset = offset_in_page(buf);
	offset = offset_in_page(buf);
@@ -357,25 +331,12 @@ int bio_integrity_prep(struct bio *bio)


	/* Auto-generate integrity metadata if this is a write */
	/* Auto-generate integrity metadata if this is a write */
	if (bio_data_dir(bio) == WRITE)
	if (bio_data_dir(bio) == WRITE)
		bio_integrity_generate(bio);
		bio_integrity_process(bio, bi->generate_fn);


	return 0;
	return 0;
}
}
EXPORT_SYMBOL(bio_integrity_prep);
EXPORT_SYMBOL(bio_integrity_prep);


/**
 * bio_integrity_verify - Verify integrity metadata for a bio
 * @bio:	bio to verify
 *
 * Description: This function is called to verify the integrity of a
 * bio.	 The data in the bio io_vec is compared to the integrity
 * metadata returned by the HBA.
 */
static int bio_integrity_verify(struct bio *bio)
{
	return bio_integrity_generate_verify(bio, 0);
}

/**
/**
 * bio_integrity_verify_fn - Integrity I/O completion worker
 * bio_integrity_verify_fn - Integrity I/O completion worker
 * @work:	Work struct stored in bio to be verified
 * @work:	Work struct stored in bio to be verified
@@ -389,9 +350,10 @@ static void bio_integrity_verify_fn(struct work_struct *work)
	struct bio_integrity_payload *bip =
	struct bio_integrity_payload *bip =
		container_of(work, struct bio_integrity_payload, bip_work);
		container_of(work, struct bio_integrity_payload, bip_work);
	struct bio *bio = bip->bip_bio;
	struct bio *bio = bip->bip_bio;
	struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
	int error;
	int error;


	error = bio_integrity_verify(bio);
	error = bio_integrity_process(bio, bi->verify_fn);


	/* Restore original bio completion handler */
	/* Restore original bio completion handler */
	bio->bi_end_io = bip->bip_end_io;
	bio->bi_end_io = bip->bip_end_io;
+56 −50
Original line number Original line Diff line number Diff line
@@ -53,42 +53,44 @@ static __u16 sd_dif_ip_fn(void *data, unsigned int len)
 * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
 * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
 * 16 bit app tag, 32 bit reference tag.
 * 16 bit app tag, 32 bit reference tag.
 */
 */
static void sd_dif_type1_generate(struct blk_integrity_exchg *bix, csum_fn *fn)
static void sd_dif_type1_generate(struct blk_integrity_iter *iter, csum_fn *fn)
{
{
	void *buf = bix->data_buf;
	void *buf = iter->data_buf;
	struct sd_dif_tuple *sdt = bix->prot_buf;
	struct sd_dif_tuple *sdt = iter->prot_buf;
	sector_t seed = bix->seed;
	sector_t seed = iter->seed;
	unsigned int i;
	unsigned int i;


	for (i = 0 ; i < bix->data_size ; i += bix->interval, sdt++) {
	for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
		sdt->guard_tag = fn(buf, bix->interval);
		sdt->guard_tag = fn(buf, iter->interval);
		sdt->ref_tag = cpu_to_be32(seed & 0xffffffff);
		sdt->ref_tag = cpu_to_be32(seed & 0xffffffff);
		sdt->app_tag = 0;
		sdt->app_tag = 0;


		buf += bix->interval;
		buf += iter->interval;
		seed++;
		seed++;
	}
	}
}
}


static void sd_dif_type1_generate_crc(struct blk_integrity_exchg *bix)
static int sd_dif_type1_generate_crc(struct blk_integrity_iter *iter)
{
{
	sd_dif_type1_generate(bix, sd_dif_crc_fn);
	sd_dif_type1_generate(iter, sd_dif_crc_fn);
	return 0;
}
}


static void sd_dif_type1_generate_ip(struct blk_integrity_exchg *bix)
static int sd_dif_type1_generate_ip(struct blk_integrity_iter *iter)
{
{
	sd_dif_type1_generate(bix, sd_dif_ip_fn);
	sd_dif_type1_generate(iter, sd_dif_ip_fn);
	return 0;
}
}


static int sd_dif_type1_verify(struct blk_integrity_exchg *bix, csum_fn *fn)
static int sd_dif_type1_verify(struct blk_integrity_iter *iter, csum_fn *fn)
{
{
	void *buf = bix->data_buf;
	void *buf = iter->data_buf;
	struct sd_dif_tuple *sdt = bix->prot_buf;
	struct sd_dif_tuple *sdt = iter->prot_buf;
	sector_t seed = bix->seed;
	sector_t seed = iter->seed;
	unsigned int i;
	unsigned int i;
	__u16 csum;
	__u16 csum;


	for (i = 0 ; i < bix->data_size ; i += bix->interval, sdt++) {
	for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
		/* Unwritten sectors */
		/* Unwritten sectors */
		if (sdt->app_tag == 0xffff)
		if (sdt->app_tag == 0xffff)
			return 0;
			return 0;
@@ -96,36 +98,36 @@ static int sd_dif_type1_verify(struct blk_integrity_exchg *bix, csum_fn *fn)
		if (be32_to_cpu(sdt->ref_tag) != (seed & 0xffffffff)) {
		if (be32_to_cpu(sdt->ref_tag) != (seed & 0xffffffff)) {
			printk(KERN_ERR
			printk(KERN_ERR
			       "%s: ref tag error on sector %lu (rcvd %u)\n",
			       "%s: ref tag error on sector %lu (rcvd %u)\n",
			       bix->disk_name, (unsigned long)seed,
			       iter->disk_name, (unsigned long)seed,
			       be32_to_cpu(sdt->ref_tag));
			       be32_to_cpu(sdt->ref_tag));
			return -EIO;
			return -EIO;
		}
		}


		csum = fn(buf, bix->interval);
		csum = fn(buf, iter->interval);


		if (sdt->guard_tag != csum) {
		if (sdt->guard_tag != csum) {
			printk(KERN_ERR "%s: guard tag error on sector %lu " \
			printk(KERN_ERR "%s: guard tag error on sector %lu " \
			       "(rcvd %04x, data %04x)\n", bix->disk_name,
			       "(rcvd %04x, data %04x)\n", iter->disk_name,
			       (unsigned long)seed,
			       (unsigned long)seed,
			       be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
			       be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
			return -EIO;
			return -EIO;
		}
		}


		buf += bix->interval;
		buf += iter->interval;
		seed++;
		seed++;
	}
	}


	return 0;
	return 0;
}
}


static int sd_dif_type1_verify_crc(struct blk_integrity_exchg *bix)
static int sd_dif_type1_verify_crc(struct blk_integrity_iter *iter)
{
{
	return sd_dif_type1_verify(bix, sd_dif_crc_fn);
	return sd_dif_type1_verify(iter, sd_dif_crc_fn);
}
}


static int sd_dif_type1_verify_ip(struct blk_integrity_exchg *bix)
static int sd_dif_type1_verify_ip(struct blk_integrity_iter *iter)
{
{
	return sd_dif_type1_verify(bix, sd_dif_ip_fn);
	return sd_dif_type1_verify(iter, sd_dif_ip_fn);
}
}


static struct blk_integrity dif_type1_integrity_crc = {
static struct blk_integrity dif_type1_integrity_crc = {
@@ -149,69 +151,71 @@ static struct blk_integrity dif_type1_integrity_ip = {
 * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
 * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
 * tag space.
 * tag space.
 */
 */
static void sd_dif_type3_generate(struct blk_integrity_exchg *bix, csum_fn *fn)
static void sd_dif_type3_generate(struct blk_integrity_iter *iter, csum_fn *fn)
{
{
	void *buf = bix->data_buf;
	void *buf = iter->data_buf;
	struct sd_dif_tuple *sdt = bix->prot_buf;
	struct sd_dif_tuple *sdt = iter->prot_buf;
	unsigned int i;
	unsigned int i;


	for (i = 0 ; i < bix->data_size ; i += bix->interval, sdt++) {
	for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
		sdt->guard_tag = fn(buf, bix->interval);
		sdt->guard_tag = fn(buf, iter->interval);
		sdt->ref_tag = 0;
		sdt->ref_tag = 0;
		sdt->app_tag = 0;
		sdt->app_tag = 0;


		buf += bix->interval;
		buf += iter->interval;
	}
	}
}
}


static void sd_dif_type3_generate_crc(struct blk_integrity_exchg *bix)
static int sd_dif_type3_generate_crc(struct blk_integrity_iter *iter)
{
{
	sd_dif_type3_generate(bix, sd_dif_crc_fn);
	sd_dif_type3_generate(iter, sd_dif_crc_fn);
	return 0;
}
}


static void sd_dif_type3_generate_ip(struct blk_integrity_exchg *bix)
static int sd_dif_type3_generate_ip(struct blk_integrity_iter *iter)
{
{
	sd_dif_type3_generate(bix, sd_dif_ip_fn);
	sd_dif_type3_generate(iter, sd_dif_ip_fn);
	return 0;
}
}


static int sd_dif_type3_verify(struct blk_integrity_exchg *bix, csum_fn *fn)
static int sd_dif_type3_verify(struct blk_integrity_iter *iter, csum_fn *fn)
{
{
	void *buf = bix->data_buf;
	void *buf = iter->data_buf;
	struct sd_dif_tuple *sdt = bix->prot_buf;
	struct sd_dif_tuple *sdt = iter->prot_buf;
	sector_t seed = bix->seed;
	sector_t seed = iter->seed;
	unsigned int i;
	unsigned int i;
	__u16 csum;
	__u16 csum;


	for (i = 0 ; i < bix->data_size ; i += bix->interval, sdt++) {
	for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
		/* Unwritten sectors */
		/* Unwritten sectors */
		if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff)
		if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff)
			return 0;
			return 0;


		csum = fn(buf, bix->interval);
		csum = fn(buf, iter->interval);


		if (sdt->guard_tag != csum) {
		if (sdt->guard_tag != csum) {
			printk(KERN_ERR "%s: guard tag error on sector %lu " \
			printk(KERN_ERR "%s: guard tag error on sector %lu " \
			       "(rcvd %04x, data %04x)\n", bix->disk_name,
			       "(rcvd %04x, data %04x)\n", iter->disk_name,
			       (unsigned long)seed,
			       (unsigned long)seed,
			       be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
			       be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
			return -EIO;
			return -EIO;
		}
		}


		buf += bix->interval;
		buf += iter->interval;
		seed++;
		seed++;
	}
	}


	return 0;
	return 0;
}
}


static int sd_dif_type3_verify_crc(struct blk_integrity_exchg *bix)
static int sd_dif_type3_verify_crc(struct blk_integrity_iter *iter)
{
{
	return sd_dif_type3_verify(bix, sd_dif_crc_fn);
	return sd_dif_type3_verify(iter, sd_dif_crc_fn);
}
}


static int sd_dif_type3_verify_ip(struct blk_integrity_exchg *bix)
static int sd_dif_type3_verify_ip(struct blk_integrity_iter *iter)
{
{
	return sd_dif_type3_verify(bix, sd_dif_ip_fn);
	return sd_dif_type3_verify(iter, sd_dif_ip_fn);
}
}


static struct blk_integrity dif_type3_integrity_crc = {
static struct blk_integrity dif_type3_integrity_crc = {
@@ -310,6 +314,7 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector,
	phys = hw_sector & 0xffffffff;
	phys = hw_sector & 0xffffffff;


	__rq_for_each_bio(bio, rq) {
	__rq_for_each_bio(bio, rq) {
		struct bio_integrity_payload *bip = bio_integrity(bio);
		struct bio_vec iv;
		struct bio_vec iv;
		struct bvec_iter iter;
		struct bvec_iter iter;
		unsigned int j;
		unsigned int j;
@@ -318,9 +323,9 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector,
		if (bio_flagged(bio, BIO_MAPPED_INTEGRITY))
		if (bio_flagged(bio, BIO_MAPPED_INTEGRITY))
			break;
			break;


		virt = bio_integrity(bio)->bip_iter.bi_sector & 0xffffffff;
		virt = bip_get_seed(bip) & 0xffffffff;


		bip_for_each_vec(iv, bio_integrity(bio), iter) {
		bip_for_each_vec(iv, bip, iter) {
			sdt = kmap_atomic(iv.bv_page)
			sdt = kmap_atomic(iv.bv_page)
				+ iv.bv_offset;
				+ iv.bv_offset;


@@ -366,12 +371,13 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
		phys >>= 3;
		phys >>= 3;


	__rq_for_each_bio(bio, scmd->request) {
	__rq_for_each_bio(bio, scmd->request) {
		struct bio_integrity_payload *bip = bio_integrity(bio);
		struct bio_vec iv;
		struct bio_vec iv;
		struct bvec_iter iter;
		struct bvec_iter iter;


		virt = bio_integrity(bio)->bip_iter.bi_sector & 0xffffffff;
		virt = bip_get_seed(bip) & 0xffffffff;


		bip_for_each_vec(iv, bio_integrity(bio), iter) {
		bip_for_each_vec(iv, bip, iter) {
			sdt = kmap_atomic(iv.bv_page)
			sdt = kmap_atomic(iv.bv_page)
				+ iv.bv_offset;
				+ iv.bv_offset;


+12 −0
Original line number Original line Diff line number Diff line
@@ -322,6 +322,18 @@ struct bio_integrity_payload {
	struct bio_vec		*bip_vec;
	struct bio_vec		*bip_vec;
	struct bio_vec		bip_inline_vecs[0];/* embedded bvec array */
	struct bio_vec		bip_inline_vecs[0];/* embedded bvec array */
};
};

static inline sector_t bip_get_seed(struct bio_integrity_payload *bip)
{
	return bip->bip_iter.bi_sector;
}

static inline void bip_set_seed(struct bio_integrity_payload *bip,
				sector_t seed)
{
	bip->bip_iter.bi_sector = seed;
}

#endif /* CONFIG_BLK_DEV_INTEGRITY */
#endif /* CONFIG_BLK_DEV_INTEGRITY */


extern void bio_trim(struct bio *bio, int offset, int size);
extern void bio_trim(struct bio *bio, int offset, int size);
+4 −5
Original line number Original line Diff line number Diff line
@@ -1461,7 +1461,7 @@ static inline uint64_t rq_io_start_time_ns(struct request *req)
#define INTEGRITY_FLAG_READ	2	/* verify data integrity on read */
#define INTEGRITY_FLAG_READ	2	/* verify data integrity on read */
#define INTEGRITY_FLAG_WRITE	4	/* generate data integrity on write */
#define INTEGRITY_FLAG_WRITE	4	/* generate data integrity on write */


struct blk_integrity_exchg {
struct blk_integrity_iter {
	void			*prot_buf;
	void			*prot_buf;
	void			*data_buf;
	void			*data_buf;
	sector_t		seed;
	sector_t		seed;
@@ -1470,12 +1470,11 @@ struct blk_integrity_exchg {
	const char		*disk_name;
	const char		*disk_name;
};
};


typedef void (integrity_gen_fn) (struct blk_integrity_exchg *);
typedef int (integrity_processing_fn) (struct blk_integrity_iter *);
typedef int (integrity_vrfy_fn) (struct blk_integrity_exchg *);


struct blk_integrity {
struct blk_integrity {
	integrity_gen_fn	*generate_fn;
	integrity_processing_fn	*generate_fn;
	integrity_vrfy_fn	*verify_fn;
	integrity_processing_fn	*verify_fn;


	unsigned short		flags;
	unsigned short		flags;
	unsigned short		tuple_size;
	unsigned short		tuple_size;