CHROMIUM: md: dm-bootcache: reinitialize bio structure
authorPaul Taysom <taysom@chromium.org>
Thu, 25 Apr 2013 00:19:58 +0000 (17:19 -0700)
committerChromeBot <chrome-bot@google.com>
Mon, 29 Apr 2013 22:19:39 +0000 (15:19 -0700)
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 <taysom@chromium.org>
Change-Id: I5b835b5f0606f6eb4116fc9719d96a48d0155f57
Reviewed-on: https://gerrit.chromium.org/gerrit/49121
Reviewed-by: Olof Johansson <olofj@chromium.org>
Tested-by: Paul Taysom <taysom@chromium.org>
Commit-Queue: Paul Taysom <taysom@chromium.org>

drivers/md/dm-bootcache.c

index d83337d..c6c0269 100644 (file)
@@ -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);