3875 panic in zfs_root() after failed rollback
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Gordon Ross <gwr@nexenta.com>

References:
  https://www.illumos.org/issues/3875
  illumos/illumos-gate@91948b51b8

Ported-by: Richard Yao <ryao@gentoo.org>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #1775
This commit is contained in:
Keith M Wesolowski
2013-07-27 10:50:07 -07:00
committed by Brian Behlendorf
parent 1958067629
commit 831baf06ef
8 changed files with 167 additions and 70 deletions
+52 -49
View File
@@ -1453,7 +1453,9 @@ EXPORT_SYMBOL(zfs_vget);
* Block out VFS ops and close zfs_sb_t
*
* Note, if successful, then we return with the 'z_teardown_lock' and
* 'z_teardown_inactive_lock' write held.
* 'z_teardown_inactive_lock' write held. We leave ownership of the underlying
* dataset and objset intact so that they can be atomically handed off during
* a subsequent rollback or recv operation and the resume thereafter.
*/
int
zfs_suspend_fs(zfs_sb_t *zsb)
@@ -1463,8 +1465,6 @@ zfs_suspend_fs(zfs_sb_t *zsb)
if ((error = zfs_sb_teardown(zsb, B_FALSE)) != 0)
return (error);
dmu_objset_disown(zsb->z_os, zsb);
return (0);
}
EXPORT_SYMBOL(zfs_suspend_fs);
@@ -1476,66 +1476,69 @@ int
zfs_resume_fs(zfs_sb_t *zsb, const char *osname)
{
int err;
znode_t *zp;
uint64_t sa_obj = 0;
ASSERT(RRW_WRITE_HELD(&zsb->z_teardown_lock));
ASSERT(RW_WRITE_HELD(&zsb->z_teardown_inactive_lock));
err = dmu_objset_own(osname, DMU_OST_ZFS, B_FALSE, zsb, &zsb->z_os);
if (err) {
zsb->z_os = NULL;
} else {
znode_t *zp;
uint64_t sa_obj = 0;
/*
* We already own this, so just hold and rele it to update the
* objset_t, as the one we had before may have been evicted.
*/
VERIFY0(dmu_objset_hold(osname, zsb, &zsb->z_os));
VERIFY3P(zsb->z_os->os_dsl_dataset->ds_owner, ==, zsb);
VERIFY(dsl_dataset_long_held(zsb->z_os->os_dsl_dataset));
dmu_objset_rele(zsb->z_os, zsb);
/*
* Make sure version hasn't changed
*/
/*
* Make sure version hasn't changed
*/
err = zfs_get_zplprop(zsb->z_os, ZFS_PROP_VERSION,
&zsb->z_version);
err = zfs_get_zplprop(zsb->z_os, ZFS_PROP_VERSION,
&zsb->z_version);
if (err)
goto bail;
if (err)
goto bail;
err = zap_lookup(zsb->z_os, MASTER_NODE_OBJ,
ZFS_SA_ATTRS, 8, 1, &sa_obj);
err = zap_lookup(zsb->z_os, MASTER_NODE_OBJ,
ZFS_SA_ATTRS, 8, 1, &sa_obj);
if (err && zsb->z_version >= ZPL_VERSION_SA)
goto bail;
if (err && zsb->z_version >= ZPL_VERSION_SA)
goto bail;
if ((err = sa_setup(zsb->z_os, sa_obj,
zfs_attr_table, ZPL_END, &zsb->z_attr_table)) != 0)
goto bail;
if ((err = sa_setup(zsb->z_os, sa_obj,
zfs_attr_table, ZPL_END, &zsb->z_attr_table)) != 0)
goto bail;
if (zsb->z_version >= ZPL_VERSION_SA)
sa_register_update_callback(zsb->z_os,
zfs_sa_upgrade);
if (zsb->z_version >= ZPL_VERSION_SA)
sa_register_update_callback(zsb->z_os,
zfs_sa_upgrade);
VERIFY(zfs_sb_setup(zsb, B_FALSE) == 0);
VERIFY(zfs_sb_setup(zsb, B_FALSE) == 0);
zfs_set_fuid_feature(zsb);
zsb->z_rollback_time = jiffies;
zfs_set_fuid_feature(zsb);
zsb->z_rollback_time = jiffies;
/*
* Attempt to re-establish all the active inodes with their
* dbufs. If a zfs_rezget() fails, then we unhash the inode
* and mark it stale. This prevents a collision if a new
* inode/object is created which must use the same inode
* number. The stale inode will be be released when the
* VFS prunes the dentry holding the remaining references
* on the stale inode.
*/
mutex_enter(&zsb->z_znodes_lock);
for (zp = list_head(&zsb->z_all_znodes); zp;
zp = list_next(&zsb->z_all_znodes, zp)) {
err2 = zfs_rezget(zp);
if (err2) {
remove_inode_hash(ZTOI(zp));
zp->z_is_stale = B_TRUE;
}
/*
* Attempt to re-establish all the active inodes with their
* dbufs. If a zfs_rezget() fails, then we unhash the inode
* and mark it stale. This prevents a collision if a new
* inode/object is created which must use the same inode
* number. The stale inode will be be released when the
* VFS prunes the dentry holding the remaining references
* on the stale inode.
*/
mutex_enter(&zsb->z_znodes_lock);
for (zp = list_head(&zsb->z_all_znodes); zp;
zp = list_next(&zsb->z_all_znodes, zp)) {
err = zfs_rezget(zp);
if (err) {
remove_inode_hash(ZTOI(zp));
zp->z_is_stale = B_TRUE;
}
mutex_exit(&zsb->z_znodes_lock);
}
mutex_exit(&zsb->z_znodes_lock);
bail:
/* release the VFS ops */
@@ -1544,8 +1547,8 @@ bail:
if (err) {
/*
* Since we couldn't reopen zfs_sb_t or, or
* setup the sa framework force unmount this file system.
* Since we couldn't setup the sa framework, try to force
* unmount this file system.
*/
if (zsb->z_os)
(void) zfs_umount(zsb->z_sb);