summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2015-07-13 14:51:59 -0700
committerBrian Behlendorf <[email protected]>2015-07-17 15:33:35 -0700
commit53b1d9794efc1dc5467a624e1d5c4cad662a3858 (patch)
treed33c73bc991eda195b2fb2fb162e67d752f355f8
parent47a4a6fd5fa1f1f60bcf6af19e453ecf0292f7d1 (diff)
Add logic to try and recover an inode with an invalid mode
When an inode is detected with invalid mode bits the safe thing to do is panic the system. This indicates a problem with the contents of a dnode and it should never be possible. This is the default behavior. Unfortunately, due to flaws in the system attribute (SA) implementation (on all platforms) it was possible that ZFS could create a damaged dnode. This was a rare issue which only impacted dnodes which used a spill block. Normally only symlinks and files with ACLs would require a spill block. However, if the dataset had the xattr=sa property set and extended attributes were used this problem could occur. As of the 0.6.4 tag the root cause of this issue has been fixed. For pools which are exhibiting this damage the 'zfs_recover=1' module option may be set. This will cause ZFS to interpret the dnode with invalid mode bits as a normal file. This may allow the files to be accessed for recovery purposes. Signed-off-by: Brian Behlendorf <[email protected]> Closes #3548
-rw-r--r--module/zfs/zfs_znode.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c
index f25ad0fc6..d72015c34 100644
--- a/module/zfs/zfs_znode.c
+++ b/module/zfs/zfs_znode.c
@@ -329,8 +329,8 @@ zfs_inode_set_ops(zfs_sb_t *zsb, struct inode *ip)
*/
case S_IFCHR:
case S_IFBLK:
- VERIFY(sa_lookup(ITOZ(ip)->z_sa_hdl, SA_ZPL_RDEV(zsb),
- &rdev, sizeof (rdev)) == 0);
+ sa_lookup(ITOZ(ip)->z_sa_hdl, SA_ZPL_RDEV(zsb), &rdev,
+ sizeof (rdev));
/*FALLTHROUGH*/
case S_IFIFO:
case S_IFSOCK:
@@ -339,8 +339,15 @@ zfs_inode_set_ops(zfs_sb_t *zsb, struct inode *ip)
break;
default:
- printk("ZFS: Invalid mode: 0x%x\n", ip->i_mode);
- VERIFY(0);
+ zfs_panic_recover("inode %llu has invalid mode: 0x%x\n",
+ (u_longlong_t)ip->i_ino, ip->i_mode);
+
+ /* Assume the inode is a file and attempt to continue */
+ ip->i_mode = S_IFREG | 0644;
+ ip->i_op = &zpl_inode_operations;
+ ip->i_fop = &zpl_file_operations;
+ ip->i_mapping->a_ops = &zpl_address_space_operations;
+ break;
}
}