diff options
Diffstat (limited to 'fs/bio.c')
-rw-r--r-- | fs/bio.c | 26 |
1 files changed, 26 insertions, 0 deletions
@@ -257,6 +257,7 @@ void bio_init(struct bio *bio) bio->bi_flags = 1 << BIO_UPTODATE; bio->bi_comp_cpu = -1; atomic_set(&bio->bi_cnt, 1); + atomic_set(&bio->bi_remaining, 1); } EXPORT_SYMBOL(bio_init); @@ -1422,16 +1423,41 @@ EXPORT_SYMBOL(bio_flush_dcache_pages); **/ void bio_endio(struct bio *bio, int error) { + int old, new; if (error) clear_bit(BIO_UPTODATE, &bio->bi_flags); else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) error = -EIO; + if (error) { + do { + old = new = atomic_read(&bio->bi_remaining); + if (!(new >> 16)) + new += -error << 16; + + } while (atomic_cmpxchg(&bio->bi_remaining, old, --new) != old); + } else { + new = atomic_sub_return(1, &bio->bi_remaining); + error = -(new >> 16); + } + + if (new & ~(~0 << 16)) + return; + atomic_set(&bio->bi_remaining, 0); + if (bio->bi_end_io) bio->bi_end_io(bio, error); } EXPORT_SYMBOL(bio_endio); +void bio_split_endio(struct bio *bio, int error) +{ + struct bio *p = bio->bi_private; + bio_put(bio); + bio_endio(p, error); +} +EXPORT_SYMBOL(bio_split_endio); + void bio_pair_release(struct bio_pair *bp) { if (atomic_dec_and_test(&bp->cnt)) { |