Btrfs: fix wrong error handle when the device is missing or is not writeable
authorMiao Xie <miaox@cn.fujitsu.com>
Thu, 19 Jun 2014 02:42:55 +0000 (10:42 +0800)
committerChris Mason <clm@fb.com>
Thu, 19 Jun 2014 21:20:56 +0000 (14:20 -0700)
The original bio might be submitted, so we shoud increase bi_remaining to
account for it when we deal with the error that the device is missing or
is not writeable, or we would skip the endio handle.

Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/volumes.c

index 4ca3c92..c83b242 100644 (file)
@@ -5359,6 +5359,15 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
        return 0;
 }
 
+static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio, int err)
+{
+       if (likely(bbio->flags & BTRFS_BIO_ORIG_BIO_SUBMITTED))
+               bio_endio_nodec(bio, err);
+       else
+               bio_endio(bio, err);
+       kfree(bbio);
+}
+
 static void btrfs_end_bio(struct bio *bio, int err)
 {
        struct btrfs_bio *bbio = bio->bi_private;
@@ -5416,11 +5425,7 @@ static void btrfs_end_bio(struct bio *bio, int err)
                        err = 0;
                }
 
-               if (likely(bbio->flags & BTRFS_BIO_ORIG_BIO_SUBMITTED))
-                       bio_endio_nodec(bio, err);
-               else
-                       bio_endio(bio, err);
-               kfree(bbio);
+               btrfs_end_bbio(bbio, bio, err);
        } else if (!is_orig_bio) {
                bio_put(bio);
        }
@@ -5583,12 +5588,15 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical)
 {
        atomic_inc(&bbio->error);
        if (atomic_dec_and_test(&bbio->stripes_pending)) {
+               /* Shoud be the original bio. */
+               WARN_ON(bio != bbio->orig_bio);
+
                bio->bi_private = bbio->private;
                bio->bi_end_io = bbio->end_io;
                btrfs_io_bio(bio)->mirror_num = bbio->mirror_num;
                bio->bi_iter.bi_sector = logical >> 9;
-               kfree(bbio);
-               bio_endio(bio, -EIO);
+
+               btrfs_end_bbio(bbio, bio, -EIO);
        }
 }