Zhiwen Zheng
2011-Jul-11 01:54 UTC
[zfs-discuss] race condition between zpool status and zio_suspend()
hello,
I encounter a deadlock condition in zfs recently, by creating a pool using
one lun of a disk array through fibre channel?unplug the fiber cable when
there is a dd writing to the pool?then do zpool status -v immediately, that
command will hang forever.
After reading the soure code and doing some experiments, I think there is a
race condition between zpool status and zio_suspend.
ffffff0008512c40 fffffffffbc2e330 0 0 60 ffffff0213995c88
PC: _resume_from_idle+0xf1 THREAD: txg_sync_thread()
stack pointer for thread ffffff0008512c40: ffffff00085129b0
[ ffffff00085129b0 _resume_from_idle+0xf1() ]
swtch+0x145()
cv_wait+0x61()
zio_wait+0x5d()
dsl_pool_sync+0xe1()
spa_sync+0x38d()
txg_sync_thread+0x247()
thread_start+8()
ffffff01e255a8c0 ffffff01efbb5008 ffffff01d743da80 1 59 ffffff01cdd02d9c
PC: _resume_from_idle+0xf1 CMD: zpool status -v test
stack pointer for thread ffffff01e255a8c0: ffffff0007bf1a70
[ ffffff0007bf1a70 _resume_from_idle+0xf1() ]
swtch+0x145()
cv_wait+0x61()
spa_config_enter+0x86()
spa_vdev_state_enter+0x3c()
spa_vdev_set_common+0x37()
spa_vdev_setpath+0x22()
zfs_ioc_vdev_setpath+0x48()
zfsdev_ioctl+0x15e()
cdev_ioctl+0x45()
spec_ioctl+0x5a()
fop_ioctl+0x7b()
ioctl+0x18e()
_sys_sysenter_post_swapgs+0x149()
Normally zfs_ioc_vdev_setpath() will return EAGAIN when spa_suspended() is
true?but before zio_suspend() get called, spa_suspended() will evaluate to
false, so zpool status passes pool_status_check(), and wants to take spa
config lock in spa_config_enter() which is already held by txg_sync_thread()
in spa_sync(). And txg_sync_thread() seems will block forever? plug in the
fiber cable and zpool clear -F does not help.
Maybe zfs_ioc_vdev_setpath should not be called in this condition, I made
the following change in zpool_vdev_name() in libzfs_pool.c?and it can solve
the problem, but I am not sure this will break something or there are
better ways to solve the problem, so please help.
if ((newpath = devid_to_path(devid)) != NULL)
{
/*
* Update the path appropriately.
*/
- set_path(zhp, nv, newpath);
+ if (strcmp(path, newpath) != 0)
+ set_path(zhp, nv, newpath);
if (nvlist_add_string(nv,
ZPOOL_CONFIG_PATH, newpath) == 0)
verify(nvlist_lookup_string(nv,
---------------
Best Regards
Zhiwen Zheng
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://mail.opensolaris.org/pipermail/zfs-discuss/attachments/20110711/071b5fe8/attachment.html>