|
@@ -78,12 +78,14 @@
|
|
|
*/
|
|
|
|
|
|
/* Check for operational errors. */
|
|
|
-bool
|
|
|
-xfs_scrub_process_error(
|
|
|
+static bool
|
|
|
+__xfs_scrub_process_error(
|
|
|
struct xfs_scrub_context *sc,
|
|
|
xfs_agnumber_t agno,
|
|
|
xfs_agblock_t bno,
|
|
|
- int *error)
|
|
|
+ int *error,
|
|
|
+ __u32 errflag,
|
|
|
+ void *ret_ip)
|
|
|
{
|
|
|
switch (*error) {
|
|
|
case 0:
|
|
@@ -95,24 +97,48 @@ xfs_scrub_process_error(
|
|
|
case -EFSBADCRC:
|
|
|
case -EFSCORRUPTED:
|
|
|
/* Note the badness but don't abort. */
|
|
|
- sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
|
|
|
+ sc->sm->sm_flags |= errflag;
|
|
|
*error = 0;
|
|
|
/* fall through */
|
|
|
default:
|
|
|
trace_xfs_scrub_op_error(sc, agno, bno, *error,
|
|
|
- __return_address);
|
|
|
+ ret_ip);
|
|
|
break;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-/* Check for operational errors for a file offset. */
|
|
|
bool
|
|
|
-xfs_scrub_fblock_process_error(
|
|
|
+xfs_scrub_process_error(
|
|
|
+ struct xfs_scrub_context *sc,
|
|
|
+ xfs_agnumber_t agno,
|
|
|
+ xfs_agblock_t bno,
|
|
|
+ int *error)
|
|
|
+{
|
|
|
+ return __xfs_scrub_process_error(sc, agno, bno, error,
|
|
|
+ XFS_SCRUB_OFLAG_CORRUPT, __return_address);
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+xfs_scrub_xref_process_error(
|
|
|
+ struct xfs_scrub_context *sc,
|
|
|
+ xfs_agnumber_t agno,
|
|
|
+ xfs_agblock_t bno,
|
|
|
+ int *error)
|
|
|
+{
|
|
|
+ return __xfs_scrub_process_error(sc, agno, bno, error,
|
|
|
+ XFS_SCRUB_OFLAG_XFAIL, __return_address);
|
|
|
+}
|
|
|
+
|
|
|
+/* Check for operational errors for a file offset. */
|
|
|
+static bool
|
|
|
+__xfs_scrub_fblock_process_error(
|
|
|
struct xfs_scrub_context *sc,
|
|
|
int whichfork,
|
|
|
xfs_fileoff_t offset,
|
|
|
- int *error)
|
|
|
+ int *error,
|
|
|
+ __u32 errflag,
|
|
|
+ void *ret_ip)
|
|
|
{
|
|
|
switch (*error) {
|
|
|
case 0:
|
|
@@ -124,17 +150,39 @@ xfs_scrub_fblock_process_error(
|
|
|
case -EFSBADCRC:
|
|
|
case -EFSCORRUPTED:
|
|
|
/* Note the badness but don't abort. */
|
|
|
- sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
|
|
|
+ sc->sm->sm_flags |= errflag;
|
|
|
*error = 0;
|
|
|
/* fall through */
|
|
|
default:
|
|
|
trace_xfs_scrub_file_op_error(sc, whichfork, offset, *error,
|
|
|
- __return_address);
|
|
|
+ ret_ip);
|
|
|
break;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+bool
|
|
|
+xfs_scrub_fblock_process_error(
|
|
|
+ struct xfs_scrub_context *sc,
|
|
|
+ int whichfork,
|
|
|
+ xfs_fileoff_t offset,
|
|
|
+ int *error)
|
|
|
+{
|
|
|
+ return __xfs_scrub_fblock_process_error(sc, whichfork, offset, error,
|
|
|
+ XFS_SCRUB_OFLAG_CORRUPT, __return_address);
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+xfs_scrub_fblock_xref_process_error(
|
|
|
+ struct xfs_scrub_context *sc,
|
|
|
+ int whichfork,
|
|
|
+ xfs_fileoff_t offset,
|
|
|
+ int *error)
|
|
|
+{
|
|
|
+ return __xfs_scrub_fblock_process_error(sc, whichfork, offset, error,
|
|
|
+ XFS_SCRUB_OFLAG_XFAIL, __return_address);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Handling scrub corruption/optimization/warning checks.
|
|
|
*
|
|
@@ -183,6 +231,16 @@ xfs_scrub_block_set_corrupt(
|
|
|
trace_xfs_scrub_block_error(sc, bp->b_bn, __return_address);
|
|
|
}
|
|
|
|
|
|
+/* Record a corruption while cross-referencing. */
|
|
|
+void
|
|
|
+xfs_scrub_block_xref_set_corrupt(
|
|
|
+ struct xfs_scrub_context *sc,
|
|
|
+ struct xfs_buf *bp)
|
|
|
+{
|
|
|
+ sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XCORRUPT;
|
|
|
+ trace_xfs_scrub_block_error(sc, bp->b_bn, __return_address);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Record a corrupt inode. The trace data will include the block given
|
|
|
* by bp if bp is given; otherwise it will use the block location of the
|
|
@@ -198,6 +256,17 @@ xfs_scrub_ino_set_corrupt(
|
|
|
trace_xfs_scrub_ino_error(sc, ino, bp ? bp->b_bn : 0, __return_address);
|
|
|
}
|
|
|
|
|
|
+/* Record a corruption while cross-referencing with an inode. */
|
|
|
+void
|
|
|
+xfs_scrub_ino_xref_set_corrupt(
|
|
|
+ struct xfs_scrub_context *sc,
|
|
|
+ xfs_ino_t ino,
|
|
|
+ struct xfs_buf *bp)
|
|
|
+{
|
|
|
+ sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XCORRUPT;
|
|
|
+ trace_xfs_scrub_ino_error(sc, ino, bp ? bp->b_bn : 0, __return_address);
|
|
|
+}
|
|
|
+
|
|
|
/* Record corruption in a block indexed by a file fork. */
|
|
|
void
|
|
|
xfs_scrub_fblock_set_corrupt(
|
|
@@ -209,6 +278,17 @@ xfs_scrub_fblock_set_corrupt(
|
|
|
trace_xfs_scrub_fblock_error(sc, whichfork, offset, __return_address);
|
|
|
}
|
|
|
|
|
|
+/* Record a corruption while cross-referencing a fork block. */
|
|
|
+void
|
|
|
+xfs_scrub_fblock_xref_set_corrupt(
|
|
|
+ struct xfs_scrub_context *sc,
|
|
|
+ int whichfork,
|
|
|
+ xfs_fileoff_t offset)
|
|
|
+{
|
|
|
+ sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XCORRUPT;
|
|
|
+ trace_xfs_scrub_fblock_error(sc, whichfork, offset, __return_address);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Warn about inodes that need administrative review but is not
|
|
|
* incorrect.
|
|
@@ -588,3 +668,38 @@ out:
|
|
|
/* scrub teardown will unlock and release the inode for us */
|
|
|
return error;
|
|
|
}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Predicate that decides if we need to evaluate the cross-reference check.
|
|
|
+ * If there was an error accessing the cross-reference btree, just delete
|
|
|
+ * the cursor and skip the check.
|
|
|
+ */
|
|
|
+bool
|
|
|
+xfs_scrub_should_check_xref(
|
|
|
+ struct xfs_scrub_context *sc,
|
|
|
+ int *error,
|
|
|
+ struct xfs_btree_cur **curpp)
|
|
|
+{
|
|
|
+ if (*error == 0)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (curpp) {
|
|
|
+ /* If we've already given up on xref, just bail out. */
|
|
|
+ if (!*curpp)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* xref error, delete cursor and bail out. */
|
|
|
+ xfs_btree_del_cursor(*curpp, XFS_BTREE_ERROR);
|
|
|
+ *curpp = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XFAIL;
|
|
|
+ trace_xfs_scrub_xref_error(sc, *error, __return_address);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Errors encountered during cross-referencing with another
|
|
|
+ * data structure should not cause this scrubber to abort.
|
|
|
+ */
|
|
|
+ *error = 0;
|
|
|
+ return false;
|
|
|
+}
|