]> granicus.if.org Git - zfs/commitdiff
Add logic to try and recover an inode with an invalid mode
authorBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 13 Jul 2015 21:51:59 +0000 (14:51 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 17 Jul 2015 22:33:35 +0000 (15:33 -0700)
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 <behlendorf1@llnl.gov>
Closes #3548

module/zfs/zfs_znode.c

index f25ad0fc6981e9a794d4d9061d09c518d1c3fe64..d72015c345f9a93351028e43439cb8c2d5370667 100644 (file)
@@ -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;
        }
 }