diff --git a/kernel/Kconfig b/kernel/Kconfig index 702615f8..03ebdcbe 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -7,10 +7,22 @@ config MARS depends on m depends on BLOCK && PROC_SYSCTL && HIGH_RES_TIMERS default n + select CRYPTO_MD5 ---help--- See https://github.com/schoebel/mars/docu/ Only compile as a module! +config MARS_BENCHMARK + bool "rough measurement of digest and compression algorithms" + depends on MARS + default y + ---help--- + Upon modprobe mars, display some rough measurements in + nanoseconds. Note that results may depend on the compressibility + of test data. Thus take the results with a grain of salt + (similarly to BogoMIPS). + If unsure, say Y here. + config MARS_CHECKS bool "enable simple runtime checks in MARS" depends on MARS diff --git a/kernel/mars.h b/kernel/mars.h index e4d5fe17..2249a0c3 100644 --- a/kernel/mars.h +++ b/kernel/mars.h @@ -162,6 +162,7 @@ enum _MREF_FLAGS { _MREF_NODATA, /* only useful for chksum reading */ /* Checksum bits, starting at the upper half */ _MREF_CHKSUM_MD5_OLD = 16, + _MREF_CHKSUM_MD5, _MREF_CHKSUM_LAST, }; @@ -173,8 +174,10 @@ enum _MREF_FLAGS { #define MREF_SKIP_SYNC (1UL << _MREF_SKIP_SYNC) #define MREF_NODATA (1UL << _MREF_NODATA) #define MREF_CHKSUM_MD5_OLD (1UL << _MREF_CHKSUM_MD5_OLD) +#define MREF_CHKSUM_MD5 (1UL << _MREF_CHKSUM_MD5) #define MREF_CHKSUM_LAST (1UL << _MREF_CHKSUM_LAST) #define MREF_CHKSUM_ANY (MREF_CHKSUM_MD5_OLD | \ + MREF_CHKSUM_MD5 | \ MREF_CHKSUM_LAST) #define MREF_OBJECT(OBJTYPE) \ diff --git a/kernel/mars_generic.c b/kernel/mars_generic.c index c68383ae..7e0d6d2f 100644 --- a/kernel/mars_generic.c +++ b/kernel/mars_generic.c @@ -191,12 +191,65 @@ void md5_old_digest(void *digest, void *data, int len) brick_mem_free(sdesc); } +static +void md5_digest(void *digest, void *data, int len) +{ + int size = sizeof(struct mars_sdesc) + crypto_shash_descsize(md5_tfm); + struct mars_sdesc *sdesc = brick_mem_alloc(size); + const int iterations = MARS_DIGEST_SIZE / MD5_DIGEST_SIZE; + int chunksize = len / iterations; + int offset = 0; + int done_len = len; + int i; + int status; + + sdesc->shash.tfm = md5_tfm; + sdesc->shash.flags = 0; + + memset(digest, 0, MARS_DIGEST_SIZE); + + /* exploit the bigger MARS_DIGEST_SIZE by computing MD5 in chunks */ + for (i = 0; i < iterations; i++) { + char this_digest[MD5_DIGEST_SIZE] = {}; + + status = crypto_shash_digest(&sdesc->shash, + data + offset, + chunksize, + this_digest); + if (unlikely(status < 0)) { + MARS_ERR("cannot calculate md5 chksum on %p len=%d, status=%d\n", + data, + chunksize, + status); + memset(digest, 0, MARS_DIGEST_SIZE); + break; + } + memcpy(digest + i * MD5_DIGEST_SIZE, + this_digest, MD5_DIGEST_SIZE); + offset += chunksize; + done_len -= chunksize; + } + if (unlikely(done_len)) + MARS_ERR("md5 chksum remain %d\n", done_len); + + brick_mem_free(sdesc); +} + __u32 mars_digest(__u32 digest_flags, __u32 *used_flags, void *digest, void *data, int len) { digest_flags &= usable_digest_mask; + /* The order defines the preference: + * place the most performant algorithms first. + */ + if (digest_flags & MREF_CHKSUM_MD5 && md5_tfm) { + md5_digest(digest, data, len); + if (used_flags) + *used_flags = MREF_CHKSUM_MD5; + return MREF_CHKSUM_MD5; + } /* always fallback to old md5 regardless of digest_flags */ md5_old_digest(digest, data, len); @@ -205,6 +258,54 @@ __u32 mars_digest(__u32 digest_flags, return MREF_CHKSUM_MD5_OLD; } +#ifdef CONFIG_MARS_BENCHMARK + +static +void benchmark_digest(char *name, __u32 flags) +{ + unsigned char*testpage = kzalloc(PAGE_SIZE, GFP_KERNEL); + unsigned char old_test[MARS_DIGEST_SIZE] = {}; + unsigned char new_test[MARS_DIGEST_SIZE]; + long long delta; + __u32 res_flags; + unsigned char bit; + int i; + + usable_digest_mask = MREF_CHKSUM_ANY; + + delta = + TIME_THIS( + for (bit = 1; bit; bit <<= 1) { + for (i = 0; i < PAGE_SIZE; i++) { + testpage[i] ^= bit; + res_flags = mars_digest(flags, + NULL, + new_test, + testpage, + PAGE_SIZE); + if (unlikely(!(res_flags & flags))) { + MARS_ERR("digest %s failed\n", + name); + goto err; + } + if (unlikely(!memcmp(old_test, new_test, MARS_DIGEST_SIZE))) { + MARS_ERR("digest %s is not good enough\n", + name); + goto err; + } + memcpy(old_test, new_test, MARS_DIGEST_SIZE); + } + } + ); + printk("%-10s digest duration = %12lld ns\n", + name, delta); + err: + kfree(testpage); + usable_digest_mask = MREF_CHKSUM_MD5_OLD; +} + +#endif + static int init_mars_digest(void) { @@ -222,7 +323,12 @@ int init_mars_digest(void) MARS_ERR("md5 bad digest size %d\n", status); return -ELIBACC; } + available_digest_mask |= MREF_CHKSUM_MD5; +#ifdef CONFIG_MARS_BENCHMARK + benchmark_digest("md5old", MREF_CHKSUM_MD5_OLD); + benchmark_digest("md5", MREF_CHKSUM_MD5); +#endif return 0; } diff --git a/kernel/sy_old/mars_main.c b/kernel/sy_old/mars_main.c index 9cddc372..3a07b19f 100644 --- a/kernel/sy_old/mars_main.c +++ b/kernel/sy_old/mars_main.c @@ -2655,6 +2655,8 @@ void _make_alive(void) _make_alivelink_str("tree", SYMLINK_TREE_VERSION); _make_alivelink_str("features", OPTIONAL_FEATURES_VERSION); _make_alivelink_str("buildtag", BUILDTAG "(" BUILDDATE ")"); + _make_alivelink("used-log-digest", used_log_digest); + _make_alivelink("used-net-digest", used_net_digest); } void from_remote_trigger(void)