mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 13:41:51 +00:00
block: simplify bio_add_page()
Since generic_make_request() can now handle arbitrary size bios, all we have to do is make sure the bvec array doesn't overflow. __bio_add_page() doesn't need to call ->merge_bvec_fn(), where we can get rid of unnecessary code paths. Removing the call to ->merge_bvec_fn() is also fine, as no driver that implements support for BLOCK_PC commands even has a ->merge_bvec_fn() method. Cc: Christoph Hellwig <hch@infradead.org> Cc: Jens Axboe <axboe@kernel.dk> Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> [dpark: rebase and resolve merge conflicts, change a couple of comments, make bio_add_page() warn once upon a cloned bio.] Signed-off-by: Dongsu Park <dpark@posteo.net> Signed-off-by: Ming Lin <ming.l@ssi.samsung.com> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
54efd50bfd
commit
c66a14d07c
135
block/bio.c
135
block/bio.c
@ -716,9 +716,23 @@ int bio_get_nr_vecs(struct block_device *bdev)
|
||||
}
|
||||
EXPORT_SYMBOL(bio_get_nr_vecs);
|
||||
|
||||
static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
|
||||
*page, unsigned int len, unsigned int offset,
|
||||
unsigned int max_sectors)
|
||||
/**
|
||||
* bio_add_pc_page - attempt to add page to bio
|
||||
* @q: the target queue
|
||||
* @bio: destination bio
|
||||
* @page: page to add
|
||||
* @len: vec entry length
|
||||
* @offset: vec entry offset
|
||||
*
|
||||
* Attempt to add a page to the bio_vec maplist. This can fail for a
|
||||
* number of reasons, such as the bio being full or target block device
|
||||
* limitations. The target block device must allow bio's up to PAGE_SIZE,
|
||||
* so it is always possible to add a single page to an empty bio.
|
||||
*
|
||||
* This should only be used by REQ_PC bios.
|
||||
*/
|
||||
int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page
|
||||
*page, unsigned int len, unsigned int offset)
|
||||
{
|
||||
int retried_segments = 0;
|
||||
struct bio_vec *bvec;
|
||||
@ -729,7 +743,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
|
||||
if (unlikely(bio_flagged(bio, BIO_CLONED)))
|
||||
return 0;
|
||||
|
||||
if (((bio->bi_iter.bi_size + len) >> 9) > max_sectors)
|
||||
if (((bio->bi_iter.bi_size + len) >> 9) > queue_max_hw_sectors(q))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -742,28 +756,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
|
||||
|
||||
if (page == prev->bv_page &&
|
||||
offset == prev->bv_offset + prev->bv_len) {
|
||||
unsigned int prev_bv_len = prev->bv_len;
|
||||
prev->bv_len += len;
|
||||
|
||||
if (q->merge_bvec_fn) {
|
||||
struct bvec_merge_data bvm = {
|
||||
/* prev_bvec is already charged in
|
||||
bi_size, discharge it in order to
|
||||
simulate merging updated prev_bvec
|
||||
as new bvec. */
|
||||
.bi_bdev = bio->bi_bdev,
|
||||
.bi_sector = bio->bi_iter.bi_sector,
|
||||
.bi_size = bio->bi_iter.bi_size -
|
||||
prev_bv_len,
|
||||
.bi_rw = bio->bi_rw,
|
||||
};
|
||||
|
||||
if (q->merge_bvec_fn(q, &bvm, prev) < prev->bv_len) {
|
||||
prev->bv_len -= len;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bio->bi_iter.bi_size += len;
|
||||
goto done;
|
||||
}
|
||||
@ -806,27 +799,6 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
|
||||
blk_recount_segments(q, bio);
|
||||
}
|
||||
|
||||
/*
|
||||
* if queue has other restrictions (eg varying max sector size
|
||||
* depending on offset), it can specify a merge_bvec_fn in the
|
||||
* queue to get further control
|
||||
*/
|
||||
if (q->merge_bvec_fn) {
|
||||
struct bvec_merge_data bvm = {
|
||||
.bi_bdev = bio->bi_bdev,
|
||||
.bi_sector = bio->bi_iter.bi_sector,
|
||||
.bi_size = bio->bi_iter.bi_size - len,
|
||||
.bi_rw = bio->bi_rw,
|
||||
};
|
||||
|
||||
/*
|
||||
* merge_bvec_fn() returns number of bytes it can accept
|
||||
* at this offset
|
||||
*/
|
||||
if (q->merge_bvec_fn(q, &bvm, bvec) < bvec->bv_len)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* If we may be able to merge these biovecs, force a recount */
|
||||
if (bio->bi_vcnt > 1 && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec)))
|
||||
bio_clear_flag(bio, BIO_SEG_VALID);
|
||||
@ -843,28 +815,6 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
|
||||
blk_recount_segments(q, bio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_add_pc_page - attempt to add page to bio
|
||||
* @q: the target queue
|
||||
* @bio: destination bio
|
||||
* @page: page to add
|
||||
* @len: vec entry length
|
||||
* @offset: vec entry offset
|
||||
*
|
||||
* Attempt to add a page to the bio_vec maplist. This can fail for a
|
||||
* number of reasons, such as the bio being full or target block device
|
||||
* limitations. The target block device must allow bio's up to PAGE_SIZE,
|
||||
* so it is always possible to add a single page to an empty bio.
|
||||
*
|
||||
* This should only be used by REQ_PC bios.
|
||||
*/
|
||||
int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page *page,
|
||||
unsigned int len, unsigned int offset)
|
||||
{
|
||||
return __bio_add_page(q, bio, page, len, offset,
|
||||
queue_max_hw_sectors(q));
|
||||
}
|
||||
EXPORT_SYMBOL(bio_add_pc_page);
|
||||
|
||||
/**
|
||||
@ -874,22 +824,47 @@ EXPORT_SYMBOL(bio_add_pc_page);
|
||||
* @len: vec entry length
|
||||
* @offset: vec entry offset
|
||||
*
|
||||
* Attempt to add a page to the bio_vec maplist. This can fail for a
|
||||
* number of reasons, such as the bio being full or target block device
|
||||
* limitations. The target block device must allow bio's up to PAGE_SIZE,
|
||||
* so it is always possible to add a single page to an empty bio.
|
||||
* Attempt to add a page to the bio_vec maplist. This will only fail
|
||||
* if either bio->bi_vcnt == bio->bi_max_vecs or it's a cloned bio.
|
||||
*/
|
||||
int bio_add_page(struct bio *bio, struct page *page, unsigned int len,
|
||||
unsigned int offset)
|
||||
int bio_add_page(struct bio *bio, struct page *page,
|
||||
unsigned int len, unsigned int offset)
|
||||
{
|
||||
struct request_queue *q = bdev_get_queue(bio->bi_bdev);
|
||||
unsigned int max_sectors;
|
||||
struct bio_vec *bv;
|
||||
|
||||
max_sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector);
|
||||
if ((max_sectors < (len >> 9)) && !bio->bi_iter.bi_size)
|
||||
max_sectors = len >> 9;
|
||||
/*
|
||||
* cloned bio must not modify vec list
|
||||
*/
|
||||
if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED)))
|
||||
return 0;
|
||||
|
||||
return __bio_add_page(q, bio, page, len, offset, max_sectors);
|
||||
/*
|
||||
* For filesystems with a blocksize smaller than the pagesize
|
||||
* we will often be called with the same page as last time and
|
||||
* a consecutive offset. Optimize this special case.
|
||||
*/
|
||||
if (bio->bi_vcnt > 0) {
|
||||
bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
|
||||
|
||||
if (page == bv->bv_page &&
|
||||
offset == bv->bv_offset + bv->bv_len) {
|
||||
bv->bv_len += len;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (bio->bi_vcnt >= bio->bi_max_vecs)
|
||||
return 0;
|
||||
|
||||
bv = &bio->bi_io_vec[bio->bi_vcnt];
|
||||
bv->bv_page = page;
|
||||
bv->bv_len = len;
|
||||
bv->bv_offset = offset;
|
||||
|
||||
bio->bi_vcnt++;
|
||||
done:
|
||||
bio->bi_iter.bi_size += len;
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(bio_add_page);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user