dm-buffered: fix bugs in __process_any_flush There were these bugs in __process_any_flush: * sync_writes only flushes bios with the REQ_SYNC flag. It should flush all write bios. * If the I/O failed and flush succeeded, bio->bi_status would erroneously overwrite bio->bi_status with zero, and the I/O error would not be reported. * We should only flush cache on write bios, the code would erroneously flush cache for read bios with REQ_SYNC or REQ_FUA too. Signed-off-by: Mikulas Patocka --- drivers/md/dm-buffered-target.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) Index: linux-2.6/drivers/md/dm-buffered-target.c =================================================================== --- linux-2.6.orig/drivers/md/dm-buffered-target.c +++ linux-2.6/drivers/md/dm-buffered-target.c @@ -256,19 +256,25 @@ static void _io(struct buffered_c *bc, s static blk_status_t __process_any_flush(struct buffered_c *bc, struct bio *bio) { bool flush = false; + blk_status_t r = BLK_STS_OK; - if (bio->bi_opf & REQ_FUA) { - atomic_inc(&bc->stats[S_FUA]); - flush = true; - } else if (bc->sync_writes && (bio->bi_opf & REQ_SYNC)) { - atomic_inc(&bc->stats[S_SYNC_WRITES]); - flush = true; + if (bio_op(bio) == REQ_OP_WRITE) { + if (bio->bi_opf & REQ_FUA) { + atomic_inc(&bc->stats[S_FUA]); + flush = true; + } else if (bc->sync_writes) { + atomic_inc(&bc->stats[S_SYNC_WRITES]); + flush = true; + } } - if (flush) - bio->bi_status = _buffered_flush(bc); + if (flush) { + r = _buffered_flush(bc); + if (r && !bio->bi_status) + bio->bi_status = r; + } - return bio->bi_status; + return r; } /*