From 652c26eda1f0de21c65ddb9e538b9592681c3da5 Mon Sep 17 00:00:00 2001 From: Paul Taysom Date: Wed, 24 Apr 2013 17:19:58 -0700 Subject: [PATCH] CHROMIUM: md: dm-bootcache: reinitialize bio structure The bootcache code does multiple large reads and was reusing the bio structure. Some device drivers appear to leave some clutter in the bio structure. Between large reads, the bootcache now frees and reallocates the bio structure. BUG=chrome-os-partner:18830 TEST=POWER-ESC-F3 with USB stick, several times. Signed-off-by: Paul Taysom Change-Id: I5b835b5f0606f6eb4116fc9719d96a48d0155f57 Reviewed-on: https://gerrit.chromium.org/gerrit/49121 Reviewed-by: Olof Johansson Tested-by: Paul Taysom Commit-Queue: Paul Taysom --- drivers/md/dm-bootcache.c | 59 ++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/drivers/md/dm-bootcache.c b/drivers/md/dm-bootcache.c index d83337d47e5a..c6c0269f9ed6 100644 --- a/drivers/md/dm-bootcache.c +++ b/drivers/md/dm-bootcache.c @@ -577,15 +577,15 @@ static int bootcache_read_sectors(struct bootcache *cache) int j; int rc = 0; - bio = bio_alloc_bioset(GFP_KERNEL, max_io, cache->bio_set); - if (unlikely(!bio)) { - DMERR("Out of memory bio_alloc_bioset"); - return -ENOMEM; - } - bio->bi_private = &waiter; - bio->bi_destructor = bootcache_bio_destructor; p = cache->sectors.pages; for (i = 0; i < chunks_to_read; i++) { + bio = bio_alloc_bioset(GFP_KERNEL, max_io, cache->bio_set); + if (unlikely(!bio)) { + DMERR("Out of memory bio_alloc_bioset"); + return -ENOMEM; + } + bio->bi_private = &waiter; + bio->bi_destructor = bootcache_bio_destructor; bio->bi_idx = 0; bio->bi_bdev = cache->dev->bdev; bio->bi_end_io = bootcache_read_sectors_end; @@ -609,6 +609,8 @@ static int bootcache_read_sectors(struct bootcache *cache) wait_for_completion(&waiter.completion); if (waiter.error) { rc = waiter.error; + bio->bi_private = cache; + bio_put(bio); break; } p = start_page; @@ -618,9 +620,9 @@ static int bootcache_read_sectors(struct bootcache *cache) p->is_filled = 1; } sector += pages_to_sectors(j); + bio->bi_private = cache; + bio_put(bio); } - bio->bi_private = cache; - bio_put(bio); atomic_set(&cache->state, BC_FILLED); return rc; } @@ -645,7 +647,6 @@ static int bootcache_dev_read(struct bootcache *cache, void *data, struct bio_vec *bvec; int pages_to_read = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; int max_io = cache->max_io; - int num_pages; int bytes_to_copy; int i; int rc = 0; @@ -653,24 +654,20 @@ static int bootcache_dev_read(struct bootcache *cache, void *data, u8 *dst = data; u8 *src; - if (pages_to_read < max_io) - num_pages = pages_to_read; - else - num_pages = max_io; - bio = bio_alloc_bioset(GFP_KERNEL, num_pages, cache->bio_set); - if (unlikely(!bio)) { - DMERR("Out of memory bio_alloc_bioset"); - return -ENOMEM; - } - bvec = bio->bi_io_vec; - for (i = 0; i < num_pages; i++, bvec++) - bvec->bv_page = alloc_page(GFP_KERNEL); - bio->bi_private = &waiter; - bio->bi_destructor = bootcache_bio_destructor; pages_read = 0; while (len) { if (pages_to_read < max_io) max_io = pages_to_read; + bio = bio_alloc_bioset(GFP_KERNEL, max_io, cache->bio_set); + if (unlikely(!bio)) { + DMERR("Out of memory bio_alloc_bioset"); + return -ENOMEM; + } + bvec = bio->bi_io_vec; + for (i = 0; i < max_io; i++, bvec++) + bvec->bv_page = alloc_page(GFP_KERNEL); + bio->bi_private = &waiter; + bio->bi_destructor = bootcache_bio_destructor; bio->bi_idx = 0; bio->bi_bdev = cache->dev->bdev; bio->bi_end_io = bootcache_dev_read_end; @@ -691,10 +688,10 @@ static int bootcache_dev_read(struct bootcache *cache, void *data, wait_for_completion(&waiter.completion); if (waiter.error) { rc = waiter.error; - goto exit; + goto error; } for (i = 0; i < max_io; i++) { - bytes_to_copy = (len < PAGE_SIZE) ? len : PAGE_SIZE; + bytes_to_copy = min(len, (int)PAGE_SIZE); src = kmap_atomic(bio_iovec_idx(bio, i)->bv_page); memcpy(dst, src, bytes_to_copy); kunmap_atomic(src); @@ -704,10 +701,16 @@ static int bootcache_dev_read(struct bootcache *cache, void *data, dst += bytes_to_copy; } sector += pages_to_sectors(max_io); + bvec = bio->bi_io_vec; + for (i = 0; i < max_io; i++, bvec++) + __free_pages(bvec->bv_page, 0); + bio->bi_private = cache; + bio_put(bio); } -exit: + return rc; +error: bvec = bio->bi_io_vec; - for (i = 0; i < num_pages; i++, bvec++) + for (i = 0; i < max_io; i++, bvec++) __free_pages(bvec->bv_page, 0); bio->bi_private = cache; bio_put(bio); -- 2.20.1