X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzvol.c;h=f8e32567609ff3cef794c152120011ef355995e8;hb=b01615d5ac86913da1e092d0378bfb8f0e72af30;hp=7a448f1948fa74436713c61d642d816bba206e8a;hpb=6c2856726fbae681649930d9620d9087080e58fc;p=zfs.git diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 7a448f1..f8e3256 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -453,20 +453,20 @@ zvol_replay_err(zvol_state_t *zv, lr_t *lr, boolean_t byteswap) * Callback vectors for replaying records. * Only TX_WRITE is needed for zvol. */ -zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = { - (zil_replay_func_t *)zvol_replay_err, /* no such transaction type */ - (zil_replay_func_t *)zvol_replay_err, /* TX_CREATE */ - (zil_replay_func_t *)zvol_replay_err, /* TX_MKDIR */ - (zil_replay_func_t *)zvol_replay_err, /* TX_MKXATTR */ - (zil_replay_func_t *)zvol_replay_err, /* TX_SYMLINK */ - (zil_replay_func_t *)zvol_replay_err, /* TX_REMOVE */ - (zil_replay_func_t *)zvol_replay_err, /* TX_RMDIR */ - (zil_replay_func_t *)zvol_replay_err, /* TX_LINK */ - (zil_replay_func_t *)zvol_replay_err, /* TX_RENAME */ - (zil_replay_func_t *)zvol_replay_write, /* TX_WRITE */ - (zil_replay_func_t *)zvol_replay_err, /* TX_TRUNCATE */ - (zil_replay_func_t *)zvol_replay_err, /* TX_SETATTR */ - (zil_replay_func_t *)zvol_replay_err, /* TX_ACL */ +zil_replay_func_t zvol_replay_vector[TX_MAX_TYPE] = { + (zil_replay_func_t)zvol_replay_err, /* no such transaction type */ + (zil_replay_func_t)zvol_replay_err, /* TX_CREATE */ + (zil_replay_func_t)zvol_replay_err, /* TX_MKDIR */ + (zil_replay_func_t)zvol_replay_err, /* TX_MKXATTR */ + (zil_replay_func_t)zvol_replay_err, /* TX_SYMLINK */ + (zil_replay_func_t)zvol_replay_err, /* TX_REMOVE */ + (zil_replay_func_t)zvol_replay_err, /* TX_RMDIR */ + (zil_replay_func_t)zvol_replay_err, /* TX_LINK */ + (zil_replay_func_t)zvol_replay_err, /* TX_RENAME */ + (zil_replay_func_t)zvol_replay_write, /* TX_WRITE */ + (zil_replay_func_t)zvol_replay_err, /* TX_TRUNCATE */ + (zil_replay_func_t)zvol_replay_err, /* TX_SETATTR */ + (zil_replay_func_t)zvol_replay_err, /* TX_ACL */ }; /* @@ -891,25 +891,49 @@ zvol_first_open(zvol_state_t *zv) { 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 (-ERESTARTSYS); + } + /* lie and say we're read-only */ error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, 1, zvol_tag, &os); if (error) - return (-error); + goto out_mutex; error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize); if (error) { - dmu_objset_disown(os, zvol_tag); - return (-error); + dmu_objset_disown(os, zvol_tag); + goto out_mutex; } zv->zv_objset = os; error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf); if (error) { - dmu_objset_disown(os, zvol_tag); - return (-error); + dmu_objset_disown(os, zvol_tag); + goto out_mutex; } set_capacity(zv->zv_disk, volsize >> 9); @@ -918,13 +942,17 @@ zvol_first_open(zvol_state_t *zv) VERIFY(dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL) == 0); if (ro || dmu_objset_is_snapshot(os)) { - set_disk_ro(zv->zv_disk, 1); - zv->zv_flags |= ZVOL_RDONLY; + set_disk_ro(zv->zv_disk, 1); + zv->zv_flags |= ZVOL_RDONLY; } else { - set_disk_ro(zv->zv_disk, 0); - zv->zv_flags &= ~ZVOL_RDONLY; + set_disk_ro(zv->zv_disk, 0); + zv->zv_flags &= ~ZVOL_RDONLY; } +out_mutex: + if (locked) + mutex_exit(&spa_namespace_lock); + return (-error); }