Skip to content

Commit a7d4383

Browse files
keithbuschaxboe
authored andcommitted
block: add pi for extended integrity
The NVMe specification defines new data integrity formats beyond the t10 tuple. Add support for the specification defined CRC64 formats, assuming the reference tag does not need to be split with the "storage tag". Cc: Hannes Reinecke <[email protected]> Cc: "Martin K. Petersen" <[email protected]> Signed-off-by: Keith Busch <[email protected]> Reviewed-by: Martin K. Petersen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent f3813f4 commit a7d4383

File tree

3 files changed

+215
-0
lines changed

3 files changed

+215
-0
lines changed

block/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ config BLK_DEV_INTEGRITY_T10
7373
tristate
7474
depends on BLK_DEV_INTEGRITY
7575
select CRC_T10DIF
76+
select CRC64_ROCKSOFT
7677

7778
config BLK_DEV_ZONED
7879
bool "Zoned block device support"

block/t10-pi.c

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
#include <linux/t10-pi.h>
88
#include <linux/blk-integrity.h>
99
#include <linux/crc-t10dif.h>
10+
#include <linux/crc64.h>
1011
#include <linux/module.h>
1112
#include <net/checksum.h>
13+
#include <asm/unaligned.h>
1214

1315
typedef __be16 (csum_fn) (void *, unsigned int);
1416

@@ -278,4 +280,196 @@ const struct blk_integrity_profile t10_pi_type3_ip = {
278280
};
279281
EXPORT_SYMBOL(t10_pi_type3_ip);
280282

283+
static __be64 ext_pi_crc64(void *data, unsigned int len)
284+
{
285+
return cpu_to_be64(crc64_rocksoft(data, len));
286+
}
287+
288+
static blk_status_t ext_pi_crc64_generate(struct blk_integrity_iter *iter,
289+
enum t10_dif_type type)
290+
{
291+
unsigned int i;
292+
293+
for (i = 0 ; i < iter->data_size ; i += iter->interval) {
294+
struct crc64_pi_tuple *pi = iter->prot_buf;
295+
296+
pi->guard_tag = ext_pi_crc64(iter->data_buf, iter->interval);
297+
pi->app_tag = 0;
298+
299+
if (type == T10_PI_TYPE1_PROTECTION)
300+
put_unaligned_be48(iter->seed, pi->ref_tag);
301+
else
302+
put_unaligned_be48(0ULL, pi->ref_tag);
303+
304+
iter->data_buf += iter->interval;
305+
iter->prot_buf += iter->tuple_size;
306+
iter->seed++;
307+
}
308+
309+
return BLK_STS_OK;
310+
}
311+
312+
static bool ext_pi_ref_escape(u8 *ref_tag)
313+
{
314+
static u8 ref_escape[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
315+
316+
return memcmp(ref_tag, ref_escape, sizeof(ref_escape)) == 0;
317+
}
318+
319+
static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
320+
enum t10_dif_type type)
321+
{
322+
unsigned int i;
323+
324+
for (i = 0; i < iter->data_size; i += iter->interval) {
325+
struct crc64_pi_tuple *pi = iter->prot_buf;
326+
u64 ref, seed;
327+
__be64 csum;
328+
329+
if (type == T10_PI_TYPE1_PROTECTION) {
330+
if (pi->app_tag == T10_PI_APP_ESCAPE)
331+
goto next;
332+
333+
ref = get_unaligned_be48(pi->ref_tag);
334+
seed = lower_48_bits(iter->seed);
335+
if (ref != seed) {
336+
pr_err("%s: ref tag error at location %llu (rcvd %llu)\n",
337+
iter->disk_name, seed, ref);
338+
return BLK_STS_PROTECTION;
339+
}
340+
} else if (type == T10_PI_TYPE3_PROTECTION) {
341+
if (pi->app_tag == T10_PI_APP_ESCAPE &&
342+
ext_pi_ref_escape(pi->ref_tag))
343+
goto next;
344+
}
345+
346+
csum = ext_pi_crc64(iter->data_buf, iter->interval);
347+
if (pi->guard_tag != csum) {
348+
pr_err("%s: guard tag error at sector %llu " \
349+
"(rcvd %016llx, want %016llx)\n",
350+
iter->disk_name, (unsigned long long)iter->seed,
351+
be64_to_cpu(pi->guard_tag), be64_to_cpu(csum));
352+
return BLK_STS_PROTECTION;
353+
}
354+
355+
next:
356+
iter->data_buf += iter->interval;
357+
iter->prot_buf += iter->tuple_size;
358+
iter->seed++;
359+
}
360+
361+
return BLK_STS_OK;
362+
}
363+
364+
static blk_status_t ext_pi_type1_verify_crc64(struct blk_integrity_iter *iter)
365+
{
366+
return ext_pi_crc64_verify(iter, T10_PI_TYPE1_PROTECTION);
367+
}
368+
369+
static blk_status_t ext_pi_type1_generate_crc64(struct blk_integrity_iter *iter)
370+
{
371+
return ext_pi_crc64_generate(iter, T10_PI_TYPE1_PROTECTION);
372+
}
373+
374+
static void ext_pi_type1_prepare(struct request *rq)
375+
{
376+
const int tuple_sz = rq->q->integrity.tuple_size;
377+
u64 ref_tag = ext_pi_ref_tag(rq);
378+
struct bio *bio;
379+
380+
__rq_for_each_bio(bio, rq) {
381+
struct bio_integrity_payload *bip = bio_integrity(bio);
382+
u64 virt = lower_48_bits(bip_get_seed(bip));
383+
struct bio_vec iv;
384+
struct bvec_iter iter;
385+
386+
/* Already remapped? */
387+
if (bip->bip_flags & BIP_MAPPED_INTEGRITY)
388+
break;
389+
390+
bip_for_each_vec(iv, bip, iter) {
391+
unsigned int j;
392+
void *p;
393+
394+
p = bvec_kmap_local(&iv);
395+
for (j = 0; j < iv.bv_len; j += tuple_sz) {
396+
struct crc64_pi_tuple *pi = p;
397+
u64 ref = get_unaligned_be48(pi->ref_tag);
398+
399+
if (ref == virt)
400+
put_unaligned_be48(ref_tag, pi->ref_tag);
401+
virt++;
402+
ref_tag++;
403+
p += tuple_sz;
404+
}
405+
kunmap_local(p);
406+
}
407+
408+
bip->bip_flags |= BIP_MAPPED_INTEGRITY;
409+
}
410+
}
411+
412+
static void ext_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
413+
{
414+
unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp;
415+
const int tuple_sz = rq->q->integrity.tuple_size;
416+
u64 ref_tag = ext_pi_ref_tag(rq);
417+
struct bio *bio;
418+
419+
__rq_for_each_bio(bio, rq) {
420+
struct bio_integrity_payload *bip = bio_integrity(bio);
421+
u64 virt = lower_48_bits(bip_get_seed(bip));
422+
struct bio_vec iv;
423+
struct bvec_iter iter;
424+
425+
bip_for_each_vec(iv, bip, iter) {
426+
unsigned int j;
427+
void *p;
428+
429+
p = bvec_kmap_local(&iv);
430+
for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) {
431+
struct crc64_pi_tuple *pi = p;
432+
u64 ref = get_unaligned_be48(pi->ref_tag);
433+
434+
if (ref == ref_tag)
435+
put_unaligned_be48(virt, pi->ref_tag);
436+
virt++;
437+
ref_tag++;
438+
intervals--;
439+
p += tuple_sz;
440+
}
441+
kunmap_local(p);
442+
}
443+
}
444+
}
445+
446+
static blk_status_t ext_pi_type3_verify_crc64(struct blk_integrity_iter *iter)
447+
{
448+
return ext_pi_crc64_verify(iter, T10_PI_TYPE3_PROTECTION);
449+
}
450+
451+
static blk_status_t ext_pi_type3_generate_crc64(struct blk_integrity_iter *iter)
452+
{
453+
return ext_pi_crc64_generate(iter, T10_PI_TYPE3_PROTECTION);
454+
}
455+
456+
const struct blk_integrity_profile ext_pi_type1_crc64 = {
457+
.name = "EXT-DIF-TYPE1-CRC64",
458+
.generate_fn = ext_pi_type1_generate_crc64,
459+
.verify_fn = ext_pi_type1_verify_crc64,
460+
.prepare_fn = ext_pi_type1_prepare,
461+
.complete_fn = ext_pi_type1_complete,
462+
};
463+
EXPORT_SYMBOL_GPL(ext_pi_type1_crc64);
464+
465+
const struct blk_integrity_profile ext_pi_type3_crc64 = {
466+
.name = "EXT-DIF-TYPE3-CRC64",
467+
.generate_fn = ext_pi_type3_generate_crc64,
468+
.verify_fn = ext_pi_type3_verify_crc64,
469+
.prepare_fn = t10_pi_type3_prepare,
470+
.complete_fn = t10_pi_type3_complete,
471+
};
472+
EXPORT_SYMBOL_GPL(ext_pi_type3_crc64);
473+
474+
MODULE_LICENSE("GPL");
281475
MODULE_LICENSE("GPL");

include/linux/t10-pi.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,24 @@ extern const struct blk_integrity_profile t10_pi_type1_ip;
5353
extern const struct blk_integrity_profile t10_pi_type3_crc;
5454
extern const struct blk_integrity_profile t10_pi_type3_ip;
5555

56+
struct crc64_pi_tuple {
57+
__be64 guard_tag;
58+
__be16 app_tag;
59+
__u8 ref_tag[6];
60+
};
61+
62+
static inline u64 ext_pi_ref_tag(struct request *rq)
63+
{
64+
unsigned int shift = ilog2(queue_logical_block_size(rq->q));
65+
66+
#ifdef CONFIG_BLK_DEV_INTEGRITY
67+
if (rq->q->integrity.interval_exp)
68+
shift = rq->q->integrity.interval_exp;
69+
#endif
70+
return lower_48_bits(blk_rq_pos(rq) >> (shift - SECTOR_SHIFT));
71+
}
72+
73+
extern const struct blk_integrity_profile ext_pi_type1_crc64;
74+
extern const struct blk_integrity_profile ext_pi_type3_crc64;
75+
5676
#endif

0 commit comments

Comments
 (0)