64-bit data integrity field support
Subsystems (7)
Keith Busch
maintainerv4 cover 64-bit data integrity field support
The NVM Express protocol added enhancements to the data integrity field formats beyond the T10 defined protection information. A detailed description of the new formats can be found in the NVMe's NVM Command Set Specification, section 5.2, available at:
https://nvmexpress.org/wp-content/uploads/NVM-Command-Set-Specification-1.0b-2021.12.18-Ratified.pdf
This series implements one possible new format: the CRC64 guard with 48-bit reference tags. This does not add support for the variable "storage tag" field, or any potential hardware acceleration.
Changes since v3:
- Replaced lower_48_bits() macro with inline function, and replaced
0xffffffffffffull with the equivalent (1ull << 48) - 1
- Replaced crc64 test module with new entry in crypto/testmgr.c
- Renamed nvme_ function prefixes with ext_pi_
- Placed bit inversion within crc64 calculation rather than rely on the caller to pass in an inverted initial value. This is necessary to update the crc value when its buffer is discontiguous, or updated in chunks.
- Removed 'inline' from nvme driver's ref tag setup.
- Added Review's for unchanged patches, removed reviews for the ones that changed.
- lib/Kconfig dependency fix
- Dropped the x86_64 PCLMULQDQ accelerated calculation. This task will be completed by people more experienced in this area, so expect a follow up soon.
Keith Busch (8):
block: support pi with extended metadata
nvme: allow integrity on extended metadata formats
asm-generic: introduce be48 unaligned accessors linux/kernel: introduce lower_48_bits function
lib: add rocksoft model crc64
crypto: add rocksoft 64b crc guard tag framework
block: add pi for nvme enhanced integrity
nvme: add support for enhanced metadata
block/Kconfig | 1 + block/bio-integrity.c | 1 + block/t10-pi.c | 198 +++++++++++++++++++++++++++++++- crypto/Kconfig | 5 + crypto/Makefile | 1 + crypto/crc64_rocksoft_generic.c | 89 ++++++++++++++ crypto/testmgr.c | 7 ++ crypto/testmgr.h | 15 +++ drivers/nvme/host/core.c | 165 +++++++++++++++++++++----- drivers/nvme/host/nvme.h | 4 +- include/asm-generic/unaligned.h | 26 +++++ include/linux/blk-integrity.h | 1 + include/linux/crc64.h | 7 ++ include/linux/kernel.h | 9 ++ include/linux/nvme.h | 53 ++++++++- include/linux/t10-pi.h | 20 ++++ lib/Kconfig | 9 ++ lib/Makefile | 1 + lib/crc64-rocksoft.c | 129 +++++++++++++++++++++ lib/crc64.c | 28 +++++ lib/gen_crc64table.c | 51 ++++++-- 21 files changed, 773 insertions(+), 47 deletions(-) create mode 100644 crypto/crc64_rocksoft_generic.c create mode 100644 lib/crc64-rocksoft.c
Signature · 1 line
2.25.4
Keith Busch
maintainerPATCH v4 1/8 block: support pi with extended metadata
The nvme spec allows protection information formats with metadata extending beyond the pi field. Use the actual size of the metadata field for incrementing the buffer.
--- block/bio-integrity.c | 1 + block/t10-pi.c | 4 ++-- include/linux/blk-integrity.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-)
block/bio-integrity.c +1 -0
@@ -165,6 +165,7 @@ static blk_status_t bio_integrity_process(struct bio *bio, iter.disk_name = bio->bi_bdev->bd_disk->disk_name; iter.interval =1 << bi->interval_exp; + iter.tuple_size = bi->tuple_size; iter.seed = proc_iter->bi_sector; iter.prot_buf =bvec_virt (bip->bip_vec);
block/t10-pi.c +2 -2
@@ -44,7 +44,7 @@ static blk_status_t t10_pi_generate(struct blk_integrity_iter *iter, pi->ref_tag =0 ; iter->data_buf += iter->interval; - iter->prot_buf +=sizeof (struct t10_pi_tuple ); + iter->prot_buf += iter->tuple_size; iter->seed++; }
@@ -93,7 +93,7 @@ static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter, next: iter->data_buf += iter->interval; - iter->prot_buf +=sizeof (struct t10_pi_tuple ); + iter->prot_buf += iter->tuple_size; iter->seed++; }
include/linux/blk-integrity.h +1 -0
@@ -19,6 +19,7 @@ struct blk_integrity_iter {sector_t seed;unsigned int data_size;unsigned short interval; +unsigned char tuple_size;const char *disk_name; };
Signature · 1 line
2.25.4
Keith Busch
maintainerPATCH v4 2/8 nvme: allow integrity on extended metadata formats
In reply to Keith BuschThe block integrity subsystem knows how to construct protection information buffers with metadata beyond the protection information fields. Remove the driver restriction.
Note, this can only work if the PI field appears first in the metadata, as the integrity subsystem doesn't calculate guard tags on preceding metadata.
--- drivers/nvme/host/core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/nvme/host/core.c +2 -5
@@ -1754,12 +1754,9 @@ static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id) {struct nvme_ctrl *ctrl = ns->ctrl; -/* -* The PI implementation requires the metadata size to be equal to the -* t10 pi tuple size. -*/ ns->ms =le16_to_cpu (id->lbaf[id->flbas &NVME_NS_FLBAS_LBA_MASK ].ms); -if (ns->ms ==sizeof (struct t10_pi_tuple )) +if (id->dps &NVME_NS_DPS_PI_FIRST || + ns->ms ==sizeof (struct t10_pi_tuple )) ns->pi_type = id->dps &NVME_NS_DPS_PI_MASK ;else ns->pi_type =0 ;
Signature · 1 line
2.25.4
Keith Busch
maintainerPATCH v4 3/8 asm-generic: introduce be48 unaligned accessors
In reply to Keith BuschThe NVMe protocol extended the data integrity fields with unaligned 48-bit reference tags. Provide some helper accessors in preparation for these.
--- include/asm-generic/unaligned.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
include/asm-generic/unaligned.h +26 -0
@@ -126,4 +126,30 @@ static inline void put_unaligned_le24(const u32 val, void *p)__put_unaligned_le24 (val, p); } +static inline void __put_unaligned_be48 (const u64 val,__u8 *p) +{ + *p++ = val >>40 ; + *p++ = val >>32 ; + *p++ = val >>24 ; + *p++ = val >>16 ; + *p++ = val >>8 ; + *p++ = val; +} + +static inline void put_unaligned_be48 (const u64 val,void *p) +{ +__put_unaligned_be48 (val, p); +} + +static inline u64 __get_unaligned_be48 (const u8 *p) +{ +return (u64 )p[0 ] <<40 | (u64 )p[1 ] <<32 | p[2 ] <<24 | + p[3 ] <<16 | p[4 ] <<8 | p[5 ]; +} + +static inline u64 get_unaligned_be48 (const void *p) +{ +return __get_unaligned_be48 (p); +} +#endif /* __ASM_GENERIC_UNALIGNED_H */
Signature · 1 line
2.25.4
Re: [PATCHv4 3/8] asm-generic: introduce be48 unaligned accessors
Quoted 3 lines · Keith Busch
The NVMe protocol extended the data integrity fields with unaligned 48-bit reference tags. Provide some helper accessors in preparation for these.
RE: [PATCHv4 3/8] asm-generic: introduce be48 unaligned accessors
In reply to Keith BuschFrom: Keith Busch
Quoted 4 lines
Sent: 03 March 2022 20:13
The NVMe protocol extended the data integrity fields with unaligned 48-bit reference tags.
If they are reference tags, are they only interpreted by the sending system?
In which case they don't need to be big-endian since the actual value doesn't really matter.
Quoted 2 lines
Provide some helper accessors in preparation for these.
...
Quoted 7 lines
include/asm-generic/unaligned.h +0
-0@@ -126,4 +126,30 @@ static inline void put_unaligned_le24(const u32 val, void *p)__put_unaligned_le24 (val, p); }
include/asm-generic/unaligned.h static inline void put_unaligned_le24(const u32 val, void *p) · line 137
Quoted 10 lines
include/asm-generic/unaligned.h +9
-0+static inline void __put_unaligned_be48 (const u64 val,__u8 *p) +{ + *p++ = val >>40 ; + *p++ = val >>32 ; + *p++ = val >>24 ; + *p++ = val >>16 ; + *p++ = val >>8 ; + *p++ = val; +}
Although that matches __put_unaligned_be24() I think I'd use array indexing not pointer increments.
The compiler will probably generate the same code anyway.
However it is probably better to do:
put_unaligned_be16(val >> 32, p); put_unaligned_be32(val, p + 2);
so you get 2 memory accesses on x86 (etc) instead of 6.
Similarly for __get_unaligned_be48() where it is likely so make a bigger difference.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCHv4 3/8] asm-generic: introduce be48 unaligned accessors
David,
Quoted 3 lines
If they are reference tags, are they only interpreted by the sending system? In which case they don't need to be big-endian since the actual value doesn't really matter.
The tags are validated by the storage device.
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
Keith Busch
maintainerRe: [PATCHv4 3/8] asm-generic: introduce be48 unaligned accessors
In reply to David LaightQuoted 8 lines · David Laight
From: Keith Busch
Quoted 4 lines
Sent: 03 March 2022 20:13
The NVMe protocol extended the data integrity fields with unaligned 48-bit reference tags.
If they are reference tags, are they only interpreted by the sending system?
No, this field participates in end-to-end data protection formats, so is verified on both sides.
Keith Busch
maintainerPATCH v4 4/8 linux/kernel: introduce lower_48_bits function
In reply to Keith BuschRecent data integrity field enhancements allow reference tags to be up to 48 bits. Introduce an inline helper function since this will be a repeated operation.
--- include/linux/kernel.h | 9 +++++++++ 1 file changed, 9 insertions(+)
include/linux/kernel.h +9 -0
@@ -63,6 +63,15 @@ } \ ) +/** +* lower_48_bits() - return bits 0-47 of a number +* @n: the number we're accessing +*/ +static inline u64 lower_48_bits (u64 n) +{ +return n & ((1ull <<48 ) -1 ); +} +/** * upper_32_bits - return bits 32-63 of a number * @n: the number we're accessing
Signature · 1 line
2.25.4
Re: [PATCHv4 4/8] linux/kernel: introduce lower_48_bits function
Quoted 3 lines · Keith Busch
Recent data integrity field enhancements allow reference tags to be up to 48 bits. Introduce an inline helper function since this will be a repeated operation.
Keith Busch
maintainerPATCH v4 5/8 lib: add rocksoft model crc64
In reply to Keith BuschThe NVM Express specification extended data integrity fields to 64 bits using the Rocksoft parameters. Add the poly to the crc64 table generation, and provide a generic library routine implementing the algorithm.
The Rocksoft 64-bit CRC model parameters are as follows:
Poly: 0xAD93D23594C93659
Initial value: 0xFFFFFFFFFFFFFFFF
Reflected Input: True
Reflected Output: True
Xor Final: 0xFFFFFFFFFFFFFFFFSince this model used reflected bits, the implementation generates the reflected table so the result is ordered consistently.
---v3->v4:
Require the caller to provide 0 for the initial value. This means the calculation is responsible to invert it now, and makes updating the crc in multiple chunks easier.
include/linux/crc64.h | 2 ++ lib/crc64.c | 28 ++++++++++++++++++++++++ lib/gen_crc64table.c | 51 +++++++++++++++++++++++++++++++++---------- 3 files changed, 70 insertions(+), 11 deletions(-)
include/linux/crc64.h +2 -0
@@ -8,4 +8,6 @@#include <linux/types.h> u64 __pure crc64_be (u64 crc,const void *p,size_t len); +u64 __pure crc64_rocksoft_generic (u64 crc,const void *p,size_t len); +#endif /* _LINUX_CRC64_H */
lib/crc64.c +28 -0
@@ -22,6 +22,13 @@* x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 + * x^7 + x^4 + x + 1 * +* crc64rocksoft[256] table is from the Rocksoft specification polynomial +* defined as, +* +* x^64 + x^63 + x^61 + x^59 + x^58 + x^56 + x^55 + x^52 + x^49 + x^48 + x^47 + +* x^46 + x^44 + x^41 + x^37 + x^36 + x^34 + x^32 + x^31 + x^28 + x^26 + x^23 + +* x^22 + x^19 + x^16 + x^13 + x^12 + x^10 + x^9 + x^6 + x^4 + x^3 + 1 +* * Copyright 2018 SUSE Linux. * Author: Coly Li <[email protected]> */
@@ -55,3 +62,24 @@ u64 __pure crc64_be(u64 crc, const void *p, size_t len)return crc; }EXPORT_SYMBOL_GPL (crc64_be); + +/** +* crc64_rocksoft_generic - Calculate bitwise Rocksoft CRC64 +* @crc: seed value for computation. 0 for a new CRC calculation, or the +* previous crc64 value if computing incrementally. +* @p: pointer to buffer over which CRC64 is run +* @len: length of buffer @p +*/ +u64 __pure crc64_rocksoft_generic (u64 crc,const void *p,size_t len) +{ +const unsigned char *_p = p; +size_t i; + + crc = ~crc; + +for (i =0 ; i < len; i++) + crc = (crc >>8 ) ^ crc64rocksofttable[(crc &0xff ) ^ *_p++]; + +return ~crc; +} +EXPORT_SYMBOL_GPL (crc64_rocksoft_generic);
lib/gen_crc64table.c +40 -11
85 lines not on this page · raw message
Signature · 1 line
2.25.4
Re: [PATCHv4 5/8] lib: add rocksoft model crc64
Keith,
Quoted 4 lines
The NVM Express specification extended data integrity fields to 64 bits using the Rocksoft parameters. Add the poly to the crc64 table generation, and provide a generic library routine implementing the algorithm.
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
RE: [PATCHv4 5/8] lib: add rocksoft model crc64
In reply to Keith BuschFrom: Keith Busch
Quoted 8 lines
Sent: 03 March 2022 20:13
The NVM Express specification extended data integrity fields to 64 bits using the Rocksoft parameters. Add the poly to the crc64 table generation, and provide a generic library routine implementing the algorithm.
The Rocksoft 64-bit CRC model parameters are as follows:
Quoted 8 lines
Poly: 0xAD93D23594C93659 Initial value: 0xFFFFFFFFFFFFFFFF Reflected Input: True Reflected Output: True Xor Final: 0xFFFFFFFFFFFFFFFFSince this model used reflected bits, the implementation generates the reflected table so the result is ordered consistently.
Since the data is processed least significant bit first the table must be setup slightly differently.
...
Quoted 6 lines
+ * crc64rocksoft[256] table is from the Rocksoft specification polynomial
+ * defined as,
+ *
+ * x^64 + x^63 + x^61 + x^59 + x^58 + x^56 + x^55 + x^52 + x^49 + x^48 + x^47 +
+ * x^46 + x^44 + x^41 + x^37 + x^36 + x^34 + x^32 + x^31 + x^28 + x^26 + x^23 +
+ * x^22 + x^19 + x^16 + x^13 + x^12 + x^10 + x^9 + x^6 + x^4 + x^3 + 1
Which matches the Poly: 0xAD93D23594C93659 above.
...
Quoted 1 line
+#define
CRC64_ROCKSOFT_POLY0x9A6C9329AC4BC9B5ULL
But that value is clearly different.
You really ought to add a comment that each byte of the constant has to be bit reversed from the polynomial coefficients.
Quoted 8 lines
lib/gen_crc64table.c +7
-1-static void generate_crc64_table (void ) +static void generate_reflected_crc64_table (uint64_t table[256 ],uint64_t poly) +{ +uint64_t i, j, c, crc; + +for (i =0 ; i <256 ; i++) { + crc =0ULL ; + c = i;
lib/gen_crc64table.c line 41
Quoted 10 lines
lib/gen_crc64table.c +10
-0+ +for (j =0 ; j <8 ; j++) { +if ((crc ^ (c >> j)) &1 ) + crc = (crc >>1 ) ^ poly; +else + crc >>=1 ; + } + table[i] = crc; + } +}
That can be speeded up by using the identity:
table[x ^ y] == table[x] ^ table[y]
something like:
crc = poly; /* actually crc(1) */ table[0] = 0; table[1] = crc; for (i = 2; i < 8; i++) [ crc = crc & 1 ? (crc >> 1) ^ poly : crc >> 1; for (j = 0; j < 1u << i; j++) table[j + (1i << i)] = table[j] ^ crc; }
I think the same code can be used for a normal MSB first crc provided both the polynomial and crc(1) are passed in.
OTOH initialisation speed may not matter.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Keith Busch
maintainerRe: [PATCHv4 5/8] lib: add rocksoft model crc64
Quoted 14 lines · David Laight
That can be speeded up by using the identity:
table[x ^ y] == table[x] ^ table[y]something like:
crc = poly; /* actually crc(1) */ table[0] = 0; table[1] = crc; for (i = 2; i < 8; i++) [ crc = crc & 1 ? (crc >> 1) ^ poly : crc >> 1; for (j = 0; j < 1u << i; j++) table[j + (1i << i)] = table[j] ^ crc; }
Quoted 4 lines
I think the same code can be used for a normal MSB first crc provided both the polynomial and crc(1) are passed in.
OTOH initialisation speed may not matter.
I don't think speed is an issue here. This part is executed just once for the initial kernel compile, then never again.
Keith Busch
maintainerPATCH v4 6/8 crypto: add rocksoft 64b crc guard tag framework
In reply to Keith BuschHardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
---v3->v4:
Updated naming, and Kconfig help texts, and Kconfig dependency
Added crc64 test vectors to crypto/testmgr.c
Use unaligned le64 macros for setting the result
Use _GPL for EXPORT_SYMBOL
crypto/Kconfig | 5 ++ crypto/Makefile | 1 + crypto/crc64_rocksoft_generic.c | 89 ++++++++++++++++++++++ crypto/testmgr.c | 7 ++ crypto/testmgr.h | 15 ++++ include/linux/crc64.h | 5 ++ lib/Kconfig | 9 +++ lib/Makefile | 1 + lib/crc64-rocksoft.c | 129 ++++++++++++++++++++++++++++++++ 9 files changed, 261 insertions(+) create mode 100644 crypto/crc64_rocksoft_generic.c create mode 100644 lib/crc64-rocksoft.c
crypto/Kconfig +5 -0
@@ -735,6 +735,11 @@ config CRYPTO_CRCT10DIF_VPMSUM multiply-sum (vpmsum) instructions, introduced in POWER8. Enable on POWER8 and newer processors for improved performance. +config CRYPTO_CRC64_ROCKSOFT + tristate "Rocksoft Model CRC64 algorithm" + depends on CRC64 + select CRYPTO_HASH + config CRYPTO_VPMSUM_TESTER tristate "Powerpc64 vpmsum hardware acceleration tester" depends on CRYPTO_CRCT10DIF_VPMSUM && CRYPTO_CRC32C_VPMSUM
crypto/Makefile +1 -0
@@ -152,6 +152,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o +obj-$(CONFIG_CRYPTO_CRC64_ROCKSOFT) += crc64_rocksoft_generic.o obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o obj-$(CONFIG_CRYPTO_LZO) += lzo.o lzo-rle.o obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
crypto/crc64_rocksoft_generic.c new file +89 -0
89 lines not on this page · raw message
crypto/testmgr.c +7 -0
@@ -4526,6 +4526,13 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(crc32c_tv_template) } + }, { + .alg = "crc64-rocksoft", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { + .hash = __VECS(crc64_rocksoft_tv_template) + } }, { .alg = "crct10dif", .test = alg_test_hash,
crypto/testmgr.h +15 -0
@@ -3679,6 +3679,21 @@ static const struct hash_testvec rmd160_tv_template[] = { } }; +static const u8 zeroes[4096 ] = { [0 ...4095 ] =0 }; +static const u8 ones[4096 ] = { [0 ...4095 ] =0xff }; + +static const struct hash_testvec crc64_rocksoft_tv_template[] = { + { + .plaintext = zeroes, + .psize =4096 , + .digest = (u8 *)(u64 []){0x6482d367eb22b64eull }, + }, { + .plaintext = ones, + .psize =4096 , + .digest = (u8 *)(u64 []){0xc0ddba7302eca3acull }, + } +}; +static const struct hash_testvec crct10dif_tv_template[] = { { .plaintext ="abc" ,
include/linux/crc64.h +5 -0
@@ -7,7 +7,12 @@#include <linux/types.h> +#define CRC64_ROCKSOFT_STRING "crc64-rocksoft" +u64 __pure crc64_be (u64 crc,const void *p,size_t len);u64 __pure crc64_rocksoft_generic (u64 crc,const void *p,size_t len); +u64 crc64_rocksoft (const unsigned char *buffer,size_t len); +u64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len); +#endif /* _LINUX_CRC64_H */
lib/Kconfig +9 -0
@@ -146,6 +146,15 @@ config CRC_T10DIF kernel tree needs to calculate CRC checks for use with the SCSI data integrity subsystem. +config CRC64_ROCKSOFT + tristate "CRC calculation for the Rocksoft model CRC64" + select CRC64 + select CRYPTO + select CRYPTO_CRC64_ROCKSOFT + help + This option provides a CRC64 API to a registered crypto driver. + This is used with the block layer's data integrity subsystem. + config CRC_ITU_T tristate "CRC ITU-T V.41 functions" help
lib/Makefile +1 -0
@@ -175,6 +175,7 @@ obj-$(CONFIG_CRC4) += crc4.o obj-$(CONFIG_CRC7) += crc7.o obj-$(CONFIG_LIBCRC32C) += libcrc32c.o obj-$(CONFIG_CRC8) += crc8.o +obj-$(CONFIG_CRC64_ROCKSOFT) += crc64-rocksoft.o obj-$(CONFIG_XXHASH) += xxhash.o obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
lib/crc64-rocksoft.c new file +126 -0
126 lines not on this page · raw message
Signature · 1 line
2.25.4
Re: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
Quoted 4 lines · Keith Busch
Hardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
Hi Keith,
this is failing on big-endian systems. I get the following on s390:
[ 0.551573] crc32: CRC_LE_BITS = 64, CRC_BE BITS = 64 [ 0.551575] crc32: self tests passed, processed 225944 bytes in 118879 nsec [ 0.551697] crc32c: CRC_LE_BITS = 64 [ 0.551698] crc32c: self tests passed, processed 112972 bytes in 58963 nsec [ 0.577325] crc32_combine: 8373 self tests passed [ 0.603321] crc32c_combine: 8373 self tests passed [ 0.603502] alg: shash: crc64-rocksoft-generic test failed (wrong result) on test vector 0, cfg="init+update+final aligned buffer" [ 0.603506] ------------[ cut here ]------------ [ 0.603507] alg: self-tests for crc64-rocksoft-generic (crc64-rocksoft) failed (rc=-22) [ 0.603542] WARNING: CPU: 0 PID: 43 at crypto/testmgr.c:5726 alg_test+0x3c2/0x638 [ 0.603554] Modules linked in: [ 0.603557] CPU: 0 PID: 43 Comm: cryptomgr_test Not tainted 5.17.0-rc7-next-20220308-118584-gcb153b68ff91 #168 [ 0.603560] Hardware name: IBM 8561 T01 701 (KVM/Linux) [ 0.603562] Krnl PSW : 0704e00180000000 00000000007d2286 (alg_test+0x3c6/0x638) [ 0.603565] R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:2 PM:0 RI:0 EA:3 [ 0.603568] Krnl GPRS: 00000000ffffffea 000000000177c350 000000000000004b 00000000ffffefff [ 0.603570] 0000000001663ed0 0000038000000001 0000000001ed1720 0000000081a4e480 [ 0.603572] 0000000081a4e400 000003800000003e ffffffffffffffea 000000000000003e [ 0.603611] 0000000081a5a100 000000000000003e 00000000007d2282 00000380001b7cf0 [ 0.603618] Krnl Code: 00000000007d2276: c02000495b9e larl %r2,00000000010fd9b2 [ 0.603618] 00000000007d227c: c0e50026dbc6 brasl %r14,0000000000cada08 [ 0.603618] #00000000007d2282: af000000 mc 0,0 [ 0.603618] >00000000007d2286: b904002a lgr %r2,%r10 [ 0.603618] 00000000007d228a: eb6ff1380004 lmg %r6,%r15,312(%r15) [ 0.603618] 00000000007d2290: 07fe bcr 15,%r14 [ 0.603618] 00000000007d2292: 47000700 bc 0,1792 [ 0.603618] 00000000007d2296: 1842 lr %r4,%r2 [ 0.603632] Call Trace: [ 0.603634] [<00000000007d2286>] alg_test+0x3c6/0x638 [ 0.603636] ([<00000000007d2282>] alg_test+0x3c2/0x638) [ 0.603638] [<00000000007cfff8>] cryptomgr_test+0x68/0x70 [ 0.603641] [<000000000017b228>] kthread+0x108/0x110 [ 0.603646] [<0000000000103374>] __ret_from_fork+0x3c/0x58 [ 0.603650] [<0000000000ccc3ba>] ret_from_fork+0xa/0x40 [ 0.603658] Last Breaking-Event-Address: [ 0.603659] [<0000000000cada68>] __warn_printk+0x60/0x68 [ 0.603663] ---[ end trace 0000000000000000 ]---
Keith Busch
maintainerRe: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
Quoted 9 lines · Vasily Gorbik
Quoted 4 lines · Keith Busch
Hardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
Hi Keith,
this is failing on big-endian systems. I get the following on s390:
Oh, I see the put_unaligned_le64() in chksum_final() was not the correct action. I'll send an update, thank you for the report.
Keith Busch
maintainerRe: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
Quoted 7 lines · Keith Busch
Quoted 6 lines · Vasily Gorbik
Quoted 4 lines · Keith Busch
Hardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
Quoted 6 lines
Quoted 3 lines
Hi Keith,
this is failing on big-endian systems. I get the following on s390:
Oh, I see the
put_unaligned_le64()inchksum_final()was not the correct action. I'll send an update, thank you for the report.
I'll set up a BE qemu target this week, but in the meantime, would you be able to confirm if the following is successful?
---
crypto/crc64_rocksoft_generic.c +2 -2
@@ -28,14 +28,14 @@ static int chksum_final(struct shash_desc *desc, u8 *out) {u64 *crc =shash_desc_ctx (desc); -put_unaligned_le64 (*crc, out); +put_unaligned (*crc, (u64 *)out);return 0 ; }static int __chksum_finup (u64 crc,const u8 *data,unsigned int len,u8 *out) { crc =crc64_rocksoft_generic (crc, data, len); -put_unaligned_le64 (crc, out); +put_unaligned (crc, (u64 *)out);return 0 ; }
--
Re: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
Quoted 10 lines · Keith Busch
Quoted 9 lines · Keith Busch
Quoted 8 lines · Vasily Gorbik
Quoted 4 lines · Keith Busch
Hardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
Hi Keith,
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
this is failing on big-endian systems. I get the following on s390:
Oh, I see the
put_unaligned_le64()inchksum_final()was not the correct action. I'll send an update, thank you for the report.I'll set up a BE qemu target this week, but in the meantime, would you be able to confirm if the following is successful?
Sure,
[ 0.543862] crc32: CRC_LE_BITS = 64, CRC_BE BITS = 64 [ 0.543864] crc32: self tests passed, processed 225944 bytes in 118678 nsec [ 0.543986] crc32c: CRC_LE_BITS = 64 [ 0.543987] crc32c: self tests passed, processed 112972 bytes in 58932 nsec [ 0.569479] crc32_combine: 8373 self tests passed [ 0.595330] crc32c_combine: 8373 self tests passed
it does the trick. Thanks!
Eric Biggers
maintainerRe: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
In reply to Keith BuschQuoted 7 lines · Keith Busch
Quoted 6 lines · Vasily Gorbik
Quoted 4 lines · Keith Busch
Hardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
Quoted 6 lines
Quoted 3 lines
Hi Keith,
this is failing on big-endian systems. I get the following on s390:
Oh, I see the
put_unaligned_le64()inchksum_final()was not the correct action. I'll send an update, thank you for the report.
Or you could make the digests in your test vectors have have a consistent byte order, probably little endian. That's how "shash" algorithms in the crypto API normally work, including crc32 and crc32c; they produce bytes as output. I see that crct10dif violates that convention, and I assume you copied it from there. I'm not sure you should do that; crct10dif might be more of a one-off quirk.
- Eric
Keith Busch
maintainerRe: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
Quoted 12 lines · Eric Biggers
Quoted 11 lines · Keith Busch
Quoted 9 lines · Vasily Gorbik
Quoted 4 lines · Keith Busch
Hardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
Hi Keith,
this is failing on big-endian systems. I get the following on s390:
Quoted 8 lines
Quoted 2 lines
Oh, I see the
put_unaligned_le64()inchksum_final()was not the correct action. I'll send an update, thank you for the report.Or you could make the digests in your test vectors have have a consistent byte order, probably little endian. That's how "shash" algorithms in the crypto API normally work, including crc32 and crc32c; they produce bytes as output. I see that crct10dif violates that convention, and I assume you copied it from there. I'm not sure you should do that; crct10dif might be more of a one-off quirk.
Right, I started with the t10dif implementation. I changed it to the unaligned accessor since you indicated the output buffer doesn't have an alignment guarantee.
Perhaps I'm missing something, but it looks easier to just use the CPU native endianess here. The only users for t10 and rocksoft transform to big-endian for the wire protocol at the end, but there's no need to maintain a specific byte order before setting the payload.
Eric Biggers
maintainerRe: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
Quoted 22 lines · Keith Busch
Quoted 12 lines · Eric Biggers
Quoted 11 lines · Keith Busch
Quoted 9 lines · Vasily Gorbik
Quoted 4 lines · Keith Busch
Hardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
Hi Keith,
this is failing on big-endian systems. I get the following on s390:
Quoted 8 lines
Quoted 2 lines
Oh, I see the
put_unaligned_le64()inchksum_final()was not the correct action. I'll send an update, thank you for the report.Or you could make the digests in your test vectors have have a consistent byte order, probably little endian. That's how "shash" algorithms in the crypto API normally work, including crc32 and crc32c; they produce bytes as output. I see that crct10dif violates that convention, and I assume you copied it from there. I'm not sure you should do that; crct10dif might be more of a one-off quirk.
Quoted 8 lines
Right, I started with the t10dif implementation. I changed it to the unaligned accessor since you indicated the output buffer doesn't have an alignment guarantee.
Perhaps I'm missing something, but it looks easier to just use the CPU native endianess here. The only users for t10 and rocksoft transform to big-endian for the wire protocol at the end, but there's no need to maintain a specific byte order before setting the payload.
The issue is that every other "shash" algorithm besides crct10dif, including crc32 and crc32c, follow the convention of treating the digest as bytes. Doing otherwise is unusual for the crypto API. So I have a slight preference for treating it as bytes. Perhaps see what Herbert Xu (maintainer of the crypto API, Cc'ed) recommends?
- Eric
Keith Busch
maintainerRe: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
Quoted 5 lines · Eric Biggers
The issue is that every other "shash" algorithm besides crct10dif, including crc32 and crc32c, follow the convention of treating the digest as bytes. Doing otherwise is unusual for the crypto API. So I have a slight preference for treating it as bytes. Perhaps see what Herbert Xu (maintainer of the crypto API, Cc'ed) recommends?
I'm okay either way, they're both simple enough. Here is an update atop this series to match the other shash conventions if this is preferred over my previous fix:
---
block/t10-pi.c +1 -1
@@ -282,7 +282,7 @@ EXPORT_SYMBOL(t10_pi_type3_ip);static __be64 ext_pi_crc64 (void *data,unsigned int len) { -return cpu_to_be64 (crc64_rocksoft (data, len)); +return cpu_to_be64 (le64_to_cpu (crc64_rocksoft (data, len))); } static blk_status_t ext_pi_crc64_generate(struct blk_integrity_iter *iter,
crypto/testmgr.h +2 -2
@@ -3686,11 +3686,11 @@ static const struct hash_testvec crc64_rocksoft_tv_template[] = { { .plaintext = zeroes, .psize = 4096, - .digest = (u8 *)(u64[]){ 0x6482d367eb22b64eull }, + .digest = "\x4e\xb6\x22\xeb\x67\xd3\x82\x64", }, { .plaintext = ones, .psize = 4096, - .digest = (u8 *)(u64[]){ 0xc0ddba7302eca3acull }, + .digest = "\xac\xa3\xec\x02\x73\xba\xdd\xc0", } };
include/linux/crc64.h +2 -2
@@ -12,7 +12,7 @@u64 __pure crc64_be (u64 crc,const void *p,size_t len);u64 __pure crc64_rocksoft_generic (u64 crc,const void *p,size_t len); -u64 crc64_rocksoft (const unsigned char *buffer,size_t len); -u64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len); +__le64 crc64_rocksoft (const unsigned char *buffer,size_t len); +__le64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len);#endif /* _LINUX_CRC64_H */
lib/crc64-rocksoft.c +4 -4
@@ -54,16 +54,16 @@ static struct notifier_block crc64_rocksoft_nb = { .notifier_call = crc64_rocksoft_notify, }; -u64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len) +__le64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len) {struct {struct shash_desc shash; -u64 crc; +__le64 crc; } desc;int err;if (static_branch_unlikely (&crc64_rocksoft_fallback)) -return crc64_rocksoft_generic (crc, buffer, len); +return cpu_to_le64 (crc64_rocksoft_generic (crc, buffer, len));rcu_read_lock (); desc.shash.tfm =rcu_dereference (crc64_rocksoft_tfm);
@@ -77,7 +77,7 @@ u64 crc64_rocksoft_update(u64 crc, const unsigned char *buffer, size_t len) }EXPORT_SYMBOL_GPL (crc64_rocksoft_update); -u64 crc64_rocksoft (const unsigned char *buffer,size_t len) +__le64 crc64_rocksoft (const unsigned char *buffer,size_t len) {return crc64_rocksoft_update (0 , buffer, len); }
--
Eric Biggers
maintainerRe: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
Quoted 82 lines · Keith Busch
Quoted 5 lines · Eric Biggers
The issue is that every other "shash" algorithm besides crct10dif, including crc32 and crc32c, follow the convention of treating the digest as bytes. Doing otherwise is unusual for the crypto API. So I have a slight preference for treating it as bytes. Perhaps see what Herbert Xu (maintainer of the crypto API, Cc'ed) recommends?
I'm okay either way, they're both simple enough. Here is an update atop this series to match the other shash conventions if this is preferred over my previous fix:
---
block/t10-pi.c +1
-1@@ -282,7 +282,7 @@ EXPORT_SYMBOL(t10_pi_type3_ip);static __be64 ext_pi_crc64 (void *data,unsigned int len) { -return cpu_to_be64 (crc64_rocksoft (data, len)); +return cpu_to_be64 (le64_to_cpu (crc64_rocksoft (data, len))); } static blk_status_t ext_pi_crc64_generate(struct blk_integrity_iter *iter,crypto/testmgr.h +2
-2@@ -3686,11 +3686,11 @@ static const struct hash_testvec crc64_rocksoft_tv_template[] = { { .plaintext = zeroes, .psize = 4096, - .digest = (u8 *)(u64[]){ 0x6482d367eb22b64eull }, + .digest = "\x4e\xb6\x22\xeb\x67\xd3\x82\x64", }, { .plaintext = ones, .psize = 4096, - .digest = (u8 *)(u64[]){ 0xc0ddba7302eca3acull }, + .digest = "\xac\xa3\xec\x02\x73\xba\xdd\xc0", } };include/linux/crc64.h +2
-2@@ -12,7 +12,7 @@u64 __pure crc64_be (u64 crc,const void *p,size_t len);u64 __pure crc64_rocksoft_generic (u64 crc,const void *p,size_t len); -u64 crc64_rocksoft (const unsigned char *buffer,size_t len); -u64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len); +__le64 crc64_rocksoft (const unsigned char *buffer,size_t len); +__le64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len);#endif /* _LINUX_CRC64_H */ lib/crc64-rocksoft.c +3
-3@@ -54,16 +54,16 @@ static struct notifier_block crc64_rocksoft_nb = { .notifier_call = crc64_rocksoft_notify, }; -u64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len) +__le64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len) {struct {struct shash_desc shash; -u64 crc; +__le64 crc; } desc;int err;if (static_branch_unlikely (&crc64_rocksoft_fallback)) -return crc64_rocksoft_generic (crc, buffer, len); +return cpu_to_le64 (crc64_rocksoft_generic (crc, buffer, len));rcu_read_lock (); desc.shash.tfm =rcu_dereference (crc64_rocksoft_tfm);
lib/crc64-rocksoft.c u64 crc64_rocksoft_update(u64 crc, const unsigned char *buffer, size_t len)
Quoted 9 lines
lib/crc64-rocksoft.c +1
-2@@ -77,7 +77,7 @@ u64 crc64_rocksoft_update(u64 crc, const unsigned char *buffer, size_t len) }EXPORT_SYMBOL_GPL (crc64_rocksoft_update); -u64 crc64_rocksoft (const unsigned char *buffer,size_t len) +__le64 crc64_rocksoft (const unsigned char *buffer,size_t len) {return crc64_rocksoft_update (0 , buffer, len); } --
I think the lib functions should still use native endianness, like what crc32 does.
- Eric
Keith Busch
maintainerRe: [PATCHv4 6/8] crypto: add rocksoft 64b crc guard tag framework
Quoted 2 lines · Eric Biggers
I think the lib functions should still use native endianness, like what crc32 does.
Gotcha, then it should simply be this patch:
---
crypto/testmgr.h +2 -2
@@ -3686,11 +3686,11 @@ static const struct hash_testvec crc64_rocksoft_tv_template[] = { { .plaintext = zeroes, .psize = 4096, - .digest = (u8 *)(u64[]){ 0x6482d367eb22b64eull }, + .digest = "\x4e\xb6\x22\xeb\x67\xd3\x82\x64", }, { .plaintext = ones, .psize = 4096, - .digest = (u8 *)(u64[]){ 0xc0ddba7302eca3acull }, + .digest = "\xac\xa3\xec\x02\x73\xba\xdd\xc0", } };
--
Keith Busch
maintainerPATCH v4 7/8 block: add pi for extended integrity
In reply to Keith BuschThe 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".
---v3->v4:
Renamed nvme_ prefixes with ext_ for extended protection information.
Use _GPL for EXPORT_SYMBOL
block/Kconfig | 1 + block/t10-pi.c | 194 +++++++++++++++++++++++++++++++++++++++++ include/linux/t10-pi.h | 20 +++++ 3 files changed, 215 insertions(+)
block/Kconfig +1 -0
@@ -73,6 +73,7 @@ config BLK_DEV_INTEGRITY_T10 tristate depends on BLK_DEV_INTEGRITY select CRC_T10DIF + select CRC64_ROCKSOFT config BLK_DEV_ZONED bool "Zoned block device support"
block/t10-pi.c +194 -0
206 lines not on this page · raw message
include/linux/t10-pi.h +20 -0
@@ -53,4 +53,24 @@ 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 { +__be64 guard_tag; +__be16 app_tag; +__u8 ref_tag[6 ]; +}; + +static inline u64 ext_pi_ref_tag (struct request *rq) +{ +unsigned int shift =ilog2 (queue_logical_block_size (rq->q)); + +#ifdef CONFIG_BLK_DEV_INTEGRITY +if (rq->q->integrity.interval_exp) + shift = rq->q->integrity.interval_exp; +#endif +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
Signature · 1 line
2.25.4
Re: [PATCHv4 7/8] block: add pi for extended integrity
Keith,
Quoted 4 lines
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".
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
Keith Busch
maintainerPATCH v4 8/8 nvme: add support for enhanced metadata
In reply to Keith BuschNVM Express ratified TP 4068 defines new protection information formats. Implement support for the CRC64 guard tags.
Since the block layer doesn't support variable length reference tags, driver support for the Storage Tag space is not supported at this time.
---v3->v4:
Removed inline for setting ref_tag
Updated new exported names from prior patches
drivers/nvme/host/core.c | 162 +++++++++++++++++++++++++++++++++------ drivers/nvme/host/nvme.h | 4 +- include/linux/nvme.h | 53 +++++++++++-- 3 files changed, 188 insertions(+), 31 deletions(-)
drivers/nvme/host/core.c +138 -24
@@ -919,6 +919,30 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,return BLK_STS_OK ; } +static void nvme_set_ref_tag (struct nvme_ns *ns,struct nvme_command *cmnd, +struct request *req) +{ +u32 upper, lower; +u64 ref48; + +/* both rw and write zeroes share the same reftag format */ +switch (ns->guard_type) { +case NVME_NVM_NS_16B_GUARD : + cmnd->rw.reftag =cpu_to_le32 (t10_pi_ref_tag (req)); +break ; +case NVME_NVM_NS_64B_GUARD : + ref48 =ext_pi_ref_tag (req); + lower =lower_32_bits (ref48); + upper =upper_32_bits (ref48); + + cmnd->rw.reftag =cpu_to_le32 (lower); + cmnd->rw.cdw3 =cpu_to_le32 (upper); +break ; +default : +break ; + } +} +static inline blk_status_t nvme_setup_write_zeroes (struct nvme_ns *ns,struct request *req,struct nvme_command *cmnd) {
@@ -940,8 +964,7 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns,switch (ns->pi_type) {case NVME_NS_DPS_PI_TYPE1 :case NVME_NS_DPS_PI_TYPE2 : - cmnd->write_zeroes.reftag = -cpu_to_le32 (t10_pi_ref_tag (req)); +nvme_set_ref_tag (ns, cmnd, req);break ; } }
@@ -968,7 +991,8 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns, cmnd->rw.opcode = op; cmnd->rw.flags =0 ; cmnd->rw.nsid =cpu_to_le32 (ns->head->ns_id); - cmnd->rw.rsvd2 =0 ; + cmnd->rw.cdw2 =0 ; + cmnd->rw.cdw3 =0 ; cmnd->rw.metadata =0 ; cmnd->rw.slba =cpu_to_le64 (nvme_sect_to_lba (ns,blk_rq_pos (req))); cmnd->rw.length =cpu_to_le16 ((blk_rq_bytes (req) >> ns->lba_shift) -1 );
@@ -1002,7 +1026,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,NVME_RW_PRINFO_PRCHK_REF ;if (op == nvme_cmd_zone_append) control |=NVME_RW_APPEND_PIREMAP ; - cmnd->rw.reftag =cpu_to_le32 (t10_pi_ref_tag (req)); +nvme_set_ref_tag (ns, cmnd, req);break ; } }
@@ -1654,33 +1678,58 @@ int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo) }#ifdef CONFIG_BLK_DEV_INTEGRITY -static void nvme_init_integrity (struct gendisk *disk,u16 ms,u8 pi_type, +static void nvme_init_integrity (struct gendisk *disk,struct nvme_ns *ns,u32 max_integrity_segments) {struct blk_integrity integrity = { }; -switch (pi_type) { +switch (ns->pi_type) {case NVME_NS_DPS_PI_TYPE3 : - integrity.profile = &t10_pi_type3_crc; - integrity.tag_size =sizeof (u16) +sizeof (u32); - integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +switch (ns->guard_type) { +case NVME_NVM_NS_16B_GUARD : + integrity.profile = &t10_pi_type3_crc; + integrity.tag_size =sizeof (u16) +sizeof (u32); + integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +break ; +case NVME_NVM_NS_64B_GUARD : + integrity.profile = &ext_pi_type3_crc64; + integrity.tag_size =sizeof (u16) +6 ; + integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +break ; +default : + integrity.profile =NULL ; +break ; + }break ;case NVME_NS_DPS_PI_TYPE1 :case NVME_NS_DPS_PI_TYPE2 : - integrity.profile = &t10_pi_type1_crc; - integrity.tag_size =sizeof (u16); - integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +switch (ns->guard_type) { +case NVME_NVM_NS_16B_GUARD : + integrity.profile = &t10_pi_type1_crc; + integrity.tag_size =sizeof (u16); + integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +break ; +case NVME_NVM_NS_64B_GUARD : + integrity.profile = &ext_pi_type1_crc64; + integrity.tag_size =sizeof (u16); + integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +break ; +default : + integrity.profile =NULL ; +break ; + }break ;default : integrity.profile =NULL ;break ; } - integrity.tuple_size = ms; + + integrity.tuple_size = ns->ms;blk_integrity_register (disk, &integrity);blk_queue_max_integrity_segments (disk->queue, max_integrity_segments); }#else -static void nvme_init_integrity (struct gendisk *disk,u16 ms,u8 pi_type, +static void nvme_init_integrity (struct gendisk *disk,struct nvme_ns *ns,u32 max_integrity_segments) { }
@@ -1750,17 +1799,73 @@ static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns,return 0 ; } -static void nvme_configure_metadata (struct nvme_ns *ns,struct nvme_id_ns *id) +static int nvme_init_ms (struct nvme_ns *ns,struct nvme_id_ns *id) { +bool first = id->dps &NVME_NS_DPS_PI_FIRST ; +unsigned lbaf =nvme_lbaf_index (id->flbas);struct nvme_ctrl *ctrl = ns->ctrl; +struct nvme_command c = { }; +struct nvme_id_ns_nvm *nvm; +int ret =0 ; +u32 elbaf; + + ns->pi_size =0 ; + ns->ms =le16_to_cpu (id->lbaf[lbaf].ms); +if (!(ctrl->ctratt &NVME_CTRL_ATTR_ELBAS )) { + ns->pi_size =sizeof (struct t10_pi_tuple ); + ns->guard_type =NVME_NVM_NS_16B_GUARD ; + goto set_pi; + } + + nvm =kzalloc (sizeof (*nvm),GFP_KERNEL ); +if (!nvm) +return -ENOMEM ; - ns->ms =le16_to_cpu (id->lbaf[id->flbas &NVME_NS_FLBAS_LBA_MASK ].ms); -if (id->dps &NVME_NS_DPS_PI_FIRST || - ns->ms ==sizeof (struct t10_pi_tuple )) + c.identify.opcode = nvme_admin_identify; + c.identify.nsid =cpu_to_le32 (ns->head->ns_id); + c.identify.cns =NVME_ID_CNS_CS_NS ; + c.identify.csi =NVME_CSI_NVM ; + + ret =nvme_submit_sync_cmd (ns->ctrl->admin_q, &c, nvm,sizeof (*nvm)); +if (ret) + goto free_data; + + elbaf =le32_to_cpu (nvm->elbaf[lbaf]); + +/* no support for storage tag formats right now */ +if (nvme_elbaf_sts (elbaf)) + goto free_data; + + ns->guard_type =nvme_elbaf_guard_type (elbaf); +switch (ns->guard_type) { +case NVME_NVM_NS_64B_GUARD : + ns->pi_size =sizeof (struct crc64_pi_tuple ); +break ; +case NVME_NVM_NS_16B_GUARD : + ns->pi_size =sizeof (struct t10_pi_tuple ); +break ; +default : +break ; + } + +free_data: +kfree (nvm); +set_pi: +if (ns->pi_size && (first || ns->ms == ns->pi_size)) ns->pi_type = id->dps &NVME_NS_DPS_PI_MASK ;else ns->pi_type =0 ; +return ret; +} + +static void nvme_configure_metadata (struct nvme_ns *ns,struct nvme_id_ns *id) +{ +struct nvme_ctrl *ctrl = ns->ctrl; + +if (nvme_init_ms (ns, id)) +return ; + ns->features &= ~(NVME_NS_METADATA_SUPPORTED |NVME_NS_EXT_LBAS );if (!ns->ms || !(ctrl->ops->flags &NVME_F_METADATA_SUPPORTED ))return ;
@@ -1877,7 +1982,7 @@ static void nvme_update_disk_info(struct gendisk *disk,if (ns->ms) {if (IS_ENABLED (CONFIG_BLK_DEV_INTEGRITY ) && (ns->features &NVME_NS_METADATA_SUPPORTED )) -nvme_init_integrity (disk, ns->ms, ns->pi_type, +nvme_init_integrity (disk, ns, ns->ctrl->max_integrity_segments);else if (!nvme_ns_has_pi (ns)) capacity =0 ;
@@ -1932,7 +2037,7 @@ static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)static int nvme_update_ns_info (struct nvme_ns *ns,struct nvme_id_ns *id) { -unsigned lbaf = id->flbas &NVME_NS_FLBAS_LBA_MASK ; +unsigned lbaf =nvme_lbaf_index (id->flbas);int ret;blk_mq_freeze_queue (ns->disk->queue);
@@ -2277,20 +2382,27 @@ static int nvme_configure_timestamp(struct nvme_ctrl *ctrl)return ret; } -static int nvme_configure_acre (struct nvme_ctrl *ctrl) +static int nvme_configure_host_options (struct nvme_ctrl *ctrl) {struct nvme_feat_host_behavior *host; +u8 acre =0 , lbafee =0 ;int ret;/* Don't bother enabling the feature if retry delay is not reported */ -if (!ctrl->crdt[0 ]) +if (ctrl->crdt[0 ]) + acre =NVME_ENABLE_ACRE ; +if (ctrl->ctratt &NVME_CTRL_ATTR_ELBAS ) + lbafee =NVME_ENABLE_LBAFEE ; + +if (!acre && !lbafee)return 0 ; host =kzalloc (sizeof (*host),GFP_KERNEL );if (!host)return 0 ; - host->acre =NVME_ENABLE_ACRE ; + host->acre = acre; + host->lbafee = lbafee; ret =nvme_set_features (ctrl,NVME_FEAT_HOST_BEHAVIOR ,0 , host,sizeof (*host),NULL );kfree (host);
@@ -3132,7 +3244,7 @@ int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl)if (ret <0 )return ret; - ret =nvme_configure_acre (ctrl); + ret =nvme_configure_host_options (ctrl);if (ret <0 )return ret;
@@ -4846,12 +4958,14 @@ static inline void _nvme_check_size(void)BUILD_BUG_ON (sizeof (struct nvme_id_ctrl ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_id_ns ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_id_ns_zns ) !=NVME_IDENTIFY_DATA_SIZE ); +BUILD_BUG_ON (sizeof (struct nvme_id_ns_nvm ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_id_ctrl_zns ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_id_ctrl_nvm ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_lba_range_type ) !=64 );BUILD_BUG_ON (sizeof (struct nvme_smart_log ) !=512 );BUILD_BUG_ON (sizeof (struct nvme_dbbuf ) !=64 );BUILD_BUG_ON (sizeof (struct nvme_directive_cmd ) !=64 ); +BUILD_BUG_ON (sizeof (struct nvme_feat_host_behavior ) !=512 ); }
drivers/nvme/host/nvme.h +3 -1
@@ -454,9 +454,11 @@ struct nvme_ns {int lba_shift;u16 ms; +u16 pi_size;u16 sgs;u32 sws;u8 pi_type; +u8 guard_type;#ifdef CONFIG_BLK_DEV_ZONED u64 zsze;#endif
@@ -479,7 +481,7 @@ struct nvme_ns {/* NVMe ns supports metadata actions by the controller (generate/strip) */ static inline bool nvme_ns_has_pi (struct nvme_ns *ns) { -return ns->pi_type && ns->ms ==sizeof (struct t10_pi_tuple ); +return ns->pi_type && ns->ms == ns->pi_size; }struct nvme_ctrl_ops {
include/linux/nvme.h +47 -6
105 lines not on this page · raw message
Signature · 1 line
2.25.4
Re: [PATCHv4 8/8] nvme: add support for enhanced metadata
Keith,
Quoted 6 lines
NVM Express ratified TP 4068 defines new protection information formats. Implement support for the CRC64 guard tags.
Since the block layer doesn't support variable length reference tags, driver support for the Storage Tag space is not supported at this time.
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
Keith Busch
maintainerHi Jens,
I believe this is looking ready at this point. Would it be too ambitious to see this applied ahead of 5.18? The block layer provides the focal point for new capabilities in this series, so I feel it should go through that tree if you're okay with this.
Thanks,
Keith
Jens Axboe
maintainerQuoted 6 lines · Keith Busch
Hi Jens,
I believe this is looking ready at this point. Would it be too ambitious to see this applied ahead of 5.18? The block layer provides the focal point for new capabilities in this series, so I feel it should go through that tree if you're okay with this.
Layered it on top of the write-streams changes to avoid a silly conflict.
Signature · 1 line
Jens Axboe
Quoted 8 lines · Keith Busch
The NVM Express protocol added enhancements to the data integrity field formats beyond the T10 defined protection information. A detailed description of the new formats can be found in the NVMe's NVM Command Set Specification, section 5.2, available at:
https://nvmexpress.org/wp-content/uploads/NVM-Command-Set-Specification-1.0b-2021.12.18-Ratified.pdf
[...]
Applied, thanks!
[1/8] block: support pi with extended metadata
commit: c340b990d58c856c1636e0c10abb9e4351ad852a
[2/8] nvme: allow integrity on extended metadata formats
commit: 84b735429f5fe6f57fc0b3fff3932dce1471e668
[3/8] asm-generic: introduce be48 unaligned accessors
commit: c2ea5fcf53d5f21e6aff0de11d55bc202822df6a
[4/8] linux/kernel: introduce lower_48_bits function
commit: 7ee8809df990d1de379002973baee1681e8d7dd3
[5/8] lib: add rocksoft model crc64
commit: cbc0a40e17da361a2ada8d669413ccfbd2028f2d
[6/8] crypto: add rocksoft 64b crc guard tag framework
commit: f3813f4b287e480b1fcd62ca798d8556644b8278
[7/8] block: add pi for extended integrity
commit: a7d4383f17e10f338ea757a849f02298790d24fb
[8/8] nvme: add support for enhanced metadata
commit: 4020aad85c6785ddac8d51f345ff9e3328ce773aBest regards,
Signature · 1 line
Jens Axboe