Skip to content

Commit 6a78699

Browse files
Ming Leiaxboe
authored andcommitted
block: always verify unfreeze lock on the owner task
commit f1be178 ("block: model freeze & enter queue as lock for supporting lockdep") tries to apply lockdep for verifying freeze & unfreeze. However, the verification is only done the outmost freeze and unfreeze. This way is actually not correct because q->mq_freeze_depth still may drop to zero on other task instead of the freeze owner task. Fix this issue by always verifying the last unfreeze lock on the owner task context, and make sure both the outmost freeze & unfreeze are verified in the current task. Fixes: f1be178 ("block: model freeze & enter queue as lock for supporting lockdep") Signed-off-by: Ming Lei <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent a471977 commit 6a78699

File tree

4 files changed

+61
-10
lines changed

4 files changed

+61
-10
lines changed

block/blk-core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ bool blk_queue_start_drain(struct request_queue *q)
287287
* entering queue, so we call blk_freeze_queue_start() to
288288
* prevent I/O from crossing blk_queue_enter().
289289
*/
290-
bool freeze = __blk_freeze_queue_start(q);
290+
bool freeze = __blk_freeze_queue_start(q, current);
291291
if (queue_is_mq(q))
292292
blk_mq_wake_waiters(q);
293293
/* Make blk_queue_enter() reexamine the DYING flag. */

block/blk-mq.c

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,28 +120,74 @@ void blk_mq_in_flight_rw(struct request_queue *q, struct block_device *part,
120120
inflight[1] = mi.inflight[1];
121121
}
122122

123-
bool __blk_freeze_queue_start(struct request_queue *q)
123+
#ifdef CONFIG_LOCKDEP
124+
static bool blk_freeze_set_owner(struct request_queue *q,
125+
struct task_struct *owner)
124126
{
125-
int freeze;
127+
if (!owner)
128+
return false;
129+
130+
if (!q->mq_freeze_depth) {
131+
q->mq_freeze_owner = owner;
132+
q->mq_freeze_owner_depth = 1;
133+
return true;
134+
}
135+
136+
if (owner == q->mq_freeze_owner)
137+
q->mq_freeze_owner_depth += 1;
138+
return false;
139+
}
140+
141+
/* verify the last unfreeze in owner context */
142+
static bool blk_unfreeze_check_owner(struct request_queue *q)
143+
{
144+
if (!q->mq_freeze_owner)
145+
return false;
146+
if (q->mq_freeze_owner != current)
147+
return false;
148+
if (--q->mq_freeze_owner_depth == 0) {
149+
q->mq_freeze_owner = NULL;
150+
return true;
151+
}
152+
return false;
153+
}
154+
155+
#else
156+
157+
static bool blk_freeze_set_owner(struct request_queue *q,
158+
struct task_struct *owner)
159+
{
160+
return false;
161+
}
162+
163+
static bool blk_unfreeze_check_owner(struct request_queue *q)
164+
{
165+
return false;
166+
}
167+
#endif
168+
169+
bool __blk_freeze_queue_start(struct request_queue *q,
170+
struct task_struct *owner)
171+
{
172+
bool freeze;
126173

127174
mutex_lock(&q->mq_freeze_lock);
175+
freeze = blk_freeze_set_owner(q, owner);
128176
if (++q->mq_freeze_depth == 1) {
129177
percpu_ref_kill(&q->q_usage_counter);
130178
mutex_unlock(&q->mq_freeze_lock);
131179
if (queue_is_mq(q))
132180
blk_mq_run_hw_queues(q, false);
133-
freeze = true;
134181
} else {
135182
mutex_unlock(&q->mq_freeze_lock);
136-
freeze = false;
137183
}
138184

139185
return freeze;
140186
}
141187

142188
void blk_freeze_queue_start(struct request_queue *q)
143189
{
144-
if (__blk_freeze_queue_start(q))
190+
if (__blk_freeze_queue_start(q, current))
145191
blk_freeze_acquire_lock(q, false, false);
146192
}
147193
EXPORT_SYMBOL_GPL(blk_freeze_queue_start);
@@ -170,7 +216,7 @@ EXPORT_SYMBOL_GPL(blk_mq_freeze_queue);
170216

171217
bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic)
172218
{
173-
int unfreeze = false;
219+
bool unfreeze;
174220

175221
mutex_lock(&q->mq_freeze_lock);
176222
if (force_atomic)
@@ -180,8 +226,8 @@ bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic)
180226
if (!q->mq_freeze_depth) {
181227
percpu_ref_resurrect(&q->q_usage_counter);
182228
wake_up_all(&q->mq_freeze_wq);
183-
unfreeze = true;
184229
}
230+
unfreeze = blk_unfreeze_check_owner(q);
185231
mutex_unlock(&q->mq_freeze_lock);
186232

187233
return unfreeze;
@@ -203,7 +249,7 @@ EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue);
203249
*/
204250
void blk_freeze_queue_start_non_owner(struct request_queue *q)
205251
{
206-
__blk_freeze_queue_start(q);
252+
__blk_freeze_queue_start(q, NULL);
207253
}
208254
EXPORT_SYMBOL_GPL(blk_freeze_queue_start_non_owner);
209255

block/blk.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ void blk_free_flush_queue(struct blk_flush_queue *q);
3737

3838
bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic);
3939
bool blk_queue_start_drain(struct request_queue *q);
40-
bool __blk_freeze_queue_start(struct request_queue *q);
40+
bool __blk_freeze_queue_start(struct request_queue *q,
41+
struct task_struct *owner);
4142
int __bio_queue_enter(struct request_queue *q, struct bio *bio);
4243
void submit_bio_noacct_nocheck(struct bio *bio);
4344
void bio_await_chain(struct bio *bio);

include/linux/blkdev.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,10 @@ struct request_queue {
575575
struct throtl_data *td;
576576
#endif
577577
struct rcu_head rcu_head;
578+
#ifdef CONFIG_LOCKDEP
579+
struct task_struct *mq_freeze_owner;
580+
int mq_freeze_owner_depth;
581+
#endif
578582
wait_queue_head_t mq_freeze_wq;
579583
/*
580584
* Protect concurrent access to q_usage_counter by

0 commit comments

Comments
 (0)