crypto: tcrypt - Fix memory leaks/crashes in multibuffer hash speed test
This patch resolves a number of issues with the mb speed test function: * The tfm is never freed. * Memory is allocated even when we're not using mb. * When an error occurs we don't wait for completion for other requests. * When an error occurs during allocation we may leak memory. * The test function ignores plen but still runs for plen != blen. * The backlog flag is incorrectly used (may crash). This patch tries to resolve all these issues as well as making the code consistent with the existing hash speed testing function. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Tested-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
This commit is contained in:
131
crypto/tcrypt.c
131
crypto/tcrypt.c
@ -578,54 +578,61 @@ static inline int do_one_ahash_op(struct ahash_request *req, int ret)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char ptext[4096];
|
struct test_mb_ahash_data {
|
||||||
struct scatterlist sg[8][8];
|
struct scatterlist sg[TVMEMSIZE];
|
||||||
char result[8][64];
|
char result[64];
|
||||||
struct ahash_request *req[8];
|
struct ahash_request *req;
|
||||||
struct tcrypt_result tresult[8];
|
struct tcrypt_result tresult;
|
||||||
char *xbuf[8][XBUFSIZE];
|
char *xbuf[XBUFSIZE];
|
||||||
unsigned long start[8], end[8], mid;
|
};
|
||||||
|
|
||||||
static void test_mb_ahash_speed(const char *algo, unsigned int sec,
|
static void test_mb_ahash_speed(const char *algo, unsigned int sec,
|
||||||
struct hash_speed *speed)
|
struct hash_speed *speed)
|
||||||
{
|
{
|
||||||
unsigned int i, j, k;
|
struct test_mb_ahash_data *data;
|
||||||
void *hash_buff;
|
|
||||||
int ret = -ENOMEM;
|
|
||||||
struct crypto_ahash *tfm;
|
struct crypto_ahash *tfm;
|
||||||
|
unsigned long start, end;
|
||||||
unsigned long cycles;
|
unsigned long cycles;
|
||||||
|
unsigned int i, j, k;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(*data) * 8, GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
tfm = crypto_alloc_ahash(algo, 0, 0);
|
tfm = crypto_alloc_ahash(algo, 0, 0);
|
||||||
if (IS_ERR(tfm)) {
|
if (IS_ERR(tfm)) {
|
||||||
pr_err("failed to load transform for %s: %ld\n",
|
pr_err("failed to load transform for %s: %ld\n",
|
||||||
algo, PTR_ERR(tfm));
|
algo, PTR_ERR(tfm));
|
||||||
return;
|
goto free_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 8; ++i) {
|
for (i = 0; i < 8; ++i) {
|
||||||
if (testmgr_alloc_buf(xbuf[i]))
|
if (testmgr_alloc_buf(data[i].xbuf))
|
||||||
goto out_nobuf;
|
goto out;
|
||||||
|
|
||||||
init_completion(&tresult[i].completion);
|
init_completion(&data[i].tresult.completion);
|
||||||
|
|
||||||
req[i] = ahash_request_alloc(tfm, GFP_KERNEL);
|
data[i].req = ahash_request_alloc(tfm, GFP_KERNEL);
|
||||||
if (!req[i]) {
|
if (!data[i].req) {
|
||||||
pr_err("alg: hash: Failed to allocate request for %s\n",
|
pr_err("alg: hash: Failed to allocate request for %s\n",
|
||||||
algo);
|
algo);
|
||||||
goto out_noreq;
|
goto out;
|
||||||
}
|
}
|
||||||
ahash_request_set_callback(req[i], CRYPTO_TFM_REQ_MAY_BACKLOG,
|
|
||||||
tcrypt_complete, &tresult[i]);
|
|
||||||
|
|
||||||
hash_buff = xbuf[i][0];
|
ahash_request_set_callback(data[i].req, 0,
|
||||||
memcpy(hash_buff, ptext, 4096);
|
tcrypt_complete, &data[i].tresult);
|
||||||
|
test_hash_sg_init(data[i].sg);
|
||||||
}
|
}
|
||||||
|
|
||||||
j = 0;
|
pr_info("\ntesting speed of multibuffer %s (%s)\n", algo,
|
||||||
|
get_driver_name(crypto_ahash, tfm));
|
||||||
pr_err("\ntesting speed of %s (%s)\n", algo,
|
|
||||||
get_driver_name(crypto_ahash, tfm));
|
|
||||||
|
|
||||||
for (i = 0; speed[i].blen != 0; i++) {
|
for (i = 0; speed[i].blen != 0; i++) {
|
||||||
|
/* For some reason this only tests digests. */
|
||||||
|
if (speed[i].blen != speed[i].plen)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (speed[i].blen > TVMEMSIZE * PAGE_SIZE) {
|
if (speed[i].blen > TVMEMSIZE * PAGE_SIZE) {
|
||||||
pr_err("template (%u) too big for tvmem (%lu)\n",
|
pr_err("template (%u) too big for tvmem (%lu)\n",
|
||||||
speed[i].blen, TVMEMSIZE * PAGE_SIZE);
|
speed[i].blen, TVMEMSIZE * PAGE_SIZE);
|
||||||
@ -635,53 +642,59 @@ static void test_mb_ahash_speed(const char *algo, unsigned int sec,
|
|||||||
if (speed[i].klen)
|
if (speed[i].klen)
|
||||||
crypto_ahash_setkey(tfm, tvmem[0], speed[i].klen);
|
crypto_ahash_setkey(tfm, tvmem[0], speed[i].klen);
|
||||||
|
|
||||||
for (k = 0; k < 8; ++k) {
|
for (k = 0; k < 8; k++)
|
||||||
sg_init_one(&sg[k][0], (void *) xbuf[k][0],
|
ahash_request_set_crypt(data[k].req, data[k].sg,
|
||||||
speed[i].blen);
|
data[k].result, speed[i].blen);
|
||||||
ahash_request_set_crypt(req[k], sg[k],
|
|
||||||
result[k], speed[i].blen);
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_err("test%3u (%5u byte blocks,%5u bytes per update,%4u updates): ",
|
pr_info("test%3u "
|
||||||
|
"(%5u byte blocks,%5u bytes per update,%4u updates): ",
|
||||||
i, speed[i].blen, speed[i].plen,
|
i, speed[i].blen, speed[i].plen,
|
||||||
speed[i].blen / speed[i].plen);
|
speed[i].blen / speed[i].plen);
|
||||||
|
|
||||||
for (k = 0; k < 8; ++k) {
|
start = get_cycles();
|
||||||
start[k] = get_cycles();
|
|
||||||
ret = crypto_ahash_digest(req[k]);
|
for (k = 0; k < 8; k++) {
|
||||||
if (ret == -EBUSY || ret == -EINPROGRESS)
|
ret = crypto_ahash_digest(data[k].req);
|
||||||
|
if (ret == -EINPROGRESS)
|
||||||
continue;
|
continue;
|
||||||
if (ret) {
|
|
||||||
pr_err("alg (%s) something wrong, ret = %d ...\n",
|
|
||||||
algo, ret);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mid = get_cycles();
|
|
||||||
|
|
||||||
for (k = 0; k < 8; ++k) {
|
|
||||||
struct tcrypt_result *tr = &tresult[k];
|
|
||||||
|
|
||||||
ret = wait_for_completion_interruptible(&tr->completion);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
pr_err("alg(%s): hash: digest failed\n", algo);
|
break;
|
||||||
end[k] = get_cycles();
|
|
||||||
|
complete(&data[k].tresult.completion);
|
||||||
|
data[k].tresult.err = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cycles = end[7] - start[0];
|
for (j = 0; j < k; j++) {
|
||||||
printk("\nBlock: %6lu cycles (%4lu cycles/byte)\n",
|
struct tcrypt_result *tr = &data[j].tresult;
|
||||||
cycles, cycles / (8 * speed[i].blen));
|
|
||||||
|
wait_for_completion(&tr->completion);
|
||||||
|
if (tr->err)
|
||||||
|
ret = tr->err;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = get_cycles();
|
||||||
|
cycles = end - start;
|
||||||
|
pr_cont("%6lu cycles/operation, %4lu cycles/byte\n",
|
||||||
|
cycles, cycles / (8 * speed[i].blen));
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("At least one hashing failed ret=%d\n", ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
for (k = 0; k < 8; ++k)
|
for (k = 0; k < 8; ++k)
|
||||||
ahash_request_free(req[k]);
|
ahash_request_free(data[k].req);
|
||||||
out_noreq:
|
|
||||||
for (k = 0; k < 8; ++k)
|
for (k = 0; k < 8; ++k)
|
||||||
testmgr_free_buf(xbuf[k]);
|
testmgr_free_buf(data[k].xbuf);
|
||||||
out_nobuf:
|
|
||||||
return;
|
crypto_free_ahash(tfm);
|
||||||
|
|
||||||
|
free_data:
|
||||||
|
kfree(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_ahash_jiffies_digest(struct ahash_request *req, int blen,
|
static int test_ahash_jiffies_digest(struct ahash_request *req, int blen,
|
||||||
|
|||||||
Reference in New Issue
Block a user