{
objset_t *os;
uint64_t volsize;
- int locked = 0;
int error;
uint64_t ro;
- /*
- * In all other cases the spa_namespace_lock is taken before the
- * bdev->bd_mutex lock. But in this case the Linux __blkdev_get()
- * function calls fops->open() with the bdev->bd_mutex lock held.
- *
- * To avoid a potential lock inversion deadlock we preemptively
- * try to take the spa_namespace_lock(). Normally it will not
- * be contended and this is safe because spa_open_common() handles
- * the case where the caller already holds the spa_namespace_lock.
- *
- * When it is contended we risk a lock inversion if we were to
- * block waiting for the lock. Luckily, the __blkdev_get()
- * function allows us to return -ERESTARTSYS which will result in
- * bdev->bd_mutex being dropped, reacquired, and fops->open() being
- * called again. This process can be repeated safely until both
- * locks are acquired.
- */
- if (!mutex_owned(&spa_namespace_lock)) {
- locked = mutex_tryenter(&spa_namespace_lock);
- if (!locked)
- return (-SET_ERROR(ERESTARTSYS));
- }
-
- error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
- if (error)
- goto out_mutex;
-
/* lie and say we're read-only */
error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, 1, zvol_tag, &os);
if (error)
- goto out_mutex;
+ return (SET_ERROR(-error));
+
+ zv->zv_objset = os;
+
+ error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
+ if (error)
+ goto out_owned;
error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
- if (error) {
- dmu_objset_disown(os, zvol_tag);
- zv->zv_objset = NULL;
- goto out_mutex;
- }
+ if (error)
+ goto out_owned;
- zv->zv_objset = os;
error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf);
- if (error) {
- dmu_objset_disown(os, zvol_tag);
- zv->zv_objset = NULL;
- goto out_mutex;
- }
+ if (error)
+ goto out_owned;
set_capacity(zv->zv_disk, volsize >> 9);
zv->zv_volsize = volsize;
zv->zv_flags &= ~ZVOL_RDONLY;
}
-out_mutex:
- if (locked)
- mutex_exit(&spa_namespace_lock);
+out_owned:
+ if (error) {
+ dmu_objset_disown(os, zvol_tag);
+ zv->zv_objset = NULL;
+ }
return (SET_ERROR(-error));
}
{
const char *name = (const char *)arg;
+ ASSERT0(MUTEX_HELD(&spa_namespace_lock));
+
/* skip the designated dataset */
if (name && strcmp(dsname, name) == 0)
return (0);
uint64_t snapdev;
int error;
+ ASSERT0(MUTEX_HELD(&spa_namespace_lock));
+
error = dsl_prop_get_integer(dsname, "snapdev", &snapdev, NULL);
if (error)
return (0);