block: test-iosched: fix bio allocation for test requests

Unit tests submit large requests of 512KB made of 128 bios.
Current allocation was done via kmalloc which may not be able
to allocate such a large buffer which is also physically contiguous.
Using kmalloc to allocate each bio separately is also problematic as
it might not be page aligned. Some bio may end up using more than a
single memory segment which will fail the mapping of the bios to
the request which supports up to 128 physical segments.
To avoid such failure, allocate a separate page for each bio
(bio size is single page size).

Change-Id: Id0da394d458942e093d924bc7aa23aa3231cdca7
Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
This commit is contained in:
Gilad Broner 2015-01-08 12:26:07 +02:00 committed by Gerrit - the friendly Code Review server
parent 4ab0976786
commit 8aeb623c2d
4 changed files with 60 additions and 60 deletions

View File

@ -112,6 +112,21 @@ static void end_test_bio(struct bio *bio, int err)
bio_put(bio);
}
void test_iosched_free_test_req_data_buffer(struct test_request *test_rq)
{
int i;
if (!test_rq)
return;
for (i = 0; i < BLK_MAX_SEGMENTS; i++)
if (test_rq->bios_buffer[i]) {
free_page((unsigned long)test_rq->bios_buffer[i]);
test_rq->bios_buffer[i] = NULL;
}
}
EXPORT_SYMBOL(test_iosched_free_test_req_data_buffer);
/*
* A callback to be called per request completion.
* the request memory is not freed here, will be freed later after the test
@ -281,17 +296,14 @@ struct test_request *test_iosched_create_test_req(
{
struct request *rq;
struct test_request *test_rq;
int rw_flags, buf_size;
int ret = 0, i;
unsigned int *bio_ptr = NULL;
struct bio *bio = NULL;
int i;
int ret;
if (!tios)
return NULL;
rw_flags = direction;
rq = blk_get_request(tios->req_q, rw_flags, GFP_KERNEL);
rq = blk_get_request(tios->req_q, direction, GFP_KERNEL);
if (!rq) {
pr_err("%s: Failed to allocate a request", __func__);
return NULL;
@ -300,35 +312,29 @@ struct test_request *test_iosched_create_test_req(
test_rq = kzalloc(sizeof(struct test_request), GFP_KERNEL);
if (!test_rq) {
pr_err("%s: Failed to allocate test request", __func__);
blk_put_request(rq);
return NULL;
}
buf_size = TEST_BIO_SIZE * num_bios;
test_rq->bios_buffer = kzalloc(buf_size, GFP_KERNEL);
if (!test_rq->bios_buffer) {
pr_err("%s: Failed to allocate the data buf", __func__);
goto err;
}
test_rq->buf_size = buf_size;
if (direction == WRITE)
fill_buf_with_pattern(test_rq->bios_buffer,
buf_size, pattern);
test_rq->buf_size = TEST_BIO_SIZE * num_bios;
test_rq->wr_rd_data_pattern = pattern;
bio_ptr = test_rq->bios_buffer;
for (i = 0; i < num_bios; ++i) {
ret = blk_rq_map_kern(tios->req_q, rq,
(void *)bio_ptr,
sizeof(unsigned int)*BIO_U32_SIZE,
GFP_KERNEL);
for (i = 0; i < num_bios; i++) {
test_rq->bios_buffer[i] = (void *)get_zeroed_page(GFP_KERNEL);
if (!test_rq->bios_buffer[i]) {
pr_err("%s: failed to kmap page for bio #%d/%d\n",
__func__, i, num_bios);
goto free_bios;
}
ret = blk_rq_map_kern(tios->req_q, rq, test_rq->bios_buffer[i],
TEST_BIO_SIZE, GFP_KERNEL);
if (ret) {
pr_err("%s: blk_rq_map_kern returned error %d",
__func__, ret);
goto err;
__func__, ret);
goto free_bios;
}
bio_ptr += BIO_U32_SIZE;
if (direction == WRITE)
fill_buf_with_pattern(test_rq->bios_buffer[i],
TEST_BIO_SIZE, pattern);
}
if (end_req_io)
@ -355,18 +361,16 @@ struct test_request *test_iosched_create_test_req(
test_rq->req_result = -EINVAL;
test_rq->rq = rq;
if (tios->test_info.get_rq_disk_fn)
test_rq->rq->rq_disk =
tios->test_info.get_rq_disk_fn(tios);
test_rq->rq->rq_disk = tios->test_info.get_rq_disk_fn(tios);
test_rq->is_err_expected = is_err_expcted;
rq->elv.priv[0] = (void *)test_rq;
pr_debug("%s: created test request %d, buf_size=%d",
__func__, test_rq->req_id, buf_size);
return test_rq;
free_bios:
test_iosched_free_test_req_data_buffer(test_rq);
kfree(test_rq);
err:
blk_put_request(rq);
kfree(test_rq->bios_buffer);
return NULL;
}
EXPORT_SYMBOL(test_iosched_create_test_req);
@ -434,8 +438,9 @@ static char *get_test_case_str(struct test_iosched *tios)
*/
int compare_buffer_to_pattern(struct test_request *test_rq)
{
int i = 0;
int num_of_dwords = test_rq->buf_size/sizeof(int);
int i;
int j;
unsigned int *buf;
/* num_bytes should be aligned to sizeof(int) */
BUG_ON((test_rq->buf_size % sizeof(int)) != 0);
@ -444,25 +449,18 @@ int compare_buffer_to_pattern(struct test_request *test_rq)
if (test_rq->wr_rd_data_pattern == TEST_NO_PATTERN)
return 0;
if (test_rq->wr_rd_data_pattern == TEST_PATTERN_SEQUENTIAL) {
for (i = 0; i < num_of_dwords; i++) {
if (test_rq->bios_buffer[i] != i) {
pr_err(
"%s: wrong pattern 0x%x in index %d",
__func__, test_rq->bios_buffer[i], i);
for (i = 0; i < test_rq->buf_size / TEST_BIO_SIZE; i++) {
buf = test_rq->bios_buffer[i];
for (j = 0; j < TEST_BIO_SIZE / sizeof(int); j++)
if ((test_rq->wr_rd_data_pattern ==
TEST_PATTERN_SEQUENTIAL && buf[j] != j) ||
(test_rq->wr_rd_data_pattern !=
TEST_PATTERN_SEQUENTIAL &&
buf[j] != test_rq->wr_rd_data_pattern)) {
pr_err("%s: wrong pattern 0x%x in index %d",
__func__, buf[j], j);
return -EINVAL;
}
}
} else {
for (i = 0; i < num_of_dwords; i++) {
if (test_rq->bios_buffer[i] !=
test_rq->wr_rd_data_pattern) {
pr_err(
"%s: wrong pattern 0x%x in index %d",
__func__, test_rq->bios_buffer[i], i);
return -EINVAL;
}
}
}
return 0;
@ -595,7 +593,7 @@ static void free_test_queue(struct list_head *test_queue)
}
}
blk_put_request(test_rq->rq);
kfree(test_rq->bios_buffer);
test_iosched_free_test_req_data_buffer(test_rq);
kfree(test_rq);
}
}

View File

@ -2102,7 +2102,7 @@ static void new_req_free_end_io_fn(struct request *rq, int err)
spin_unlock_irq(&tios->lock);
__blk_put_request(tios->req_q, test_rq->rq);
kfree(test_rq->bios_buffer);
test_iosched_free_test_req_data_buffer(test_rq);
kfree(test_rq);
mbtd->completed_req_count++;
}
@ -2857,7 +2857,7 @@ static void long_seq_write_free_end_io_fn(struct request *rq, int err)
__blk_put_request(tios->req_q, test_rq->rq);
spin_unlock_irq(&tios->lock);
kfree(test_rq->bios_buffer);
test_iosched_free_test_req_data_buffer(test_rq);
kfree(test_rq);
mbtd->completed_req_count++;

View File

@ -683,7 +683,7 @@ static void scenario_free_end_io_fn(struct request *rq, int err)
__blk_put_request(test_iosched->req_q, test_rq->rq);
spin_unlock_irq(&test_iosched->lock);
kfree(test_rq->bios_buffer);
test_iosched_free_test_req_data_buffer(test_rq);
kfree(test_rq);
if (err)
@ -977,7 +977,7 @@ static void long_test_free_end_io_fn(struct request *rq, int err)
return;
}
kfree(test_rq->bios_buffer);
test_iosched_free_test_req_data_buffer(test_rq);
kfree(test_rq);
utd->completed_req_count++;

View File

@ -92,7 +92,7 @@ struct test_debug {
/**
* struct test_request - defines a test request
* @queuelist: The test requests list
* @bios_buffer: Write/read requests data buffer
* @bios_buffer: Write/read requests data buffer, one page per bio
* @buf_size: Write/read requests data buffer size (in
* bytes)
* @rq: A block request, to be dispatched
@ -110,7 +110,7 @@ struct test_debug {
*/
struct test_request {
struct list_head queuelist;
unsigned int *bios_buffer;
void *bios_buffer[BLK_MAX_SEGMENTS];
int buf_size;
struct request *rq;
bool req_completed;
@ -250,6 +250,8 @@ extern struct test_request *test_iosched_create_test_req(struct test_iosched *,
int is_err_expcted, int direction, int start_sec, int num_bios,
int pattern, rq_end_io_fn *end_req_io);
extern void test_iosched_free_test_req_data_buffer(struct test_request *);
extern void test_iosched_set_test_result(struct test_iosched*, int test_result);
extern void test_iosched_set_ignore_round(struct test_iosched *,