block: support PI at non-zero offset within metadata
authorKanchan Joshi <joshi.k@samsung.com>
Thu, 1 Feb 2024 13:01:25 +0000 (18:31 +0530)
committerJens Axboe <axboe@kernel.dk>
Mon, 12 Feb 2024 15:49:31 +0000 (08:49 -0700)
Block layer integrity processing assumes that protection information
(PI) is placed in the first bytes of each metadata block.

Remove this limitation and include the metadata before the PI in the
calculation of the guard tag.

Signed-off-by: Kanchan Joshi <joshi.k@samsung.com>
Signed-off-by: Chinmay Gameti <c.gameti@samsung.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Link: https://lore.kernel.org/r/20240201130126.211402-3-joshi.k@samsung.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/bio-integrity.c
block/blk-integrity.c
block/t10-pi.c
include/linux/blk-integrity.h
include/linux/blkdev.h

index c9a16fba58b9c47f5424be9a8c7c6681d176b986..2e3e8e04961eaeaa04f9ec0470d15bbf64867191 100644 (file)
@@ -395,6 +395,7 @@ static blk_status_t bio_integrity_process(struct bio *bio,
        iter.tuple_size = bi->tuple_size;
        iter.seed = proc_iter->bi_sector;
        iter.prot_buf = bvec_virt(bip->bip_vec);
+       iter.pi_offset = bi->pi_offset;
 
        __bio_for_each_segment(bv, bio, bviter, *proc_iter) {
                void *kaddr = bvec_kmap_local(&bv);
index d4e9b4556d14b2ca9931b3123d5e1ba0884720ca..ccbeb6dfa87a4dc5f63a485cd0bec9e800704ff6 100644 (file)
@@ -370,6 +370,7 @@ void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template
        bi->profile = template->profile ? template->profile : &nop_profile;
        bi->tuple_size = template->tuple_size;
        bi->tag_size = template->tag_size;
+       bi->pi_offset = template->pi_offset;
 
        blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue);
 
index 251a7b188963a92de8f48483424d67375503470e..d90892fd6f2ad5faf295b7c91f3bcf1e90a5a713 100644 (file)
@@ -32,12 +32,16 @@ static __be16 t10_pi_ip_fn(__be16 csum, void *data, unsigned int len)
 static blk_status_t t10_pi_generate(struct blk_integrity_iter *iter,
                csum_fn *fn, enum t10_dif_type type)
 {
+       u8 offset = iter->pi_offset;
        unsigned int i;
 
        for (i = 0 ; i < iter->data_size ; i += iter->interval) {
-               struct t10_pi_tuple *pi = iter->prot_buf;
+               struct t10_pi_tuple *pi = iter->prot_buf + offset;
 
                pi->guard_tag = fn(0, iter->data_buf, iter->interval);
+               if (offset)
+                       pi->guard_tag = fn(pi->guard_tag, iter->prot_buf,
+                                          offset);
                pi->app_tag = 0;
 
                if (type == T10_PI_TYPE1_PROTECTION)
@@ -56,12 +60,13 @@ static blk_status_t t10_pi_generate(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)
 {
+       u8 offset = iter->pi_offset;
        unsigned int i;
 
        BUG_ON(type == T10_PI_TYPE0_PROTECTION);
 
        for (i = 0 ; i < iter->data_size ; i += iter->interval) {
-               struct t10_pi_tuple *pi = iter->prot_buf;
+               struct t10_pi_tuple *pi = iter->prot_buf + offset;
                __be16 csum;
 
                if (type == T10_PI_TYPE1_PROTECTION ||
@@ -84,6 +89,8 @@ static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter,
                }
 
                csum = fn(0, iter->data_buf, iter->interval);
+               if (offset)
+                       csum = fn(csum, iter->prot_buf, offset);
 
                if (pi->guard_tag != csum) {
                        pr_err("%s: guard tag error at sector %llu " \
@@ -134,8 +141,10 @@ static blk_status_t t10_pi_type1_verify_ip(struct blk_integrity_iter *iter)
  */
 static void t10_pi_type1_prepare(struct request *rq)
 {
-       const int tuple_sz = rq->q->integrity.tuple_size;
+       struct blk_integrity *bi = &rq->q->integrity;
+       const int tuple_sz = bi->tuple_size;
        u32 ref_tag = t10_pi_ref_tag(rq);
+       u8 offset = bi->pi_offset;
        struct bio *bio;
 
        __rq_for_each_bio(bio, rq) {
@@ -154,7 +163,7 @@ static void t10_pi_type1_prepare(struct request *rq)
 
                        p = bvec_kmap_local(&iv);
                        for (j = 0; j < iv.bv_len; j += tuple_sz) {
-                               struct t10_pi_tuple *pi = p;
+                               struct t10_pi_tuple *pi = p + offset;
 
                                if (be32_to_cpu(pi->ref_tag) == virt)
                                        pi->ref_tag = cpu_to_be32(ref_tag);
@@ -183,9 +192,11 @@ static void t10_pi_type1_prepare(struct request *rq)
  */
 static void t10_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
 {
-       unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp;
-       const int tuple_sz = rq->q->integrity.tuple_size;
+       struct blk_integrity *bi = &rq->q->integrity;
+       unsigned intervals = nr_bytes >> bi->interval_exp;
+       const int tuple_sz = bi->tuple_size;
        u32 ref_tag = t10_pi_ref_tag(rq);
+       u8 offset = bi->pi_offset;
        struct bio *bio;
 
        __rq_for_each_bio(bio, rq) {
@@ -200,7 +211,7 @@ static void t10_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
 
                        p = bvec_kmap_local(&iv);
                        for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) {
-                               struct t10_pi_tuple *pi = p;
+                               struct t10_pi_tuple *pi = p + offset;
 
                                if (be32_to_cpu(pi->ref_tag) == ref_tag)
                                        pi->ref_tag = cpu_to_be32(virt);
@@ -288,12 +299,16 @@ static __be64 ext_pi_crc64(u64 crc, void *data, unsigned int len)
 static blk_status_t ext_pi_crc64_generate(struct blk_integrity_iter *iter,
                                        enum t10_dif_type type)
 {
+       u8 offset = iter->pi_offset;
        unsigned int i;
 
        for (i = 0 ; i < iter->data_size ; i += iter->interval) {
-               struct crc64_pi_tuple *pi = iter->prot_buf;
+               struct crc64_pi_tuple *pi = iter->prot_buf + offset;
 
                pi->guard_tag = ext_pi_crc64(0, iter->data_buf, iter->interval);
+               if (offset)
+                       pi->guard_tag = ext_pi_crc64(be64_to_cpu(pi->guard_tag),
+                                       iter->prot_buf, offset);
                pi->app_tag = 0;
 
                if (type == T10_PI_TYPE1_PROTECTION)
@@ -319,10 +334,11 @@ static bool ext_pi_ref_escape(u8 *ref_tag)
 static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
                                      enum t10_dif_type type)
 {
+       u8 offset = iter->pi_offset;
        unsigned int i;
 
        for (i = 0; i < iter->data_size; i += iter->interval) {
-               struct crc64_pi_tuple *pi = iter->prot_buf;
+               struct crc64_pi_tuple *pi = iter->prot_buf + offset;
                u64 ref, seed;
                __be64 csum;
 
@@ -344,6 +360,10 @@ static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
                }
 
                csum = ext_pi_crc64(0, iter->data_buf, iter->interval);
+               if (offset)
+                       csum = ext_pi_crc64(be64_to_cpu(csum), iter->prot_buf,
+                                           offset);
+
                if (pi->guard_tag != csum) {
                        pr_err("%s: guard tag error at sector %llu " \
                               "(rcvd %016llx, want %016llx)\n",
@@ -373,8 +393,10 @@ static blk_status_t ext_pi_type1_generate_crc64(struct blk_integrity_iter *iter)
 
 static void ext_pi_type1_prepare(struct request *rq)
 {
-       const int tuple_sz = rq->q->integrity.tuple_size;
+       struct blk_integrity *bi = &rq->q->integrity;
+       const int tuple_sz = bi->tuple_size;
        u64 ref_tag = ext_pi_ref_tag(rq);
+       u8 offset = bi->pi_offset;
        struct bio *bio;
 
        __rq_for_each_bio(bio, rq) {
@@ -393,7 +415,7 @@ static void ext_pi_type1_prepare(struct request *rq)
 
                        p = bvec_kmap_local(&iv);
                        for (j = 0; j < iv.bv_len; j += tuple_sz) {
-                               struct crc64_pi_tuple *pi = p;
+                               struct crc64_pi_tuple *pi = p +  offset;
                                u64 ref = get_unaligned_be48(pi->ref_tag);
 
                                if (ref == virt)
@@ -411,9 +433,11 @@ static void ext_pi_type1_prepare(struct request *rq)
 
 static void ext_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
 {
-       unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp;
-       const int tuple_sz = rq->q->integrity.tuple_size;
+       struct blk_integrity *bi = &rq->q->integrity;
+       unsigned intervals = nr_bytes >> bi->interval_exp;
+       const int tuple_sz = bi->tuple_size;
        u64 ref_tag = ext_pi_ref_tag(rq);
+       u8 offset = bi->pi_offset;
        struct bio *bio;
 
        __rq_for_each_bio(bio, rq) {
@@ -428,7 +452,7 @@ static void ext_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
 
                        p = bvec_kmap_local(&iv);
                        for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) {
-                               struct crc64_pi_tuple *pi = p;
+                               struct crc64_pi_tuple *pi = p + offset;
                                u64 ref = get_unaligned_be48(pi->ref_tag);
 
                                if (ref == ref_tag)
index 378b2459efe2da03565997d0980ed10656516c17..e253e7bd0d1793f23f1de2fb03a9032c66bbe659 100644 (file)
@@ -20,6 +20,7 @@ struct blk_integrity_iter {
        unsigned int            data_size;
        unsigned short          interval;
        unsigned char           tuple_size;
+       unsigned char           pi_offset;
        const char              *disk_name;
 };
 
index fac580976e3a693d8948c64d64857dc8b7deb6db..0058783a4c4351f8e14d9a8822de4410b4cd77b5 100644 (file)
@@ -108,6 +108,7 @@ struct blk_integrity {
        const struct blk_integrity_profile      *profile;
        unsigned char                           flags;
        unsigned char                           tuple_size;
+       unsigned char                           pi_offset;
        unsigned char                           interval_exp;
        unsigned char                           tag_size;
 };