summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub/repair.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/scrub/repair.c')
-rw-r--r--fs/xfs/scrub/repair.c58
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;
+}