]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/phase3.c
b35ef164be7eb5855d4675120ad3808d27cfdc2d
[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 int
29 scrub_fd(
30 struct scrub_ctx *ctx,
31 int (*fn)(struct scrub_ctx *ctx, uint64_t ino,
32 uint32_t gen, struct action_list *a),
33 struct xfs_bulkstat *bs,
34 struct action_list *alist)
35 {
36 return fn(ctx, bs->bs_ino, bs->bs_gen, 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_bulkstat *bstat)
49 {
50 char descr[DESCR_BUFSZ];
51 int old_errno = errno;
52
53 scrub_render_ino_descr(ctx, descr, DESCR_BUFSZ, bstat->bs_ino,
54 bstat->bs_gen, NULL);
55 errno = old_errno;
56 str_errno(ctx, descr);
57 }
58
59 /* Verify the contents, xattrs, and extent maps of an inode. */
60 static int
61 xfs_scrub_inode(
62 struct scrub_ctx *ctx,
63 struct xfs_handle *handle,
64 struct xfs_bulkstat *bstat,
65 void *arg)
66 {
67 struct action_list alist;
68 struct scrub_inode_ctx *ictx = arg;
69 struct ptcounter *icount = ictx->icount;
70 xfs_agnumber_t agno;
71 bool moveon = true;
72 int fd = -1;
73 int error;
74
75 action_list_init(&alist);
76 agno = cvt_ino_to_agno(&ctx->mnt, bstat->bs_ino);
77 background_sleep();
78
79 /* Try to open the inode to pin it. */
80 if (S_ISREG(bstat->bs_mode)) {
81 fd = scrub_open_handle(handle);
82 /* Stale inode means we scan the whole cluster again. */
83 if (fd < 0 && errno == ESTALE)
84 return ESTALE;
85 }
86
87 /* Scrub the inode. */
88 error = scrub_fd(ctx, xfs_scrub_inode_fields, bstat, &alist);
89 if (error)
90 goto out;
91
92 error = action_list_process_or_defer(ctx, agno, &alist);
93 if (error)
94 goto out;
95
96 /* Scrub all block mappings. */
97 error = scrub_fd(ctx, xfs_scrub_data_fork, bstat, &alist);
98 if (error)
99 goto out;
100 error = scrub_fd(ctx, xfs_scrub_attr_fork, bstat, &alist);
101 if (error)
102 goto out;
103 error = scrub_fd(ctx, xfs_scrub_cow_fork, bstat, &alist);
104 if (error)
105 goto out;
106
107 error = action_list_process_or_defer(ctx, agno, &alist);
108 if (error)
109 goto out;
110
111 if (S_ISLNK(bstat->bs_mode)) {
112 /* Check symlink contents. */
113 error = xfs_scrub_symlink(ctx, bstat->bs_ino, bstat->bs_gen,
114 &alist);
115 } else if (S_ISDIR(bstat->bs_mode)) {
116 /* Check the directory entries. */
117 error = scrub_fd(ctx, xfs_scrub_dir, bstat, &alist);
118 }
119 if (error)
120 goto out;
121
122 /* Check all the extended attributes. */
123 error = scrub_fd(ctx, xfs_scrub_attr, bstat, &alist);
124 if (error)
125 goto out;
126
127 /* Check parent pointers. */
128 error = scrub_fd(ctx, xfs_scrub_parent, bstat, &alist);
129 if (error)
130 goto out;
131
132 /* Try to repair the file while it's open. */
133 error = action_list_process_or_defer(ctx, agno, &alist);
134 if (error)
135 goto out;
136
137 out:
138 if (error)
139 moveon = false;
140 error = ptcounter_add(icount, 1);
141 if (error) {
142 str_liberror(ctx, error,
143 _("incrementing scanned inode counter"));
144 return false;
145 }
146 progress_add(1);
147 action_list_defer(ctx, agno, &alist);
148 if (fd >= 0) {
149 error = close(fd);
150 if (error)
151 xfs_scrub_inode_vfs_error(ctx, bstat);
152 }
153 if (!moveon)
154 ictx->moveon = false;
155 return ictx->moveon ? 0 : XFS_ITERATE_INODES_ABORT;
156 }
157
158 /* Verify all the inodes in a filesystem. */
159 bool
160 xfs_scan_inodes(
161 struct scrub_ctx *ctx)
162 {
163 struct scrub_inode_ctx ictx;
164 uint64_t val;
165 int err;
166
167 ictx.moveon = true;
168 err = ptcounter_alloc(scrub_nproc(ctx), &ictx.icount);
169 if (err) {
170 str_liberror(ctx, err, _("creating scanned inode counter"));
171 return false;
172 }
173
174 err = scrub_scan_all_inodes(ctx, xfs_scrub_inode, &ictx);
175 if (err)
176 ictx.moveon = false;
177 if (!ictx.moveon)
178 goto free;
179 xfs_scrub_report_preen_triggers(ctx);
180 err = ptcounter_value(ictx.icount, &val);
181 if (err) {
182 str_liberror(ctx, err, _("summing scanned inode counter"));
183 return false;
184 }
185 ctx->inodes_checked = val;
186 free:
187 ptcounter_free(ictx.icount);
188 return ictx.moveon;
189 }
190
191 /* Estimate how much work we're going to do. */
192 bool
193 xfs_estimate_inodes_work(
194 struct scrub_ctx *ctx,
195 uint64_t *items,
196 unsigned int *nr_threads,
197 int *rshift)
198 {
199 *items = ctx->mnt_sv.f_files - ctx->mnt_sv.f_ffree;
200 *nr_threads = scrub_nproc(ctx);
201 *rshift = 0;
202 return true;
203 }