mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 02:19:51 +00:00
![Ming Lei](/assets/img/avatar_default.png)
In theory, IO scheduler belongs to request queue, and the request pool of sched tags belongs to the request queue too. However, the current tags allocation interfaces are re-used for both driver tags and sched tags, and driver tags is definitely host wide, and doesn't belong to any request queue, same with its request pool. So we need tagset instance for freeing request of sched tags. Meantime, blk_mq_free_tag_set() often follows blk_cleanup_queue() in case of non-BLK_MQ_F_TAG_SHARED, this way requires that request pool of sched tags to be freed before calling blk_mq_free_tag_set(). Commit47cdee29ef
("block: move blk_exit_queue into __blk_release_queue") moves blk_exit_queue into __blk_release_queue for simplying the fast path in generic_make_request(), then causes oops during freeing requests of sched tags in __blk_release_queue(). Fix the above issue by move freeing request pool of sched tags into blk_cleanup_queue(), this way is safe becasue queue has been frozen and no any in-queue requests at that time. Freeing sched tags has to be kept in queue's release handler becasue there might be un-completed dispatch activity which might refer to sched tags. Cc: Bart Van Assche <bvanassche@acm.org> Cc: Christoph Hellwig <hch@lst.de> Fixes:47cdee29ef
("block: move blk_exit_queue into __blk_release_queue") Tested-by: Yi Zhang <yi.zhang@redhat.com> Reported-by: kernel test robot <rong.a.chen@intel.com> Signed-off-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
95 lines
2.7 KiB
C
95 lines
2.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef BLK_MQ_SCHED_H
|
|
#define BLK_MQ_SCHED_H
|
|
|
|
#include "blk-mq.h"
|
|
#include "blk-mq-tag.h"
|
|
|
|
void blk_mq_sched_free_hctx_data(struct request_queue *q,
|
|
void (*exit)(struct blk_mq_hw_ctx *));
|
|
|
|
void blk_mq_sched_assign_ioc(struct request *rq);
|
|
|
|
void blk_mq_sched_request_inserted(struct request *rq);
|
|
bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
|
|
struct request **merged_request);
|
|
bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio);
|
|
bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq);
|
|
void blk_mq_sched_mark_restart_hctx(struct blk_mq_hw_ctx *hctx);
|
|
void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx);
|
|
|
|
void blk_mq_sched_insert_request(struct request *rq, bool at_head,
|
|
bool run_queue, bool async);
|
|
void blk_mq_sched_insert_requests(struct blk_mq_hw_ctx *hctx,
|
|
struct blk_mq_ctx *ctx,
|
|
struct list_head *list, bool run_queue_async);
|
|
|
|
void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx);
|
|
|
|
int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e);
|
|
void blk_mq_exit_sched(struct request_queue *q, struct elevator_queue *e);
|
|
void blk_mq_sched_free_requests(struct request_queue *q);
|
|
|
|
static inline bool
|
|
blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio)
|
|
{
|
|
if (blk_queue_nomerges(q) || !bio_mergeable(bio))
|
|
return false;
|
|
|
|
return __blk_mq_sched_bio_merge(q, bio);
|
|
}
|
|
|
|
static inline bool
|
|
blk_mq_sched_allow_merge(struct request_queue *q, struct request *rq,
|
|
struct bio *bio)
|
|
{
|
|
struct elevator_queue *e = q->elevator;
|
|
|
|
if (e && e->type->ops.allow_merge)
|
|
return e->type->ops.allow_merge(q, rq, bio);
|
|
|
|
return true;
|
|
}
|
|
|
|
static inline void blk_mq_sched_completed_request(struct request *rq, u64 now)
|
|
{
|
|
struct elevator_queue *e = rq->q->elevator;
|
|
|
|
if (e && e->type->ops.completed_request)
|
|
e->type->ops.completed_request(rq, now);
|
|
}
|
|
|
|
static inline void blk_mq_sched_started_request(struct request *rq)
|
|
{
|
|
struct request_queue *q = rq->q;
|
|
struct elevator_queue *e = q->elevator;
|
|
|
|
if (e && e->type->ops.started_request)
|
|
e->type->ops.started_request(rq);
|
|
}
|
|
|
|
static inline void blk_mq_sched_requeue_request(struct request *rq)
|
|
{
|
|
struct request_queue *q = rq->q;
|
|
struct elevator_queue *e = q->elevator;
|
|
|
|
if (e && e->type->ops.requeue_request)
|
|
e->type->ops.requeue_request(rq);
|
|
}
|
|
|
|
static inline bool blk_mq_sched_has_work(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
struct elevator_queue *e = hctx->queue->elevator;
|
|
|
|
if (e && e->type->ops.has_work)
|
|
return e->type->ops.has_work(hctx);
|
|
|
|
return false;
|
|
}
|
|
|
|
static inline bool blk_mq_sched_needs_restart(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
return test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
|
|
}
|
|
|
|
#endif
|