diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2010-07-04 00:08:57 -0700 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2010-07-04 00:08:57 -0700 |
commit | 6d4844bb7aeae01a639c50fb84727fb51c7716c9 (patch) | |
tree | ff787c54029bfcf6382e06b4918beab2f2a306e8 | |
parent | f71c2693027f73e90b693ca5a8c2b8a06ba116cb (diff) |
Hooksbcache-6
-rw-r--r-- | block/blk-core.c | 10 | ||||
-rw-r--r-- | fs/bio.c | 26 | ||||
-rw-r--r-- | include/linux/bio.h | 3 | ||||
-rw-r--r-- | include/linux/blkdev.h | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 5 |
5 files changed, 43 insertions, 3 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index f0640d7f800f..4d54e9e9951c 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1428,11 +1428,11 @@ static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors) * bi_sector for remaps as it sees fit. So the values of these fields * should NOT be depended on after the call to generic_make_request. */ -static inline void __generic_make_request(struct bio *bio) +inline void __generic_make_request(struct bio *bio) { struct request_queue *q; sector_t old_sector; - int ret, nr_sectors = bio_sectors(bio); + int ret = 1, nr_sectors = bio_sectors(bio); dev_t old_dev; int err = -EIO; @@ -1505,7 +1505,10 @@ static inline void __generic_make_request(struct bio *bio) trace_block_bio_queue(q, bio); - ret = q->make_request_fn(q, bio); + if (bio->bi_bdev->bd_cache_fn) + ret = bio->bi_bdev->bd_cache_fn(q, bio); + if (ret) + ret = q->make_request_fn(q, bio); } while (ret); return; @@ -1513,6 +1516,7 @@ static inline void __generic_make_request(struct bio *bio) end_io: bio_endio(bio, err); } +EXPORT_SYMBOL_GPL(__generic_make_request); /* * We only want one ->make_request_fn to be active at a time, @@ -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)) { diff --git a/include/linux/bio.h b/include/linux/bio.h index 7fc5606e6ea5..d9c84da76a01 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -94,6 +94,8 @@ struct bio { struct bio_vec *bi_io_vec; /* the actual vec list */ + atomic_t bi_remaining; /* split count */ + bio_end_io_t *bi_end_io; void *bi_private; @@ -364,6 +366,7 @@ extern void bio_put(struct bio *); extern void bio_free(struct bio *, struct bio_set *); extern void bio_endio(struct bio *, int); +extern void bio_split_endio(struct bio *bio, int error); struct request_queue; extern int bio_phys_segments(struct request_queue *, struct bio *); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 09a840264d6f..8978c29b899e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -347,6 +347,7 @@ struct request_queue make_request_fn *make_request_fn; prep_rq_fn *prep_rq_fn; unplug_fn *unplug_fn; + unplug_fn *cache_unplug_fn; merge_bvec_fn *merge_bvec_fn; prepare_flush_fn *prepare_flush_fn; softirq_done_fn *softirq_done_fn; @@ -772,6 +773,7 @@ static inline void rq_flush_dcache_pages(struct request *rq) extern int blk_register_queue(struct gendisk *disk); extern void blk_unregister_queue(struct gendisk *disk); extern void register_disk(struct gendisk *dev); +extern void __generic_make_request(struct bio *bio); extern void generic_make_request(struct bio *bio); extern void blk_rq_init(struct request_queue *q, struct request *rq); extern void blk_put_request(struct request *); diff --git a/include/linux/fs.h b/include/linux/fs.h index 471e1ff5079a..0c0a04ee6232 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -514,6 +514,8 @@ enum positive_aop_returns { struct page; struct address_space; struct writeback_control; +struct bio; +struct request_queue; struct iov_iter { const struct iovec *iov; @@ -665,6 +667,9 @@ struct block_device { int bd_invalidated; struct gendisk * bd_disk; struct list_head bd_list; + + int (*bd_cache_fn)(struct request_queue *q, struct bio *bio); + char bd_cache_identifier; /* * Private data. You must have bd_claim'ed the block_device * to use this. NOTE: bd_claim allows an owner to claim |