]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/phase3.c
libfrog: move path.h to libfrog/
[thirdparty/xfsprogs-dev.git] / scrub / phase3.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 */
6 #include "xfs.h"
7 #include <stdint.h>
8 #include <sys/types.h>
9 #include <sys/statvfs.h>
10 #include "list.h"
11 #include "libfrog/paths.h"
12 #include "libfrog/workqueue.h"
13 #include "xfs_scrub.h"
14 #include "common.h"
15 #include "counter.h"
16 #include "inodes.h"
17 #include "progress.h"
18 #include "scrub.h"
19 #include "repair.h"
20
21 /* Phase 3: Scan all inodes. */
22
23 /*
24 * Run a per-file metadata scanner. We use the ino/gen interface to
25 * ensure that the inode we're checking matches what the inode scan
26 * told us to look at.
27 */
28 static bool
29 xfs_scrub_fd(
30 struct scrub_ctx *ctx,
31 bool (*fn)(struct scrub_ctx *, uint64_t,
32 uint32_t, int, struct xfs_action_list *),
33 struct xfs_bstat *bs,
34 struct xfs_action_list *alist)
35 {
36 return fn(ctx, bs->bs_ino, bs->bs_gen, ctx->mnt.fd, alist);
37 }
38
39 struct scrub_inode_ctx {
40 struct ptcounter *icount;
41 bool moveon;
42 };
43
44 /* Report a filesystem error that the vfs fed us on close. */
45 static void
46 xfs_scrub_inode_vfs_error(
47 struct scrub_ctx *ctx,
48 struct xfs_bstat *bstat)
49 {
50 char descr[DESCR_BUFSZ];
51 xfs_agnumber_t agno;
52 xfs_agino_t agino;
53 int old_errno = errno;
54
55 agno = cvt_ino_to_agno(&ctx->mnt, bstat->bs_ino);
56 agino = cvt_ino_to_agino(&ctx->mnt, bstat->bs_ino);
57 snprintf(descr, DESCR_BUFSZ, _("inode %"PRIu64" (%u/%u)"),
58 (uint64_t)bstat->bs_ino, agno, agino);
59 errno = old_errno;
60 str_errno(ctx, descr);
61 }
62
63 /* Verify the contents, xattrs, and extent maps of an inode. */
64 static int
65 xfs_scrub_inode(
66 struct scrub_ctx *ctx,
67 struct xfs_handle *handle,
68 struct xfs_bstat *bstat,
69 void *arg)
70 {
71 struct xfs_action_list alist;
72 struct scrub_inode_ctx *ictx = arg;
73 struct ptcounter *icount = ictx->icount;
74 xfs_agnumber_t agno;
75 bool moveon = true;
76 int fd = -1;
77 int error;
78
79 xfs_action_list_init(&alist);
80 agno = cvt_ino_to_agno(&ctx->mnt, bstat->bs_ino);
81 background_sleep();
82
83 /* Try to open the inode to pin it. */
84 if (S_ISREG(bstat->bs_mode)) {
85 fd = xfs_open_handle(handle);
86 /* Stale inode means we scan the whole cluster again. */
87 if (fd < 0 && errno == ESTALE)
88 return ESTALE;
89 }
90
91 /* Scrub the inode. */
92 moveon = xfs_scrub_fd(ctx, xfs_scrub_inode_fields, bstat, &alist);
93 if (!moveon)
94 goto out;
95
96 moveon = xfs_action_list_process_or_defer(ctx, agno, &alist);
97 if (!moveon)
98 goto out;
99
100 /* Scrub all block mappings. */
101 moveon = xfs_scrub_fd(ctx, xfs_scrub_data_fork, bstat, &alist);
102 if (!moveon)
103 goto out;
104 moveon = xfs_scrub_fd(ctx, xfs_scrub_attr_fork, bstat, &alist);
105 if (!moveon)
106 goto out;
107 moveon = xfs_scrub_fd(ctx, xfs_scrub_cow_fork, bstat, &alist);
108 if (!moveon)
109 goto out;
110
111 moveon = xfs_action_list_process_or_defer(ctx, agno, &alist);
112 if (!moveon)
113 goto out;
114
115 if (S_ISLNK(bstat->bs_mode)) {
116 /* Check symlink contents. */
117 moveon = xfs_scrub_symlink(ctx, bstat->bs_ino,
118 bstat->bs_gen, ctx->mnt.fd, &alist);
119 } else if (S_ISDIR(bstat->bs_mode)) {
120 /* Check the directory entries. */
121 moveon = xfs_scrub_fd(ctx, xfs_scrub_dir, bstat, &alist);
122 }
123 if (!moveon)
124 goto out;
125
126 /* Check all the extended attributes. */
127 moveon = xfs_scrub_fd(ctx, xfs_scrub_attr, bstat, &alist);
128 if (!moveon)
129 goto out;
130
131 /* Check parent pointers. */
132 moveon = xfs_scrub_fd(ctx, xfs_scrub_parent, bstat, &alist);
133 if (!moveon)
134 goto out;
135
136 /* Try to repair the file while it's open. */
137 moveon = xfs_action_list_process_or_defer(ctx, agno, &alist);
138 if (!moveon)
139 goto out;
140
141 out:
142 ptcounter_add(icount, 1);
143 progress_add(1);
144 xfs_action_list_defer(ctx, agno, &alist);
145 if (fd >= 0) {
146 error = close(fd);
147 if (error)
148 xfs_scrub_inode_vfs_error(ctx, bstat);
149 }
150 if (!moveon)
151 ictx->moveon = false;
152 return ictx->moveon ? 0 : XFS_ITERATE_INODES_ABORT;
153 }
154
155 /* Verify all the inodes in a filesystem. */
156 bool
157 xfs_scan_inodes(
158 struct scrub_ctx *ctx)
159 {
160 struct scrub_inode_ctx ictx;
161 bool ret;
162
163 ictx.moveon = true;
164 ictx.icount = ptcounter_init(scrub_nproc(ctx));
165 if (!ictx.icount) {
166 str_info(ctx, ctx->mntpoint, _("Could not create counter."));
167 return false;
168 }
169
170 ret = xfs_scan_all_inodes(ctx, xfs_scrub_inode, &ictx);
171 if (!ret)
172 ictx.moveon = false;
173 if (!ictx.moveon)
174 goto free;
175 xfs_scrub_report_preen_triggers(ctx);
176 ctx->inodes_checked = ptcounter_value(ictx.icount);
177
178 free:
179 ptcounter_free(ictx.icount);
180 return ictx.moveon;
181 }
182
183 /* Estimate how much work we're going to do. */
184 bool
185 xfs_estimate_inodes_work(
186 struct scrub_ctx *ctx,
187 uint64_t *items,
188 unsigned int *nr_threads,
189 int *rshift)
190 {
191 *items = ctx->mnt_sv.f_files - ctx->mnt_sv.f_ffree;
192 *nr_threads = scrub_nproc(ctx);
193 *rshift = 0;
194 return true;
195 }