* [syzbot] possible deadlock in __loop_clr_fd (3)
@ 2021-11-10 17:00 syzbot
2021-11-10 22:10 ` Tetsuo Handa
0 siblings, 1 reply; 10+ messages in thread
From: syzbot @ 2021-11-10 17:00 UTC (permalink / raw)
To: axboe, linux-block, linux-kernel, syzkaller-bugs
Hello,
syzbot found the following issue on:
HEAD commit: cb690f5238d7 Merge tag 'for-5.16/drivers-2021-11-09' of gi..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=1611368ab00000
kernel config: https://syzkaller.appspot.com/x/.config?x=9d7259f0deb293aa
dashboard link: https://syzkaller.appspot.com/bug?extid=63614029dfb79abd4383
compiler: gcc (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2
Unfortunately, I don't have any reproducer for this issue yet.
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+63614029dfb79abd4383@syzkaller.appspotmail.com
======================================================
WARNING: possible circular locking dependency detected
5.15.0-syzkaller #0 Not tainted
------------------------------------------------------
syz-executor.1/23454 is trying to acquire lock:
ffff8880222c2938 ((wq_completion)loop1){+.+.}-{0:0}, at: flush_workqueue+0xe1/0x15b0 kernel/workqueue.c:2815
but task is already holding lock:
ffff88801a7e9360 (&lo->lo_mutex){+.+.}-{3:3}, at: __loop_clr_fd+0x7a/0x1070 drivers/block/loop.c:1106
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #7 (&lo->lo_mutex){+.+.}-{3:3}:
__mutex_lock_common kernel/locking/mutex.c:607 [inline]
__mutex_lock+0x12f/0x12f0 kernel/locking/mutex.c:740
lo_open+0x75/0x120 drivers/block/loop.c:1733
blkdev_get_whole+0x99/0x2d0 block/bdev.c:671
blkdev_get_by_dev.part.0+0x354/0xb50 block/bdev.c:826
blkdev_get_by_dev+0x6b/0x80 block/bdev.c:859
blkdev_open+0x154/0x2e0 block/fops.c:501
do_dentry_open+0x4c8/0x1250 fs/open.c:822
do_open fs/namei.c:3426 [inline]
path_openat+0x1cad/0x2750 fs/namei.c:3559
do_filp_open+0x1aa/0x400 fs/namei.c:3586
do_sys_openat2+0x16d/0x4d0 fs/open.c:1212
do_sys_open fs/open.c:1228 [inline]
__do_sys_open fs/open.c:1236 [inline]
__se_sys_open fs/open.c:1232 [inline]
__x64_sys_open+0x119/0x1c0 fs/open.c:1232
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x44/0xae
-> #6 (&disk->open_mutex){+.+.}-{3:3}:
__mutex_lock_common kernel/locking/mutex.c:607 [inline]
__mutex_lock+0x12f/0x12f0 kernel/locking/mutex.c:740
blkdev_get_by_dev.part.0+0x24e/0xb50 block/bdev.c:819
blkdev_get_by_dev+0x6b/0x80 block/bdev.c:859
swsusp_check+0x97/0x2f0 kernel/power/swap.c:1520
software_resume.part.0+0x102/0x1f0 kernel/power/hibernate.c:979
software_resume kernel/power/hibernate.c:86 [inline]
resume_store+0x161/0x190 kernel/power/hibernate.c:1181
kobj_attr_store+0x50/0x80 lib/kobject.c:856
sysfs_kf_write+0x110/0x160 fs/sysfs/file.c:136
kernfs_fop_write_iter+0x342/0x500 fs/kernfs/file.c:296
call_write_iter include/linux/fs.h:2162 [inline]
new_sync_write+0x429/0x660 fs/read_write.c:503
vfs_write+0x7cd/0xae0 fs/read_write.c:590
ksys_write+0x12d/0x250 fs/read_write.c:643
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x44/0xae
-> #5 (system_transition_mutex/1){+.+.}-{3:3}:
__mutex_lock_common kernel/locking/mutex.c:607 [inline]
__mutex_lock+0x12f/0x12f0 kernel/locking/mutex.c:740
software_resume.part.0+0x19/0x1f0 kernel/power/hibernate.c:934
software_resume kernel/power/hibernate.c:86 [inline]
resume_store+0x161/0x190 kernel/power/hibernate.c:1181
kobj_attr_store+0x50/0x80 lib/kobject.c:856
sysfs_kf_write+0x110/0x160 fs/sysfs/file.c:136
kernfs_fop_write_iter+0x342/0x500 fs/kernfs/file.c:296
call_write_iter include/linux/fs.h:2162 [inline]
new_sync_write+0x429/0x660 fs/read_write.c:503
vfs_write+0x7cd/0xae0 fs/read_write.c:590
ksys_write+0x12d/0x250 fs/read_write.c:643
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x44/0xae
-> #4 (&of->mutex){+.+.}-{3:3}:
__mutex_lock_common kernel/locking/mutex.c:607 [inline]
__mutex_lock+0x12f/0x12f0 kernel/locking/mutex.c:740
kernfs_fop_write_iter+0x287/0x500 fs/kernfs/file.c:287
call_write_iter include/linux/fs.h:2162 [inline]
do_iter_readv_writev+0x472/0x750 fs/read_write.c:725
do_iter_write+0x188/0x710 fs/read_write.c:851
vfs_iter_write+0x70/0xa0 fs/read_write.c:892
iter_file_splice_write+0x723/0xc70 fs/splice.c:689
do_splice_from fs/splice.c:767 [inline]
do_splice+0xb7e/0x1960 fs/splice.c:1079
__do_splice+0x134/0x250 fs/splice.c:1144
__do_sys_splice fs/splice.c:1350 [inline]
__se_sys_splice fs/splice.c:1332 [inline]
__x64_sys_splice+0x198/0x250 fs/splice.c:1332
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x44/0xae
-> #3 (&pipe->mutex/1){+.+.}-{3:3}:
__mutex_lock_common kernel/locking/mutex.c:607 [inline]
__mutex_lock+0x12f/0x12f0 kernel/locking/mutex.c:740
pipe_lock_nested fs/pipe.c:81 [inline]
pipe_lock+0x5a/0x70 fs/pipe.c:89
iter_file_splice_write+0x183/0xc70 fs/splice.c:635
do_splice_from fs/splice.c:767 [inline]
do_splice+0xb7e/0x1960 fs/splice.c:1079
__do_splice+0x134/0x250 fs/splice.c:1144
__do_sys_splice fs/splice.c:1350 [inline]
__se_sys_splice fs/splice.c:1332 [inline]
__x64_sys_splice+0x198/0x250 fs/splice.c:1332
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x44/0xae
-> #2 (sb_writers#3){.+.+}-{0:0}:
percpu_down_read include/linux/percpu-rwsem.h:51 [inline]
__sb_start_write include/linux/fs.h:1810 [inline]
sb_start_write include/linux/fs.h:1880 [inline]
file_start_write include/linux/fs.h:3009 [inline]
lo_write_bvec drivers/block/loop.c:242 [inline]
lo_write_simple drivers/block/loop.c:265 [inline]
do_req_filebacked drivers/block/loop.c:494 [inline]
loop_handle_cmd drivers/block/loop.c:1857 [inline]
loop_process_work+0x1499/0x1db0 drivers/block/loop.c:1897
process_one_work+0x9b2/0x1690 kernel/workqueue.c:2298
worker_thread+0x658/0x11f0 kernel/workqueue.c:2445
kthread+0x405/0x4f0 kernel/kthread.c:327
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295
-> #1 ((work_completion)(&lo->rootcg_work)){+.+.}-{0:0}:
process_one_work+0x921/0x1690 kernel/workqueue.c:2274
worker_thread+0x658/0x11f0 kernel/workqueue.c:2445
kthread+0x405/0x4f0 kernel/kthread.c:327
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295
-> #0 ((wq_completion)loop1){+.+.}-{0:0}:
check_prev_add kernel/locking/lockdep.c:3063 [inline]
check_prevs_add kernel/locking/lockdep.c:3186 [inline]
validate_chain kernel/locking/lockdep.c:3801 [inline]
__lock_acquire+0x2a07/0x54a0 kernel/locking/lockdep.c:5027
lock_acquire kernel/locking/lockdep.c:5637 [inline]
lock_acquire+0x1ab/0x510 kernel/locking/lockdep.c:5602
flush_workqueue+0x110/0x15b0 kernel/workqueue.c:2818
drain_workqueue+0x1a5/0x3c0 kernel/workqueue.c:2983
destroy_workqueue+0x71/0x800 kernel/workqueue.c:4420
__loop_clr_fd+0x1de/0x1070 drivers/block/loop.c:1124
loop_clr_fd drivers/block/loop.c:1237 [inline]
lo_ioctl+0x398/0x17c0 drivers/block/loop.c:1562
blkdev_ioctl+0x37a/0x800 block/ioctl.c:597
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:874 [inline]
__se_sys_ioctl fs/ioctl.c:860 [inline]
__x64_sys_ioctl+0x193/0x200 fs/ioctl.c:860
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x44/0xae
other info that might help us debug this:
Chain exists of:
(wq_completion)loop1 --> &disk->open_mutex --> &lo->lo_mutex
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&lo->lo_mutex);
lock(&disk->open_mutex);
lock(&lo->lo_mutex);
lock((wq_completion)loop1);
*** DEADLOCK ***
1 lock held by syz-executor.1/23454:
#0: ffff88801a7e9360 (&lo->lo_mutex){+.+.}-{3:3}, at: __loop_clr_fd+0x7a/0x1070 drivers/block/loop.c:1106
stack backtrace:
CPU: 1 PID: 23454 Comm: syz-executor.1 Not tainted 5.15.0-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106
check_noncircular+0x25f/0x2e0 kernel/locking/lockdep.c:2143
check_prev_add kernel/locking/lockdep.c:3063 [inline]
check_prevs_add kernel/locking/lockdep.c:3186 [inline]
validate_chain kernel/locking/lockdep.c:3801 [inline]
__lock_acquire+0x2a07/0x54a0 kernel/locking/lockdep.c:5027
lock_acquire kernel/locking/lockdep.c:5637 [inline]
lock_acquire+0x1ab/0x510 kernel/locking/lockdep.c:5602
flush_workqueue+0x110/0x15b0 kernel/workqueue.c:2818
drain_workqueue+0x1a5/0x3c0 kernel/workqueue.c:2983
destroy_workqueue+0x71/0x800 kernel/workqueue.c:4420
__loop_clr_fd+0x1de/0x1070 drivers/block/loop.c:1124
loop_clr_fd drivers/block/loop.c:1237 [inline]
lo_ioctl+0x398/0x17c0 drivers/block/loop.c:1562
blkdev_ioctl+0x37a/0x800 block/ioctl.c:597
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:874 [inline]
__se_sys_ioctl fs/ioctl.c:860 [inline]
__x64_sys_ioctl+0x193/0x200 fs/ioctl.c:860
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x44/0xae
RIP: 0033:0x7f77a49078a7
Code: 3c 1c 48 f7 d8 49 39 c4 72 b8 e8 04 54 02 00 85 c0 78 bd 48 83 c4 08 4c 89 e0 5b 41 5c c3 0f 1f 44 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 bc ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f77a4f4ed78 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f77a4f4ee00 RCX: 00007f77a49078a7
RDX: 0000000000000000 RSI: 0000000000004c01 RDI: 0000000000000003
RBP: 0000000000000003 R08: 0000000000000000 R09: 00007f77a4f4ec10
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000032
R13: 0000000000000000 R14: 0000000000000014 R15: 00007f77a4f4ee40
</TASK>
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [syzbot] possible deadlock in __loop_clr_fd (3) 2021-11-10 17:00 [syzbot] possible deadlock in __loop_clr_fd (3) syzbot @ 2021-11-10 22:10 ` Tetsuo Handa 2021-11-11 0:55 ` Dan Schatzberg 0 siblings, 1 reply; 10+ messages in thread From: Tetsuo Handa @ 2021-11-10 22:10 UTC (permalink / raw) To: Dan Schatzberg, Ming Lei; +Cc: axboe, linux-block Hello. Commit 87579e9b7d8dc36e ("loop: use worker per cgroup instead of kworker") is calling destroy_workqueue() with lo->lo_mutex held, and syzbot is reporting circular locking dependency &disk->open_mutex => &lo->lo_mutex => (wq_completion)loop$M => (work_completion)(&lo->rootcg_work) => sb_writers#$N => &p->lock => &of->mutex => system_transition_mutex/1 => &disk->open_mutex . Can you somehow call destroy_workqueue() without holding a lock (e.g. breaking &lo->lo_mutex => (wq_completion)loop$M dependency chain by making sure that below change is safe) ? @@ -1365,7 +1365,9 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) /* freeze request queue during the transition */ blk_mq_freeze_queue(lo->lo_queue); + mutex_unlock(&lo->lo_mutex); destroy_workqueue(lo->workqueue); + mutex_lock(&lo->lo_mutex); spin_lock_irq(&lo->lo_work_lock); list_for_each_entry_safe(worker, pos, &lo->idle_worker_list, idle_list) { On 2021/11/11 2:00, syzbot wrote: > Hello, > > syzbot found the following issue on: > > HEAD commit: cb690f5238d7 Merge tag 'for-5.16/drivers-2021-11-09' of gi.. > git tree: upstream > console output: https://syzkaller.appspot.com/x/log.txt?x=1611368ab00000 > kernel config: https://syzkaller.appspot.com/x/.config?x=9d7259f0deb293aa > dashboard link: https://syzkaller.appspot.com/bug?extid=63614029dfb79abd4383 > compiler: gcc (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [syzbot] possible deadlock in __loop_clr_fd (3) 2021-11-10 22:10 ` Tetsuo Handa @ 2021-11-11 0:55 ` Dan Schatzberg 2021-11-11 15:14 ` Tetsuo Handa 0 siblings, 1 reply; 10+ messages in thread From: Dan Schatzberg @ 2021-11-11 0:55 UTC (permalink / raw) To: Tetsuo Handa; +Cc: Ming Lei, axboe, linux-block On Thu, Nov 11, 2021 at 07:10:56AM +0900, Tetsuo Handa wrote: > Hello. > > Commit 87579e9b7d8dc36e ("loop: use worker per cgroup instead of kworker") > is calling destroy_workqueue() with lo->lo_mutex held, and syzbot is > reporting circular locking dependency The commit changed the logic from a separate kthread + queue to a workqueue. So I don't believe this changed anything regarding this circular locking dependency, it's just that the dependency is now clear via workqueue whereas it wasn't with the kthread. > > &disk->open_mutex => &lo->lo_mutex => (wq_completion)loop$M => > (work_completion)(&lo->rootcg_work) => sb_writers#$N => &p->lock => > &of->mutex => system_transition_mutex/1 => &disk->open_mutex > > . Can you somehow call destroy_workqueue() without holding a lock (e.g. > breaking &lo->lo_mutex => (wq_completion)loop$M dependency chain by > making sure that below change is safe) ? It's really not clear to me - the lo_mutex protects a lot of entry points (ioctls and others) and it's hard to tell if the observed state will be sane if they can race in the middle of __loop_clr_fd. > > @@ -1365,7 +1365,9 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) > /* freeze request queue during the transition */ > blk_mq_freeze_queue(lo->lo_queue); > > + mutex_unlock(&lo->lo_mutex); > destroy_workqueue(lo->workqueue); > + mutex_lock(&lo->lo_mutex); > spin_lock_irq(&lo->lo_work_lock); > list_for_each_entry_safe(worker, pos, &lo->idle_worker_list, > idle_list) { > > On 2021/11/11 2:00, syzbot wrote: > > Hello, > > > > syzbot found the following issue on: > > > > HEAD commit: cb690f5238d7 Merge tag 'for-5.16/drivers-2021-11-09' of gi.. > > git tree: upstream > > console output: https://syzkaller.appspot.com/x/log.txt?x=1611368ab00000 > > kernel config: https://syzkaller.appspot.com/x/.config?x=9d7259f0deb293aa > > dashboard link: https://syzkaller.appspot.com/bug?extid=63614029dfb79abd4383 > > compiler: gcc (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2 > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [syzbot] possible deadlock in __loop_clr_fd (3) 2021-11-11 0:55 ` Dan Schatzberg @ 2021-11-11 15:14 ` Tetsuo Handa 2021-11-12 6:20 ` Christoph Hellwig 0 siblings, 1 reply; 10+ messages in thread From: Tetsuo Handa @ 2021-11-11 15:14 UTC (permalink / raw) To: Dan Schatzberg; +Cc: Ming Lei, axboe, linux-block, Christoph Hellwig On 2021/11/11 9:55, Dan Schatzberg wrote: >> . Can you somehow call destroy_workqueue() without holding a lock (e.g. >> breaking &lo->lo_mutex => (wq_completion)loop$M dependency chain by >> making sure that below change is safe) ? > > It's really not clear to me - the lo_mutex protects a lot of entry > points (ioctls and others) and it's hard to tell if the observed state > will be sane if they can race in the middle of __loop_clr_fd. > I'm not familiar with the block layer, but I think it is clear. We check lo_state with lo_mutex held. The loop functions fail if lo_state is not what each function expected. Is blk_mq_freeze_queue() for waiting for "loop_queue_work() from loop_queue_rq()" to complete and for blocking further loop_queue_rq() until blk_mq_unfreeze_queue() ? If yes, we need to call blk_mq_freeze_queue() before destroy_workqueue(). But I think lo_state is helping us, like a patch shown below. From e36f23c081e0b8ed08239f4e3fbc954b4d7d3feb Mon Sep 17 00:00:00 2001 From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Date: Thu, 11 Nov 2021 23:55:43 +0900 Subject: [PATCH] loop: destroy workqueue without holding locks syzbot is reporting circular locking problem at __loop_clr_fd() [1], for commit 87579e9b7d8dc36e ("loop: use worker per cgroup instead of kworker") is calling destroy_workqueue() with lo->lo_mutex held. Since all functions where lo->lo_state matters are already checking lo->lo_state with lo->lo_mutex held (in order to avoid racing with e.g. ioctl(LOOP_CTL_REMOVE)), and __loop_clr_fd() can be called from either ioctl(LOOP_CLR_FD) or close(), lo->lo_state == Lo_rundown is considered as an exclusive lock for __loop_clr_fd(). Therefore, it is safe to temporarily drop lo->lo_mutex when calling destroy_workqueue(). Link: https://syzkaller.appspot.com/bug?extid=63614029dfb79abd4383 [1] Reported-by: syzbot <syzbot+63614029dfb79abd4383@syzkaller.appspotmail.com> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> --- drivers/block/loop.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index a154cab6cd98..b98ec1c2d950 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1104,16 +1104,20 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) */ mutex_lock(&lo->lo_mutex); - if (WARN_ON_ONCE(lo->lo_state != Lo_rundown)) { - err = -ENXIO; - goto out_unlock; - } + /* + * Since this function is called upon "ioctl(LOOP_CLR_FD)" xor "close() + * after ioctl(LOOP_CLR_FD)", it is a sign of something going wrong if + * lo->lo_state has changed while waiting for lo->lo_mutex. + */ + BUG_ON(lo->lo_state != Lo_rundown); + /* + * Since ioctl(LOOP_CLR_FD) depends on lo->lo_state == Lo_bound, it is + * a sign of something going wrong if lo->lo_backing_file was not + * assigned by ioctl(LOOP_SET_FD) or ioctl(LOOP_CONFIGURE). + */ filp = lo->lo_backing_file; - if (filp == NULL) { - err = -EINVAL; - goto out_unlock; - } + BUG_ON(!filp); if (test_bit(QUEUE_FLAG_WC, &lo->lo_queue->queue_flags)) blk_queue_write_cache(lo->lo_queue, false, false); @@ -1121,7 +1125,20 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) /* freeze request queue during the transition */ blk_mq_freeze_queue(lo->lo_queue); + /* + * To avoid circular locking dependency, call destroy_workqueue() + * without holding lo->lo_mutex. + */ + mutex_unlock(&lo->lo_mutex); destroy_workqueue(lo->workqueue); + mutex_lock(&lo->lo_mutex); + + /* + * As explained above, lo->lo_state cannot be changed while waiting for + * lo->lo_mutex. + */ + BUG_ON(lo->lo_state != Lo_rundown); + spin_lock_irq(&lo->lo_work_lock); list_for_each_entry_safe(worker, pos, &lo->idle_worker_list, idle_list) { @@ -1156,7 +1173,6 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) partscan = lo->lo_flags & LO_FLAGS_PARTSCAN; lo_number = lo->lo_number; disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE); -out_unlock: mutex_unlock(&lo->lo_mutex); if (partscan) { /* -- 2.18.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [syzbot] possible deadlock in __loop_clr_fd (3) 2021-11-11 15:14 ` Tetsuo Handa @ 2021-11-12 6:20 ` Christoph Hellwig 2021-11-12 16:25 ` Tetsuo Handa 0 siblings, 1 reply; 10+ messages in thread From: Christoph Hellwig @ 2021-11-12 6:20 UTC (permalink / raw) To: Tetsuo Handa Cc: Dan Schatzberg, Ming Lei, axboe, linux-block, Christoph Hellwig Hi Tetsuo, I think this approach is fine, but we can further simplify it. > + /* > + * Since ioctl(LOOP_CLR_FD) depends on lo->lo_state == Lo_bound, it is > + * a sign of something going wrong if lo->lo_backing_file was not > + * assigned by ioctl(LOOP_SET_FD) or ioctl(LOOP_CONFIGURE). > + */ > filp = lo->lo_backing_file; > - if (filp == NULL) { > - err = -EINVAL; > - goto out_unlock; > - } > + BUG_ON(!filp); I'd just drop the check here entirely. > if (test_bit(QUEUE_FLAG_WC, &lo->lo_queue->queue_flags)) > blk_queue_write_cache(lo->lo_queue, false, false); > @@ -1121,7 +1125,20 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) > /* freeze request queue during the transition */ > blk_mq_freeze_queue(lo->lo_queue); > > + /* > + * To avoid circular locking dependency, call destroy_workqueue() > + * without holding lo->lo_mutex. > + */ > + mutex_unlock(&lo->lo_mutex); > destroy_workqueue(lo->workqueue); > + mutex_lock(&lo->lo_mutex); As far as I can tell there is absolutely no need to hold lo_mutex above these changes at all, as the Lo_rundown check prevents access to all the other fields we're changing. So I think we can drop this entire critical section and just keep the one at the end of the funtion where lo_state is changed. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [syzbot] possible deadlock in __loop_clr_fd (3) 2021-11-12 6:20 ` Christoph Hellwig @ 2021-11-12 16:25 ` Tetsuo Handa 2021-11-15 9:58 ` Christoph Hellwig 0 siblings, 1 reply; 10+ messages in thread From: Tetsuo Handa @ 2021-11-12 16:25 UTC (permalink / raw) To: Christoph Hellwig; +Cc: Dan Schatzberg, Ming Lei, axboe, linux-block On 2021/11/12 15:20, Christoph Hellwig wrote: >> @@ -1121,7 +1125,20 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) >> /* freeze request queue during the transition */ >> blk_mq_freeze_queue(lo->lo_queue); >> >> + /* >> + * To avoid circular locking dependency, call destroy_workqueue() >> + * without holding lo->lo_mutex. >> + */ >> + mutex_unlock(&lo->lo_mutex); >> destroy_workqueue(lo->workqueue); >> + mutex_lock(&lo->lo_mutex); > > As far as I can tell there is absolutely no need to hold lo_mutex > above these changes at all, as the Lo_rundown check prevents > access to all the other fields we're changing. So I think we can > drop this entire critical section and just keep the one at the > end of the funtion where lo_state is changed. Indeed, since the access pattern is mutex_lock(&lo->lo_mutex); if (lo->lo_state == Lo_expected_state) { /* Do something here. */ lo->lo_state = Lo_new_state; } mutex_unlock(&lo->lo_mutex); , assigning a dedicated state for individual operation (e.g. Lo_deleting for loop_remove(), Lo_rundown for __loop_clr_fd()) eliminates the need to hold lo->lo_mutex throughout that operation (which in turn helps shortening locking dependency chains). mutex_lock(&lo->lo_mutex); if (lo->lo_state != Lo_expected_state) { mutex_unlock(&lo->lo_mutex); return; } lo->lo_state = Lo_state_for_this_operation; mutex_unlock(&lo->lo_mutex); /* Do something here without lo->lo_mutex. */ mutex_lock(&lo->lo_mutex); lo->lo_state = Lo_new_state; mutex_unlock(&lo->lo_mutex); From 4ba8c1de297d6a09649a434ac4fa81e3f07bedba Mon Sep 17 00:00:00 2001 From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Date: Sat, 13 Nov 2021 10:19:15 +0900 Subject: [PATCH v2] loop: don't hold lo_mutex during __loop_clr_fd() syzbot is reporting circular locking problem at __loop_clr_fd() [1], for commit 87579e9b7d8dc36e ("loop: use worker per cgroup instead of kworker") is calling destroy_workqueue() with lo->lo_mutex held. Since all functions where lo->lo_state matters are already checking lo->lo_state with lo->lo_mutex held (in order to avoid racing with e.g. ioctl(LOOP_CTL_REMOVE)), and __loop_clr_fd() can be called from either ioctl(LOOP_CLR_FD) xor close(), lo->lo_state == Lo_rundown is considered as an exclusive lock for __loop_clr_fd(). Therefore, hold lo->lo_mutex inside __loop_clr_fd() only when asserting/updating lo->lo_state. Since ioctl(LOOP_CLR_FD) depends on lo->lo_state == Lo_bound, a valid lo->lo_backing_file must have been assigned by ioctl(LOOP_SET_FD) or ioctl(LOOP_CONFIGURE). Thus, we can remove lo->lo_backing_file test, and convert __loop_clr_fd() into a void function. Link: https://syzkaller.appspot.com/bug?extid=63614029dfb79abd4383 [1] Reported-by: syzbot <syzbot+63614029dfb79abd4383@syzkaller.appspotmail.com> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> --- Changes in v2: Hold lo->lo_mutex only when asserting/updating lo->lo_state. Convert __loop_clr_fd() to return void. drivers/block/loop.c | 55 ++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index a154cab6cd98..30ee34c6498e 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1082,13 +1082,10 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, return error; } -static int __loop_clr_fd(struct loop_device *lo, bool release) +static void __loop_clr_fd(struct loop_device *lo, bool release) { - struct file *filp = NULL; + struct file *filp; gfp_t gfp = lo->old_gfp_mask; - int err = 0; - bool partscan = false; - int lo_number; struct loop_worker *pos, *worker; /* @@ -1103,17 +1100,14 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) * became visible. */ + /* + * Since this function is called upon "ioctl(LOOP_CLR_FD)" xor "close() + * after ioctl(LOOP_CLR_FD)", it is a sign of something going wrong if + * lo->lo_state has changed while waiting for lo->lo_mutex. + */ mutex_lock(&lo->lo_mutex); - if (WARN_ON_ONCE(lo->lo_state != Lo_rundown)) { - err = -ENXIO; - goto out_unlock; - } - - filp = lo->lo_backing_file; - if (filp == NULL) { - err = -EINVAL; - goto out_unlock; - } + BUG_ON(lo->lo_state != Lo_rundown); + mutex_unlock(&lo->lo_mutex); if (test_bit(QUEUE_FLAG_WC, &lo->lo_queue->queue_flags)) blk_queue_write_cache(lo->lo_queue, false, false); @@ -1134,6 +1128,7 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) del_timer_sync(&lo->timer); spin_lock_irq(&lo->lo_lock); + filp = lo->lo_backing_file; lo->lo_backing_file = NULL; spin_unlock_irq(&lo->lo_lock); @@ -1153,12 +1148,11 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) module_put(THIS_MODULE); blk_mq_unfreeze_queue(lo->lo_queue); - partscan = lo->lo_flags & LO_FLAGS_PARTSCAN; - lo_number = lo->lo_number; disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE); -out_unlock: - mutex_unlock(&lo->lo_mutex); - if (partscan) { + + if (lo->lo_flags & LO_FLAGS_PARTSCAN) { + int err; + /* * open_mutex has been held already in release path, so don't * acquire it if this function is called in such case. @@ -1174,24 +1168,20 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) mutex_unlock(&lo->lo_disk->open_mutex); if (err) pr_warn("%s: partition scan of loop%d failed (rc=%d)\n", - __func__, lo_number, err); + __func__, lo->lo_number, err); /* Device is gone, no point in returning error */ - err = 0; } /* * lo->lo_state is set to Lo_unbound here after above partscan has - * finished. - * - * There cannot be anybody else entering __loop_clr_fd() as - * lo->lo_backing_file is already cleared and Lo_rundown state - * protects us from all the other places trying to change the 'lo' - * device. + * finished. There cannot be anybody else entering __loop_clr_fd() as + * Lo_rundown state protects us from all the other places trying to + * change the 'lo' device. */ - mutex_lock(&lo->lo_mutex); lo->lo_flags = 0; if (!part_shift) lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; + mutex_lock(&lo->lo_mutex); lo->lo_state = Lo_unbound; mutex_unlock(&lo->lo_mutex); @@ -1200,9 +1190,7 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) * lo_mutex triggers a circular lock dependency possibility warning as * fput can take open_mutex which is usually taken before lo_mutex. */ - if (filp) - fput(filp); - return err; + fput(filp); } static int loop_clr_fd(struct loop_device *lo) @@ -1234,7 +1222,8 @@ static int loop_clr_fd(struct loop_device *lo) lo->lo_state = Lo_rundown; mutex_unlock(&lo->lo_mutex); - return __loop_clr_fd(lo, false); + __loop_clr_fd(lo, false); + return 0; } static int -- 2.18.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [syzbot] possible deadlock in __loop_clr_fd (3) 2021-11-12 16:25 ` Tetsuo Handa @ 2021-11-15 9:58 ` Christoph Hellwig 2021-11-15 10:20 ` [PATCH v2] loop: don't hold lo_mutex during __loop_clr_fd() Tetsuo Handa 0 siblings, 1 reply; 10+ messages in thread From: Christoph Hellwig @ 2021-11-15 9:58 UTC (permalink / raw) To: Tetsuo Handa Cc: Christoph Hellwig, Dan Schatzberg, Ming Lei, axboe, linux-block Looks good, Reviewed-by: Christoph Hellwig <hch@lst.de> ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2] loop: don't hold lo_mutex during __loop_clr_fd() 2021-11-15 9:58 ` Christoph Hellwig @ 2021-11-15 10:20 ` Tetsuo Handa 2021-11-24 10:47 ` [PATCH v3] " Tetsuo Handa 0 siblings, 1 reply; 10+ messages in thread From: Tetsuo Handa @ 2021-11-15 10:20 UTC (permalink / raw) To: axboe; +Cc: linux-block syzbot is reporting circular locking problem at __loop_clr_fd() [1], for commit 87579e9b7d8dc36e ("loop: use worker per cgroup instead of kworker") is calling destroy_workqueue() with lo->lo_mutex held. Since all functions where lo->lo_state matters are already checking lo->lo_state with lo->lo_mutex held (in order to avoid racing with e.g. ioctl(LOOP_CTL_REMOVE)), and __loop_clr_fd() can be called from either ioctl(LOOP_CLR_FD) xor close(), lo->lo_state == Lo_rundown is considered as an exclusive lock for __loop_clr_fd(). Therefore, hold lo->lo_mutex inside __loop_clr_fd() only when asserting/updating lo->lo_state. Since ioctl(LOOP_CLR_FD) depends on lo->lo_state == Lo_bound, a valid lo->lo_backing_file must have been assigned by ioctl(LOOP_SET_FD) or ioctl(LOOP_CONFIGURE). Thus, we can remove lo->lo_backing_file test, and convert __loop_clr_fd() into a void function. Link: https://syzkaller.appspot.com/bug?extid=63614029dfb79abd4383 [1] Reported-by: syzbot <syzbot+63614029dfb79abd4383@syzkaller.appspotmail.com> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Reviewed-by: Christoph Hellwig <hch@lst.de> --- Changes in v2: Hold lo->lo_mutex only when asserting/updating lo->lo_state. Convert __loop_clr_fd() to return void. drivers/block/loop.c | 55 ++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index a154cab6cd98..30ee34c6498e 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1082,13 +1082,10 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, return error; } -static int __loop_clr_fd(struct loop_device *lo, bool release) +static void __loop_clr_fd(struct loop_device *lo, bool release) { - struct file *filp = NULL; + struct file *filp; gfp_t gfp = lo->old_gfp_mask; - int err = 0; - bool partscan = false; - int lo_number; struct loop_worker *pos, *worker; /* @@ -1103,17 +1100,14 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) * became visible. */ + /* + * Since this function is called upon "ioctl(LOOP_CLR_FD)" xor "close() + * after ioctl(LOOP_CLR_FD)", it is a sign of something going wrong if + * lo->lo_state has changed while waiting for lo->lo_mutex. + */ mutex_lock(&lo->lo_mutex); - if (WARN_ON_ONCE(lo->lo_state != Lo_rundown)) { - err = -ENXIO; - goto out_unlock; - } - - filp = lo->lo_backing_file; - if (filp == NULL) { - err = -EINVAL; - goto out_unlock; - } + BUG_ON(lo->lo_state != Lo_rundown); + mutex_unlock(&lo->lo_mutex); if (test_bit(QUEUE_FLAG_WC, &lo->lo_queue->queue_flags)) blk_queue_write_cache(lo->lo_queue, false, false); @@ -1134,6 +1128,7 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) del_timer_sync(&lo->timer); spin_lock_irq(&lo->lo_lock); + filp = lo->lo_backing_file; lo->lo_backing_file = NULL; spin_unlock_irq(&lo->lo_lock); @@ -1153,12 +1148,11 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) module_put(THIS_MODULE); blk_mq_unfreeze_queue(lo->lo_queue); - partscan = lo->lo_flags & LO_FLAGS_PARTSCAN; - lo_number = lo->lo_number; disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE); -out_unlock: - mutex_unlock(&lo->lo_mutex); - if (partscan) { + + if (lo->lo_flags & LO_FLAGS_PARTSCAN) { + int err; + /* * open_mutex has been held already in release path, so don't * acquire it if this function is called in such case. @@ -1174,24 +1168,20 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) mutex_unlock(&lo->lo_disk->open_mutex); if (err) pr_warn("%s: partition scan of loop%d failed (rc=%d)\n", - __func__, lo_number, err); + __func__, lo->lo_number, err); /* Device is gone, no point in returning error */ - err = 0; } /* * lo->lo_state is set to Lo_unbound here after above partscan has - * finished. - * - * There cannot be anybody else entering __loop_clr_fd() as - * lo->lo_backing_file is already cleared and Lo_rundown state - * protects us from all the other places trying to change the 'lo' - * device. + * finished. There cannot be anybody else entering __loop_clr_fd() as + * Lo_rundown state protects us from all the other places trying to + * change the 'lo' device. */ - mutex_lock(&lo->lo_mutex); lo->lo_flags = 0; if (!part_shift) lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; + mutex_lock(&lo->lo_mutex); lo->lo_state = Lo_unbound; mutex_unlock(&lo->lo_mutex); @@ -1200,9 +1190,7 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) * lo_mutex triggers a circular lock dependency possibility warning as * fput can take open_mutex which is usually taken before lo_mutex. */ - if (filp) - fput(filp); - return err; + fput(filp); } static int loop_clr_fd(struct loop_device *lo) @@ -1234,7 +1222,8 @@ static int loop_clr_fd(struct loop_device *lo) lo->lo_state = Lo_rundown; mutex_unlock(&lo->lo_mutex); - return __loop_clr_fd(lo, false); + __loop_clr_fd(lo, false); + return 0; } static int -- 2.18.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3] loop: don't hold lo_mutex during __loop_clr_fd() 2021-11-15 10:20 ` [PATCH v2] loop: don't hold lo_mutex during __loop_clr_fd() Tetsuo Handa @ 2021-11-24 10:47 ` Tetsuo Handa 2021-11-24 15:35 ` Jens Axboe 0 siblings, 1 reply; 10+ messages in thread From: Tetsuo Handa @ 2021-11-24 10:47 UTC (permalink / raw) To: axboe; +Cc: linux-block syzbot is reporting circular locking problem at __loop_clr_fd() [1], for commit 87579e9b7d8dc36e ("loop: use worker per cgroup instead of kworker") is calling destroy_workqueue() with lo->lo_mutex held. Since all functions where lo->lo_state matters are already checking lo->lo_state with lo->lo_mutex held (in order to avoid racing with e.g. ioctl(LOOP_CTL_REMOVE)), and __loop_clr_fd() can be called from either ioctl(LOOP_CLR_FD) xor close(), lo->lo_state == Lo_rundown is considered as an exclusive lock for __loop_clr_fd(). Therefore, hold lo->lo_mutex inside __loop_clr_fd() only when asserting/updating lo->lo_state. Since ioctl(LOOP_CLR_FD) depends on lo->lo_state == Lo_bound, a valid lo->lo_backing_file must have been assigned by ioctl(LOOP_SET_FD) or ioctl(LOOP_CONFIGURE). Thus, we can remove lo->lo_backing_file test, and convert __loop_clr_fd() into a void function. Link: https://syzkaller.appspot.com/bug?extid=63614029dfb79abd4383 [1] Reported-by: syzbot <syzbot+63614029dfb79abd4383@syzkaller.appspotmail.com> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Reviewed-by: Christoph Hellwig <hch@lst.de> --- Changes in v3: Rebased on for-5.17/block. Changes in v2: Hold lo->lo_mutex only when asserting/updating lo->lo_state. Convert __loop_clr_fd() to return void. drivers/block/loop.c | 55 ++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 0954ea8cf9e3..ba76319b5544 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1082,13 +1082,10 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, return error; } -static int __loop_clr_fd(struct loop_device *lo, bool release) +static void __loop_clr_fd(struct loop_device *lo, bool release) { - struct file *filp = NULL; + struct file *filp; gfp_t gfp = lo->old_gfp_mask; - int err = 0; - bool partscan = false; - int lo_number; struct loop_worker *pos, *worker; /* @@ -1103,17 +1100,14 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) * became visible. */ + /* + * Since this function is called upon "ioctl(LOOP_CLR_FD)" xor "close() + * after ioctl(LOOP_CLR_FD)", it is a sign of something going wrong if + * lo->lo_state has changed while waiting for lo->lo_mutex. + */ mutex_lock(&lo->lo_mutex); - if (WARN_ON_ONCE(lo->lo_state != Lo_rundown)) { - err = -ENXIO; - goto out_unlock; - } - - filp = lo->lo_backing_file; - if (filp == NULL) { - err = -EINVAL; - goto out_unlock; - } + BUG_ON(lo->lo_state != Lo_rundown); + mutex_unlock(&lo->lo_mutex); if (test_bit(QUEUE_FLAG_WC, &lo->lo_queue->queue_flags)) blk_queue_write_cache(lo->lo_queue, false, false); @@ -1134,6 +1128,7 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) del_timer_sync(&lo->timer); spin_lock_irq(&lo->lo_lock); + filp = lo->lo_backing_file; lo->lo_backing_file = NULL; spin_unlock_irq(&lo->lo_lock); @@ -1153,12 +1148,11 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) module_put(THIS_MODULE); blk_mq_unfreeze_queue(lo->lo_queue); - partscan = lo->lo_flags & LO_FLAGS_PARTSCAN; - lo_number = lo->lo_number; disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE); -out_unlock: - mutex_unlock(&lo->lo_mutex); - if (partscan) { + + if (lo->lo_flags & LO_FLAGS_PARTSCAN) { + int err; + /* * open_mutex has been held already in release path, so don't * acquire it if this function is called in such case. @@ -1174,24 +1168,20 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) mutex_unlock(&lo->lo_disk->open_mutex); if (err) pr_warn("%s: partition scan of loop%d failed (rc=%d)\n", - __func__, lo_number, err); + __func__, lo->lo_number, err); /* Device is gone, no point in returning error */ - err = 0; } /* * lo->lo_state is set to Lo_unbound here after above partscan has - * finished. - * - * There cannot be anybody else entering __loop_clr_fd() as - * lo->lo_backing_file is already cleared and Lo_rundown state - * protects us from all the other places trying to change the 'lo' - * device. + * finished. There cannot be anybody else entering __loop_clr_fd() as + * Lo_rundown state protects us from all the other places trying to + * change the 'lo' device. */ - mutex_lock(&lo->lo_mutex); lo->lo_flags = 0; if (!part_shift) lo->lo_disk->flags |= GENHD_FL_NO_PART; + mutex_lock(&lo->lo_mutex); lo->lo_state = Lo_unbound; mutex_unlock(&lo->lo_mutex); @@ -1200,9 +1190,7 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) * lo_mutex triggers a circular lock dependency possibility warning as * fput can take open_mutex which is usually taken before lo_mutex. */ - if (filp) - fput(filp); - return err; + fput(filp); } static int loop_clr_fd(struct loop_device *lo) @@ -1234,7 +1222,8 @@ static int loop_clr_fd(struct loop_device *lo) lo->lo_state = Lo_rundown; mutex_unlock(&lo->lo_mutex); - return __loop_clr_fd(lo, false); + __loop_clr_fd(lo, false); + return 0; } static int -- 2.18.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3] loop: don't hold lo_mutex during __loop_clr_fd() 2021-11-24 10:47 ` [PATCH v3] " Tetsuo Handa @ 2021-11-24 15:35 ` Jens Axboe 0 siblings, 0 replies; 10+ messages in thread From: Jens Axboe @ 2021-11-24 15:35 UTC (permalink / raw) To: Tetsuo Handa; +Cc: linux-block On Wed, 24 Nov 2021 19:47:40 +0900, Tetsuo Handa wrote: > syzbot is reporting circular locking problem at __loop_clr_fd() [1], for > commit 87579e9b7d8dc36e ("loop: use worker per cgroup instead of kworker") > is calling destroy_workqueue() with lo->lo_mutex held. > > Since all functions where lo->lo_state matters are already checking > lo->lo_state with lo->lo_mutex held (in order to avoid racing with e.g. > ioctl(LOOP_CTL_REMOVE)), and __loop_clr_fd() can be called from either > ioctl(LOOP_CLR_FD) xor close(), lo->lo_state == Lo_rundown is considered > as an exclusive lock for __loop_clr_fd(). Therefore, hold lo->lo_mutex > inside __loop_clr_fd() only when asserting/updating lo->lo_state. > > [...] Applied, thanks! [1/1] loop: don't hold lo_mutex during __loop_clr_fd() commit: c895b784c699224d690c7dfbdcff309df82366e3 Best regards, -- Jens Axboe ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2021-11-24 15:36 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2021-11-10 17:00 [syzbot] possible deadlock in __loop_clr_fd (3) syzbot 2021-11-10 22:10 ` Tetsuo Handa 2021-11-11 0:55 ` Dan Schatzberg 2021-11-11 15:14 ` Tetsuo Handa 2021-11-12 6:20 ` Christoph Hellwig 2021-11-12 16:25 ` Tetsuo Handa 2021-11-15 9:58 ` Christoph Hellwig 2021-11-15 10:20 ` [PATCH v2] loop: don't hold lo_mutex during __loop_clr_fd() Tetsuo Handa 2021-11-24 10:47 ` [PATCH v3] " Tetsuo Handa 2021-11-24 15:35 ` Jens Axboe
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).