From 464c65df5abdb6cdc7920c910c099001c8878a2a Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 19 Jan 2016 14:13:43 -0500 Subject: [PATCH] Fix recursive locking in zfs_ioc_dataset_list_next_impl [257324.124447] VERIFY(!rrw_held(&dp->dp_config_rwlock, RW_READER)) failed [257324.124450] PANIC at dsl_pool.c:1052:dsl_pool_config_enter() [257324.124451] Showing stack for process 29206 [257324.124453] CPU: 6 PID: 29206 Comm: zfs Tainted: P OE 4.1.3 #4 [257324.124454] Hardware name: Supermicro X10SAE/X10SAE, BIOS 3.0 05/20/2015 [257324.124455] 000000000000041c ffff88040c7aba88 ffffffff8161db7f 0000000080000000 [257324.124457] ffffffffc0bf6238 ffff88040c7aba98 ffffffffc07f95c4 ffff88040c7abc28 [257324.124458] ffffffffc07f968b ffff88040c7abb58 ffff8807e82f34e8 ffff880400000028 [257324.124459] Call Trace: [257324.124465] [] dump_stack+0x4f/0x7b [257324.124484] [] spl_dumpstack+0x44/0x50 [spl] [257324.124488] [] spl_panic+0xbb/0x100 [spl] [257324.124491] [] ? preempt_count_add+0x5d/0xb0 [257324.124492] [] ? get_parent_ip+0x11/0x50 [257324.124493] [] ? preempt_count_add+0x5d/0xb0 [257324.124495] [] ? _raw_spin_lock+0x1b/0x70 [257324.124496] [] ? _raw_spin_unlock+0x17/0x30 [257324.124501] [] ? tsd_hash_search.isra.0+0x77/0xa0 [spl] [257324.124502] [] ? get_parent_ip+0x11/0x50 [257324.124503] [] ? preempt_count_add+0x5d/0xb0 [257324.124504] [] ? _raw_spin_lock+0x1b/0x70 [257324.124505] [] ? _raw_spin_unlock+0x17/0x30 [257324.124525] [] dsl_pool_config_enter+0x68/0x70 [zfs] [257324.124539] [] dsl_pool_hold+0x42/0x50 [zfs] [257324.124550] [] dmu_objset_hold+0x26/0xb0 [zfs] [257324.124571] [] zfs_ioc_objset_stats_impl.constprop.31+0x29/0x60 [zfs] [257324.124589] [] ? dataset_name_hidden+0x3d/0x50 [zfs] [257324.124607] [] zfs_ioc_dataset_list_next_impl+0x12b/0x170 [zfs] [257324.124626] [] zfs_ioc_list_next+0x89/0x280 [zfs] [257324.124629] [] ? strdup+0x3c/0x70 [spl] [257324.124646] [] zfs_ioc_dataset_list_next+0x10/0x20 [zfs] [257324.124664] [] zfsdev_ioctl+0x4e6/0x5b0 [zfs] [257324.124666] [] do_vfs_ioctl+0x2e0/0x4e0 [257324.124668] [] ? file_has_perm+0x87/0xa0 [257324.124669] [] SyS_ioctl+0x81/0xa0 [257324.124671] [] system_call_fastpath+0x16/0x6e Signed-off-by: Richard Yao --- module/zfs/zfs_ioctl.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index a6592990f187..fcc2903d4782 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -2157,7 +2157,7 @@ zfs_ioc_vdev_setfru(zfs_cmd_t *zc) * The caller frees the nvlist on success. */ static int -zfs_ioc_objset_stats_impl_nohold(nvlist_t **nv, dmu_objset_stats_t *stat, +zfs_ioc_objset_stats_impl(nvlist_t **nv, dmu_objset_stats_t *stat, objset_t *os, boolean_t str_indices) { int error = 0; @@ -2189,25 +2189,6 @@ zfs_ioc_objset_stats_impl_nohold(nvlist_t **nv, dmu_objset_stats_t *stat, return (error); } -static int -zfs_ioc_objset_stats_impl(nvlist_t **nvp, dmu_objset_stats_t *stat, - char *fsname, boolean_t str_indices) -{ - objset_t *os; - int error; - - error = dmu_objset_hold(fsname, FTAG, &os); - if (error == 0) { - error = zfs_ioc_objset_stats_impl_nohold(nvp, stat, - os, str_indices); - - dmu_objset_rele(os, FTAG); - } - - - return (error); -} - /* * inputs: * zc_name name of filesystem @@ -2223,10 +2204,16 @@ zfs_ioc_objset_stats(zfs_cmd_t *zc) { nvlist_t *nv = NULL; nvlist_t **nvp = (zc->zc_nvlist_dst) ? &nv : NULL; + objset_t *os; int error; - error = zfs_ioc_objset_stats_impl(nvp, &zc->zc_objset_stats, - zc->zc_name, B_FALSE); + error = dmu_objset_hold(zc->zc_name, FTAG, &os); + if (error == 0) { + error = zfs_ioc_objset_stats_impl(nvp, &zc->zc_objset_stats, + os, B_FALSE); + + dmu_objset_rele(os, FTAG); + } if (nv) { if (error == 0) { @@ -2406,7 +2393,7 @@ zfs_ioc_dataset_list_next_impl(zfs_list_t *zl) if (error == 0 && strchr(zl->zl_name, '$') == NULL) { /* fill in the stats */ error = zfs_ioc_objset_stats_impl(&zl->zl_nvlist, - zl->zl_objset_stats, zl->zl_name, B_FALSE); + zl->zl_objset_stats, os, B_FALSE); if (error == ENOENT) { /* we lost a race with destroy, get the next one. */ zl->zl_name[orig_len] = '\0'; @@ -2464,7 +2451,7 @@ zfs_ioc_snapshot_list_next_impl(zfs_list_t *zl, boolean_t simple) error = dmu_objset_from_ds(ds, &ossnap); if (error == 0) { - error = zfs_ioc_objset_stats_impl_nohold(&nv, + error = zfs_ioc_objset_stats_impl(&nv, zl->zl_objset_stats, ossnap, B_FALSE); } dsl_dataset_rele(ds, FTAG); @@ -5984,7 +5971,7 @@ dump_ds(dsl_dataset_t *ds, const char *bmark, void *data) goto out1; } - err = zfs_ioc_objset_stats_impl_nohold(&nvl, + err = zfs_ioc_objset_stats_impl(&nvl, &objset_stats, osp, B_TRUE); if (err) goto out1;