From d3e9d454964e44e9cb6e457923fa5a0cdf021094 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Thu, 3 Jul 2014 13:25:56 -0600 Subject: [PATCH] LU-5279 crypto: no vmalloc() for speed test buffer Since the patch LU-5053 "libcfs: clean up cfs_crypto_hash code" (commit 0723b8be34503b31dbfc6c877d7a855091c625b4) was landed the cfs_crypto_performance_test() code can fail if CONFIG_DEBUG_VIRTUAL is enabled. This causes problems in SG handling because it expects physical addresses: kernel BUG at arch/x86/mm/physaddr.c:20! RIP: 0010:[] __phys_addr+0x67/0x80 sg_init_one+0x36/0x80 cfs_crypto_hash_digest+0x94/0xf0 [libcfs] cfs_crypto_register+0x108/0x330 [libcfs] init_libcfs_module+0x0/0x3c0 [libcfs] sys_init_module+0xe3/0x260 Don't use vmalloc() to allocate the cfs_crypto_test_hashes() test buffer. Use alloc_page() and use cfs_crypto_hash_update_page() to compute the hash instead of cfs_crypto_hash_digest(), since tgt_checksum_bulk() computes the hash by page anyway. Signed-off-by: Andreas Dilger Change-Id: I27ec3cf2931b6bf385dd91191abba8955b500c1e Reviewed-on: http://review.whamcloud.com/10982 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: John L. Hammond Tested-by: John L. Hammond Reviewed-by: James Simmons Reviewed-by: Alexander Boyko Reviewed-by: Bob Glossman Reviewed-by: Oleg Drokin --- libcfs/include/libcfs/libcfs_crypto.h | 3 +- libcfs/libcfs/linux/linux-crypto.c | 81 +++++++++++++++++++++-------------- libcfs/libcfs/user-crypto.c | 6 +-- 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/libcfs/include/libcfs/libcfs_crypto.h b/libcfs/include/libcfs/libcfs_crypto.h index 10f94d3..2910a9e 100644 --- a/libcfs/include/libcfs/libcfs_crypto.h +++ b/libcfs/include/libcfs/libcfs_crypto.h @@ -115,7 +115,8 @@ char *cfs_crypto_hash_name(enum cfs_crypto_hash_alg hash_alg) * \retval hash algorithm digest size in bytes * \retval 0 if hash algorithm type is unknown */ -static inline int cfs_crypto_hash_digestsize(enum cfs_crypto_hash_alg hash_alg) +static inline +unsigned int cfs_crypto_hash_digestsize(enum cfs_crypto_hash_alg hash_alg) { const struct cfs_crypto_hash_type *ht; diff --git a/libcfs/libcfs/linux/linux-crypto.c b/libcfs/libcfs/linux/linux-crypto.c index b5f376d..c694aab 100644 --- a/libcfs/libcfs/linux/linux-crypto.c +++ b/libcfs/libcfs/linux/linux-crypto.c @@ -243,13 +243,14 @@ EXPORT_SYMBOL(cfs_crypto_hash_update); /** * Finish hash calculation, copy hash digest to buffer, clean up hash descriptor * - * \param[in] hdesc hash descriptor - * \param[out] hash pointer to hash buffer to store hash digest - * \param[in,out] hash_len pointer to hash buffer size, if \a hdesc = NULL - * only free \a hdesc instead of computing the hash + * \param[in] hdesc hash descriptor + * \param[out] hash pointer to hash buffer to store hash digest + * \param[in,out] hash_len pointer to hash buffer size, if \a hash == NULL + * or hash_len == NULL only free \a hdesc instead + * of computing the hash * - * \retval -ENOSPC if \a hash = NULL, or \a hash_len < digest size * \retval 0 for success + * \retval -EOVERFLOW if hash_len is too small for the hash digest * \retval negative errno for other errors from lower layers */ int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *hdesc, @@ -258,15 +259,18 @@ int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *hdesc, int size = crypto_hash_digestsize(((struct hash_desc *)hdesc)->tfm); int err; - if (hash_len == NULL) { + if (hash == NULL || hash_len == NULL) { err = 0; goto free; } - if (hash == NULL || *hash_len < size) { - err = -ENOSPC; + if (*hash_len < size) { + err = -EOVERFLOW; goto free; } + err = crypto_hash_final((struct hash_desc *)hdesc, hash); + if (err == 0) + *hash_len = size; free: crypto_free_hash(((struct hash_desc *)hdesc)->tfm); kfree(hdesc); @@ -286,26 +290,51 @@ EXPORT_SYMBOL(cfs_crypto_hash_final); * \param[in] buf data buffer on which to compute the hash * \param[in] buf_len length of \buf on which to compute hash */ -static void cfs_crypto_performance_test(enum cfs_crypto_hash_alg hash_alg, - const unsigned char *buf, - unsigned int buf_len) +static void cfs_crypto_performance_test(enum cfs_crypto_hash_alg hash_alg) { + int buf_len = max(PAGE_SIZE, 1048576UL); + void *buf; unsigned long start, end; int bcount, err = 0; - int sec = 1; /* do test only 1 sec */ - unsigned char hash[64]; + struct page *page; + unsigned char hash[CFS_CRYPTO_HASH_DIGESTSIZE_MAX]; unsigned int hash_len = sizeof(hash); - for (start = jiffies, end = start + sec * HZ, bcount = 0; - time_before(jiffies, end); bcount++) { - err = cfs_crypto_hash_digest(hash_alg, buf, buf_len, NULL, 0, - hash, &hash_len); - if (err != 0) + page = alloc_page(GFP_KERNEL); + if (page == NULL) { + err = -ENOMEM; + goto out_err; + } + + buf = kmap(page); + memset(buf, 0xAD, PAGE_SIZE); + kunmap(page); + + for (start = jiffies, end = start + HZ, bcount = 0; + time_before(jiffies, end) && err == 0; bcount++) { + struct cfs_crypto_hash_desc *hdesc; + int i; + + hdesc = cfs_crypto_hash_init(hash_alg, NULL, 0); + if (IS_ERR(hdesc)) { + err = PTR_ERR(hdesc); break; + } + for (i = 0; i < buf_len / PAGE_SIZE; i++) { + err = cfs_crypto_hash_update_page(hdesc, page, 0, + PAGE_SIZE); + if (err != 0) + break; + } + + err = cfs_crypto_hash_final(hdesc, hash, &hash_len); + if (err != 0) + break; } end = jiffies; - + __free_page(page); +out_err: if (err != 0) { cfs_crypto_hash_speeds[hash_alg] = err; CDEBUG(D_INFO, "Crypto hash algorithm %s test error: rc = %d\n", @@ -364,22 +393,10 @@ EXPORT_SYMBOL(cfs_crypto_hash_speed); static int cfs_crypto_test_hashes(void) { enum cfs_crypto_hash_alg hash_alg; - unsigned char *data; - /* Data block size for testing hash. Use bulk RPC size. */ - unsigned int data_len = 1024 * 1024; - - data = vmalloc(data_len); - if (data == NULL) { - CERROR("Failed to allocate buffer for hash speed test\n"); - return -ENOMEM; - } - - memset(data, 0xAD, data_len); for (hash_alg = 0; hash_alg < CFS_HASH_ALG_MAX; hash_alg++) - cfs_crypto_performance_test(hash_alg, data, data_len); + cfs_crypto_performance_test(hash_alg); - vfree(data); return 0; } diff --git a/libcfs/libcfs/user-crypto.c b/libcfs/libcfs/user-crypto.c index 9c549b5..1d0acab 100644 --- a/libcfs/libcfs/user-crypto.c +++ b/libcfs/libcfs/user-crypto.c @@ -272,12 +272,12 @@ int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *desc, LASSERT(type != NULL); size = type->cht_size; - if (hash_len == NULL) { + if (hash == NULL || hash_len == NULL) { err = 0; goto free; } - if (hash == NULL || *hash_len < size) { - err = -ENOMEM; + if (*hash_len < size) { + err = -EOVERFLOW; goto free; } -- 1.8.3.1