Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib: add crc64 calculation routines

Patch series "add crc64 calculation as kernel library", v5.

This patchset adds basic implementation of crc64 calculation as a Linux
kernel library. Since bcache already does crc64 by itself, this patchset
also modifies bcache code to use the new crc64 library routine.

Currently bcache is the only user of crc64 calculation, another potential
user is bcachefs which is on the way to be in mainline kernel. Therefore
it makes sense to make crc64 calculation to be a public library.

bcache uses crc64 as storage checksum, if a change of crc lib routines
results an inconsistent result, the unmatched checksum may make bcache
'think' the on-disk is corrupted, such a change should be avoided or
detected as early as possible. Therefore a patch is being prepared which
adds a crc test framework, to check consistency of different calculations.

This patch (of 2):

Add the re-write crc64 calculation routines for Linux kernel. The CRC64
polynomical arithmetic follows ECMA-182 specification, inspired by CRC
paper of Dr. Ross N. Williams (see
http://www.ross.net/crc/download/crc_v3.txt) and other public domain
implementations.

All the changes work in this way,
- When Linux kernel is built, host program lib/gen_crc64table.c will be
compiled to lib/gen_crc64table and executed.
- The output of gen_crc64table execution is an array called as lookup
table (a.k.a POLY 0x42f0e1eba9ea369) which contain 256 64-bit long
numbers, this table is dumped into header file lib/crc64table.h.
- Then the header file is included by lib/crc64.c for normal 64bit crc
calculation.
- Function declaration of the crc64 calculation routines is placed in
include/linux/crc64.h

Currently bcache is the only user of crc64_be(), another potential user is
bcachefs which is on the way to be in mainline kernel. Therefore it makes
sense to move crc64 calculation into lib/crc64.c as public code.

[colyli@suse.de: fix review comments from v4]
Link: http://lkml.kernel.org/r/20180726053352.2781-2-colyli@suse.de
Link: http://lkml.kernel.org/r/20180718165545.1622-2-colyli@suse.de
Signed-off-by: Coly Li <colyli@suse.de>
Co-developed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Michael Lyle <mlyle@lyle.org>
Cc: Kent Overstreet <kent.overstreet@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Kate Stewart <kstewart@linuxfoundation.org>
Cc: Eric Biggers <ebiggers3@gmail.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Noah Massey <noah.massey@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Coly Li and committed by
Linus Torvalds
feba04fd b15f5f1a

+156
+11
include/linux/crc64.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * See lib/crc64.c for the related specification and polynomial arithmetic. 4 + */ 5 + #ifndef _LINUX_CRC64_H 6 + #define _LINUX_CRC64_H 7 + 8 + #include <linux/types.h> 9 + 10 + u64 __pure crc64_be(u64 crc, const void *p, size_t len); 11 + #endif /* _LINUX_CRC64_H */
+2
lib/.gitignore
··· 2 2 # Generated files 3 3 # 4 4 gen_crc32table 5 + gen_crc64table 5 6 crc32table.h 7 + crc64table.h 6 8 oid_registry_data.c
+8
lib/Kconfig
··· 170 170 171 171 endchoice 172 172 173 + config CRC64 174 + tristate "CRC64 functions" 175 + help 176 + This option is provided for the case where no in-kernel-tree 177 + modules require CRC64 functions, but a module built outside 178 + the kernel tree does. Such modules that use library CRC64 179 + functions require M here. 180 + 173 181 config CRC4 174 182 tristate "CRC4 functions" 175 183 help
+11
lib/Makefile
··· 103 103 obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o 104 104 obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o 105 105 obj-$(CONFIG_CRC32) += crc32.o 106 + obj-$(CONFIG_CRC64) += crc64.o 106 107 obj-$(CONFIG_CRC32_SELFTEST) += crc32test.o 107 108 obj-$(CONFIG_CRC4) += crc4.o 108 109 obj-$(CONFIG_CRC7) += crc7.o ··· 218 217 obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o 219 218 220 219 hostprogs-y := gen_crc32table 220 + hostprogs-y += gen_crc64table 221 221 clean-files := crc32table.h 222 + clean-files += crc64table.h 222 223 223 224 $(obj)/crc32.o: $(obj)/crc32table.h 224 225 ··· 229 226 230 227 $(obj)/crc32table.h: $(obj)/gen_crc32table 231 228 $(call cmd,crc32) 229 + 230 + $(obj)/crc64.o: $(obj)/crc64table.h 231 + 232 + quiet_cmd_crc64 = GEN $@ 233 + cmd_crc64 = $< > $@ 234 + 235 + $(obj)/crc64table.h: $(obj)/gen_crc64table 236 + $(call cmd,crc64) 232 237 233 238 # 234 239 # Build a fast OID lookip registry from include/linux/oid_registry.h
+56
lib/crc64.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Normal 64-bit CRC calculation. 4 + * 5 + * This is a basic crc64 implementation following ECMA-182 specification, 6 + * which can be found from, 7 + * http://www.ecma-international.org/publications/standards/Ecma-182.htm 8 + * 9 + * Dr. Ross N. Williams has a great document to introduce the idea of CRC 10 + * algorithm, here the CRC64 code is also inspired by the table-driven 11 + * algorithm and detail example from this paper. This paper can be found 12 + * from, 13 + * http://www.ross.net/crc/download/crc_v3.txt 14 + * 15 + * crc64table[256] is the lookup table of a table-driven 64-bit CRC 16 + * calculation, which is generated by gen_crc64table.c in kernel build 17 + * time. The polynomial of crc64 arithmetic is from ECMA-182 specification 18 + * as well, which is defined as, 19 + * 20 + * x^64 + x^62 + x^57 + x^55 + x^54 + x^53 + x^52 + x^47 + x^46 + x^45 + 21 + * x^40 + x^39 + x^38 + x^37 + x^35 + x^33 + x^32 + x^31 + x^29 + x^27 + 22 + * x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 + 23 + * x^7 + x^4 + x + 1 24 + * 25 + * Copyright 2018 SUSE Linux. 26 + * Author: Coly Li <colyli@suse.de> 27 + */ 28 + 29 + #include <linux/module.h> 30 + #include <linux/types.h> 31 + #include "crc64table.h" 32 + 33 + MODULE_DESCRIPTION("CRC64 calculations"); 34 + MODULE_LICENSE("GPL v2"); 35 + 36 + /** 37 + * crc64_be - Calculate bitwise big-endian ECMA-182 CRC64 38 + * @crc: seed value for computation. 0 or (u64)~0 for a new CRC calculation, 39 + or the previous crc64 value if computing incrementally. 40 + * @p: pointer to buffer over which CRC64 is run 41 + * @len: length of buffer @p 42 + */ 43 + u64 __pure crc64_be(u64 crc, const void *p, size_t len) 44 + { 45 + size_t i, t; 46 + 47 + const unsigned char *_p = p; 48 + 49 + for (i = 0; i < len; i++) { 50 + t = ((crc >> 56) ^ (*_p++)) & 0xFF; 51 + crc = crc64table[t] ^ (crc << 8); 52 + } 53 + 54 + return crc; 55 + } 56 + EXPORT_SYMBOL_GPL(crc64_be);
+68
lib/gen_crc64table.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Generate lookup table for the table-driven CRC64 calculation. 4 + * 5 + * gen_crc64table is executed in kernel build time and generates 6 + * lib/crc64table.h. This header is included by lib/crc64.c for 7 + * the table-driven CRC64 calculation. 8 + * 9 + * See lib/crc64.c for more information about which specification 10 + * and polynomial arithmetic that gen_crc64table.c follows to 11 + * generate the lookup table. 12 + * 13 + * Copyright 2018 SUSE Linux. 14 + * Author: Coly Li <colyli@suse.de> 15 + */ 16 + #include <inttypes.h> 17 + #include <stdio.h> 18 + 19 + #include <linux/swab.h> 20 + 21 + #define CRC64_ECMA182_POLY 0x42F0E1EBA9EA3693ULL 22 + 23 + static uint64_t crc64_table[256] = {0}; 24 + 25 + static void generate_crc64_table(void) 26 + { 27 + uint64_t i, j, c, crc; 28 + 29 + for (i = 0; i < 256; i++) { 30 + crc = 0; 31 + c = i << 56; 32 + 33 + for (j = 0; j < 8; j++) { 34 + if ((crc ^ c) & 0x8000000000000000ULL) 35 + crc = (crc << 1) ^ CRC64_ECMA182_POLY; 36 + else 37 + crc <<= 1; 38 + c <<= 1; 39 + } 40 + 41 + crc64_table[i] = crc; 42 + } 43 + } 44 + 45 + static void print_crc64_table(void) 46 + { 47 + int i; 48 + 49 + printf("/* this file is generated - do not edit */\n\n"); 50 + printf("#include <linux/types.h>\n"); 51 + printf("#include <linux/cache.h>\n\n"); 52 + printf("static const u64 ____cacheline_aligned crc64table[256] = {\n"); 53 + for (i = 0; i < 256; i++) { 54 + printf("\t0x%016" PRIx64 "ULL", crc64_table[i]); 55 + if (i & 0x1) 56 + printf(",\n"); 57 + else 58 + printf(", "); 59 + } 60 + printf("};\n"); 61 + } 62 + 63 + int main(int argc, char *argv[]) 64 + { 65 + generate_crc64_table(); 66 + print_crc64_table(); 67 + return 0; 68 + }