From: Damien Le Moal <damien.lemoal@wdc.com>
To: linux-scsi@vger.kernel.org,
"Martin K . Petersen" <martin.petersen@oracle.com>,
linux-block@vger.kernel.org, Jens Axboe <axboe@kernel.dk>
Cc: Christoph Hellwig <hch@lst.de>, Bart Van Assche <Bart.VanAssche@wdc.com>
Subject: [PATCH V6 13/14] block: mq-deadline: Limit write request dispatch for zoned block devices
Date: Mon, 2 Oct 2017 16:15:34 +0900 [thread overview]
Message-ID: <20171002071535.8007-14-damien.lemoal@wdc.com> (raw)
In-Reply-To: <20171002071535.8007-1-damien.lemoal@wdc.com>
When dispatching write requests to a zoned block device, only allow
requests targeting an unlocked zone. Requests targeting a locked zone
are left in the scheduler queue to preserve the initial write order.
If no write request can be dispatched, allow reads to be dispatched
even if the write batch is not done.
To ensure that the search for an appropriate write request is atomic
in deadline_fifo_request() and deadline_next_request() with reagrd to
write requests zone lock state, introduce the spinlock zone_lock.
Holding this lock while doing the search in these functions as well as
when unlocking the target zone of a completed write request in
dd_completed_request() ensure that the search does not pickup a write
request in the middle of a zone queued write sequence.
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
block/mq-deadline.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 68 insertions(+), 3 deletions(-)
diff --git a/block/mq-deadline.c b/block/mq-deadline.c
index 93a1aede5dd0..cbca24e1f96e 100644
--- a/block/mq-deadline.c
+++ b/block/mq-deadline.c
@@ -61,6 +61,7 @@ struct deadline_data {
spinlock_t lock;
struct list_head dispatch;
+ spinlock_t zone_lock;
unsigned long *zones_wlock;
};
@@ -244,12 +245,24 @@ static void deadline_wlock_zone(struct deadline_data *dd,
/*
* Write unlock the target zone of a write request.
+ * Clearing the target zone write lock bit is done with the scheduler zone_lock
+ * spinlock held so that deadline_next_request() and deadline_fifo_request()
+ * cannot see the lock state of a zone change due to a request completion during
+ * their eventual search for an appropriate write request. Otherwise, for a zone
+ * with multiple write requests queued, a non sequential write request
+ * can be chosen.
*/
static void deadline_wunlock_zone(struct deadline_data *dd,
struct request *rq)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dd->zone_lock, flags);
+
WARN_ON_ONCE(!test_and_clear_bit(blk_rq_zone_no(rq), dd->zones_wlock));
deadline_clear_request_zone_wlock(rq);
+
+ spin_unlock_irqrestore(&dd->zone_lock, flags);
}
/*
@@ -279,19 +292,47 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir)
}
/*
+ * Test if a request can be dispatched.
+ */
+static inline bool deadline_can_dispatch_request(struct deadline_data *dd,
+ struct request *rq)
+{
+ if (!deadline_request_needs_zone_wlock(dd, rq))
+ return true;
+ return !deadline_zone_is_wlocked(dd, rq);
+}
+
+/*
* For the specified data direction, return the next request to
* dispatch using arrival ordered lists.
*/
static struct request *
deadline_fifo_request(struct deadline_data *dd, int data_dir)
{
+ struct request *rq;
+ unsigned long flags;
+
if (WARN_ON_ONCE(data_dir != READ && data_dir != WRITE))
return NULL;
if (list_empty(&dd->fifo_list[data_dir]))
return NULL;
- return rq_entry_fifo(dd->fifo_list[data_dir].next);
+ if (!dd->zones_wlock || data_dir == READ)
+ return rq_entry_fifo(dd->fifo_list[data_dir].next);
+
+ spin_lock_irqsave(&dd->zone_lock, flags);
+
+ list_for_each_entry(rq, &dd->fifo_list[WRITE], queuelist) {
+ if (deadline_can_dispatch_request(dd, rq))
+ goto out;
+ }
+ rq = NULL;
+
+out:
+ spin_unlock_irqrestore(&dd->zone_lock, flags);
+
+ return rq;
}
/*
@@ -301,10 +342,25 @@ deadline_fifo_request(struct deadline_data *dd, int data_dir)
static struct request *
deadline_next_request(struct deadline_data *dd, int data_dir)
{
+ struct request *rq;
+ unsigned long flags;
+
if (WARN_ON_ONCE(data_dir != READ && data_dir != WRITE))
return NULL;
- return dd->next_rq[data_dir];
+ rq = dd->next_rq[data_dir];
+ if (!dd->zones_wlock || data_dir == READ)
+ return rq;
+
+ spin_lock_irqsave(&dd->zone_lock, flags);
+ while (rq) {
+ if (deadline_can_dispatch_request(dd, rq))
+ break;
+ rq = deadline_latter_request(rq);
+ }
+ spin_unlock_irqrestore(&dd->zone_lock, flags);
+
+ return rq;
}
/*
@@ -346,7 +402,8 @@ static struct request *__dd_dispatch_request(struct blk_mq_hw_ctx *hctx)
if (reads) {
BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[READ]));
- if (writes && (dd->starved++ >= dd->writes_starved))
+ if (deadline_fifo_request(dd, WRITE) &&
+ (dd->starved++ >= dd->writes_starved))
goto dispatch_writes;
data_dir = READ;
@@ -391,6 +448,13 @@ static struct request *__dd_dispatch_request(struct blk_mq_hw_ctx *hctx)
rq = next_rq;
}
+ /*
+ * If we only have writes queued and none of them can be dispatched,
+ * rq will be NULL.
+ */
+ if (!rq)
+ return NULL;
+
dd->batching = 0;
dispatch_request:
@@ -490,6 +554,7 @@ static int dd_init_queue(struct request_queue *q, struct elevator_type *e)
spin_lock_init(&dd->lock);
INIT_LIST_HEAD(&dd->dispatch);
+ spin_lock_init(&dd->zone_lock);
ret = deadline_init_zones_wlock(q, dd);
if (ret)
goto out_free_dd;
--
2.13.6
next prev parent reply other threads:[~2017-10-02 7:15 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-02 7:15 [PATCH V6 00/14] scsi-mq support for ZBC disks Damien Le Moal
2017-10-02 7:15 ` [PATCH V6 01/14] scsi: sd_zbc: Move ZBC declarations to scsi_proto.h Damien Le Moal
2017-10-02 7:15 ` [PATCH V6 02/14] scsi: sd_zbc: Fix comments and indentation Damien Le Moal
2017-10-02 16:50 ` Bart Van Assche
2017-10-02 7:15 ` [PATCH V6 03/14] scsi: sd_zbc: Rearrange code Damien Le Moal
2017-10-02 7:15 ` [PATCH V6 04/14] scsi: sd_zbc: Use well defined macros Damien Le Moal
2017-10-02 7:15 ` [PATCH V6 05/14] scsi: sd_zbc: Fix sd_zbc_read_zoned_characteristics() Damien Le Moal
2017-10-02 7:15 ` [PATCH V6 06/14] block: Add zoned block device information to request queue Damien Le Moal
2017-10-02 7:15 ` [PATCH V6 07/14] scsi: sd_zbc: Initialize device request queue zoned data Damien Le Moal
2017-10-02 16:57 ` Bart Van Assche
2017-10-02 7:15 ` [PATCH V6 08/14] scsi: sd_zbc: Limit zone write locking to sequential zones Damien Le Moal
2017-10-02 17:00 ` Bart Van Assche
2017-10-02 7:15 ` [PATCH V6 09/14] scsi: sd_zbc: Disable zone write locking with scsi-mq Damien Le Moal
2017-10-02 7:15 ` [PATCH V6 10/14] block: mq-deadline: Add zoned block device data Damien Le Moal
2017-10-02 23:06 ` Bart Van Assche
2017-10-02 7:15 ` [PATCH V6 11/14] blokc: mq-deadline: Introduce dispatch helpers Damien Le Moal
2017-10-02 7:15 ` [PATCH V6 12/14] block: mq-deadline: Introduce zone locking support Damien Le Moal
2017-10-02 23:12 ` Bart Van Assche
2017-10-02 7:15 ` Damien Le Moal [this message]
2017-10-02 23:44 ` [PATCH V6 13/14] block: mq-deadline: Limit write request dispatch for zoned block devices Bart Van Assche
2017-10-03 0:19 ` Damien Le Moal
2017-10-03 20:56 ` Bart Van Assche
2017-10-03 23:03 ` Damien Le Moal
2017-10-02 7:15 ` [PATCH V6 14/14] block: do not set mq default scheduler Damien Le Moal
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=20171002071535.8007-14-damien.lemoal@wdc.com \
--to=damien.lemoal@wdc.com \
--cc=Bart.VanAssche@wdc.com \
--cc=axboe@kernel.dk \
--cc=hch@lst.de \
--cc=linux-block@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.com \
/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