btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_FLUSH_ERRS);
 }
 
-static struct workqueue_struct *btrfs_end_io_wq(struct btrfs_io_context *bioc)
+static struct workqueue_struct *btrfs_end_io_wq(struct btrfs_fs_info *fs_info,
+                                               struct bio *bio)
 {
-       if (bioc->orig_bio->bi_opf & REQ_META)
-               return bioc->fs_info->endio_meta_workers;
-       return bioc->fs_info->endio_workers;
+       if (bio->bi_opf & REQ_META)
+               return fs_info->endio_meta_workers;
+       return fs_info->endio_workers;
 }
 
 static void btrfs_end_bio_work(struct work_struct *work)
        bbio->end_io(bbio);
 }
 
+static void btrfs_simple_end_io(struct bio *bio)
+{
+       struct btrfs_fs_info *fs_info = bio->bi_private;
+       struct btrfs_bio *bbio = btrfs_bio(bio);
+
+       btrfs_bio_counter_dec(fs_info);
+
+       if (bio->bi_status)
+               btrfs_log_dev_io_error(bio, bbio->device);
+
+       if (bio_op(bio) == REQ_OP_READ) {
+               INIT_WORK(&bbio->end_io_work, btrfs_end_bio_work);
+               queue_work(btrfs_end_io_wq(fs_info, bio), &bbio->end_io_work);
+       } else {
+               bbio->end_io(bbio);
+       }
+}
+
 static void btrfs_raid56_end_io(struct bio *bio)
 {
        struct btrfs_io_context *bioc = bio->bi_private;
        btrfs_put_bioc(bioc);
 }
 
-static void btrfs_end_bio(struct bio *bio)
+static void btrfs_orig_write_end_io(struct bio *bio)
 {
        struct btrfs_io_stripe *stripe = bio->bi_private;
        struct btrfs_io_context *bioc = stripe->bioc;
                btrfs_log_dev_io_error(bio, stripe->dev);
        }
 
-       bbio->mirror_num = bioc->mirror_num;
-
        /*
         * Only send an error to the higher layers if it is beyond the tolerance
         * threshold.
        else
                bio->bi_status = BLK_STS_OK;
 
-       if (btrfs_op(bio) == BTRFS_MAP_READ) {
-               INIT_WORK(&bbio->end_io_work, btrfs_end_bio_work);
-               queue_work(btrfs_end_io_wq(bioc), &bbio->end_io_work);
-       } else {
-               bbio->end_io(bbio);
-       }
-
+       bbio->end_io(bbio);
        btrfs_put_bioc(bioc);
 }
 
        submit_bio(bio);
 }
 
-static void submit_stripe_bio(struct btrfs_io_context *bioc, int dev_nr)
+static void btrfs_submit_mirrored_bio(struct btrfs_io_context *bioc, int dev_nr)
 {
        struct bio *orig_bio = bioc->orig_bio, *bio;
 
+       ASSERT(bio_op(orig_bio) != REQ_OP_READ);
+
        /* Reuse the bio embedded into the btrfs_bio for the last mirror */
        if (dev_nr == bioc->num_stripes - 1) {
                bio = orig_bio;
-               btrfs_bio(bio)->device = bioc->stripes[dev_nr].dev;
-               bio->bi_end_io = btrfs_end_bio;
+               bio->bi_end_io = btrfs_orig_write_end_io;
        } else {
                bio = bio_alloc_clone(NULL, orig_bio, GFP_NOFS, &fs_bio_set);
                bio_inc_remaining(orig_bio);
        u64 logical = bio->bi_iter.bi_sector << 9;
        u64 length = bio->bi_iter.bi_size;
        u64 map_length = length;
-       int ret;
-       int dev_nr;
-       int total_devs;
        struct btrfs_io_context *bioc = NULL;
+       struct btrfs_io_stripe smap;
+       int ret;
 
        btrfs_bio_counter_inc_blocked(fs_info);
        ret = __btrfs_map_block(fs_info, btrfs_op(bio), logical, &map_length,
-                               &bioc, NULL, &mirror_num, 1);
+                               &bioc, &smap, &mirror_num, 1);
        if (ret) {
                btrfs_bio_counter_dec(fs_info);
                btrfs_bio_end_io(btrfs_bio(bio), errno_to_blk_status(ret));
                return;
        }
 
-       total_devs = bioc->num_stripes;
-       bioc->orig_bio = bio;
-
-       if ((bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) &&
-           ((btrfs_op(bio) == BTRFS_MAP_WRITE) || (mirror_num > 1))) {
-               bio->bi_private = bioc;
-               bio->bi_end_io = btrfs_raid56_end_io;
-               if (btrfs_op(bio) == BTRFS_MAP_WRITE)
-                       raid56_parity_write(bio, bioc);
-               else
-                       raid56_parity_recover(bio, bioc, mirror_num);
-               return;
-       }
-
        if (map_length < length) {
                btrfs_crit(fs_info,
                           "mapping failed logical %llu bio len %llu len %llu",
                BUG();
        }
 
-       for (dev_nr = 0; dev_nr < total_devs; dev_nr++)
-               submit_stripe_bio(bioc, dev_nr);
+       if (!bioc) {
+               /* Single mirror read/write fast path */
+               btrfs_bio(bio)->mirror_num = mirror_num;
+               btrfs_bio(bio)->device = smap.dev;
+               bio->bi_iter.bi_sector = smap.physical >> SECTOR_SHIFT;
+               bio->bi_private = fs_info;
+               bio->bi_end_io = btrfs_simple_end_io;
+               btrfs_submit_dev_bio(smap.dev, bio);
+       } else if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
+               /* Parity RAID write or read recovery */
+               bio->bi_private = bioc;
+               bio->bi_end_io = btrfs_raid56_end_io;
+               if (bio_op(bio) == REQ_OP_READ)
+                       raid56_parity_recover(bio, bioc, mirror_num);
+               else
+                       raid56_parity_write(bio, bioc);
+       } else {
+               /* Write to multiple mirrors */
+               int total_devs = bioc->num_stripes;
+               int dev_nr;
+
+               bioc->orig_bio = bio;
+               for (dev_nr = 0; dev_nr < total_devs; dev_nr++)
+                       btrfs_submit_mirrored_bio(bioc, dev_nr);
+       }
 }
 
 static bool dev_args_match_fs_devices(const struct btrfs_dev_lookup_args *args,