Skip to content

Commit 365ea7c

Browse files
ming1axboe
authored andcommitted
ublk: allow buffer registration before device is started
Before START_DEV, there is no disk, no queue, no I/O dispatch, so the maple tree can be safely modified under ub->mutex alone without freezing the queue. Add ublk_lock_buf_tree()/ublk_unlock_buf_tree() helpers that take ub->mutex first, then freeze the queue if device is started. This ordering (mutex -> freeze) is safe because ublk_stop_dev_unlocked() already holds ub->mutex when calling del_gendisk() which freezes the queue. Suggested-by: Caleb Sander Mateos <csander@purestorage.com> Signed-off-by: Ming Lei <tom.leiming@gmail.com> Link: https://patch.msgid.link/20260409133020.3780098-6-tom.leiming@gmail.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 5e86443 commit 365ea7c

1 file changed

Lines changed: 28 additions & 51 deletions

File tree

drivers/block/ublk_drv.c

Lines changed: 28 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5238,23 +5238,29 @@ static int ublk_char_dev_permission(struct ublk_device *ub,
52385238
}
52395239

52405240
/*
5241-
* Drain inflight I/O and quiesce the queue. Freeze drains all inflight
5242-
* requests, quiesce_nowait marks the queue so no new requests dispatch,
5243-
* then unfreeze allows new submissions (which won't dispatch due to
5244-
* quiesce). This keeps freeze and ub->mutex non-nested.
5245-
*/
5246-
static void ublk_quiesce_and_release(struct gendisk *disk)
5241+
* Lock for maple tree modification: acquire ub->mutex, then freeze queue
5242+
* if device is started. If device is not yet started, only mutex is
5243+
* needed since no I/O path can access the tree.
5244+
*
5245+
* This ordering (mutex -> freeze) is safe because ublk_stop_dev_unlocked()
5246+
* already holds ub->mutex when calling del_gendisk() which freezes the queue.
5247+
*/
5248+
static unsigned int ublk_lock_buf_tree(struct ublk_device *ub)
52475249
{
5248-
unsigned int memflags;
5250+
unsigned int memflags = 0;
5251+
5252+
mutex_lock(&ub->mutex);
5253+
if (ub->ub_disk)
5254+
memflags = blk_mq_freeze_queue(ub->ub_disk->queue);
52495255

5250-
memflags = blk_mq_freeze_queue(disk->queue);
5251-
blk_mq_quiesce_queue_nowait(disk->queue);
5252-
blk_mq_unfreeze_queue(disk->queue, memflags);
5256+
return memflags;
52535257
}
52545258

5255-
static void ublk_unquiesce_and_resume(struct gendisk *disk)
5259+
static void ublk_unlock_buf_tree(struct ublk_device *ub, unsigned int memflags)
52565260
{
5257-
blk_mq_unquiesce_queue(disk->queue);
5261+
if (ub->ub_disk)
5262+
blk_mq_unfreeze_queue(ub->ub_disk->queue, memflags);
5263+
mutex_unlock(&ub->mutex);
52585264
}
52595265

52605266
/* Erase coalesced PFN ranges from the maple tree matching buf_index */
@@ -5327,7 +5333,7 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
53275333
unsigned long addr, size, nr_pages;
53285334
struct page **pages = NULL;
53295335
unsigned int gup_flags;
5330-
struct gendisk *disk;
5336+
unsigned int memflags;
53315337
long pinned;
53325338
int index;
53335339
int ret;
@@ -5354,16 +5360,10 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
53545360
!PAGE_ALIGNED(size) || !PAGE_ALIGNED(addr))
53555361
return -EINVAL;
53565362

5357-
disk = ublk_get_disk(ub);
5358-
if (!disk)
5359-
return -ENODEV;
5360-
5361-
/* Pin pages before quiescing (may sleep) */
5363+
/* Pin pages before any locks (may sleep) */
53625364
pages = kvmalloc_array(nr_pages, sizeof(*pages), GFP_KERNEL);
5363-
if (!pages) {
5364-
ret = -ENOMEM;
5365-
goto put_disk;
5366-
}
5365+
if (!pages)
5366+
return -ENOMEM;
53675367

53685368
gup_flags = FOLL_LONGTERM;
53695369
if (!(buf_reg.flags & UBLK_SHMEM_BUF_READ_ONLY))
@@ -5379,14 +5379,7 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
53795379
goto err_unpin;
53805380
}
53815381

5382-
/*
5383-
* Drain inflight I/O and quiesce the queue so no new requests
5384-
* are dispatched while we modify the maple tree. Keep freeze
5385-
* and mutex non-nested to avoid lock dependency.
5386-
*/
5387-
ublk_quiesce_and_release(disk);
5388-
5389-
mutex_lock(&ub->mutex);
5382+
memflags = ublk_lock_buf_tree(ub);
53905383

53915384
index = ida_alloc_max(&ub->buf_ida, USHRT_MAX, GFP_KERNEL);
53925385
if (index < 0) {
@@ -5400,22 +5393,16 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
54005393
goto err_unlock;
54015394
}
54025395

5403-
mutex_unlock(&ub->mutex);
5404-
5396+
ublk_unlock_buf_tree(ub, memflags);
54055397
kvfree(pages);
5406-
ublk_unquiesce_and_resume(disk);
5407-
ublk_put_disk(disk);
54085398
return index;
54095399

54105400
err_unlock:
5411-
mutex_unlock(&ub->mutex);
5412-
ublk_unquiesce_and_resume(disk);
5401+
ublk_unlock_buf_tree(ub, memflags);
54135402
err_unpin:
54145403
unpin_user_pages(pages, pinned);
54155404
err_free_pages:
54165405
kvfree(pages);
5417-
put_disk:
5418-
ublk_put_disk(disk);
54195406
return ret;
54205407
}
54215408

@@ -5459,7 +5446,7 @@ static int ublk_ctrl_unreg_buf(struct ublk_device *ub,
54595446
struct ublksrv_ctrl_cmd *header)
54605447
{
54615448
int index = (int)header->data[0];
5462-
struct gendisk *disk;
5449+
unsigned int memflags;
54635450
int ret;
54645451

54655452
if (!ublk_dev_support_shmem_zc(ub))
@@ -5468,23 +5455,13 @@ static int ublk_ctrl_unreg_buf(struct ublk_device *ub,
54685455
if (index < 0 || index > USHRT_MAX)
54695456
return -EINVAL;
54705457

5471-
disk = ublk_get_disk(ub);
5472-
if (!disk)
5473-
return -ENODEV;
5474-
5475-
/* Drain inflight I/O before modifying the maple tree */
5476-
ublk_quiesce_and_release(disk);
5477-
5478-
mutex_lock(&ub->mutex);
5458+
memflags = ublk_lock_buf_tree(ub);
54795459

54805460
ret = __ublk_ctrl_unreg_buf(ub, index);
54815461
if (!ret)
54825462
ida_free(&ub->buf_ida, index);
54835463

5484-
mutex_unlock(&ub->mutex);
5485-
5486-
ublk_unquiesce_and_resume(disk);
5487-
ublk_put_disk(disk);
5464+
ublk_unlock_buf_tree(ub, memflags);
54885465
return ret;
54895466
}
54905467

0 commit comments

Comments
 (0)