diff options
Diffstat (limited to 'fs/xfs/scrub/repair.c')
-rw-r--r-- | fs/xfs/scrub/repair.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c index 88142a186f95..6f13c9874224 100644 --- a/fs/xfs/scrub/repair.c +++ b/fs/xfs/scrub/repair.c @@ -27,6 +27,8 @@ #include "xfs_bmap.h" #include "xfs_defer.h" #include "xfs_extfree_item.h" +#include "xfs_attr.h" +#include "xfs_reflink.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h" @@ -1280,3 +1282,59 @@ xrep_reset_perag_resv( out: return error; } + +/* + * Repair the attr/data forks of a metadata inode. The metadata inode must be + * pointed to by sc->ip and the ILOCK must be held. + */ +int +xrep_metadata_inode_forks( + struct xfs_scrub *sc) +{ + __u32 smtype; + __u32 smflags; + int error; + + smtype = sc->sm->sm_type; + smflags = sc->sm->sm_flags; + + /* Let's see if the forks need repair. */ + sc->sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT; + error = xchk_metadata_inode_forks(sc); + if (error || !xfs_scrub_needs_repair(sc->sm)) + goto out; + + xfs_trans_ijoin(sc->tp, sc->ip, 0); + + /* Clear the reflink flag & attr forks that we shouldn't have. */ + if (xfs_is_reflink_inode(sc->ip)) { + error = xfs_reflink_clear_inode_flag(sc->ip, &sc->tp); + if (error) + goto out; + } + + if (xfs_inode_hasattr(sc->ip)) { + error = xrep_xattr_reset_fork(sc, 0); + if (error) + goto out; + } + + /* Repair the data fork. */ + sc->sm->sm_type = XFS_SCRUB_TYPE_BMBTD; + error = xrep_bmap_data(sc); + sc->sm->sm_type = smtype; + if (error) + goto out; + + /* Bail out if we still need repairs. */ + sc->sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT; + error = xchk_metadata_inode_forks(sc); + if (error) + goto out; + if (xfs_scrub_needs_repair(sc->sm)) + error = -EFSCORRUPTED; +out: + sc->sm->sm_type = smtype; + sc->sm->sm_flags = smflags; + return error; +} |