Ilya Dryomov
2011-Apr-09 11:29 UTC
[PATCH] btrfs scrub - restore bios properly after media errors
The current code reallocates a bio after a media error. This is a temporary measure introduced in v3 after a serious problem related to bio reuse was found in v2 of scrub patchset. Basically we did not reset bv_offset and bv_len fields of the bio_vec structure. They are changed in case I/O error happens, for example, at offset 512 or 1024 into the page. Also bi_flags field wasn''t properly setup before reusing the bio. Signed-off-by: Ilya Dryomov <idryomov@gmail.com> --- fs/btrfs/scrub.c | 48 +++++++++++++----------------------------------- 1 files changed, 13 insertions(+), 35 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index e862167..1631327 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -418,45 +418,24 @@ static void scrub_checksum(scrub_work_t *work) int ret; if (sbio->err) { - struct bio *bio; - struct bio *old_bio; - - for (i = 0; i < sbio->count; ++i) { + for (i = 0; i < sbio->count; ++i) scrub_recheck_error(sbio, i); + + sbio->bio->bi_flags &= ~(BIO_POOL_MASK - 1); + sbio->bio->bi_flags |= 1 << BIO_UPTODATE; + sbio->bio->bi_phys_segments = 0; + sbio->bio->bi_idx = 0; + + for (i = 0; i < sbio->count; i++) { + struct bio_vec *bi; + bi = &sbio->bio->bi_io_vec[i]; + bi->bv_offset = 0; + bi->bv_len = PAGE_SIZE; } + spin_lock(&sdev->stat_lock); ++sdev->stat.read_errors; spin_unlock(&sdev->stat_lock); - - /* - * FIXME: allocate a new bio after a media error. I haven''t - * figured out how to reuse this one - */ - old_bio = sbio->bio; - bio = bio_kmalloc(GFP_NOFS, SCRUB_PAGES_PER_BIO); - if (!bio) { - /* - * alloc failed. cancel the scrub and don''t requeue - * this sbio - */ - printk(KERN_ERR "btrfs scrub: allocation failure, " - "cancelling scrub\n"); - atomic_inc(&sdev->dev->dev_root->fs_info-> - scrub_cancel_req); - goto out_no_enqueue; - } - sbio->bio = bio; - bio->bi_private = sbio; - bio->bi_end_io = scrub_bio_end_io; - bio->bi_sector = 0; - bio->bi_bdev = sbio->sdev->dev->bdev; - bio->bi_size = 0; - for (i = 0; i < SCRUB_PAGES_PER_BIO; ++i) { - struct page *page; - page = old_bio->bi_io_vec[i].bv_page; - bio_add_page(bio, page, PAGE_SIZE, 0); - } - bio_put(old_bio); goto out; } for (i = 0; i < sbio->count; ++i) { @@ -486,7 +465,6 @@ out: sbio->next_free = sdev->first_free; sdev->first_free = sbio->index; spin_unlock(&sdev->list_lock); -out_no_enqueue: atomic_dec(&sdev->in_flight); wake_up(&sdev->list_wait); } -- 1.7.2.5 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html