Fix zpool on zvol deadlock

Commit 65d56083b4 fixes the lock
inversion between spa_namespace_lock and bdev->bd_mutex but only
for the first user of spa_namespace_lock: dmu_objset_own().
Later spa_namespace_lock gets acquired by dsl_prop_get_integer()
though dsl_prop_get()->dsl_dataset_hold()->dsl_dir_open_spa()->
spa_open()->spa_open_common() without this "protection".  By
moving the mutex release after this second use, even this
acquisition of the lock is "protected" by the ERESTARTSYS trick.

Signed-off-by: Massimo Maggi <me@massimo-maggi.eu>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1220
This commit is contained in:
Massimo Maggi 2013-01-18 09:44:09 -08:00 committed by Brian Behlendorf
parent 7973e464de
commit babf3f9b6d

View File

@ -920,24 +920,20 @@ zvol_first_open(zvol_state_t *zv)
/* lie and say we're read-only */ /* lie and say we're read-only */
error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, 1, zvol_tag, &os); error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, 1, zvol_tag, &os);
if (locked)
mutex_exit(&spa_namespace_lock);
if (error) if (error)
return (-error); goto out_mutex;
error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize); error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
if (error) { if (error) {
dmu_objset_disown(os, zvol_tag); dmu_objset_disown(os, zvol_tag);
return (-error); goto out_mutex;
} }
zv->zv_objset = os; zv->zv_objset = os;
error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf); error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf);
if (error) { if (error) {
dmu_objset_disown(os, zvol_tag); dmu_objset_disown(os, zvol_tag);
return (-error); goto out_mutex;
} }
set_capacity(zv->zv_disk, volsize >> 9); set_capacity(zv->zv_disk, volsize >> 9);
@ -953,6 +949,10 @@ zvol_first_open(zvol_state_t *zv)
zv->zv_flags &= ~ZVOL_RDONLY; zv->zv_flags &= ~ZVOL_RDONLY;
} }
out_mutex:
if (locked)
mutex_exit(&spa_namespace_lock);
return (-error); return (-error);
} }