From 7fc38a82d40c049be6ab7bd272a9f7ee9b3b1478 Mon Sep 17 00:00:00 2001 From: Matthew Ahrens Date: Fri, 8 Dec 2023 17:08:18 -0800 Subject: [PATCH] zvol_disk_open() may spin on CPU `zvol_disk_open()` waits for up to `zfs_vdev_open_timeout_ms` (1 second by default) (e.g. if the block device does not exist). While in this loop, it calls `schedule_timeout()`. The problem is that `schedule_timeout()` may not actually cause the thread to go off-CPU. Per the "documentation" (comment in the source code): ``` * The function behavior depends on the current task state: * %TASK_RUNNING - the scheduler is called, but the task does not sleep * at all. That happens because sched_submit_work() does nothing for * tasks in %TASK_RUNNING state. ``` In my experience, `schedule_timeout()` never sleeps from this code path. This is especially noticeable if `zfs_vdev_open_timeout_ms` has been increased from its default. This commit uses `msleep()` to actually sleep. Note that this is how it was before https://github.com/openzfs/zfs/pull/7629. Signed-off-by: Matthew Ahrens --- module/os/linux/zfs/vdev_disk.c | 4 ++-- module/os/linux/zfs/zvol_os.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c index 48ac55f07034..a859544651d2 100644 --- a/module/os/linux/zfs/vdev_disk.c +++ b/module/os/linux/zfs/vdev_disk.c @@ -364,10 +364,10 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, if (v->vdev_removed) break; - schedule_timeout(MSEC_TO_TICK(10)); + msleep(10); } else if (unlikely(PTR_ERR(bdev) == -ERESTARTSYS)) { timeout = MSEC2NSEC(zfs_vdev_open_timeout_ms * 10); - continue; + msleep(10); } else if (IS_ERR(bdev)) { break; } diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c index 8d5d1f06fce9..693e052c441b 100644 --- a/module/os/linux/zfs/zvol_os.c +++ b/module/os/linux/zfs/zvol_os.c @@ -769,7 +769,7 @@ zvol_open(struct block_device *bdev, fmode_t flag) if ((gethrtime() - start) > timeout) return (SET_ERROR(-ERESTARTSYS)); - schedule_timeout(MSEC_TO_TICK(10)); + msleep(10); goto retry; #endif } else {