Skip to content

Commit bd63141

Browse files
Ming Leiaxboe
authored andcommitted
blk-mq: clear stale request in tags->rq[] before freeing one request pool
refcount_inc_not_zero() in bt_tags_iter() still may read one freed request. Fix the issue by the following approach: 1) hold a per-tags spinlock when reading ->rqs[tag] and calling refcount_inc_not_zero in bt_tags_iter() 2) clearing stale request referred via ->rqs[tag] before freeing request pool, the per-tags spinlock is held for clearing stale ->rq[tag] So after we cleared stale requests, bt_tags_iter() won't observe freed request any more, also the clearing will wait for pending request reference. The idea of clearing ->rqs[] is borrowed from John Garry's previous patch and one recent David's patch. Tested-by: John Garry <john.garry@huawei.com> Reviewed-by: David Jeffery <djeffery@redhat.com> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Ming Lei <ming.lei@redhat.com> Link: https://lore.kernel.org/r/20210511152236.763464-4-ming.lei@redhat.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 2e315dc commit bd63141

File tree

3 files changed

+54
-7
lines changed

3 files changed

+54
-7
lines changed

block/blk-mq-tag.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,14 @@ struct bt_iter_data {
202202
static struct request *blk_mq_find_and_get_req(struct blk_mq_tags *tags,
203203
unsigned int bitnr)
204204
{
205-
struct request *rq = tags->rqs[bitnr];
205+
struct request *rq;
206+
unsigned long flags;
206207

208+
spin_lock_irqsave(&tags->lock, flags);
209+
rq = tags->rqs[bitnr];
207210
if (!rq || !refcount_inc_not_zero(&rq->ref))
208-
return NULL;
211+
rq = NULL;
212+
spin_unlock_irqrestore(&tags->lock, flags);
209213
return rq;
210214
}
211215

@@ -538,6 +542,7 @@ struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags,
538542

539543
tags->nr_tags = total_tags;
540544
tags->nr_reserved_tags = reserved_tags;
545+
spin_lock_init(&tags->lock);
541546

542547
if (blk_mq_is_sbitmap_shared(flags))
543548
return tags;

block/blk-mq-tag.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ struct blk_mq_tags {
2020
struct request **rqs;
2121
struct request **static_rqs;
2222
struct list_head page_list;
23+
24+
/*
25+
* used to clear request reference in rqs[] before freeing one
26+
* request pool
27+
*/
28+
spinlock_t lock;
2329
};
2430

2531
extern struct blk_mq_tags *blk_mq_init_tags(unsigned int nr_tags,

block/blk-mq.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,45 @@ blk_qc_t blk_mq_submit_bio(struct bio *bio)
23072307
return BLK_QC_T_NONE;
23082308
}
23092309

2310+
static size_t order_to_size(unsigned int order)
2311+
{
2312+
return (size_t)PAGE_SIZE << order;
2313+
}
2314+
2315+
/* called before freeing request pool in @tags */
2316+
static void blk_mq_clear_rq_mapping(struct blk_mq_tag_set *set,
2317+
struct blk_mq_tags *tags, unsigned int hctx_idx)
2318+
{
2319+
struct blk_mq_tags *drv_tags = set->tags[hctx_idx];
2320+
struct page *page;
2321+
unsigned long flags;
2322+
2323+
list_for_each_entry(page, &tags->page_list, lru) {
2324+
unsigned long start = (unsigned long)page_address(page);
2325+
unsigned long end = start + order_to_size(page->private);
2326+
int i;
2327+
2328+
for (i = 0; i < set->queue_depth; i++) {
2329+
struct request *rq = drv_tags->rqs[i];
2330+
unsigned long rq_addr = (unsigned long)rq;
2331+
2332+
if (rq_addr >= start && rq_addr < end) {
2333+
WARN_ON_ONCE(refcount_read(&rq->ref) != 0);
2334+
cmpxchg(&drv_tags->rqs[i], rq, NULL);
2335+
}
2336+
}
2337+
}
2338+
2339+
/*
2340+
* Wait until all pending iteration is done.
2341+
*
2342+
* Request reference is cleared and it is guaranteed to be observed
2343+
* after the ->lock is released.
2344+
*/
2345+
spin_lock_irqsave(&drv_tags->lock, flags);
2346+
spin_unlock_irqrestore(&drv_tags->lock, flags);
2347+
}
2348+
23102349
void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
23112350
unsigned int hctx_idx)
23122351
{
@@ -2325,6 +2364,8 @@ void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
23252364
}
23262365
}
23272366

2367+
blk_mq_clear_rq_mapping(set, tags, hctx_idx);
2368+
23282369
while (!list_empty(&tags->page_list)) {
23292370
page = list_first_entry(&tags->page_list, struct page, lru);
23302371
list_del_init(&page->lru);
@@ -2384,11 +2425,6 @@ struct blk_mq_tags *blk_mq_alloc_rq_map(struct blk_mq_tag_set *set,
23842425
return tags;
23852426
}
23862427

2387-
static size_t order_to_size(unsigned int order)
2388-
{
2389-
return (size_t)PAGE_SIZE << order;
2390-
}
2391-
23922428
static int blk_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
23932429
unsigned int hctx_idx, int node)
23942430
{

0 commit comments

Comments
 (0)