-
Notifications
You must be signed in to change notification settings - Fork 0
loop: respect REQ_NOWAIT for memory allocation #376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: linus-master_base
Are you sure you want to change the base?
Conversation
|
Upstream branch: f824272 |
00d5e5c to
d782508
Compare
|
Upstream branch: f824272 |
848f87f to
73d4a32
Compare
d782508 to
6099a4d
Compare
|
Upstream branch: e7c375b |
73d4a32 to
eccd7c6
Compare
6099a4d to
5121c4d
Compare
|
Upstream branch: e7c375b |
eccd7c6 to
ea94f6f
Compare
5121c4d to
4458758
Compare
|
Upstream branch: 8b69055 |
ea94f6f to
5d631a7
Compare
4458758 to
6f43942
Compare
|
Upstream branch: fd95357 |
5d631a7 to
632e0e9
Compare
6f43942 to
ec9caac
Compare
loop advertises REQ_NOWAIT support via BLK_FEAT_NOWAIT (set by
default for all blk-mq devices), but violates REQ_NOWAIT semantics
by using GFP_NOIO allocations which can block.
BLK_FEAT_NOWAIT is advertised through this call chain:
loop_add()
blk_mq_alloc_disk(&lim, ...)
__blk_mq_alloc_disk()
blk_mq_alloc_queue()
lim->features |= BLK_FEAT_NOWAIT <-- Set by default for blk-mq
However, the REQ_NOWAIT I/O path violates this contract. For io_uring
inline submissions, the call chain is:
1. Userspace (io_uring setup):
io_uring_setup(entries, ¶ms)
fd = io_uring_register(IORING_REGISTER_FILES, &zloop_fd, 1)
2. Userspace (submit I/O with NOWAIT):
sqe = io_uring_get_sqe(ring)
io_uring_prep_write(sqe, zloop_fd, buf, len, offset)
io_uring_submit(ring) <-- inline submission
3. io_uring core (inline path):
io_submit_sqes()
io_submit_sqe()
io_queue_sqe()
issue_flags = IO_URING_F_NONBLOCK <-- Sets inline/nowait mode
io_issue_sqe()
io_write()
if (force_nonblock) <-- true for inline submission
kiocb->ki_flags |= IOCB_NOWAIT
4. VFS layer:
call_write_iter()
blkdev_write_iter()
-> propagates IOCB_NOWAIT to REQ_NOWAIT on bio
__blkdev_direct_IO_simple() OR
__blkdev_direct_IO() OR
__blkdev_direct_IO_async()
5. Block layer:
blk_mq_submit_bio()
blk_mq_get_new_requests()
__blk_mq_alloc_requests()
blk_mq_rq_ctx_init()
-> propagates REQ_NOWAIT to request->cmd_flags
__blk_mq_try_issue_directly() OR blk_mq_sched_insert_request()
blk_mq_run_hw_queue()
__blk_mq_delay_run_hw_queue()
__blk_mq_run_hw_queue()
blk_mq_sched_dispatch_requests()
6. Loop driver:
loop_queue_rq()
lo_rw_aio()
kmalloc_array(..., GFP_NOIO) <-- BLOCKS (REQ_NOWAIT violation)
-> Should use GFP_NOWAIT when rq->cmd_flags & REQ_NOWAIT
Fix by using GFP_NOWAIT when REQ_NOWAIT is set, and return -EAGAIN
instead of -ENOMEM when NOWAIT allocation fails, allowing io_uring
to retry the operation with blocking allowed.
Signed-off-by: Chaitanya Kulkarni <ckulkarnilinux@gmail.com>
zloop advertises REQ_NOWAIT support via BLK_FEAT_NOWAIT (set by
default for all blk-mq devices), but violates REQ_NOWAIT semantics
by using GFP_NOIO allocations which can block.
BLK_FEAT_NOWAIT is advertised through this call chain:
zloop_add()
blk_mq_alloc_disk(&lim, ...)
__blk_mq_alloc_disk()
blk_mq_alloc_queue()
lim->features |= BLK_FEAT_NOWAIT <-- Set by default for blk-mq
However, the REQ_NOWAIT I/O path violates this contract. For io_uring
inline submissions, the call chain is:
1. Userspace (io_uring setup):
io_uring_setup(entries, ¶ms)
fd = io_uring_register(IORING_REGISTER_FILES, &zloop_fd, 1)
2. Userspace (submit I/O with NOWAIT):
sqe = io_uring_get_sqe(ring)
io_uring_prep_write(sqe, zloop_fd, buf, len, offset)
io_uring_submit(ring) <-- inline submission
3. io_uring core (inline path):
io_submit_sqes()
io_submit_sqe()
io_queue_sqe()
issue_flags = IO_URING_F_NONBLOCK <-- Sets inline/nowait mode
io_issue_sqe()
io_write()
if (force_nonblock) <-- true for inline submission
kiocb->ki_flags |= IOCB_NOWAIT
4. VFS layer:
call_write_iter()
blkdev_write_iter()
-> propagates IOCB_NOWAIT to REQ_NOWAIT on bio
__blkdev_direct_IO_simple() OR
__blkdev_direct_IO() OR
__blkdev_direct_IO_async()
5. Block layer:
blk_mq_submit_bio()
blk_mq_get_new_requests()
__blk_mq_alloc_requests()
blk_mq_rq_ctx_init()
-> propagates REQ_NOWAIT to request->cmd_flags
__blk_mq_try_issue_directly() OR blk_mq_sched_insert_request()
blk_mq_run_hw_queue()
__blk_mq_delay_run_hw_queue()
__blk_mq_run_hw_queue()
blk_mq_sched_dispatch_requests()
6. Zloop driver:
zloop_queue_rq()
zloop_rw()
kmalloc_array(..., GFP_NOIO) <-- BLOCKS (REQ_NOWAIT violation)
-> Should use GFP_NOWAIT when rq->cmd_flags & REQ_NOWAIT
Fix by using GFP_NOWAIT when REQ_NOWAIT is set, and return -EAGAIN
instead of -ENOMEM when NOWAIT allocation fails, allowing io_uring
to retry the operation with blocking allowed.
Signed-off-by: Chaitanya Kulkarni <ckulkarnilinux@gmail.com>
|
Upstream branch: c2f2b01 |
632e0e9 to
d0523f7
Compare
Pull request for series with
subject: loop: respect REQ_NOWAIT for memory allocation
version: 1
url: https://patchwork.kernel.org/project/linux-block/list/?series=1023918