INFO: task hung in blk_mq_freeze_queue_nomemsave (3)

Status: upstream: reported C repro on 2026/11/02 03:47
Subsystems: block
Labels: prio:low
[Documentation on labels]
Reported-by: syzbot+a31cda410a4ccd419712@syzkaller.appspotmail.com
First crash: 1d10h, last: 1d10h
✨ AI-generated root cause summary:

The loop driver's backing file validation in loop_validate_file() and loop_check_backing_file() only checks for the presence of read_iter/write_iter operations, S_ISREG/S_ISBLK inode mode, and direct loop-to-loop device recursion. Because sysfs/kernfs attribute files are regular files (S_IFREG) and implement read_iter/write_iter, a loop device can be configured with its own sysfs queue attribute (such as /sys/block/loop0/queue/scheduler) as its backing file. When an I/O request is submitted to the loop device, loop_workfn processes the request while holding a reference on the queue's q->q_usage_counter and writes to the sysfs file via lo_rw_aio(). The sysfs write handler (elv_iosched_store -> elevator_change -> blk_mq_freeze_queue) then attempts to freeze the loop device's own queue, waiting indefinitely in blk_mq_freeze_queue_wait() for q->q_usage_counter to reach zero, causing an unresolvable self-deadlock.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 7a19f0cc94ad:

Root Cause Analysis: Self-Deadlock on Loop Backing File Freeze

1. Functions, Structs, Fields, and Files Involved

  • drivers/block/loop.c:
    • loop_configure(): Sets up the backing file for the loop device.
    • loop_check_backing_file(): Verifies that the file operations include .read_iter and .write_iter.
    • loop_validate_file(): Validates that the backing file inode is either S_ISREG or S_ISBLK, and only checks for direct loop-to-loop recursion (is_loop_device()).
    • loop_workfn() / loop_process_work() / loop_handle_cmd() / do_req_filebacked() / lo_rw_aio(): Dispatches and processes queued block requests on the backing file.
    • struct loop_device::lo_backing_file: Points to the file backing the loop device.
  • fs/kernfs/file.c & block/blk-sysfs.c:
    • kernfs_file_fops: Kernfs regular file operations, providing .write_iter = kernfs_fop_write_iter.
    • sysfs_kf_write() / queue_attr_store(): Handles sysfs writes to block device queue attributes.
  • block/elevator.c & block/blk-mq.c:
    • elv_iosched_store() / elevator_change(): Called when writing to .../queue/scheduler.
    • blk_mq_freeze_queue() / blk_mq_freeze_queue_nomemsave() / blk_mq_freeze_queue_wait(): Freezes the queue by waiting on percpu_ref_is_zero(&q->q_usage_counter).
    • struct request_queue::q_usage_counter: Per-CPU refcount tracking active and in-flight requests on the request queue.

2. Trigger and Invariant Violation

  1. Permissive Backing File Validation: When configuring a loop device via ioctl LOOP_SET_FD or LOOP_CONFIGURE, the driver invokes loop_check_backing_file() and loop_validate_file(). These checks only verify that:

    • file->f_op->read_iter (and if writable, file->f_op->write_iter) is present.
    • The inode mode satisfies S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode).
    • If the file is itself a loop device (is_loop_device(f)), it does not create a circular loop of loop devices.

    However, sysfs / kernfs attribute files are regular files (kn->mode | S_IFREG), have an i_size (PAGE_SIZE), and use kernfs_file_fops, which defines both .read_iter and .write_iter. Consequently, nothing prevents userspace from configuring /dev/loop0 with its own sysfs attribute file (specifically ./sys/block/loop0/queue/scheduler) as its backing file.

  2. I/O Submission and Request Queue Refcount: When data is written to /dev/loop0:

    • An I/O request (REQ_OP_WRITE) is allocated and queued onto loop0's request_queue (q).
    • While this request is active, q->q_usage_counter holds an incremented reference representing this in-flight request.
    • The request is picked up by the worker thread running loop_workfn().
  3. Self-Deadlock on Queue Freezing:

    • Inside loop_workfn() -> loop_process_work() -> loop_handle_cmd() -> do_req_filebacked() -> lo_rw_aio(), the worker calls file->f_op->write_iter(&cmd->iocb, &iter) on lo->lo_backing_file.
    • Because lo_backing_file is /sys/block/loop0/queue/scheduler, kernfs_fop_write_iter() calls sysfs_kf_write(), which invokes elv_iosched_store() on loop0's queue.
    • elv_iosched_store() calls elevator_change(q, ctx), which attempts to freeze loop0's queue via blk_mq_freeze_queue(q).
    • blk_mq_freeze_queue_wait(q) halts execution via wait_event(q->mq_freeze_wq, percpu_ref_is_zero(&q->q_usage_counter)).
    • However, q->q_usage_counter cannot drop to zero because the write request currently being executed by loop_workfn is holding a reference on q->q_usage_counter, and it cannot complete until lo_rw_aio() finishes.

This creates an unresolvable circular dependency: the request processing thread waits for all requests on q to complete before returning, while the active request on q waits for the processing thread to complete it. The worker thread hangs indefinitely in D state (blk_mq_freeze_queue_wait), which additionally blocks any subsequent device release or sync operations (bdev_release -> folio_wait_writeback).

▶ ▼ ✨ AI Jobs (1)
ID Workflow Result Correct Bug Created Started Finished Revision
020cedab assessment-security DenialOfService: ✅ Exploitable: ❌ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ❌ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ INFO: task hung in blk_mq_freeze_queue_nomemsave (3) 2026/11/01 12:38 2026/11/01 12:38 2026/11/01 13:07 25a0ae84
▶ ▼ Discussions (2)
Title Replies (including bot) Last reply
[PATCH] loop: prohibit the use of sysfs as a backing file 4 (4) 2026/11/02 22:49
[syzbot] [block?] INFO: task hung in blk_mq_freeze_queue_nomemsave (3) 0 (1) 2026/11/02 03:47
▶ ▼ Similar bugs (2)
Kernel Title Rank 🛈 Repro Cause bisect Fix bisect Count Last Reported Patched Status
upstream INFO: task hung in blk_mq_freeze_queue_nomemsave block 1 1 270d 270d 0/29 auto-obsoleted due to no activity on 2026/05/06 03:14
upstream INFO: task hung in blk_mq_freeze_queue_nomemsave (2) prio:low block 1 1 112d 112d 0/29 auto-obsoleted due to no activity on 2026/10/11 21:46

Sample crash report:
INFO: task kworker/u8:1:13 blocked for more than 143 seconds.
      Not tainted syzkaller #0
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:kworker/u8:1    state:D stack:0     pid:13    tgid:13    ppid:2      task_flags:0x4388060 flags:0x00000010
Workqueue: loop0 loop_workfn
Call trace:
 __switch_to+0x2b4/0x6e4 arch/arm64/kernel/process.c:775 (T)
 context_switch kernel/sched/core.c:5533 [inline]
 __schedule+0x135c/0x2b00 kernel/sched/core.c:7284
 __schedule_loop kernel/sched/core.c:7361 [inline]
 schedule+0x13c/0x20c kernel/sched/core.c:7376
 blk_mq_freeze_queue_wait+0xe0/0x160 block/blk-mq.c:191
 blk_mq_freeze_queue_nomemsave+0x28/0x38 block/blk-mq.c:207
 blk_mq_freeze_queue include/linux/blk-mq.h:956 [inline]
 elevator_change+0x174/0x35c block/elevator.c:668
 elv_iosched_store+0x2a8/0x3bc block/elevator.c:826
 queue_attr_store+0x1c0/0x24c block/blk-sysfs.c:906
 sysfs_kf_write+0xe0/0x108 fs/sysfs/file.c:145
 kernfs_fop_write_iter+0x260/0x3b8 fs/kernfs/file.c:345
 lo_rw_aio+0xaa0/0xd04 include/linux/percpu-rwsem.h:-1
 do_req_filebacked drivers/block/loop.c:-1 [inline]
 loop_handle_cmd drivers/block/loop.c:1949 [inline]
 loop_process_work+0x4c8/0x960 drivers/block/loop.c:1984
 loop_workfn+0x48/0x58 drivers/block/loop.c:2008
 process_one_work kernel/workqueue.c:3396 [inline]
 process_scheduled_works+0x91c/0x1250 kernel/workqueue.c:3479
 worker_thread+0x798/0xbd0 kernel/workqueue.c:3560
 kthread+0x304/0x3d4 kernel/kthread.c:436
 ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:854
INFO: task syz.0.17:4976 blocked in I/O wait for more than 143 seconds.
      Not tainted syzkaller #0
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:syz.0.17        state:D stack:0     pid:4976  tgid:4976  ppid:4887   task_flags:0x400140 flags:0x00800001
Call trace:
 __switch_to+0x2b4/0x6e4 arch/arm64/kernel/process.c:775 (T)
 context_switch kernel/sched/core.c:5533 [inline]
 __schedule+0x135c/0x2b00 kernel/sched/core.c:7284
 __schedule_loop kernel/sched/core.c:7361 [inline]
 schedule+0x13c/0x20c kernel/sched/core.c:7376
 io_schedule+0x1c/0xe0 kernel/sched/core.c:8220
 folio_wait_bit_common+0x6b8/0xa30 mm/filemap.c:1329
 folio_wait_bit+0x30/0x40 mm/filemap.c:1473
 folio_wait_writeback+0x9c/0xf8 mm/page-writeback.c:3062
 __filemap_fdatawait_range+0x168/0x260 mm/filemap.c:532
 filemap_write_and_wait_range+0xe0/0x114 mm/filemap.c:692
 filemap_write_and_wait include/linux/pagemap.h:65 [inline]
 sync_blockdev block/bdev.c:275 [inline]
 bdev_release+0x114/0x328 block/bdev.c:1171
 blkdev_release+0x20/0x34 block/fops.c:687
 __fput+0x338/0x74c fs/file_table.c:512
 ____fput+0x20/0x30 fs/file_table.c:541
 task_work_run+0x1cc/0x25c kernel/task_work.c:233
 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
 __exit_to_user_mode_loop kernel/entry/common.c:70 [inline]
 exit_to_user_mode_loop+0x10c/0x17c kernel/entry/common.c:101
 __exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
 syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:230 [inline]
 arm64_syscall_exit_to_user_mode arch/arm64/kernel/entry-common.c:146 [inline]
 el0_svc+0x12c/0x1d8 arch/arm64/kernel/entry-common.c:797
 el0t_64_sync_handler+0x44/0x104 arch/arm64/kernel/entry-common.c:815
 el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:606

Showing all locks held in the system:
locks held by kworker/u8:1/13: 7, on CPU#1:
 #0: ffff0000c3bd9940 ((wq_completion)loop0){+.+.}-{0:0}, at: process_one_work kernel/workqueue.c:3371 [inline]
 #0: ffff0000c3bd9940 ((wq_completion)loop0){+.+.}-{0:0}, at: process_scheduled_works+0x8c8/0x1250 kernel/workqueue.c:3479
 #1: ffff80008f997c20 ((work_completion)(&worker->work)){+.+.}-{0:0}, at: process_one_work kernel/workqueue.c:3371 [inline]
 #1: ffff80008f997c20 ((work_completion)(&worker->work)){+.+.}-{0:0}, at: process_scheduled_works+0x8d0/0x1250 kernel/workqueue.c:3479
 #2: ffff0000d6c59c80 (&of->mutex){+.+.}-{4:4}, at: kernfs_fop_write_iter+0x1b0/0x3b8 fs/kernfs/file.c:336
 #3: ffff0000c77fe878 (kn->active#57){.+.+}-{0:0}, at: kernfs_get_active_of fs/kernfs/file.c:73 [inline]
 #3: ffff0000c77fe878 (kn->active#57){.+.+}-{0:0}, at: kernfs_fop_write_iter+0x1f0/0x3b8 fs/kernfs/file.c:337
 #4: ffff0000c77b83a0 (&set->update_nr_hwq_lock){++++}-{4:4}, at: elv_iosched_store+0x260/0x3bc block/elevator.c:821
 #5: ffff0000c7783810 (&q->q_usage_counter(io)#17){++++}-{0:0}, at: blk_mq_freeze_queue_nomemsave+0x20/0x38 block/blk-mq.c:206
 #6: ffff0000c7783848 (&q->q_usage_counter(queue)){+.+.}-{0:0}, at: blk_mq_freeze_queue_nomemsave+0x20/0x38 block/blk-mq.c:206
locks held by khungtaskd/31: 1, last CPU#0:
 #0: ffff8000899e1820 (rcu_read_lock){....}-{1:3}, at: rcu_lock_acquire include/linux/rcupdate.h:309 [inline]
 #0: ffff8000899e1820 (rcu_read_lock){....}-{1:3}, at: rcu_read_lock include/linux/rcupdate.h:849 [inline]
 #0: ffff8000899e1820 (rcu_read_lock){....}-{1:3}, at: debug_show_all_locks+0x4c/0x188 kernel/locking/lockdep.c:6871
locks held by kworker/0:2/875: 3, on CPU#0:
 #0: ffff0000c002b540 ((wq_completion)events){+.+.}-{0:0}, at: process_one_work kernel/workqueue.c:3371 [inline]
 #0: ffff0000c002b540 ((wq_completion)events){+.+.}-{0:0}, at: process_scheduled_works+0x8c8/0x1250 kernel/workqueue.c:3479
 #1: ffff800094497c20 ((work_completion)(&data->fib_event_work)){+.+.}-{0:0}, at: process_one_work kernel/workqueue.c:3371 [inline]
 #1: ffff800094497c20 ((work_completion)(&data->fib_event_work)){+.+.}-{0:0}, at: process_scheduled_works+0x8d0/0x1250 kernel/workqueue.c:3479
 #2: ffff0000e922e250 (&data->fib_lock){+.+.}-{4:4}, at: nsim_fib_event_work+0x198/0x320 drivers/net/netdevsim/fib.c:1490
locks held by getty/4522: 2, on CPU#1:
 #0: ffff0000cf9db0a0 (&tty->ldisc_sem){++++}-{0:0}, at: ldsem_down_read+0x3c/0x4c drivers/tty/tty_ldsem.c:340
 #1: ffff8000931fe2e8 (&ldata->atomic_read_lock){+.+.}-{4:4}, at: n_tty_read+0x348/0xf78 drivers/tty/n_tty.c:2211

=============================================


Crashes (1):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/11/01 12:37 git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci 7a19f0cc94ad 25a0ae84 .config console log report syz / log C [disk image] [vmlinux] [kernel image] ci-upstream-gce-arm64 INFO: task hung in blk_mq_freeze_queue_nomemsave
* Struck through repros no longer work on HEAD.