zvol: return EBUSY when setting volmode/snapdev on in-use device - #18843
zvol: return EBUSY when setting volmode/snapdev on in-use device#18843lhjnano wants to merge 1 commit into
Conversation
|
I haven't looked deep, but IIRC unlike Linux FreeBSD should actually be able to destroy open device. So I have feeling this might be a step in wrong direction. |
|
Thanks for taking a look. My reasoning was that Would it make sense to limit the pre-check to Linux for now, so FreeBSD behavior stays as-is? I'd appreciate any thoughts. |
Unfortunately the last time I saw it on FreeBSD, the ZFS ZVOL side was no implemented right to work. So the problem may exist there too, but could be (and I'd prefer it to be) fixed in a better way. |
8a4fbab to
bd9f617
Compare
|
Sounds good. I'll limit the pre-check to Linux for now so FreeBSD behavior stays unchanged. |
f42d7e7 to
c894c33
Compare
That's not exactly what I meant. More of provoking somebody to look on the original problem. |
ffeda30 to
5083ebe
Compare
|
Fixed the regression. |
Changing volmode or snapdev on a dataset with open descendant zvols would cause zvol_remove_minors_impl() to block indefinitely waiting for the open count to reach zero, resulting in a D-state hang. Add zvol_minors_in_use() to check if the target dataset or any of its descendant zvols are currently open. Return EBUSY from zvol_set_common() before modifying the property on disk, allowing the caller to close the device and retry. For transient opens (e.g., udev/blkid), the existing cv_wait() in zvol_remove_minors_impl() handles the brief wait as before. Signed-off-by: HeonJe LEE <lhjnano@gmail.com>
5083ebe to
39ebfd0
Compare
Motivation and Context
Setting
volmodeorsnapdev=hiddenon a zvol whose block device is held open(e.g. by a mounted filesystem) causes the calling process to enter an
uninterruptible D-state sleep.
zvol_remove_minors_impl()blocks indefinitelyon
cv_wait()becausezv_open_countnever reaches zero while the devicestays open. On Linux,
zvol_wait_close()is a no-op, so the blocking waitnever completes. The only recovery is a system reboot.
The same
cv_waitinzvol_remove_minors_impl()is shared code(
module/zfs/zvol.c); FreeBSD has a 10-secondmsleepdelay inzvol_wait_close(), but the subsequentcv_waitstill has no timeout.This is consistent with how
zpool exportalready handles in-use zvols(
spa_export_common()returnsEBUSYwhen zvol minors are in use).Description
Add two non-blocking helpers:
zvol_minor_in_use(name)— checks if a specific zvol minor haszv_open_count > 0.zvol_snapshot_minors_in_use(name)— checks if any snapshot minor underthe given dataset is open.
Call them in
zvol_set_common()before the property is written. If therelevant minor is in use, return
EBUSYimmediately.Defensive checks in
zvol_set_volmode_impl()andzvol_set_snapdev_cb()cover the race window between the pre-check and the async taskq execution:
if
zv_open_count > 0is detected at that point, the task recordsEBUSYinstead of blocking on
cv_wait.How Has This Been Tested?
New tests:
zvol_misc_volmode_inuse.ksh— creates a zvol, formats and mounts it,verifies
volmode=none/devfails withEBUSY, then unmounts and verifiesvolmodecan be changed.zvol_misc_snapdev_inuse.ksh— creates a zvol with a snapshot, holds thesnapshot device open, verifies
snapdev=hiddenfails withEBUSY, thenreleases and verifies
snapdev=hiddensucceeds.Both pass on Rocky Linux 8.10 (kernel
4.18.0-553.111.1.el8_10.x86_64),OpenZFS master (
2.4.99).Types of changes
Checklist
Signed-off-by.