Otherwise we won't be able to retrieve the request from
the tag.
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
---
block/blk-mq.c | 1 +
1 file changed, 1 insertion(+)
@@ -454,7 +454,8 @@ int blk_mq_sched_setup(struct request_queue *q)*/ret=0;queue_for_each_hw_ctx(q,hctx,i){-hctx->sched_tags=blk_mq_alloc_rq_map(set,i,q->nr_requests,0);+hctx->sched_tags=blk_mq_alloc_rq_map(set,i,+q->nr_requests,set->reserved_tags);if(!hctx->sched_tags){ret=-ENOMEM;break;
--
2.7.4
Hm, this may fix the crash, but I'm not sure it'll work as intended.
When we allocate the request, we'll get a reserved scheduler tag, but
then when we go to dispatch the request and call
blk_mq_get_driver_tag(), we'll be competing with all of the normal
requests for a regular driver tag. So maybe on top of this we should add
the BLK_MQ_REQ_RESERVED flag to the allocation attempt in
blk_mq_get_driver_tag() if the scheduler tag is reserved? I'm hazy on
what we expect from reserved tags, so feel free to call me crazy.
@@ -454,7 +454,8 @@ int blk_mq_sched_setup(struct request_queue *q)*/ret=0;queue_for_each_hw_ctx(q,hctx,i){-hctx->sched_tags=blk_mq_alloc_rq_map(set,i,q->nr_requests,0);+hctx->sched_tags=blk_mq_alloc_rq_map(set,i,+q->nr_requests,set->reserved_tags);if(!hctx->sched_tags){ret=-ENOMEM;break;
--
2.7.4
Hm, this may fix the crash, but I'm not sure it'll work as intended.
When we allocate the request, we'll get a reserved scheduler tag, but
then when we go to dispatch the request and call
blk_mq_get_driver_tag(), we'll be competing with all of the normal
requests for a regular driver tag. So maybe on top of this we should add
the BLK_MQ_REQ_RESERVED flag to the allocation attempt in
blk_mq_get_driver_tag() if the scheduler tag is reserved? I'm hazy on
what we expect from reserved tags, so feel free to call me crazy.
Yeah good point, we need to carry it through. Reserved tags exist
because drivers often need a request/tag for error handling. If all
tags currently are used up for regular IO that is stuck, you need
a reserved tag for error handling to guarantee progress.
So Sagi's patch does take it half the way there, but get_driver_tag
really needs to know about this as well, or we will just get stuck
there as well. Two solutions, I can think of:
1) Check the tag value in get_driver_tag, add BLK_MQ_REQ_RESERVED
when allocating a driver tag if above X.
2) Add an RQF_SOMETHING_RESERVED. Add BLK_MQ_REQ_RESERVED in
get_driver_tag if that is set.
Comments?
--
Jens Axboe
Hm, this may fix the crash, but I'm not sure it'll work as intended.
When we allocate the request, we'll get a reserved scheduler tag, but
then when we go to dispatch the request and call
blk_mq_get_driver_tag(), we'll be competing with all of the normal
requests for a regular driver tag. So maybe on top of this we should add
the BLK_MQ_REQ_RESERVED flag to the allocation attempt in
blk_mq_get_driver_tag() if the scheduler tag is reserved? I'm hazy on
what we expect from reserved tags, so feel free to call me crazy.
Yeah good point, we need to carry it through. Reserved tags exist
because drivers often need a request/tag for error handling. If all
tags currently are used up for regular IO that is stuck, you need
a reserved tag for error handling to guarantee progress.
So Sagi's patch does take it half the way there, but get_driver_tag
really needs to know about this as well, or we will just get stuck
there as well. Two solutions, I can think of:
1) Check the tag value in get_driver_tag, add BLK_MQ_REQ_RESERVED
when allocating a driver tag if above X.
2) Add an RQF_SOMETHING_RESERVED. Add BLK_MQ_REQ_RESERVED in
get_driver_tag if that is set.
Comments?
Can't we just not go through the scheduler for reserved tags? Obviously
there is no point in scheduling them...
On Mon, Feb 27, 2017 at 06:10:01PM +0200, Sagi Grimberg wrote:
quoted
quoted
Hm, this may fix the crash, but I'm not sure it'll work as intended.
When we allocate the request, we'll get a reserved scheduler tag, but
then when we go to dispatch the request and call
blk_mq_get_driver_tag(), we'll be competing with all of the normal
requests for a regular driver tag. So maybe on top of this we should add
the BLK_MQ_REQ_RESERVED flag to the allocation attempt in
blk_mq_get_driver_tag() if the scheduler tag is reserved? I'm hazy on
what we expect from reserved tags, so feel free to call me crazy.
Yeah good point, we need to carry it through. Reserved tags exist
because drivers often need a request/tag for error handling. If all
tags currently are used up for regular IO that is stuck, you need
a reserved tag for error handling to guarantee progress.
So Sagi's patch does take it half the way there, but get_driver_tag
really needs to know about this as well, or we will just get stuck
there as well. Two solutions, I can think of:
1) Check the tag value in get_driver_tag, add BLK_MQ_REQ_RESERVED
when allocating a driver tag if above X.
2) Add an RQF_SOMETHING_RESERVED. Add BLK_MQ_REQ_RESERVED in
get_driver_tag if that is set.
Comments?
Option 1 looks simple enough that I don't think it warrants a new
request flag (compile tested only):
Can't we just not go through the scheduler for reserved tags? Obviously
there is no point in scheduling them...
That sounds nice, since I'd be worried about the scheduler also needing
to be aware of the reserved status lest it also get the reserved request
stuck behind some normal requests. But, we special case flush in this
way, and it has been a huge pain.
Hm, this may fix the crash, but I'm not sure it'll work as intended.
When we allocate the request, we'll get a reserved scheduler tag, but
then when we go to dispatch the request and call
blk_mq_get_driver_tag(), we'll be competing with all of the normal
requests for a regular driver tag. So maybe on top of this we should add
the BLK_MQ_REQ_RESERVED flag to the allocation attempt in
blk_mq_get_driver_tag() if the scheduler tag is reserved? I'm hazy on
what we expect from reserved tags, so feel free to call me crazy.
Yeah good point, we need to carry it through. Reserved tags exist
because drivers often need a request/tag for error handling. If all
tags currently are used up for regular IO that is stuck, you need
a reserved tag for error handling to guarantee progress.
So Sagi's patch does take it half the way there, but get_driver_tag
really needs to know about this as well, or we will just get stuck
there as well. Two solutions, I can think of:
1) Check the tag value in get_driver_tag, add BLK_MQ_REQ_RESERVED
when allocating a driver tag if above X.
2) Add an RQF_SOMETHING_RESERVED. Add BLK_MQ_REQ_RESERVED in
get_driver_tag if that is set.
Comments?
Can't we just not go through the scheduler for reserved tags? Obviously
there is no point in scheduling them...
Right, that would be possible. But I'd rather not treat any requests
differently, it's a huge pain in the ass that flush request currently
insert with a driver tag already allocated. So it's not because
scheduling will add anything at all, it's more that I'd like to move
flush requests to use regular inserts as well and not deal with some
request being "special" in any way.
The below should hopefully work. Totally untested...
On Mon, Feb 27, 2017 at 06:10:01PM +0200, Sagi Grimberg wrote:
quoted
quoted
quoted
Hm, this may fix the crash, but I'm not sure it'll work as intended.
When we allocate the request, we'll get a reserved scheduler tag, but
then when we go to dispatch the request and call
blk_mq_get_driver_tag(), we'll be competing with all of the normal
requests for a regular driver tag. So maybe on top of this we should add
the BLK_MQ_REQ_RESERVED flag to the allocation attempt in
blk_mq_get_driver_tag() if the scheduler tag is reserved? I'm hazy on
what we expect from reserved tags, so feel free to call me crazy.
Yeah good point, we need to carry it through. Reserved tags exist
because drivers often need a request/tag for error handling. If all
tags currently are used up for regular IO that is stuck, you need
a reserved tag for error handling to guarantee progress.
So Sagi's patch does take it half the way there, but get_driver_tag
really needs to know about this as well, or we will just get stuck
there as well. Two solutions, I can think of:
1) Check the tag value in get_driver_tag, add BLK_MQ_REQ_RESERVED
when allocating a driver tag if above X.
2) Add an RQF_SOMETHING_RESERVED. Add BLK_MQ_REQ_RESERVED in
get_driver_tag if that is set.
Comments?
Option 1 looks simple enough that I don't think it warrants a new
request flag (compile tested only):
Agree, that's identical to what I just sent out as well, functionally.
quoted
Can't we just not go through the scheduler for reserved tags? Obviously
there is no point in scheduling them...
That sounds nice, since I'd be worried about the scheduler also needing
to be aware of the reserved status lest it also get the reserved request
stuck behind some normal requests. But, we special case flush in this
way, and it has been a huge pain.
The caller better be using head insertion for this, in case we already
have requests in the queue. But that's no different than the current
logic.
So I think it should work fine.
--
Jens Axboe
Can't we just not go through the scheduler for reserved tags? Obviously
there is no point in scheduling them...
Right, that would be possible. But I'd rather not treat any requests
differently, it's a huge pain in the ass that flush request currently
insert with a driver tag already allocated. So it's not because
scheduling will add anything at all, it's more that I'd like to move
flush requests to use regular inserts as well and not deal with some
request being "special" in any way.
The below should hopefully work. Totally untested...
On Mon, Feb 27, 2017 at 09:15:27AM -0700, Jens Axboe wrote:
On 02/27/2017 09:10 AM, Sagi Grimberg wrote:
quoted
quoted
quoted
Hm, this may fix the crash, but I'm not sure it'll work as intended.
When we allocate the request, we'll get a reserved scheduler tag, but
then when we go to dispatch the request and call
blk_mq_get_driver_tag(), we'll be competing with all of the normal
requests for a regular driver tag. So maybe on top of this we should add
the BLK_MQ_REQ_RESERVED flag to the allocation attempt in
blk_mq_get_driver_tag() if the scheduler tag is reserved? I'm hazy on
what we expect from reserved tags, so feel free to call me crazy.
Yeah good point, we need to carry it through. Reserved tags exist
because drivers often need a request/tag for error handling. If all
tags currently are used up for regular IO that is stuck, you need
a reserved tag for error handling to guarantee progress.
So Sagi's patch does take it half the way there, but get_driver_tag
really needs to know about this as well, or we will just get stuck
there as well. Two solutions, I can think of:
1) Check the tag value in get_driver_tag, add BLK_MQ_REQ_RESERVED
when allocating a driver tag if above X.
2) Add an RQF_SOMETHING_RESERVED. Add BLK_MQ_REQ_RESERVED in
get_driver_tag if that is set.
Comments?
Can't we just not go through the scheduler for reserved tags? Obviously
there is no point in scheduling them...
Right, that would be possible. But I'd rather not treat any requests
differently, it's a huge pain in the ass that flush request currently
insert with a driver tag already allocated. So it's not because
scheduling will add anything at all, it's more that I'd like to move
flush requests to use regular inserts as well and not deal with some
request being "special" in any way.
The below should hopefully work. Totally untested...
I like your variant if it works for Sagi. My only complaint (which was
already there) is that the BUG_ON(tag >= tags->nr_reserved_tags) in
blk_mq_put_tag() looks kind of silly since we just checked that exact
same condition.
On Mon, Feb 27, 2017 at 09:15:27AM -0700, Jens Axboe wrote:
quoted
On 02/27/2017 09:10 AM, Sagi Grimberg wrote:
quoted
quoted
quoted
Hm, this may fix the crash, but I'm not sure it'll work as intended.
When we allocate the request, we'll get a reserved scheduler tag, but
then when we go to dispatch the request and call
blk_mq_get_driver_tag(), we'll be competing with all of the normal
requests for a regular driver tag. So maybe on top of this we should add
the BLK_MQ_REQ_RESERVED flag to the allocation attempt in
blk_mq_get_driver_tag() if the scheduler tag is reserved? I'm hazy on
what we expect from reserved tags, so feel free to call me crazy.
Yeah good point, we need to carry it through. Reserved tags exist
because drivers often need a request/tag for error handling. If all
tags currently are used up for regular IO that is stuck, you need
a reserved tag for error handling to guarantee progress.
So Sagi's patch does take it half the way there, but get_driver_tag
really needs to know about this as well, or we will just get stuck
there as well. Two solutions, I can think of:
1) Check the tag value in get_driver_tag, add BLK_MQ_REQ_RESERVED
when allocating a driver tag if above X.
2) Add an RQF_SOMETHING_RESERVED. Add BLK_MQ_REQ_RESERVED in
get_driver_tag if that is set.
Comments?
Can't we just not go through the scheduler for reserved tags? Obviously
there is no point in scheduling them...
Right, that would be possible. But I'd rather not treat any requests
differently, it's a huge pain in the ass that flush request currently
insert with a driver tag already allocated. So it's not because
scheduling will add anything at all, it's more that I'd like to move
flush requests to use regular inserts as well and not deal with some
request being "special" in any way.
The below should hopefully work. Totally untested...
I like your variant if it works for Sagi. My only complaint (which was
already there) is that the BUG_ON(tag >= tags->nr_reserved_tags) in
blk_mq_put_tag() looks kind of silly since we just checked that exact
same condition.
Yeah, that check is nonsensical. Let's kill it.
--
Jens Axboe
On Mon, Feb 27, 2017 at 05:36:21PM +0200, Sagi Grimberg wrote:
quoted hunk
Otherwise we won't be able to retrieve the request from
the tag.
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
---
block/blk-mq.c | 1 +
1 file changed, 1 insertion(+)
Looking a little closer at the caller, though, this is kind of weird:
struct request *nvme_alloc_request(struct request_queue *q,
struct nvme_command *cmd, unsigned int flags, int qid)
{
unsigned op = nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
struct request *req;
if (qid == NVME_QID_ANY) {
req = blk_mq_alloc_request(q, op, flags);
} else {
req = blk_mq_alloc_request_hctx(q, op, flags,
qid ? qid - 1 : 0);
}
if (IS_ERR(req))
return req;
req->cmd_flags |= REQ_FAILFAST_DRIVER;
nvme_req(req)->cmd = cmd;
return req;
}
In the "any" case, we allocate a request with a scheduler tag and go
through the scheduler as usual. In the hctx case, we're getting a
request with a driver tag, meaning we go through the
blk_mq_sched_bypass_insert() path when we run the request.
There's nothing really wrong about that, it just seems weird. Not sure
if it's weird enough to act on :)
On Mon, Feb 27, 2017 at 05:36:21PM +0200, Sagi Grimberg wrote:
quoted
Otherwise we won't be able to retrieve the request from
the tag.
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
---
block/blk-mq.c | 1 +
1 file changed, 1 insertion(+)
Looking a little closer at the caller, though, this is kind of weird:
struct request *nvme_alloc_request(struct request_queue *q,
struct nvme_command *cmd, unsigned int flags, int qid)
{
unsigned op = nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
struct request *req;
if (qid == NVME_QID_ANY) {
req = blk_mq_alloc_request(q, op, flags);
} else {
req = blk_mq_alloc_request_hctx(q, op, flags,
qid ? qid - 1 : 0);
}
if (IS_ERR(req))
return req;
req->cmd_flags |= REQ_FAILFAST_DRIVER;
nvme_req(req)->cmd = cmd;
return req;
}
In the "any" case, we allocate a request with a scheduler tag and go
through the scheduler as usual. In the hctx case, we're getting a
request with a driver tag, meaning we go through the
blk_mq_sched_bypass_insert() path when we run the request.
There's nothing really wrong about that, it just seems weird. Not sure
if it's weird enough to act on :)
That's just broken, we need to fix that up. _hctx() request alloc
should return scheduler request as well.
Omar, care to rework patch #1 and incorporate a fix for the hctx
alloc? Then I'll fix up patch #2, adding the carry-over of the
reserved flag. We'll just rebase for-linus, it's not a stable
branch.
--
Jens Axboe
On Mon, Feb 27, 2017 at 10:03:29AM -0700, Jens Axboe wrote:
On 02/27/2017 09:59 AM, Omar Sandoval wrote:
quoted
On Mon, Feb 27, 2017 at 05:36:21PM +0200, Sagi Grimberg wrote:
quoted
Otherwise we won't be able to retrieve the request from
the tag.
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
---
block/blk-mq.c | 1 +
1 file changed, 1 insertion(+)
Looking a little closer at the caller, though, this is kind of weird:
struct request *nvme_alloc_request(struct request_queue *q,
struct nvme_command *cmd, unsigned int flags, int qid)
{
unsigned op = nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
struct request *req;
if (qid == NVME_QID_ANY) {
req = blk_mq_alloc_request(q, op, flags);
} else {
req = blk_mq_alloc_request_hctx(q, op, flags,
qid ? qid - 1 : 0);
}
if (IS_ERR(req))
return req;
req->cmd_flags |= REQ_FAILFAST_DRIVER;
nvme_req(req)->cmd = cmd;
return req;
}
In the "any" case, we allocate a request with a scheduler tag and go
through the scheduler as usual. In the hctx case, we're getting a
request with a driver tag, meaning we go through the
blk_mq_sched_bypass_insert() path when we run the request.
There's nothing really wrong about that, it just seems weird. Not sure
if it's weird enough to act on :)
That's just broken, we need to fix that up. _hctx() request alloc
should return scheduler request as well.
Omar, care to rework patch #1 and incorporate a fix for the hctx
alloc? Then I'll fix up patch #2, adding the carry-over of the
reserved flag. We'll just rebase for-linus, it's not a stable
branch.
Will do, I'll make sure to add Sagi's reported-by.
On Mon, Feb 27, 2017 at 10:03:29AM -0700, Jens Axboe wrote:
quoted
On 02/27/2017 09:59 AM, Omar Sandoval wrote:
quoted
On Mon, Feb 27, 2017 at 05:36:21PM +0200, Sagi Grimberg wrote:
quoted
Otherwise we won't be able to retrieve the request from
the tag.
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
---
block/blk-mq.c | 1 +
1 file changed, 1 insertion(+)
Looking a little closer at the caller, though, this is kind of weird:
struct request *nvme_alloc_request(struct request_queue *q,
struct nvme_command *cmd, unsigned int flags, int qid)
{
unsigned op = nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
struct request *req;
if (qid == NVME_QID_ANY) {
req = blk_mq_alloc_request(q, op, flags);
} else {
req = blk_mq_alloc_request_hctx(q, op, flags,
qid ? qid - 1 : 0);
}
if (IS_ERR(req))
return req;
req->cmd_flags |= REQ_FAILFAST_DRIVER;
nvme_req(req)->cmd = cmd;
return req;
}
In the "any" case, we allocate a request with a scheduler tag and go
through the scheduler as usual. In the hctx case, we're getting a
request with a driver tag, meaning we go through the
blk_mq_sched_bypass_insert() path when we run the request.
There's nothing really wrong about that, it just seems weird. Not sure
if it's weird enough to act on :)
That's just broken, we need to fix that up. _hctx() request alloc
should return scheduler request as well.
Omar, care to rework patch #1 and incorporate a fix for the hctx
alloc? Then I'll fix up patch #2, adding the carry-over of the
reserved flag. We'll just rebase for-linus, it's not a stable
branch.
Will do, I'll make sure to add Sagi's reported-by.