Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1742521 > unrolled thread
| Started by | Ming Lei <ming.lei@redhat.com> |
|---|---|
| First post | 2017-09-30 08:20 +0200 |
| Last post | 2017-09-30 12:00 +0200 |
| Articles | 9 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH V7 0/6] block/scsi: safe SCSI quiescing Ming Lei <ming.lei@redhat.com> - 2017-09-30 08:20 +0200
[PATCH V7 5/6] block: support PREEMPT_ONLY Ming Lei <ming.lei@redhat.com> - 2017-09-30 08:20 +0200
Re: [PATCH V7 5/6] block: support PREEMPT_ONLY Bart Van Assche <Bart.VanAssche@wdc.com> - 2017-10-02 22:50 +0200
[PATCH V7 2/6] block: tracking request allocation with q_usage_counter Ming Lei <ming.lei@redhat.com> - 2017-09-30 08:20 +0200
Re: [PATCH V7 2/6] block: tracking request allocation with q_usage_counter Christoph Hellwig <hch@infradead.org> - 2017-10-02 22:50 +0200
Re: [PATCH V7 2/6] block: tracking request allocation with q_usage_counter Bart Van Assche <Bart.VanAssche@wdc.com> - 2017-10-02 22:50 +0200
[PATCH V7 4/6] block: prepare for passing RQF_PREEMPT to request allocation Ming Lei <ming.lei@redhat.com> - 2017-09-30 08:20 +0200
Re: [PATCH V7 0/6] block/scsi: safe SCSI quiescing Martin Steigerwald <martin@lichtvoll.de> - 2017-09-30 11:50 +0200
Re: [PATCH V7 0/6] block/scsi: safe SCSI quiescing Ming Lei <ming.lei@redhat.com> - 2017-09-30 12:00 +0200
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 08:20 +0200 |
| Subject | [PATCH V7 0/6] block/scsi: safe SCSI quiescing |
| Message-ID | <uvji1-nu-3@gated-at.bofh.it> |
Hi Jens,
Please consider this patchset for V4.15, and it fixes one
kind of long-term I/O hang issue in either block legacy path
or blk-mq.
The current SCSI quiesce isn't safe and easy to trigger I/O deadlock.
Once SCSI device is put into QUIESCE, no new request except for
RQF_PREEMPT can be dispatched to SCSI successfully, and
scsi_device_quiesce() just simply waits for completion of I/Os
dispatched to SCSI stack. It isn't enough at all.
Because new request still can be comming, but all the allocated
requests can't be dispatched successfully, so request pool can be
consumed up easily.
Then request with RQF_PREEMPT can't be allocated and wait forever,
then system hangs forever, such as during system suspend or
sending SCSI domain alidation in case of transport_spi.
Both IO hang inside system suspend[1] or SCSI domain validation
were reported before.
This patch introduces preempt only mode, and solves the issue
by allowing RQF_PREEMP only during SCSI quiesce.
Both SCSI and SCSI_MQ have this IO deadlock issue, this patch fixes
them all.
V7:
- add Reviewed-by & Tested-by
- one line change in patch 5 for checking preempt request
V6:
- borrow Bart's idea of preempt only, with clean
implementation(patch 5/patch 6)
- needn't any external driver's dependency, such as MD's
change
V5:
- fix one tiny race by introducing blk_queue_enter_preempt_freeze()
given this change is small enough compared with V4, I added
tested-by directly
V4:
- reorganize patch order to make it more reasonable
- support nested preempt freeze, as required by SCSI transport spi
- check preempt freezing in slow path of of blk_queue_enter()
- add "SCSI: transport_spi: resume a quiesced device"
- wake up freeze queue in setting dying for both blk-mq and legacy
- rename blk_mq_[freeze|unfreeze]_queue() in one patch
- rename .mq_freeze_wq and .mq_freeze_depth
- improve comment
V3:
- introduce q->preempt_unfreezing to fix one bug of preempt freeze
- call blk_queue_enter_live() only when queue is preempt frozen
- cleanup a bit on the implementation of preempt freeze
- only patch 6 and 7 are changed
V2:
- drop the 1st patch in V1 because percpu_ref_is_dying() is
enough as pointed by Tejun
- introduce preempt version of blk_[freeze|unfreeze]_queue
- sync between preempt freeze and normal freeze
- fix warning from percpu-refcount as reported by Oleksandr
[1] https://marc.info/?t=150340250100013&r=3&w=2
Thanks,
Ming
Ming Lei (6):
blk-mq: only run hw queues for blk-mq
block: tracking request allocation with q_usage_counter
block: pass flags to blk_queue_enter()
block: prepare for passing RQF_PREEMPT to request allocation
block: support PREEMPT_ONLY
SCSI: set block queue at preempt only when SCSI device is put into
quiesce
block/blk-core.c | 63 +++++++++++++++++++++++++++++++++++++++----------
block/blk-mq.c | 14 ++++-------
block/blk-timeout.c | 2 +-
drivers/scsi/scsi_lib.c | 25 +++++++++++++++++---
fs/block_dev.c | 4 ++--
include/linux/blk-mq.h | 7 +++---
include/linux/blkdev.h | 27 ++++++++++++++++++---
7 files changed, 107 insertions(+), 35 deletions(-)
--
2.9.5
[toc] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 08:20 +0200 |
| Subject | [PATCH V7 5/6] block: support PREEMPT_ONLY |
| Message-ID | <uvji2-nu-19@gated-at.bofh.it> |
| In reply to | #1742521 |
When queue is in PREEMPT_ONLY mode, only RQF_PREEMPT request
can be allocated and dispatched, other requests won't be allowed
to enter I/O path.
This is useful for supporting safe SCSI quiesce.
Part of this patch is from Bart's '[PATCH v4 4∕7] block: Add the QUEUE_FLAG_PREEMPT_ONLY
request queue flag'.
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Martin Steigerwald <martin@lichtvoll.de>
Cc: Bart Van Assche <Bart.VanAssche@wdc.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/blk-core.c | 26 ++++++++++++++++++++++++--
include/linux/blkdev.h | 5 +++++
2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index 95b1c5e50be3..bb683bfe37b2 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -346,6 +346,17 @@ void blk_sync_queue(struct request_queue *q)
}
EXPORT_SYMBOL(blk_sync_queue);
+void blk_set_preempt_only(struct request_queue *q, bool preempt_only)
+{
+ blk_mq_freeze_queue(q);
+ if (preempt_only)
+ queue_flag_set_unlocked(QUEUE_FLAG_PREEMPT_ONLY, q);
+ else
+ queue_flag_clear_unlocked(QUEUE_FLAG_PREEMPT_ONLY, q);
+ blk_mq_unfreeze_queue(q);
+}
+EXPORT_SYMBOL(blk_set_preempt_only);
+
/**
* __blk_run_queue_uncond - run a queue whether or not it has been stopped
* @q: The queue to run
@@ -771,9 +782,18 @@ int blk_queue_enter(struct request_queue *q, unsigned flags)
while (true) {
int ret;
+ /*
+ * preempt_only flag has to be set after queue is frozen,
+ * so it can be checked here lockless and safely
+ */
+ if (blk_queue_preempt_only(q)) {
+ if (!(flags & BLK_REQ_PREEMPT))
+ goto slow_path;
+ }
+
if (percpu_ref_tryget_live(&q->q_usage_counter))
return 0;
-
+ slow_path:
if (flags & BLK_REQ_NOWAIT)
return -EBUSY;
@@ -787,7 +807,9 @@ int blk_queue_enter(struct request_queue *q, unsigned flags)
smp_rmb();
ret = wait_event_interruptible(q->mq_freeze_wq,
- !atomic_read(&q->mq_freeze_depth) ||
+ (!atomic_read(&q->mq_freeze_depth) &&
+ ((flags & BLK_REQ_PREEMPT) ||
+ !blk_queue_preempt_only(q))) ||
blk_queue_dying(q));
if (blk_queue_dying(q))
return -ENODEV;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 68445adc8765..b01a0c6bb1f0 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -631,6 +631,7 @@ struct request_queue {
#define QUEUE_FLAG_REGISTERED 26 /* queue has been registered to a disk */
#define QUEUE_FLAG_SCSI_PASSTHROUGH 27 /* queue supports SCSI commands */
#define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */
+#define QUEUE_FLAG_PREEMPT_ONLY 29 /* only process REQ_PREEMPT requests */
#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
(1 << QUEUE_FLAG_STACKABLE) | \
@@ -735,6 +736,10 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
REQ_FAILFAST_DRIVER))
#define blk_queue_quiesced(q) test_bit(QUEUE_FLAG_QUIESCED, &(q)->queue_flags)
+#define blk_queue_preempt_only(q) \
+ test_bit(QUEUE_FLAG_PREEMPT_ONLY, &(q)->queue_flags)
+
+extern void blk_set_preempt_only(struct request_queue *q, bool preempt_only);
static inline bool blk_account_rq(struct request *rq)
{
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Bart Van Assche <Bart.VanAssche@wdc.com> |
|---|---|
| Date | 2017-10-02 22:50 +0200 |
| Subject | Re: [PATCH V7 5/6] block: support PREEMPT_ONLY |
| Message-ID | <uwfP5-ur-45@gated-at.bofh.it> |
| In reply to | #1742522 |
On Sat, 2017-09-30 at 14:12 +0800, Ming Lei wrote:
> +void blk_set_preempt_only(struct request_queue *q, bool preempt_only)
> +{
> + blk_mq_freeze_queue(q);
> + if (preempt_only)
> + queue_flag_set_unlocked(QUEUE_FLAG_PREEMPT_ONLY, q);
> + else
> + queue_flag_clear_unlocked(QUEUE_FLAG_PREEMPT_ONLY, q);
> + blk_mq_unfreeze_queue(q);
> +}
> +EXPORT_SYMBOL(blk_set_preempt_only);
> +
> /**
> * __blk_run_queue_uncond - run a queue whether or not it has been stopped
> * @q: The queue to run
> @@ -771,9 +782,18 @@ int blk_queue_enter(struct request_queue *q, unsigned flags)
> while (true) {
> int ret;
>
> + /*
> + * preempt_only flag has to be set after queue is frozen,
> + * so it can be checked here lockless and safely
> + */
> + if (blk_queue_preempt_only(q)) {
> + if (!(flags & BLK_REQ_PREEMPT))
> + goto slow_path;
> + }
> +
> if (percpu_ref_tryget_live(&q->q_usage_counter))
> return 0;
Sorry but I don't think that it is possible with these changes to prevent
that a non-preempt request gets allocated after a (SCSI) queue has been
quiesced. If the CPU that calls blk_queue_enter() observes the set of the
PREEMPT_ONLY flag after the queue has been unfrozen and after the SCSI
device state has been changed into QUIESCED then blk_queue_enter() can
succeed for a non-preempt request. I think this is exactly the scenario
we want to avoid. This is why a synchronize_rcu() call is present in my
patch before the queue is unfrozen and also why in my patch the
percpu_ref_tryget_live() call occurs before the test of the PREEMPT_ONLY
flag.
Bart.
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 08:20 +0200 |
| Subject | [PATCH V7 2/6] block: tracking request allocation with q_usage_counter |
| Message-ID | <uvji2-nu-17@gated-at.bofh.it> |
| In reply to | #1742521 |
This usage is basically same with blk-mq, so that we can
support to freeze legacy queue easily.
Also 'wake_up_all(&q->mq_freeze_wq)' has to be moved
into blk_set_queue_dying() since both legacy and blk-mq
may wait on the wait queue of .mq_freeze_wq.
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Martin Steigerwald <martin@lichtvoll.de>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Cc: Bart Van Assche <Bart.VanAssche@wdc.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/blk-core.c | 14 ++++++++++++++
block/blk-mq.c | 7 -------
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index 048be4aa6024..a5011c824ac6 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -610,6 +610,12 @@ void blk_set_queue_dying(struct request_queue *q)
}
spin_unlock_irq(q->queue_lock);
}
+
+ /*
+ * We need to ensure that processes currently waiting on
+ * the queue are notified as well.
+ */
+ wake_up_all(&q->mq_freeze_wq);
}
EXPORT_SYMBOL_GPL(blk_set_queue_dying);
@@ -1395,16 +1401,21 @@ static struct request *blk_old_get_request(struct request_queue *q,
unsigned int op, gfp_t gfp_mask)
{
struct request *rq;
+ int ret = 0;
WARN_ON_ONCE(q->mq_ops);
/* create ioc upfront */
create_io_context(gfp_mask, q->node);
+ ret = blk_queue_enter(q, !(gfp_mask & __GFP_DIRECT_RECLAIM));
+ if (ret)
+ return ERR_PTR(ret);
spin_lock_irq(q->queue_lock);
rq = get_request(q, op, NULL, gfp_mask);
if (IS_ERR(rq)) {
spin_unlock_irq(q->queue_lock);
+ blk_queue_exit(q);
return rq;
}
@@ -1576,6 +1587,7 @@ void __blk_put_request(struct request_queue *q, struct request *req)
blk_free_request(rl, req);
freed_request(rl, sync, rq_flags);
blk_put_rl(rl);
+ blk_queue_exit(q);
}
}
EXPORT_SYMBOL_GPL(__blk_put_request);
@@ -1857,8 +1869,10 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
* Grab a free request. This is might sleep but can not fail.
* Returns with the queue unlocked.
*/
+ blk_queue_enter_live(q);
req = get_request(q, bio->bi_opf, bio, GFP_NOIO);
if (IS_ERR(req)) {
+ blk_queue_exit(q);
__wbt_done(q->rq_wb, wb_acct);
if (PTR_ERR(req) == -ENOMEM)
bio->bi_status = BLK_STS_RESOURCE;
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 6fd9f86fc86d..10c1f49f663d 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -256,13 +256,6 @@ void blk_mq_wake_waiters(struct request_queue *q)
queue_for_each_hw_ctx(q, hctx, i)
if (blk_mq_hw_queue_mapped(hctx))
blk_mq_tag_wakeup_all(hctx->tags, true);
-
- /*
- * If we are called because the queue has now been marked as
- * dying, we need to ensure that processes currently waiting on
- * the queue are notified as well.
- */
- wake_up_all(&q->mq_freeze_wq);
}
bool blk_mq_can_queue(struct blk_mq_hw_ctx *hctx)
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@infradead.org> |
|---|---|
| Date | 2017-10-02 22:50 +0200 |
| Subject | Re: [PATCH V7 2/6] block: tracking request allocation with q_usage_counter |
| Message-ID | <uwfP4-ur-27@gated-at.bofh.it> |
| In reply to | #1742523 |
I think I already gate it to basically the same patch as queued up by Bart, but here again: Reviewed-by: Christoph Hellwig <hch@lst.de>
[toc] | [prev] | [next] | [standalone]
| From | Bart Van Assche <Bart.VanAssche@wdc.com> |
|---|---|
| Date | 2017-10-02 22:50 +0200 |
| Subject | Re: [PATCH V7 2/6] block: tracking request allocation with q_usage_counter |
| Message-ID | <uwfPa-ur-135@gated-at.bofh.it> |
| In reply to | #1742523 |
On Sat, 2017-09-30 at 14:12 +0800, Ming Lei wrote:
> @@ -1395,16 +1401,21 @@ static struct request *blk_old_get_request(struct request_queue *q,
> unsigned int op, gfp_t gfp_mask)
> {
> struct request *rq;
> + int ret = 0;
>
> WARN_ON_ONCE(q->mq_ops);
>
> /* create ioc upfront */
> create_io_context(gfp_mask, q->node);
>
> + ret = blk_queue_enter(q, !(gfp_mask & __GFP_DIRECT_RECLAIM));
> + if (ret)
> + return ERR_PTR(ret);
Can the above blk_queue_enter() call block if the REQ_NOWAIT flag has been
set in the op argument and e.g. gfp_mask == GFP_KERNEL? If so, isn't that a
bug?
Bart.
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 08:20 +0200 |
| Subject | [PATCH V7 4/6] block: prepare for passing RQF_PREEMPT to request allocation |
| Message-ID | <uvji2-nu-23@gated-at.bofh.it> |
| In reply to | #1742521 |
REQF_PREEMPT is a bit special because the request is required
to be dispatched to lld even when SCSI device is quiesced.
So this patch introduces __blk_get_request() and allows users to pass
RQF_PREEMPT flag in, then we can allow to allocate request of RQF_PREEMPT
when queue is in mode of PREEMPT ONLY which will be introduced
in the following patch.
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Martin Steigerwald <martin@lichtvoll.de>
Cc: Bart Van Assche <Bart.VanAssche@wdc.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/blk-core.c | 19 +++++++++----------
block/blk-mq.c | 3 +--
include/linux/blk-mq.h | 7 ++++---
include/linux/blkdev.h | 17 ++++++++++++++---
4 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index 7d5040a6d5a4..95b1c5e50be3 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1398,7 +1398,8 @@ static struct request *get_request(struct request_queue *q, unsigned int op,
}
static struct request *blk_old_get_request(struct request_queue *q,
- unsigned int op, gfp_t gfp_mask)
+ unsigned int op, gfp_t gfp_mask,
+ unsigned int flags)
{
struct request *rq;
int ret = 0;
@@ -1408,8 +1409,7 @@ static struct request *blk_old_get_request(struct request_queue *q,
/* create ioc upfront */
create_io_context(gfp_mask, q->node);
- ret = blk_queue_enter(q, !(gfp_mask & __GFP_DIRECT_RECLAIM) ?
- BLK_REQ_NOWAIT : 0);
+ ret = blk_queue_enter(q, flags & BLK_REQ_BITS_MASK);
if (ret)
return ERR_PTR(ret);
spin_lock_irq(q->queue_lock);
@@ -1427,26 +1427,25 @@ static struct request *blk_old_get_request(struct request_queue *q,
return rq;
}
-struct request *blk_get_request(struct request_queue *q, unsigned int op,
- gfp_t gfp_mask)
+struct request *__blk_get_request(struct request_queue *q, unsigned int op,
+ gfp_t gfp_mask, unsigned int flags)
{
struct request *req;
+ flags |= gfp_mask & __GFP_DIRECT_RECLAIM ? 0 : BLK_REQ_NOWAIT;
if (q->mq_ops) {
- req = blk_mq_alloc_request(q, op,
- (gfp_mask & __GFP_DIRECT_RECLAIM) ?
- 0 : BLK_MQ_REQ_NOWAIT);
+ req = blk_mq_alloc_request(q, op, flags);
if (!IS_ERR(req) && q->mq_ops->initialize_rq_fn)
q->mq_ops->initialize_rq_fn(req);
} else {
- req = blk_old_get_request(q, op, gfp_mask);
+ req = blk_old_get_request(q, op, gfp_mask, flags);
if (!IS_ERR(req) && q->initialize_rq_fn)
q->initialize_rq_fn(req);
}
return req;
}
-EXPORT_SYMBOL(blk_get_request);
+EXPORT_SYMBOL(__blk_get_request);
/**
* blk_requeue_request - put a request back on queue
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 45bff90e08f7..90b43f607e3c 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -384,8 +384,7 @@ struct request *blk_mq_alloc_request(struct request_queue *q, unsigned int op,
struct request *rq;
int ret;
- ret = blk_queue_enter(q, (flags & BLK_MQ_REQ_NOWAIT) ?
- BLK_REQ_NOWAIT : 0);
+ ret = blk_queue_enter(q, flags & BLK_REQ_BITS_MASK);
if (ret)
return ERR_PTR(ret);
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 50c6485cb04f..066a676d7749 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -197,9 +197,10 @@ void blk_mq_free_request(struct request *rq);
bool blk_mq_can_queue(struct blk_mq_hw_ctx *);
enum {
- BLK_MQ_REQ_NOWAIT = (1 << 0), /* return when out of requests */
- BLK_MQ_REQ_RESERVED = (1 << 1), /* allocate from reserved pool */
- BLK_MQ_REQ_INTERNAL = (1 << 2), /* allocate internal/sched tag */
+ BLK_MQ_REQ_NOWAIT = BLK_REQ_NOWAIT, /* return when out of requests */
+ BLK_MQ_REQ_PREEMPT = BLK_REQ_PREEMPT, /* allocate for RQF_PREEMPT */
+ BLK_MQ_REQ_RESERVED = (1 << BLK_REQ_MQ_START_BIT), /* allocate from reserved pool */
+ BLK_MQ_REQ_INTERNAL = (1 << (BLK_REQ_MQ_START_BIT + 1)), /* allocate internal/sched tag */
};
struct request *blk_mq_alloc_request(struct request_queue *q, unsigned int op,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 127f64c7012c..68445adc8765 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -860,7 +860,10 @@ enum {
/* passed to blk_queue_enter */
enum {
- BLK_REQ_NOWAIT = (1 << 0),
+ BLK_REQ_NOWAIT = (1 << 0),
+ BLK_REQ_PREEMPT = (1 << 1),
+ BLK_REQ_MQ_START_BIT = 2,
+ BLK_REQ_BITS_MASK = (1U << BLK_REQ_MQ_START_BIT) - 1,
};
extern unsigned long blk_max_low_pfn, blk_max_pfn;
@@ -945,8 +948,9 @@ extern void blk_rq_init(struct request_queue *q, struct request *rq);
extern void blk_init_request_from_bio(struct request *req, struct bio *bio);
extern void blk_put_request(struct request *);
extern void __blk_put_request(struct request_queue *, struct request *);
-extern struct request *blk_get_request(struct request_queue *, unsigned int op,
- gfp_t gfp_mask);
+extern struct request *__blk_get_request(struct request_queue *,
+ unsigned int op, gfp_t gfp_mask,
+ unsigned int flags);
extern void blk_requeue_request(struct request_queue *, struct request *);
extern int blk_lld_busy(struct request_queue *q);
extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
@@ -997,6 +1001,13 @@ blk_status_t errno_to_blk_status(int errno);
bool blk_mq_poll(struct request_queue *q, blk_qc_t cookie);
+static inline struct request *blk_get_request(struct request_queue *q,
+ unsigned int op,
+ gfp_t gfp_mask)
+{
+ return __blk_get_request(q, op, gfp_mask, 0);
+}
+
static inline struct request_queue *bdev_get_queue(struct block_device *bdev)
{
return bdev->bd_disk->queue; /* this is never NULL */
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Martin Steigerwald <martin@lichtvoll.de> |
|---|---|
| Date | 2017-09-30 11:50 +0200 |
| Message-ID | <uvmzg-2mW-9@gated-at.bofh.it> |
| In reply to | #1742521 |
Hi Ming. Ming Lei - 30.09.17, 14:12: > Please consider this patchset for V4.15, and it fixes one > kind of long-term I/O hang issue in either block legacy path > or blk-mq. > > The current SCSI quiesce isn't safe and easy to trigger I/O deadlock. Isn´t that material for -stable as well? I´d love to see this go into 4.14. Especially as its an LTS release. Thanks, Martin > Once SCSI device is put into QUIESCE, no new request except for > RQF_PREEMPT can be dispatched to SCSI successfully, and > scsi_device_quiesce() just simply waits for completion of I/Os > dispatched to SCSI stack. It isn't enough at all. > > Because new request still can be comming, but all the allocated > requests can't be dispatched successfully, so request pool can be > consumed up easily. > > Then request with RQF_PREEMPT can't be allocated and wait forever, > then system hangs forever, such as during system suspend or > sending SCSI domain alidation in case of transport_spi. > > Both IO hang inside system suspend[1] or SCSI domain validation > were reported before. > > This patch introduces preempt only mode, and solves the issue > by allowing RQF_PREEMP only during SCSI quiesce. > > Both SCSI and SCSI_MQ have this IO deadlock issue, this patch fixes > them all. > > V7: > - add Reviewed-by & Tested-by > - one line change in patch 5 for checking preempt request > > V6: > - borrow Bart's idea of preempt only, with clean > implementation(patch 5/patch 6) > - needn't any external driver's dependency, such as MD's > change > > V5: > - fix one tiny race by introducing blk_queue_enter_preempt_freeze() > given this change is small enough compared with V4, I added > tested-by directly > > V4: > - reorganize patch order to make it more reasonable > - support nested preempt freeze, as required by SCSI transport spi > - check preempt freezing in slow path of of blk_queue_enter() > - add "SCSI: transport_spi: resume a quiesced device" > - wake up freeze queue in setting dying for both blk-mq and legacy > - rename blk_mq_[freeze|unfreeze]_queue() in one patch > - rename .mq_freeze_wq and .mq_freeze_depth > - improve comment > > V3: > - introduce q->preempt_unfreezing to fix one bug of preempt freeze > - call blk_queue_enter_live() only when queue is preempt frozen > - cleanup a bit on the implementation of preempt freeze > - only patch 6 and 7 are changed > > V2: > - drop the 1st patch in V1 because percpu_ref_is_dying() is > enough as pointed by Tejun > - introduce preempt version of blk_[freeze|unfreeze]_queue > - sync between preempt freeze and normal freeze > - fix warning from percpu-refcount as reported by Oleksandr > > > [1] https://marc.info/?t=150340250100013&r=3&w=2 > > > Thanks, > Ming > > Ming Lei (6): > blk-mq: only run hw queues for blk-mq > block: tracking request allocation with q_usage_counter > block: pass flags to blk_queue_enter() > block: prepare for passing RQF_PREEMPT to request allocation > block: support PREEMPT_ONLY > SCSI: set block queue at preempt only when SCSI device is put into > quiesce > > block/blk-core.c | 63 > +++++++++++++++++++++++++++++++++++++++---------- block/blk-mq.c | > 14 ++++------- > block/blk-timeout.c | 2 +- > drivers/scsi/scsi_lib.c | 25 +++++++++++++++++--- > fs/block_dev.c | 4 ++-- > include/linux/blk-mq.h | 7 +++--- > include/linux/blkdev.h | 27 ++++++++++++++++++--- > 7 files changed, 107 insertions(+), 35 deletions(-) -- Martin
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 12:00 +0200 |
| Message-ID | <uvmIV-2qS-5@gated-at.bofh.it> |
| In reply to | #1742582 |
Hi Martin, On Sat, Sep 30, 2017 at 11:47:10AM +0200, Martin Steigerwald wrote: > Hi Ming. > > Ming Lei - 30.09.17, 14:12: > > Please consider this patchset for V4.15, and it fixes one > > kind of long-term I/O hang issue in either block legacy path > > or blk-mq. > > > > The current SCSI quiesce isn't safe and easy to trigger I/O deadlock. > > Isn´t that material for -stable as well? Yeah, the patch 6 is CCed to -stable. > > I´d love to see this go into 4.14. Especially as its an LTS release. I am fine with either 4.14 or 4.15, and it is up to Jens. Thanks Ming
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web