mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
block: remove the blk_integrity_profile structure
Block layer integrity configuration is a bit complex right now, as it indirects through operation vectors for a simple two-dimensional configuration: a) the checksum type of none, ip checksum, crc, crc64 b) the presence or absence of a reference tag Remove the integrity profile, and instead add a separate csum_type flag which replaces the existing ip-checksum field and a new flag that indicates the presence of the reference tag. This removes up to two layers of indirect calls, remove the need to offload the no-op verification of non-PI metadata to a workqueue and generally simplifies the code. The downside is that block/t10-pi.c now has to be built into the kernel when CONFIG_BLK_DEV_INTEGRITY is supported. Given that both nvme and SCSI require t10-pi.ko, it is loaded for all usual configurations that enabled CONFIG_BLK_DEV_INTEGRITY already, though. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Kanchan Joshi <joshi.k@samsung.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Link: https://lore.kernel.org/r/20240613084839.1044015-6-hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
63e649594a
commit
e9f5f44ad3
@ -62,6 +62,8 @@ config BLK_DEV_BSGLIB
|
|||||||
|
|
||||||
config BLK_DEV_INTEGRITY
|
config BLK_DEV_INTEGRITY
|
||||||
bool "Block layer data integrity support"
|
bool "Block layer data integrity support"
|
||||||
|
select CRC_T10DIF
|
||||||
|
select CRC64_ROCKSOFT
|
||||||
help
|
help
|
||||||
Some storage devices allow extra information to be
|
Some storage devices allow extra information to be
|
||||||
stored/retrieved to help protect the data. The block layer
|
stored/retrieved to help protect the data. The block layer
|
||||||
@ -72,12 +74,6 @@ config BLK_DEV_INTEGRITY
|
|||||||
T10/SCSI Data Integrity Field or the T13/ATA External Path
|
T10/SCSI Data Integrity Field or the T13/ATA External Path
|
||||||
Protection. If in doubt, say N.
|
Protection. If in doubt, say N.
|
||||||
|
|
||||||
config BLK_DEV_INTEGRITY_T10
|
|
||||||
tristate
|
|
||||||
depends on BLK_DEV_INTEGRITY
|
|
||||||
select CRC_T10DIF
|
|
||||||
select CRC64_ROCKSOFT
|
|
||||||
|
|
||||||
config BLK_DEV_WRITE_MOUNTED
|
config BLK_DEV_WRITE_MOUNTED
|
||||||
bool "Allow writing to mounted block devices"
|
bool "Allow writing to mounted block devices"
|
||||||
default y
|
default y
|
||||||
|
@ -26,8 +26,7 @@ obj-$(CONFIG_MQ_IOSCHED_KYBER) += kyber-iosched.o
|
|||||||
bfq-y := bfq-iosched.o bfq-wf2q.o bfq-cgroup.o
|
bfq-y := bfq-iosched.o bfq-wf2q.o bfq-cgroup.o
|
||||||
obj-$(CONFIG_IOSCHED_BFQ) += bfq.o
|
obj-$(CONFIG_IOSCHED_BFQ) += bfq.o
|
||||||
|
|
||||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o
|
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o
|
||||||
obj-$(CONFIG_BLK_DEV_INTEGRITY_T10) += t10-pi.o
|
|
||||||
obj-$(CONFIG_BLK_MQ_PCI) += blk-mq-pci.o
|
obj-$(CONFIG_BLK_MQ_PCI) += blk-mq-pci.o
|
||||||
obj-$(CONFIG_BLK_MQ_VIRTIO) += blk-mq-virtio.o
|
obj-$(CONFIG_BLK_MQ_VIRTIO) += blk-mq-virtio.o
|
||||||
obj-$(CONFIG_BLK_DEV_ZONED) += blk-zoned.o
|
obj-$(CONFIG_BLK_DEV_ZONED) += blk-zoned.o
|
||||||
|
@ -378,10 +378,9 @@ EXPORT_SYMBOL_GPL(bio_integrity_map_user);
|
|||||||
* bio_integrity_process - Process 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
|
||||||
* @proc_iter: iterator to process
|
* @proc_iter: iterator to process
|
||||||
* @proc_fn: Pointer to the relevant processing function
|
|
||||||
*/
|
*/
|
||||||
static blk_status_t bio_integrity_process(struct bio *bio,
|
static blk_status_t bio_integrity_process(struct bio *bio,
|
||||||
struct bvec_iter *proc_iter, integrity_processing_fn *proc_fn)
|
struct bvec_iter *proc_iter)
|
||||||
{
|
{
|
||||||
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
|
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
|
||||||
struct blk_integrity_iter iter;
|
struct blk_integrity_iter iter;
|
||||||
@ -392,17 +391,18 @@ static blk_status_t bio_integrity_process(struct bio *bio,
|
|||||||
|
|
||||||
iter.disk_name = bio->bi_bdev->bd_disk->disk_name;
|
iter.disk_name = bio->bi_bdev->bd_disk->disk_name;
|
||||||
iter.interval = 1 << bi->interval_exp;
|
iter.interval = 1 << bi->interval_exp;
|
||||||
iter.tuple_size = bi->tuple_size;
|
|
||||||
iter.seed = proc_iter->bi_sector;
|
iter.seed = proc_iter->bi_sector;
|
||||||
iter.prot_buf = bvec_virt(bip->bip_vec);
|
iter.prot_buf = bvec_virt(bip->bip_vec);
|
||||||
iter.pi_offset = bi->pi_offset;
|
|
||||||
|
|
||||||
__bio_for_each_segment(bv, bio, bviter, *proc_iter) {
|
__bio_for_each_segment(bv, bio, bviter, *proc_iter) {
|
||||||
void *kaddr = bvec_kmap_local(&bv);
|
void *kaddr = bvec_kmap_local(&bv);
|
||||||
|
|
||||||
iter.data_buf = kaddr;
|
iter.data_buf = kaddr;
|
||||||
iter.data_size = bv.bv_len;
|
iter.data_size = bv.bv_len;
|
||||||
ret = proc_fn(&iter);
|
if (bio_data_dir(bio) == WRITE)
|
||||||
|
blk_integrity_generate(&iter, bi);
|
||||||
|
else
|
||||||
|
ret = blk_integrity_verify(&iter, bi);
|
||||||
kunmap_local(kaddr);
|
kunmap_local(kaddr);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -448,12 +448,10 @@ bool bio_integrity_prep(struct bio *bio)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (bio_data_dir(bio) == READ) {
|
if (bio_data_dir(bio) == READ) {
|
||||||
if (!bi->profile->verify_fn ||
|
if (!(bi->flags & BLK_INTEGRITY_VERIFY))
|
||||||
!(bi->flags & BLK_INTEGRITY_VERIFY))
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (!bi->profile->generate_fn ||
|
if (!(bi->flags & BLK_INTEGRITY_GENERATE))
|
||||||
!(bi->flags & BLK_INTEGRITY_GENERATE))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -488,7 +486,7 @@ bool bio_integrity_prep(struct bio *bio)
|
|||||||
bip->bip_flags |= BIP_BLOCK_INTEGRITY;
|
bip->bip_flags |= BIP_BLOCK_INTEGRITY;
|
||||||
bip_set_seed(bip, bio->bi_iter.bi_sector);
|
bip_set_seed(bip, bio->bi_iter.bi_sector);
|
||||||
|
|
||||||
if (bi->flags & BLK_INTEGRITY_IP_CHECKSUM)
|
if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
|
||||||
bip->bip_flags |= BIP_IP_CHECKSUM;
|
bip->bip_flags |= BIP_IP_CHECKSUM;
|
||||||
|
|
||||||
/* Map it */
|
/* Map it */
|
||||||
@ -511,12 +509,10 @@ bool 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_process(bio, &bio->bi_iter,
|
bio_integrity_process(bio, &bio->bi_iter);
|
||||||
bi->profile->generate_fn);
|
else
|
||||||
} else {
|
|
||||||
bip->bio_iter = bio->bi_iter;
|
bip->bio_iter = bio->bi_iter;
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
err_end_io:
|
err_end_io:
|
||||||
@ -539,15 +535,13 @@ 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 = blk_get_integrity(bio->bi_bdev->bd_disk);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At the moment verify is called bio's iterator was advanced
|
* At the moment verify is called bio's iterator was advanced
|
||||||
* during split and completion, we need to rewind iterator to
|
* during split and completion, we need to rewind iterator to
|
||||||
* it's original position.
|
* it's original position.
|
||||||
*/
|
*/
|
||||||
bio->bi_status = bio_integrity_process(bio, &bip->bio_iter,
|
bio->bi_status = bio_integrity_process(bio, &bip->bio_iter);
|
||||||
bi->profile->verify_fn);
|
|
||||||
bio_integrity_free(bio);
|
bio_integrity_free(bio);
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
}
|
}
|
||||||
@ -569,7 +563,7 @@ bool __bio_integrity_endio(struct bio *bio)
|
|||||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||||
|
|
||||||
if (bio_op(bio) == REQ_OP_READ && !bio->bi_status &&
|
if (bio_op(bio) == REQ_OP_READ && !bio->bi_status &&
|
||||||
(bip->bip_flags & BIP_BLOCK_INTEGRITY) && bi->profile->verify_fn) {
|
(bip->bip_flags & BIP_BLOCK_INTEGRITY) && bi->csum_type) {
|
||||||
INIT_WORK(&bip->bip_work, bio_integrity_verify_fn);
|
INIT_WORK(&bip->bip_work, bio_integrity_verify_fn);
|
||||||
queue_work(kintegrityd_wq, &bip->bip_work);
|
queue_work(kintegrityd_wq, &bip->bip_work);
|
||||||
return false;
|
return false;
|
||||||
|
@ -123,10 +123,10 @@ int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
|
|||||||
struct blk_integrity *b1 = &gd1->queue->integrity;
|
struct blk_integrity *b1 = &gd1->queue->integrity;
|
||||||
struct blk_integrity *b2 = &gd2->queue->integrity;
|
struct blk_integrity *b2 = &gd2->queue->integrity;
|
||||||
|
|
||||||
if (!b1->profile && !b2->profile)
|
if (!b1->tuple_size && !b2->tuple_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!b1->profile || !b2->profile)
|
if (!b1->tuple_size || !b2->tuple_size)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (b1->interval_exp != b2->interval_exp) {
|
if (b1->interval_exp != b2->interval_exp) {
|
||||||
@ -150,10 +150,13 @@ int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b1->profile != b2->profile) {
|
if (b1->csum_type != b2->csum_type ||
|
||||||
|
(b1->flags & BLK_INTEGRITY_REF_TAG) !=
|
||||||
|
(b2->flags & BLK_INTEGRITY_REF_TAG)) {
|
||||||
pr_err("%s: %s/%s type %s != %s\n", __func__,
|
pr_err("%s: %s/%s type %s != %s\n", __func__,
|
||||||
gd1->disk_name, gd2->disk_name,
|
gd1->disk_name, gd2->disk_name,
|
||||||
b1->profile->name, b2->profile->name);
|
blk_integrity_profile_name(b1),
|
||||||
|
blk_integrity_profile_name(b2));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,14 +220,37 @@ static inline struct blk_integrity *dev_to_bi(struct device *dev)
|
|||||||
return &dev_to_disk(dev)->queue->integrity;
|
return &dev_to_disk(dev)->queue->integrity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *blk_integrity_profile_name(struct blk_integrity *bi)
|
||||||
|
{
|
||||||
|
switch (bi->csum_type) {
|
||||||
|
case BLK_INTEGRITY_CSUM_IP:
|
||||||
|
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||||
|
return "T10-DIF-TYPE1-IP";
|
||||||
|
return "T10-DIF-TYPE3-IP";
|
||||||
|
case BLK_INTEGRITY_CSUM_CRC:
|
||||||
|
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||||
|
return "T10-DIF-TYPE1-CRC";
|
||||||
|
return "T10-DIF-TYPE3-CRC";
|
||||||
|
case BLK_INTEGRITY_CSUM_CRC64:
|
||||||
|
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||||
|
return "EXT-DIF-TYPE1-CRC64";
|
||||||
|
return "EXT-DIF-TYPE3-CRC64";
|
||||||
|
case BLK_INTEGRITY_CSUM_NONE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "nop";
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(blk_integrity_profile_name);
|
||||||
|
|
||||||
static ssize_t format_show(struct device *dev, struct device_attribute *attr,
|
static ssize_t format_show(struct device *dev, struct device_attribute *attr,
|
||||||
char *page)
|
char *page)
|
||||||
{
|
{
|
||||||
struct blk_integrity *bi = dev_to_bi(dev);
|
struct blk_integrity *bi = dev_to_bi(dev);
|
||||||
|
|
||||||
if (bi->profile && bi->profile->name)
|
if (!bi->tuple_size)
|
||||||
return sysfs_emit(page, "%s\n", bi->profile->name);
|
|
||||||
return sysfs_emit(page, "none\n");
|
return sysfs_emit(page, "none\n");
|
||||||
|
return sysfs_emit(page, "%s\n", blk_integrity_profile_name(bi));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t tag_size_show(struct device *dev, struct device_attribute *attr,
|
static ssize_t tag_size_show(struct device *dev, struct device_attribute *attr,
|
||||||
@ -326,28 +352,6 @@ const struct attribute_group blk_integrity_attr_group = {
|
|||||||
.attrs = integrity_attrs,
|
.attrs = integrity_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static blk_status_t blk_integrity_nop_fn(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return BLK_STS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void blk_integrity_nop_prepare(struct request *rq)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void blk_integrity_nop_complete(struct request *rq,
|
|
||||||
unsigned int nr_bytes)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct blk_integrity_profile nop_profile = {
|
|
||||||
.name = "nop",
|
|
||||||
.generate_fn = blk_integrity_nop_fn,
|
|
||||||
.verify_fn = blk_integrity_nop_fn,
|
|
||||||
.prepare_fn = blk_integrity_nop_prepare,
|
|
||||||
.complete_fn = blk_integrity_nop_complete,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* blk_integrity_register - Register a gendisk as being integrity-capable
|
* blk_integrity_register - Register a gendisk as being integrity-capable
|
||||||
* @disk: struct gendisk pointer to make integrity-aware
|
* @disk: struct gendisk pointer to make integrity-aware
|
||||||
@ -363,11 +367,11 @@ void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template
|
|||||||
{
|
{
|
||||||
struct blk_integrity *bi = &disk->queue->integrity;
|
struct blk_integrity *bi = &disk->queue->integrity;
|
||||||
|
|
||||||
|
bi->csum_type = template->csum_type;
|
||||||
bi->flags = BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE |
|
bi->flags = BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE |
|
||||||
template->flags;
|
template->flags;
|
||||||
bi->interval_exp = template->interval_exp ? :
|
bi->interval_exp = template->interval_exp ? :
|
||||||
ilog2(queue_logical_block_size(disk->queue));
|
ilog2(queue_logical_block_size(disk->queue));
|
||||||
bi->profile = template->profile ? template->profile : &nop_profile;
|
|
||||||
bi->tuple_size = template->tuple_size;
|
bi->tuple_size = template->tuple_size;
|
||||||
bi->tag_size = template->tag_size;
|
bi->tag_size = template->tag_size;
|
||||||
bi->pi_offset = template->pi_offset;
|
bi->pi_offset = template->pi_offset;
|
||||||
@ -394,7 +398,7 @@ void blk_integrity_unregister(struct gendisk *disk)
|
|||||||
{
|
{
|
||||||
struct blk_integrity *bi = &disk->queue->integrity;
|
struct blk_integrity *bi = &disk->queue->integrity;
|
||||||
|
|
||||||
if (!bi->profile)
|
if (!bi->tuple_size)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ensure all bios are off the integrity workqueue */
|
/* ensure all bios are off the integrity workqueue */
|
||||||
|
@ -804,10 +804,8 @@ static void blk_complete_request(struct request *req)
|
|||||||
if (!bio)
|
if (!bio)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_DEV_INTEGRITY
|
|
||||||
if (blk_integrity_rq(req) && req_op(req) == REQ_OP_READ)
|
if (blk_integrity_rq(req) && req_op(req) == REQ_OP_READ)
|
||||||
req->q->integrity.profile->complete_fn(req, total_bytes);
|
blk_integrity_complete(req, total_bytes);
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Upper layers may call blk_crypto_evict_key() anytime after the last
|
* Upper layers may call blk_crypto_evict_key() anytime after the last
|
||||||
@ -875,11 +873,9 @@ bool blk_update_request(struct request *req, blk_status_t error,
|
|||||||
if (!req->bio)
|
if (!req->bio)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_DEV_INTEGRITY
|
|
||||||
if (blk_integrity_rq(req) && req_op(req) == REQ_OP_READ &&
|
if (blk_integrity_rq(req) && req_op(req) == REQ_OP_READ &&
|
||||||
error == BLK_STS_OK)
|
error == BLK_STS_OK)
|
||||||
req->q->integrity.profile->complete_fn(req, nr_bytes);
|
blk_integrity_complete(req, nr_bytes);
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Upper layers may call blk_crypto_evict_key() anytime after the last
|
* Upper layers may call blk_crypto_evict_key() anytime after the last
|
||||||
@ -1264,10 +1260,9 @@ void blk_mq_start_request(struct request *rq)
|
|||||||
WRITE_ONCE(rq->state, MQ_RQ_IN_FLIGHT);
|
WRITE_ONCE(rq->state, MQ_RQ_IN_FLIGHT);
|
||||||
rq->mq_hctx->tags->rqs[rq->tag] = rq;
|
rq->mq_hctx->tags->rqs[rq->tag] = rq;
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_DEV_INTEGRITY
|
|
||||||
if (blk_integrity_rq(rq) && req_op(rq) == REQ_OP_WRITE)
|
if (blk_integrity_rq(rq) && req_op(rq) == REQ_OP_WRITE)
|
||||||
q->integrity.profile->prepare_fn(rq);
|
blk_integrity_prepare(rq);
|
||||||
#endif
|
|
||||||
if (rq->bio && rq->bio->bi_opf & REQ_POLLED)
|
if (rq->bio && rq->bio->bi_opf & REQ_POLLED)
|
||||||
WRITE_ONCE(rq->bio->bi_cookie, rq->mq_hctx->queue_num);
|
WRITE_ONCE(rq->bio->bi_cookie, rq->mq_hctx->queue_num);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <xen/xen.h>
|
#include <xen/xen.h>
|
||||||
#include "blk-crypto-internal.h"
|
#include "blk-crypto-internal.h"
|
||||||
|
|
||||||
|
struct blk_integrity_iter;
|
||||||
struct elevator_type;
|
struct elevator_type;
|
||||||
|
|
||||||
/* Max future timer expiry for timeouts */
|
/* Max future timer expiry for timeouts */
|
||||||
@ -673,4 +674,11 @@ int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder,
|
|||||||
const struct blk_holder_ops *hops, struct file *bdev_file);
|
const struct blk_holder_ops *hops, struct file *bdev_file);
|
||||||
int bdev_permission(dev_t dev, blk_mode_t mode, void *holder);
|
int bdev_permission(dev_t dev, blk_mode_t mode, void *holder);
|
||||||
|
|
||||||
|
void blk_integrity_generate(struct blk_integrity_iter *iter,
|
||||||
|
struct blk_integrity *bi);
|
||||||
|
blk_status_t blk_integrity_verify(struct blk_integrity_iter *iter,
|
||||||
|
struct blk_integrity *bi);
|
||||||
|
void blk_integrity_prepare(struct request *rq);
|
||||||
|
void blk_integrity_complete(struct request *rq, unsigned int nr_bytes);
|
||||||
|
|
||||||
#endif /* BLK_INTERNAL_H */
|
#endif /* BLK_INTERNAL_H */
|
||||||
|
237
block/t10-pi.c
237
block/t10-pi.c
@ -11,17 +11,14 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <net/checksum.h>
|
#include <net/checksum.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
#include "blk.h"
|
||||||
|
|
||||||
typedef __be16 (csum_fn) (__be16, void *, unsigned int);
|
static __be16 t10_pi_csum(__be16 csum, void *data, unsigned int len,
|
||||||
|
unsigned char csum_type)
|
||||||
static __be16 t10_pi_crc_fn(__be16 crc, void *data, unsigned int len)
|
|
||||||
{
|
|
||||||
return cpu_to_be16(crc_t10dif_update(be16_to_cpu(crc), data, len));
|
|
||||||
}
|
|
||||||
|
|
||||||
static __be16 t10_pi_ip_fn(__be16 csum, void *data, unsigned int len)
|
|
||||||
{
|
{
|
||||||
|
if (csum_type == BLK_INTEGRITY_CSUM_IP)
|
||||||
return (__force __be16)ip_compute_csum(data, len);
|
return (__force __be16)ip_compute_csum(data, len);
|
||||||
|
return cpu_to_be16(crc_t10dif_update(be16_to_cpu(csum), data, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -29,48 +26,44 @@ static __be16 t10_pi_ip_fn(__be16 csum, void *data, unsigned int len)
|
|||||||
* 16 bit app tag, 32 bit reference tag. Type 3 does not define the ref
|
* 16 bit app tag, 32 bit reference tag. Type 3 does not define the ref
|
||||||
* tag.
|
* tag.
|
||||||
*/
|
*/
|
||||||
static blk_status_t t10_pi_generate(struct blk_integrity_iter *iter,
|
static void t10_pi_generate(struct blk_integrity_iter *iter,
|
||||||
csum_fn *fn, enum t10_dif_type type)
|
struct blk_integrity *bi)
|
||||||
{
|
{
|
||||||
u8 offset = iter->pi_offset;
|
u8 offset = bi->pi_offset;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0 ; i < iter->data_size ; i += iter->interval) {
|
for (i = 0 ; i < iter->data_size ; i += iter->interval) {
|
||||||
struct t10_pi_tuple *pi = iter->prot_buf + offset;
|
struct t10_pi_tuple *pi = iter->prot_buf + offset;
|
||||||
|
|
||||||
pi->guard_tag = fn(0, iter->data_buf, iter->interval);
|
pi->guard_tag = t10_pi_csum(0, iter->data_buf, iter->interval,
|
||||||
|
bi->csum_type);
|
||||||
if (offset)
|
if (offset)
|
||||||
pi->guard_tag = fn(pi->guard_tag, iter->prot_buf,
|
pi->guard_tag = t10_pi_csum(pi->guard_tag,
|
||||||
offset);
|
iter->prot_buf, offset, bi->csum_type);
|
||||||
pi->app_tag = 0;
|
pi->app_tag = 0;
|
||||||
|
|
||||||
if (type == T10_PI_TYPE1_PROTECTION)
|
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||||
pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed));
|
pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed));
|
||||||
else
|
else
|
||||||
pi->ref_tag = 0;
|
pi->ref_tag = 0;
|
||||||
|
|
||||||
iter->data_buf += iter->interval;
|
iter->data_buf += iter->interval;
|
||||||
iter->prot_buf += iter->tuple_size;
|
iter->prot_buf += bi->tuple_size;
|
||||||
iter->seed++;
|
iter->seed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BLK_STS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter,
|
static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter,
|
||||||
csum_fn *fn, enum t10_dif_type type)
|
struct blk_integrity *bi)
|
||||||
{
|
{
|
||||||
u8 offset = iter->pi_offset;
|
u8 offset = bi->pi_offset;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
BUG_ON(type == T10_PI_TYPE0_PROTECTION);
|
|
||||||
|
|
||||||
for (i = 0 ; i < iter->data_size ; i += iter->interval) {
|
for (i = 0 ; i < iter->data_size ; i += iter->interval) {
|
||||||
struct t10_pi_tuple *pi = iter->prot_buf + offset;
|
struct t10_pi_tuple *pi = iter->prot_buf + offset;
|
||||||
__be16 csum;
|
__be16 csum;
|
||||||
|
|
||||||
if (type == T10_PI_TYPE1_PROTECTION ||
|
if (bi->flags & BLK_INTEGRITY_REF_TAG) {
|
||||||
type == T10_PI_TYPE2_PROTECTION) {
|
|
||||||
if (pi->app_tag == T10_PI_APP_ESCAPE)
|
if (pi->app_tag == T10_PI_APP_ESCAPE)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
@ -82,15 +75,17 @@ static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter,
|
|||||||
iter->seed, be32_to_cpu(pi->ref_tag));
|
iter->seed, be32_to_cpu(pi->ref_tag));
|
||||||
return BLK_STS_PROTECTION;
|
return BLK_STS_PROTECTION;
|
||||||
}
|
}
|
||||||
} else if (type == T10_PI_TYPE3_PROTECTION) {
|
} else {
|
||||||
if (pi->app_tag == T10_PI_APP_ESCAPE &&
|
if (pi->app_tag == T10_PI_APP_ESCAPE &&
|
||||||
pi->ref_tag == T10_PI_REF_ESCAPE)
|
pi->ref_tag == T10_PI_REF_ESCAPE)
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
csum = fn(0, iter->data_buf, iter->interval);
|
csum = t10_pi_csum(0, iter->data_buf, iter->interval,
|
||||||
|
bi->csum_type);
|
||||||
if (offset)
|
if (offset)
|
||||||
csum = fn(csum, iter->prot_buf, offset);
|
csum = t10_pi_csum(csum, iter->prot_buf, offset,
|
||||||
|
bi->csum_type);
|
||||||
|
|
||||||
if (pi->guard_tag != csum) {
|
if (pi->guard_tag != csum) {
|
||||||
pr_err("%s: guard tag error at sector %llu " \
|
pr_err("%s: guard tag error at sector %llu " \
|
||||||
@ -102,33 +97,13 @@ static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter,
|
|||||||
|
|
||||||
next:
|
next:
|
||||||
iter->data_buf += iter->interval;
|
iter->data_buf += iter->interval;
|
||||||
iter->prot_buf += iter->tuple_size;
|
iter->prot_buf += bi->tuple_size;
|
||||||
iter->seed++;
|
iter->seed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BLK_STS_OK;
|
return BLK_STS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_status_t t10_pi_type1_generate_crc(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE1_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
static blk_status_t t10_pi_type1_generate_ip(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE1_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
static blk_status_t t10_pi_type1_verify_crc(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE1_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
static blk_status_t t10_pi_type1_verify_ip(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE1_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* t10_pi_type1_prepare - prepare PI prior submitting request to device
|
* t10_pi_type1_prepare - prepare PI prior submitting request to device
|
||||||
* @rq: request with PI that should be prepared
|
* @rq: request with PI that should be prepared
|
||||||
@ -225,81 +200,15 @@ static void t10_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_status_t t10_pi_type3_generate_crc(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
static blk_status_t t10_pi_type3_generate_ip(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
static blk_status_t t10_pi_type3_verify_crc(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
static blk_status_t t10_pi_type3_verify_ip(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Type 3 does not have a reference tag so no remapping is required. */
|
|
||||||
static void t10_pi_type3_prepare(struct request *rq)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Type 3 does not have a reference tag so no remapping is required. */
|
|
||||||
static void t10_pi_type3_complete(struct request *rq, unsigned int nr_bytes)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct blk_integrity_profile t10_pi_type1_crc = {
|
|
||||||
.name = "T10-DIF-TYPE1-CRC",
|
|
||||||
.generate_fn = t10_pi_type1_generate_crc,
|
|
||||||
.verify_fn = t10_pi_type1_verify_crc,
|
|
||||||
.prepare_fn = t10_pi_type1_prepare,
|
|
||||||
.complete_fn = t10_pi_type1_complete,
|
|
||||||
};
|
|
||||||
EXPORT_SYMBOL(t10_pi_type1_crc);
|
|
||||||
|
|
||||||
const struct blk_integrity_profile t10_pi_type1_ip = {
|
|
||||||
.name = "T10-DIF-TYPE1-IP",
|
|
||||||
.generate_fn = t10_pi_type1_generate_ip,
|
|
||||||
.verify_fn = t10_pi_type1_verify_ip,
|
|
||||||
.prepare_fn = t10_pi_type1_prepare,
|
|
||||||
.complete_fn = t10_pi_type1_complete,
|
|
||||||
};
|
|
||||||
EXPORT_SYMBOL(t10_pi_type1_ip);
|
|
||||||
|
|
||||||
const struct blk_integrity_profile t10_pi_type3_crc = {
|
|
||||||
.name = "T10-DIF-TYPE3-CRC",
|
|
||||||
.generate_fn = t10_pi_type3_generate_crc,
|
|
||||||
.verify_fn = t10_pi_type3_verify_crc,
|
|
||||||
.prepare_fn = t10_pi_type3_prepare,
|
|
||||||
.complete_fn = t10_pi_type3_complete,
|
|
||||||
};
|
|
||||||
EXPORT_SYMBOL(t10_pi_type3_crc);
|
|
||||||
|
|
||||||
const struct blk_integrity_profile t10_pi_type3_ip = {
|
|
||||||
.name = "T10-DIF-TYPE3-IP",
|
|
||||||
.generate_fn = t10_pi_type3_generate_ip,
|
|
||||||
.verify_fn = t10_pi_type3_verify_ip,
|
|
||||||
.prepare_fn = t10_pi_type3_prepare,
|
|
||||||
.complete_fn = t10_pi_type3_complete,
|
|
||||||
};
|
|
||||||
EXPORT_SYMBOL(t10_pi_type3_ip);
|
|
||||||
|
|
||||||
static __be64 ext_pi_crc64(u64 crc, void *data, unsigned int len)
|
static __be64 ext_pi_crc64(u64 crc, void *data, unsigned int len)
|
||||||
{
|
{
|
||||||
return cpu_to_be64(crc64_rocksoft_update(crc, data, len));
|
return cpu_to_be64(crc64_rocksoft_update(crc, data, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_status_t ext_pi_crc64_generate(struct blk_integrity_iter *iter,
|
static void ext_pi_crc64_generate(struct blk_integrity_iter *iter,
|
||||||
enum t10_dif_type type)
|
struct blk_integrity *bi)
|
||||||
{
|
{
|
||||||
u8 offset = iter->pi_offset;
|
u8 offset = bi->pi_offset;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0 ; i < iter->data_size ; i += iter->interval) {
|
for (i = 0 ; i < iter->data_size ; i += iter->interval) {
|
||||||
@ -311,17 +220,15 @@ static blk_status_t ext_pi_crc64_generate(struct blk_integrity_iter *iter,
|
|||||||
iter->prot_buf, offset);
|
iter->prot_buf, offset);
|
||||||
pi->app_tag = 0;
|
pi->app_tag = 0;
|
||||||
|
|
||||||
if (type == T10_PI_TYPE1_PROTECTION)
|
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||||
put_unaligned_be48(iter->seed, pi->ref_tag);
|
put_unaligned_be48(iter->seed, pi->ref_tag);
|
||||||
else
|
else
|
||||||
put_unaligned_be48(0ULL, pi->ref_tag);
|
put_unaligned_be48(0ULL, pi->ref_tag);
|
||||||
|
|
||||||
iter->data_buf += iter->interval;
|
iter->data_buf += iter->interval;
|
||||||
iter->prot_buf += iter->tuple_size;
|
iter->prot_buf += bi->tuple_size;
|
||||||
iter->seed++;
|
iter->seed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BLK_STS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ext_pi_ref_escape(u8 *ref_tag)
|
static bool ext_pi_ref_escape(u8 *ref_tag)
|
||||||
@ -332,9 +239,9 @@ static bool ext_pi_ref_escape(u8 *ref_tag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
|
static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
|
||||||
enum t10_dif_type type)
|
struct blk_integrity *bi)
|
||||||
{
|
{
|
||||||
u8 offset = iter->pi_offset;
|
u8 offset = bi->pi_offset;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < iter->data_size; i += iter->interval) {
|
for (i = 0; i < iter->data_size; i += iter->interval) {
|
||||||
@ -342,7 +249,7 @@ static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
|
|||||||
u64 ref, seed;
|
u64 ref, seed;
|
||||||
__be64 csum;
|
__be64 csum;
|
||||||
|
|
||||||
if (type == T10_PI_TYPE1_PROTECTION) {
|
if (bi->flags & BLK_INTEGRITY_REF_TAG) {
|
||||||
if (pi->app_tag == T10_PI_APP_ESCAPE)
|
if (pi->app_tag == T10_PI_APP_ESCAPE)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
@ -353,7 +260,7 @@ static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
|
|||||||
iter->disk_name, seed, ref);
|
iter->disk_name, seed, ref);
|
||||||
return BLK_STS_PROTECTION;
|
return BLK_STS_PROTECTION;
|
||||||
}
|
}
|
||||||
} else if (type == T10_PI_TYPE3_PROTECTION) {
|
} else {
|
||||||
if (pi->app_tag == T10_PI_APP_ESCAPE &&
|
if (pi->app_tag == T10_PI_APP_ESCAPE &&
|
||||||
ext_pi_ref_escape(pi->ref_tag))
|
ext_pi_ref_escape(pi->ref_tag))
|
||||||
goto next;
|
goto next;
|
||||||
@ -374,23 +281,13 @@ static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
|
|||||||
|
|
||||||
next:
|
next:
|
||||||
iter->data_buf += iter->interval;
|
iter->data_buf += iter->interval;
|
||||||
iter->prot_buf += iter->tuple_size;
|
iter->prot_buf += bi->tuple_size;
|
||||||
iter->seed++;
|
iter->seed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BLK_STS_OK;
|
return BLK_STS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_status_t ext_pi_type1_verify_crc64(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return ext_pi_crc64_verify(iter, T10_PI_TYPE1_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
static blk_status_t ext_pi_type1_generate_crc64(struct blk_integrity_iter *iter)
|
|
||||||
{
|
|
||||||
return ext_pi_crc64_generate(iter, T10_PI_TYPE1_PROTECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ext_pi_type1_prepare(struct request *rq)
|
static void ext_pi_type1_prepare(struct request *rq)
|
||||||
{
|
{
|
||||||
struct blk_integrity *bi = &rq->q->integrity;
|
struct blk_integrity *bi = &rq->q->integrity;
|
||||||
@ -467,33 +364,61 @@ static void ext_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_status_t ext_pi_type3_verify_crc64(struct blk_integrity_iter *iter)
|
void blk_integrity_generate(struct blk_integrity_iter *iter,
|
||||||
|
struct blk_integrity *bi)
|
||||||
{
|
{
|
||||||
return ext_pi_crc64_verify(iter, T10_PI_TYPE3_PROTECTION);
|
switch (bi->csum_type) {
|
||||||
|
case BLK_INTEGRITY_CSUM_CRC64:
|
||||||
|
ext_pi_crc64_generate(iter, bi);
|
||||||
|
break;
|
||||||
|
case BLK_INTEGRITY_CSUM_CRC:
|
||||||
|
case BLK_INTEGRITY_CSUM_IP:
|
||||||
|
t10_pi_generate(iter, bi);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_status_t ext_pi_type3_generate_crc64(struct blk_integrity_iter *iter)
|
blk_status_t blk_integrity_verify(struct blk_integrity_iter *iter,
|
||||||
|
struct blk_integrity *bi)
|
||||||
{
|
{
|
||||||
return ext_pi_crc64_generate(iter, T10_PI_TYPE3_PROTECTION);
|
switch (bi->csum_type) {
|
||||||
|
case BLK_INTEGRITY_CSUM_CRC64:
|
||||||
|
return ext_pi_crc64_verify(iter, bi);
|
||||||
|
case BLK_INTEGRITY_CSUM_CRC:
|
||||||
|
case BLK_INTEGRITY_CSUM_IP:
|
||||||
|
return t10_pi_verify(iter, bi);
|
||||||
|
default:
|
||||||
|
return BLK_STS_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct blk_integrity_profile ext_pi_type1_crc64 = {
|
void blk_integrity_prepare(struct request *rq)
|
||||||
.name = "EXT-DIF-TYPE1-CRC64",
|
{
|
||||||
.generate_fn = ext_pi_type1_generate_crc64,
|
struct blk_integrity *bi = &rq->q->integrity;
|
||||||
.verify_fn = ext_pi_type1_verify_crc64,
|
|
||||||
.prepare_fn = ext_pi_type1_prepare,
|
|
||||||
.complete_fn = ext_pi_type1_complete,
|
|
||||||
};
|
|
||||||
EXPORT_SYMBOL_GPL(ext_pi_type1_crc64);
|
|
||||||
|
|
||||||
const struct blk_integrity_profile ext_pi_type3_crc64 = {
|
if (!(bi->flags & BLK_INTEGRITY_REF_TAG))
|
||||||
.name = "EXT-DIF-TYPE3-CRC64",
|
return;
|
||||||
.generate_fn = ext_pi_type3_generate_crc64,
|
|
||||||
.verify_fn = ext_pi_type3_verify_crc64,
|
if (bi->csum_type == BLK_INTEGRITY_CSUM_CRC64)
|
||||||
.prepare_fn = t10_pi_type3_prepare,
|
ext_pi_type1_prepare(rq);
|
||||||
.complete_fn = t10_pi_type3_complete,
|
else
|
||||||
};
|
t10_pi_type1_prepare(rq);
|
||||||
EXPORT_SYMBOL_GPL(ext_pi_type3_crc64);
|
}
|
||||||
|
|
||||||
|
void blk_integrity_complete(struct request *rq, unsigned int nr_bytes)
|
||||||
|
{
|
||||||
|
struct blk_integrity *bi = &rq->q->integrity;
|
||||||
|
|
||||||
|
if (!(bi->flags & BLK_INTEGRITY_REF_TAG))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bi->csum_type == BLK_INTEGRITY_CSUM_CRC64)
|
||||||
|
ext_pi_type1_complete(rq, nr_bytes);
|
||||||
|
else
|
||||||
|
t10_pi_type1_complete(rq, nr_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
MODULE_DESCRIPTION("T10 Protection Information module");
|
MODULE_DESCRIPTION("T10 Protection Information module");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@ -1177,7 +1177,7 @@ static int crypt_integrity_ctr(struct crypt_config *cc, struct dm_target *ti)
|
|||||||
struct mapped_device *md = dm_table_get_md(ti->table);
|
struct mapped_device *md = dm_table_get_md(ti->table);
|
||||||
|
|
||||||
/* We require an underlying device with non-PI metadata */
|
/* We require an underlying device with non-PI metadata */
|
||||||
if (!bi || strcmp(bi->profile->name, "nop")) {
|
if (!bi || bi->csum_type != BLK_INTEGRITY_CSUM_NONE) {
|
||||||
ti->error = "Integrity profile not supported.";
|
ti->error = "Integrity profile not supported.";
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
config NVME_CORE
|
config NVME_CORE
|
||||||
tristate
|
tristate
|
||||||
select BLK_DEV_INTEGRITY_T10 if BLK_DEV_INTEGRITY
|
|
||||||
|
|
||||||
config BLK_DEV_NVME
|
config BLK_DEV_NVME
|
||||||
tristate "NVM Express block device"
|
tristate "NVM Express block device"
|
||||||
|
@ -1744,17 +1744,16 @@ static bool nvme_init_integrity(struct gendisk *disk, struct nvme_ns_head *head)
|
|||||||
case NVME_NS_DPS_PI_TYPE3:
|
case NVME_NS_DPS_PI_TYPE3:
|
||||||
switch (head->guard_type) {
|
switch (head->guard_type) {
|
||||||
case NVME_NVM_NS_16B_GUARD:
|
case NVME_NVM_NS_16B_GUARD:
|
||||||
integrity.profile = &t10_pi_type3_crc;
|
integrity.csum_type = BLK_INTEGRITY_CSUM_CRC;
|
||||||
integrity.tag_size = sizeof(u16) + sizeof(u32);
|
integrity.tag_size = sizeof(u16) + sizeof(u32);
|
||||||
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
|
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
|
||||||
break;
|
break;
|
||||||
case NVME_NVM_NS_64B_GUARD:
|
case NVME_NVM_NS_64B_GUARD:
|
||||||
integrity.profile = &ext_pi_type3_crc64;
|
integrity.csum_type = BLK_INTEGRITY_CSUM_CRC64;
|
||||||
integrity.tag_size = sizeof(u16) + 6;
|
integrity.tag_size = sizeof(u16) + 6;
|
||||||
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
|
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
integrity.profile = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1762,22 +1761,22 @@ static bool nvme_init_integrity(struct gendisk *disk, struct nvme_ns_head *head)
|
|||||||
case NVME_NS_DPS_PI_TYPE2:
|
case NVME_NS_DPS_PI_TYPE2:
|
||||||
switch (head->guard_type) {
|
switch (head->guard_type) {
|
||||||
case NVME_NVM_NS_16B_GUARD:
|
case NVME_NVM_NS_16B_GUARD:
|
||||||
integrity.profile = &t10_pi_type1_crc;
|
integrity.csum_type = BLK_INTEGRITY_CSUM_CRC;
|
||||||
integrity.tag_size = sizeof(u16);
|
integrity.tag_size = sizeof(u16);
|
||||||
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
|
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE |
|
||||||
|
BLK_INTEGRITY_REF_TAG;
|
||||||
break;
|
break;
|
||||||
case NVME_NVM_NS_64B_GUARD:
|
case NVME_NVM_NS_64B_GUARD:
|
||||||
integrity.profile = &ext_pi_type1_crc64;
|
integrity.csum_type = BLK_INTEGRITY_CSUM_CRC64;
|
||||||
integrity.tag_size = sizeof(u16);
|
integrity.tag_size = sizeof(u16);
|
||||||
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
|
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE |
|
||||||
|
BLK_INTEGRITY_REF_TAG;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
integrity.profile = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
integrity.profile = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ config NVME_TARGET
|
|||||||
depends on CONFIGFS_FS
|
depends on CONFIGFS_FS
|
||||||
select NVME_KEYRING if NVME_TARGET_TCP_TLS
|
select NVME_KEYRING if NVME_TARGET_TCP_TLS
|
||||||
select KEYS if NVME_TARGET_TCP_TLS
|
select KEYS if NVME_TARGET_TCP_TLS
|
||||||
select BLK_DEV_INTEGRITY_T10 if BLK_DEV_INTEGRITY
|
|
||||||
select SGL_ALLOC
|
select SGL_ALLOC
|
||||||
help
|
help
|
||||||
This enabled target side support for the NVMe protocol, that is
|
This enabled target side support for the NVMe protocol, that is
|
||||||
|
@ -61,14 +61,16 @@ static void nvmet_bdev_ns_enable_integrity(struct nvmet_ns *ns)
|
|||||||
{
|
{
|
||||||
struct blk_integrity *bi = bdev_get_integrity(ns->bdev);
|
struct blk_integrity *bi = bdev_get_integrity(ns->bdev);
|
||||||
|
|
||||||
if (bi) {
|
if (!bi)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bi->csum_type == BLK_INTEGRITY_CSUM_CRC) {
|
||||||
ns->metadata_size = bi->tuple_size;
|
ns->metadata_size = bi->tuple_size;
|
||||||
if (bi->profile == &t10_pi_type1_crc)
|
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||||
ns->pi_type = NVME_NS_DPS_PI_TYPE1;
|
ns->pi_type = NVME_NS_DPS_PI_TYPE1;
|
||||||
else if (bi->profile == &t10_pi_type3_crc)
|
|
||||||
ns->pi_type = NVME_NS_DPS_PI_TYPE3;
|
|
||||||
else
|
else
|
||||||
/* Unsupported metadata type */
|
ns->pi_type = NVME_NS_DPS_PI_TYPE3;
|
||||||
|
} else {
|
||||||
ns->metadata_size = 0;
|
ns->metadata_size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,7 +104,7 @@ int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
|
|||||||
|
|
||||||
ns->pi_type = 0;
|
ns->pi_type = 0;
|
||||||
ns->metadata_size = 0;
|
ns->metadata_size = 0;
|
||||||
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY_T10))
|
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY))
|
||||||
nvmet_bdev_ns_enable_integrity(ns);
|
nvmet_bdev_ns_enable_integrity(ns);
|
||||||
|
|
||||||
if (bdev_is_zoned(ns->bdev)) {
|
if (bdev_is_zoned(ns->bdev)) {
|
||||||
|
@ -82,7 +82,6 @@ comment "SCSI support type (disk, tape, CD-ROM)"
|
|||||||
config BLK_DEV_SD
|
config BLK_DEV_SD
|
||||||
tristate "SCSI disk support"
|
tristate "SCSI disk support"
|
||||||
depends on SCSI
|
depends on SCSI
|
||||||
select BLK_DEV_INTEGRITY_T10 if BLK_DEV_INTEGRITY
|
|
||||||
help
|
help
|
||||||
If you want to use SCSI hard disks, Fibre Channel disks,
|
If you want to use SCSI hard disks, Fibre Channel disks,
|
||||||
Serial ATA (SATA) or Parallel ATA (PATA) hard disks,
|
Serial ATA (SATA) or Parallel ATA (PATA) hard disks,
|
||||||
|
@ -47,18 +47,13 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
|
|||||||
memset(&bi, 0, sizeof(bi));
|
memset(&bi, 0, sizeof(bi));
|
||||||
|
|
||||||
/* Enable DMA of protection information */
|
/* Enable DMA of protection information */
|
||||||
if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) {
|
if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP)
|
||||||
if (type == T10_PI_TYPE3_PROTECTION)
|
bi.csum_type = BLK_INTEGRITY_CSUM_IP;
|
||||||
bi.profile = &t10_pi_type3_ip;
|
|
||||||
else
|
else
|
||||||
bi.profile = &t10_pi_type1_ip;
|
bi.csum_type = BLK_INTEGRITY_CSUM_CRC;
|
||||||
|
|
||||||
bi.flags |= BLK_INTEGRITY_IP_CHECKSUM;
|
if (type != T10_PI_TYPE3_PROTECTION)
|
||||||
} else
|
bi.flags |= BLK_INTEGRITY_REF_TAG;
|
||||||
if (type == T10_PI_TYPE3_PROTECTION)
|
|
||||||
bi.profile = &t10_pi_type3_crc;
|
|
||||||
else
|
|
||||||
bi.profile = &t10_pi_type1_crc;
|
|
||||||
|
|
||||||
bi.tuple_size = sizeof(struct t10_pi_tuple);
|
bi.tuple_size = sizeof(struct t10_pi_tuple);
|
||||||
|
|
||||||
@ -76,7 +71,7 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
|
|||||||
|
|
||||||
sd_first_printk(KERN_NOTICE, sdkp,
|
sd_first_printk(KERN_NOTICE, sdkp,
|
||||||
"Enabling DIX %s, application tag size %u bytes\n",
|
"Enabling DIX %s, application tag size %u bytes\n",
|
||||||
bi.profile->name, bi.tag_size);
|
blk_integrity_profile_name(&bi), bi.tag_size);
|
||||||
out:
|
out:
|
||||||
blk_integrity_register(disk, &bi);
|
blk_integrity_register(disk, &bi);
|
||||||
}
|
}
|
||||||
|
@ -148,24 +148,28 @@ static int iblock_configure_device(struct se_device *dev)
|
|||||||
dev->dev_attrib.is_nonrot = 1;
|
dev->dev_attrib.is_nonrot = 1;
|
||||||
|
|
||||||
bi = bdev_get_integrity(bd);
|
bi = bdev_get_integrity(bd);
|
||||||
if (bi) {
|
if (!bi)
|
||||||
struct bio_set *bs = &ib_dev->ibd_bio_set;
|
return 0;
|
||||||
|
|
||||||
if (!strcmp(bi->profile->name, "T10-DIF-TYPE3-IP") ||
|
switch (bi->csum_type) {
|
||||||
!strcmp(bi->profile->name, "T10-DIF-TYPE1-IP")) {
|
case BLK_INTEGRITY_CSUM_IP:
|
||||||
pr_err("IBLOCK export of blk_integrity: %s not"
|
pr_err("IBLOCK export of blk_integrity: %s not supported\n",
|
||||||
" supported\n", bi->profile->name);
|
blk_integrity_profile_name(bi));
|
||||||
ret = -ENOSYS;
|
ret = -ENOSYS;
|
||||||
goto out_blkdev_put;
|
goto out_blkdev_put;
|
||||||
}
|
case BLK_INTEGRITY_CSUM_CRC:
|
||||||
|
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||||
if (!strcmp(bi->profile->name, "T10-DIF-TYPE3-CRC")) {
|
|
||||||
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE3_PROT;
|
|
||||||
} else if (!strcmp(bi->profile->name, "T10-DIF-TYPE1-CRC")) {
|
|
||||||
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE1_PROT;
|
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE1_PROT;
|
||||||
|
else
|
||||||
|
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE3_PROT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->dev_attrib.pi_prot_type) {
|
if (dev->dev_attrib.pi_prot_type) {
|
||||||
|
struct bio_set *bs = &ib_dev->ibd_bio_set;
|
||||||
|
|
||||||
if (bioset_integrity_create(bs, IBLOCK_BIO_POOL_SIZE) < 0) {
|
if (bioset_integrity_create(bs, IBLOCK_BIO_POOL_SIZE) < 0) {
|
||||||
pr_err("Unable to allocate bioset for PI\n");
|
pr_err("Unable to allocate bioset for PI\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
@ -174,9 +178,8 @@ static int iblock_configure_device(struct se_device *dev)
|
|||||||
pr_debug("IBLOCK setup BIP bs->bio_integrity_pool: %p\n",
|
pr_debug("IBLOCK setup BIP bs->bio_integrity_pool: %p\n",
|
||||||
&bs->bio_integrity_pool);
|
&bs->bio_integrity_pool);
|
||||||
}
|
}
|
||||||
dev->dev_attrib.hw_pi_prot_type = dev->dev_attrib.pi_prot_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
dev->dev_attrib.hw_pi_prot_type = dev->dev_attrib.pi_prot_type;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_blkdev_put:
|
out_blkdev_put:
|
||||||
|
@ -10,7 +10,7 @@ enum blk_integrity_flags {
|
|||||||
BLK_INTEGRITY_VERIFY = 1 << 0,
|
BLK_INTEGRITY_VERIFY = 1 << 0,
|
||||||
BLK_INTEGRITY_GENERATE = 1 << 1,
|
BLK_INTEGRITY_GENERATE = 1 << 1,
|
||||||
BLK_INTEGRITY_DEVICE_CAPABLE = 1 << 2,
|
BLK_INTEGRITY_DEVICE_CAPABLE = 1 << 2,
|
||||||
BLK_INTEGRITY_IP_CHECKSUM = 1 << 3,
|
BLK_INTEGRITY_REF_TAG = 1 << 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct blk_integrity_iter {
|
struct blk_integrity_iter {
|
||||||
@ -19,22 +19,10 @@ struct blk_integrity_iter {
|
|||||||
sector_t seed;
|
sector_t seed;
|
||||||
unsigned int data_size;
|
unsigned int data_size;
|
||||||
unsigned short interval;
|
unsigned short interval;
|
||||||
unsigned char tuple_size;
|
|
||||||
unsigned char pi_offset;
|
|
||||||
const char *disk_name;
|
const char *disk_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef blk_status_t (integrity_processing_fn) (struct blk_integrity_iter *);
|
const char *blk_integrity_profile_name(struct blk_integrity *bi);
|
||||||
typedef void (integrity_prepare_fn) (struct request *);
|
|
||||||
typedef void (integrity_complete_fn) (struct request *, unsigned int);
|
|
||||||
|
|
||||||
struct blk_integrity_profile {
|
|
||||||
integrity_processing_fn *generate_fn;
|
|
||||||
integrity_processing_fn *verify_fn;
|
|
||||||
integrity_prepare_fn *prepare_fn;
|
|
||||||
integrity_complete_fn *complete_fn;
|
|
||||||
const char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_DEV_INTEGRITY
|
#ifdef CONFIG_BLK_DEV_INTEGRITY
|
||||||
void blk_integrity_register(struct gendisk *, struct blk_integrity *);
|
void blk_integrity_register(struct gendisk *, struct blk_integrity *);
|
||||||
@ -44,14 +32,17 @@ int blk_rq_map_integrity_sg(struct request_queue *, struct bio *,
|
|||||||
struct scatterlist *);
|
struct scatterlist *);
|
||||||
int blk_rq_count_integrity_sg(struct request_queue *, struct bio *);
|
int blk_rq_count_integrity_sg(struct request_queue *, struct bio *);
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
blk_integrity_queue_supports_integrity(struct request_queue *q)
|
||||||
|
{
|
||||||
|
return q->integrity.tuple_size;
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk)
|
static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk)
|
||||||
{
|
{
|
||||||
struct blk_integrity *bi = &disk->queue->integrity;
|
if (!blk_integrity_queue_supports_integrity(disk->queue))
|
||||||
|
|
||||||
if (!bi->profile)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
return &disk->queue->integrity;
|
||||||
return bi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct blk_integrity *
|
static inline struct blk_integrity *
|
||||||
@ -60,12 +51,6 @@ bdev_get_integrity(struct block_device *bdev)
|
|||||||
return blk_get_integrity(bdev->bd_disk);
|
return blk_get_integrity(bdev->bd_disk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
|
||||||
blk_integrity_queue_supports_integrity(struct request_queue *q)
|
|
||||||
{
|
|
||||||
return q->integrity.profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned short
|
static inline unsigned short
|
||||||
queue_max_integrity_segments(const struct request_queue *q)
|
queue_max_integrity_segments(const struct request_queue *q)
|
||||||
{
|
{
|
||||||
|
@ -105,9 +105,16 @@ enum {
|
|||||||
struct disk_events;
|
struct disk_events;
|
||||||
struct badblocks;
|
struct badblocks;
|
||||||
|
|
||||||
|
enum blk_integrity_checksum {
|
||||||
|
BLK_INTEGRITY_CSUM_NONE = 0,
|
||||||
|
BLK_INTEGRITY_CSUM_IP = 1,
|
||||||
|
BLK_INTEGRITY_CSUM_CRC = 2,
|
||||||
|
BLK_INTEGRITY_CSUM_CRC64 = 3,
|
||||||
|
} __packed ;
|
||||||
|
|
||||||
struct blk_integrity {
|
struct blk_integrity {
|
||||||
const struct blk_integrity_profile *profile;
|
|
||||||
unsigned char flags;
|
unsigned char flags;
|
||||||
|
enum blk_integrity_checksum csum_type;
|
||||||
unsigned char tuple_size;
|
unsigned char tuple_size;
|
||||||
unsigned char pi_offset;
|
unsigned char pi_offset;
|
||||||
unsigned char interval_exp;
|
unsigned char interval_exp;
|
||||||
|
@ -48,11 +48,6 @@ static inline u32 t10_pi_ref_tag(struct request *rq)
|
|||||||
return blk_rq_pos(rq) >> (shift - SECTOR_SHIFT) & 0xffffffff;
|
return blk_rq_pos(rq) >> (shift - SECTOR_SHIFT) & 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern const struct blk_integrity_profile t10_pi_type1_crc;
|
|
||||||
extern const struct blk_integrity_profile t10_pi_type1_ip;
|
|
||||||
extern const struct blk_integrity_profile t10_pi_type3_crc;
|
|
||||||
extern const struct blk_integrity_profile t10_pi_type3_ip;
|
|
||||||
|
|
||||||
struct crc64_pi_tuple {
|
struct crc64_pi_tuple {
|
||||||
__be64 guard_tag;
|
__be64 guard_tag;
|
||||||
__be16 app_tag;
|
__be16 app_tag;
|
||||||
@ -79,7 +74,4 @@ static inline u64 ext_pi_ref_tag(struct request *rq)
|
|||||||
return lower_48_bits(blk_rq_pos(rq) >> (shift - SECTOR_SHIFT));
|
return lower_48_bits(blk_rq_pos(rq) >> (shift - SECTOR_SHIFT));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern const struct blk_integrity_profile ext_pi_type1_crc64;
|
|
||||||
extern const struct blk_integrity_profile ext_pi_type3_crc64;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user