From: Bijan Mottahedeh <[email protected]>
To: [email protected]
Cc: [email protected], [email protected]
Subject: [PATCH 1/1] block: Manage bio references so the bio persists until necessary
Date: Thu, 30 Jan 2020 19:23:42 -0800 [thread overview]
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
Get a reference to a bio, so it won't be freed if end_io() gets to
it before submit_io() returns. Defer the release of the first bio
in a mult-bio request until the last end_io() since the first bio is
embedded in the dio structure and must therefore persist through an
entire multi-bio request.
Signed-off-by: Bijan Mottahedeh <[email protected]>
---
fs/block_dev.c | 78 ++++++++++++++++++++++++++++++----------------------------
1 file changed, 40 insertions(+), 38 deletions(-)
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 69bf2fb..19fff6b 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -303,7 +303,9 @@ static void blkdev_bio_end_io(struct bio *bio)
if (bio->bi_status && !dio->bio.bi_status)
dio->bio.bi_status = bio->bi_status;
- if (!dio->multi_bio || atomic_dec_and_test(&dio->ref)) {
+ if (atomic_dec_and_test(&dio->ref)) {
+ if (dio->multi_bio)
+ bio_put(&dio->bio);
if (!dio->is_sync) {
struct kiocb *iocb = dio->iocb;
ssize_t ret;
@@ -316,8 +318,6 @@ static void blkdev_bio_end_io(struct bio *bio)
}
dio->iocb->ki_complete(iocb, ret, 0);
- if (dio->multi_bio)
- bio_put(&dio->bio);
} else {
struct task_struct *waiter = dio->waiter;
@@ -348,6 +348,7 @@ static void blkdev_bio_end_io(struct bio *bio)
loff_t pos = iocb->ki_pos;
blk_qc_t qc = BLK_QC_T_NONE;
int ret = 0;
+ int nr_bios = 1;
if ((pos | iov_iter_alignment(iter)) &
(bdev_logical_block_size(bdev) - 1))
@@ -357,16 +358,15 @@ static void blkdev_bio_end_io(struct bio *bio)
dio = container_of(bio, struct blkdev_dio, bio);
dio->is_sync = is_sync = is_sync_kiocb(iocb);
- if (dio->is_sync) {
+ if (dio->is_sync)
dio->waiter = current;
- bio_get(bio);
- } else {
+ else
dio->iocb = iocb;
- }
dio->size = 0;
dio->multi_bio = false;
dio->should_dirty = is_read && iter_is_iovec(iter);
+ atomic_set(&dio->ref, 1);
/*
* Don't plug for HIPRI/polled IO, as those should go straight
@@ -375,7 +375,7 @@ static void blkdev_bio_end_io(struct bio *bio)
if (!is_poll)
blk_start_plug(&plug);
- for (;;) {
+ do {
bio_set_dev(bio, bdev);
bio->bi_iter.bi_sector = pos >> 9;
bio->bi_write_hint = iocb->ki_hint;
@@ -403,62 +403,64 @@ static void blkdev_bio_end_io(struct bio *bio)
pos += bio->bi_iter.bi_size;
nr_pages = iov_iter_npages(iter, BIO_MAX_PAGES);
- if (!nr_pages) {
- bool polled = false;
+ if (!nr_pages && is_poll)
+ bio_set_polled(bio, iocb);
- if (iocb->ki_flags & IOCB_HIPRI) {
- bio_set_polled(bio, iocb);
- polled = true;
- }
+ /*
+ * Get a reference to a bio, so it won't be freed
+ * if end_io() gets to it before submit_io() returns.
+ * Defer the release of the first bio in a mult-bio
+ * request until the last end_io() since the first bio
+ * is embedded in the dio structure and must therefore
+ * persist through an entire multi-bio request.
+ */
+ bio_get(bio);
- qc = submit_bio(bio);
+ qc = submit_bio(bio);
- if (polled)
- WRITE_ONCE(iocb->ki_cookie, qc);
- break;
- }
+ if (bio->bi_opf & REQ_HIPRI)
+ WRITE_ONCE(iocb->ki_cookie, qc);
- if (!dio->multi_bio) {
- /*
- * AIO needs an extra reference to ensure the dio
- * structure which is embedded into the first bio
- * stays around.
- */
- if (!is_sync)
- bio_get(bio);
- dio->multi_bio = true;
- atomic_set(&dio->ref, 2);
- } else {
+ if (nr_pages) {
+ if (++nr_bios == 2)
+ dio->multi_bio = true;
+ else
+ bio_put(bio);
+ bio = bio_alloc(GFP_KERNEL, nr_pages);
atomic_inc(&dio->ref);
}
-
- submit_bio(bio);
- bio = bio_alloc(GFP_KERNEL, nr_pages);
- }
+ } while (nr_pages);
if (!is_poll)
blk_finish_plug(&plug);
- if (!is_sync)
- return -EIOCBQUEUED;
+ if (!is_sync) {
+ ret = -EIOCBQUEUED;
+ goto done;
+ }
+
+ if (!blk_qc_t_valid(qc))
+ goto done;
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (!READ_ONCE(dio->waiter))
break;
- if (!(iocb->ki_flags & IOCB_HIPRI) ||
+ if (!is_poll ||
!blk_poll(bdev_get_queue(bdev), qc, true))
io_schedule();
}
__set_current_state(TASK_RUNNING);
+done:
if (!ret)
ret = blk_status_to_errno(dio->bio.bi_status);
if (likely(!ret))
ret = dio->size;
- bio_put(&dio->bio);
+ if (!dio->multi_bio)
+ bio_put(&dio->bio);
return ret;
}
--
1.8.3.1
next prev parent reply other threads:[~2020-01-31 3:24 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-01-31 3:23 [PATCH 0/1] block: Manage bio references so the bio persists until necessary Bijan Mottahedeh
2020-01-31 3:23 ` Bijan Mottahedeh [this message]
2020-01-31 6:42 ` [PATCH 1/1] " Christoph Hellwig
2020-01-31 18:08 ` Bijan Mottahedeh
2020-02-03 8:34 ` Christoph Hellwig
2020-02-03 21:07 ` Bijan Mottahedeh
2020-02-04 7:51 ` Christoph Hellwig
2020-02-04 20:59 ` Jens Axboe
2020-02-04 22:41 ` Bijan Mottahedeh
2020-02-24 23:32 ` Bijan Mottahedeh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1580441022-59129-2-git-send-email-bijan.mottahedeh@oracle.com \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox