static int
try_inode_repair(
struct scrub_inode_ctx *ictx,
+ int fd,
xfs_agnumber_t agno,
struct action_list *alist)
{
+ int ret;
+
/*
* If at the start of phase 3 we already had ag/rt metadata repairs
* queued up for phase 4, leave the action list untouched so that file
if (ictx->always_defer_repairs)
return 0;
- return action_list_process_or_defer(ictx->ctx, agno, alist);
+ ret = action_list_process(ictx->ctx, fd, alist,
+ ALP_REPAIR_ONLY | ALP_NOPROGRESS);
+ if (ret)
+ return ret;
+
+ action_list_defer(ictx->ctx, agno, alist);
+ return 0;
}
/* Verify the contents, xattrs, and extent maps of an inode. */
if (error)
goto out;
- error = try_inode_repair(ictx, agno, &alist);
+ error = try_inode_repair(ictx, fd, agno, &alist);
if (error)
goto out;
if (error)
goto out;
- error = try_inode_repair(ictx, agno, &alist);
+ error = try_inode_repair(ictx, fd, agno, &alist);
if (error)
goto out;
goto out;
/* Try to repair the file while it's open. */
- error = try_inode_repair(ictx, agno, &alist);
+ error = try_inode_repair(ictx, fd, agno, &alist);
if (error)
goto out;
/* Repair anything broken until we fail to make progress. */
do {
- ret = action_list_process(ctx, ctx->mnt.fd, alist, flags);
+ ret = action_list_process(ctx, -1, alist, flags);
if (ret) {
*aborted = true;
return;
/* Try once more, but this time complain if we can't fix things. */
flags |= ALP_COMPLAIN_IF_UNFIXED;
- ret = action_list_process(ctx, ctx->mnt.fd, alist, flags);
+ ret = action_list_process(ctx, -1, alist, flags);
if (ret)
*aborted = true;
}
error = scrub_fs_summary(ctx, &alist);
if (error)
return error;
- error = action_list_process(ctx, ctx->mnt.fd, &alist,
+ error = action_list_process(ctx, -1, &alist,
ALP_COMPLAIN_IF_UNFIXED | ALP_NOPROGRESS);
if (error)
return error;
struct action_list *alist,
unsigned int repair_flags)
{
+ struct xfs_fd xfd;
+ struct xfs_fd *xfdp = &ctx->mnt;
struct action_item *aitem;
struct action_item *n;
enum check_outcome fix;
+ /*
+ * If the caller passed us a file descriptor for a scrub, use it
+ * instead of scrub-by-handle because this enables the kernel to skip
+ * costly inode btree lookups.
+ */
+ if (fd >= 0) {
+ memcpy(&xfd, xfdp, sizeof(xfd));
+ xfd.fd = fd;
+ xfdp = &xfd;
+ }
+
if (!alist->sorted) {
list_sort(NULL, &alist->list, xfs_action_item_compare);
alist->sorted = true;
}
list_for_each_entry_safe(aitem, n, &alist->list, list) {
- fix = xfs_repair_metadata(ctx, fd, aitem, repair_flags);
+ fix = xfs_repair_metadata(ctx, xfdp, aitem, repair_flags);
switch (fix) {
case CHECK_DONE:
if (!(repair_flags & ALP_NOPROGRESS))
{
int ret;
- ret = action_list_process(ctx, ctx->mnt.fd, alist,
+ ret = action_list_process(ctx, -1, alist,
ALP_REPAIR_ONLY | ALP_NOPROGRESS);
if (ret)
return ret;
enum check_outcome
xfs_repair_metadata(
struct scrub_ctx *ctx,
- int fd,
+ struct xfs_fd *xfdp,
struct action_item *aitem,
unsigned int repair_flags)
{
str_info(ctx, descr_render(&dsc),
_("Attempting optimization."));
- error = -xfrog_scrub_metadata(&ctx->mnt, &meta);
+ error = -xfrog_scrub_metadata(xfdp, &meta);
switch (error) {
case 0:
/* No operational errors encountered. */
/* Complain if still broken even after fix. */
#define XRM_COMPLAIN_IF_UNFIXED (1U << 1)
-enum check_outcome xfs_repair_metadata(struct scrub_ctx *ctx, int fd,
- struct action_item *aitem, unsigned int repair_flags);
+enum check_outcome xfs_repair_metadata(struct scrub_ctx *ctx,
+ struct xfs_fd *xfdp, struct action_item *aitem,
+ unsigned int repair_flags);
#endif /* XFS_SCRUB_SCRUB_H_ */