]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
fa16b376 DW |
2 | /* |
3 | * Copyright (C) 2018 Oracle. All Rights Reserved. | |
fa16b376 | 4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> |
fa16b376 | 5 | */ |
a440f877 | 6 | #include "xfs.h" |
fa16b376 | 7 | #include <stdint.h> |
fa16b376 | 8 | #include <sys/types.h> |
fa16b376 | 9 | #include <sys/statvfs.h> |
19852474 | 10 | #include "list.h" |
42b4c8e8 | 11 | #include "libfrog/paths.h" |
56598728 | 12 | #include "libfrog/workqueue.h" |
fa16b376 DW |
13 | #include "xfs_scrub.h" |
14 | #include "common.h" | |
15 | #include "counter.h" | |
16 | #include "inodes.h" | |
ed60d210 | 17 | #include "progress.h" |
fa16b376 | 18 | #include "scrub.h" |
ee310b0c | 19 | #include "repair.h" |
fa16b376 DW |
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, | |
991e5a84 DW |
31 | bool (*fn)(struct scrub_ctx *ctx, uint64_t ino, |
32 | uint32_t gen, struct xfs_action_list *a), | |
4cca629d | 33 | struct xfs_bulkstat *bs, |
ee310b0c | 34 | struct xfs_action_list *alist) |
fa16b376 | 35 | { |
991e5a84 | 36 | return fn(ctx, bs->bs_ino, bs->bs_gen, alist); |
fa16b376 DW |
37 | } |
38 | ||
39 | struct scrub_inode_ctx { | |
40 | struct ptcounter *icount; | |
41 | bool moveon; | |
42 | }; | |
43 | ||
6c05cc5d DW |
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, | |
4cca629d | 48 | struct xfs_bulkstat *bstat) |
6c05cc5d DW |
49 | { |
50 | char descr[DESCR_BUFSZ]; | |
6c05cc5d DW |
51 | int old_errno = errno; |
52 | ||
15589f0a DW |
53 | scrub_render_ino_descr(ctx, descr, DESCR_BUFSZ, bstat->bs_ino, |
54 | bstat->bs_gen, NULL); | |
6c05cc5d DW |
55 | errno = old_errno; |
56 | str_errno(ctx, descr); | |
57 | } | |
58 | ||
fa16b376 DW |
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, | |
4cca629d | 64 | struct xfs_bulkstat *bstat, |
fa16b376 DW |
65 | void *arg) |
66 | { | |
ee310b0c | 67 | struct xfs_action_list alist; |
fa16b376 DW |
68 | struct scrub_inode_ctx *ictx = arg; |
69 | struct ptcounter *icount = ictx->icount; | |
ee310b0c | 70 | xfs_agnumber_t agno; |
fa16b376 DW |
71 | bool moveon = true; |
72 | int fd = -1; | |
6c05cc5d | 73 | int error; |
fa16b376 | 74 | |
ee310b0c | 75 | xfs_action_list_init(&alist); |
a749451c | 76 | agno = cvt_ino_to_agno(&ctx->mnt, bstat->bs_ino); |
fa16b376 DW |
77 | background_sleep(); |
78 | ||
79 | /* Try to open the inode to pin it. */ | |
80 | if (S_ISREG(bstat->bs_mode)) { | |
59f79e0a | 81 | fd = scrub_open_handle(handle); |
fa16b376 DW |
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. */ | |
ee310b0c DW |
88 | moveon = xfs_scrub_fd(ctx, xfs_scrub_inode_fields, bstat, &alist); |
89 | if (!moveon) | |
90 | goto out; | |
91 | ||
92 | moveon = xfs_action_list_process_or_defer(ctx, agno, &alist); | |
fa16b376 DW |
93 | if (!moveon) |
94 | goto out; | |
95 | ||
96 | /* Scrub all block mappings. */ | |
ee310b0c | 97 | moveon = xfs_scrub_fd(ctx, xfs_scrub_data_fork, bstat, &alist); |
fa16b376 DW |
98 | if (!moveon) |
99 | goto out; | |
ee310b0c | 100 | moveon = xfs_scrub_fd(ctx, xfs_scrub_attr_fork, bstat, &alist); |
fa16b376 DW |
101 | if (!moveon) |
102 | goto out; | |
ee310b0c DW |
103 | moveon = xfs_scrub_fd(ctx, xfs_scrub_cow_fork, bstat, &alist); |
104 | if (!moveon) | |
105 | goto out; | |
106 | ||
107 | moveon = xfs_action_list_process_or_defer(ctx, agno, &alist); | |
fa16b376 DW |
108 | if (!moveon) |
109 | goto out; | |
110 | ||
111 | if (S_ISLNK(bstat->bs_mode)) { | |
112 | /* Check symlink contents. */ | |
991e5a84 DW |
113 | moveon = xfs_scrub_symlink(ctx, bstat->bs_ino, bstat->bs_gen, |
114 | &alist); | |
fa16b376 DW |
115 | } else if (S_ISDIR(bstat->bs_mode)) { |
116 | /* Check the directory entries. */ | |
ee310b0c | 117 | moveon = xfs_scrub_fd(ctx, xfs_scrub_dir, bstat, &alist); |
fa16b376 DW |
118 | } |
119 | if (!moveon) | |
120 | goto out; | |
121 | ||
122 | /* Check all the extended attributes. */ | |
ee310b0c | 123 | moveon = xfs_scrub_fd(ctx, xfs_scrub_attr, bstat, &alist); |
fa16b376 DW |
124 | if (!moveon) |
125 | goto out; | |
126 | ||
127 | /* Check parent pointers. */ | |
ee310b0c DW |
128 | moveon = xfs_scrub_fd(ctx, xfs_scrub_parent, bstat, &alist); |
129 | if (!moveon) | |
130 | goto out; | |
131 | ||
132 | /* Try to repair the file while it's open. */ | |
133 | moveon = xfs_action_list_process_or_defer(ctx, agno, &alist); | |
fa16b376 DW |
134 | if (!moveon) |
135 | goto out; | |
136 | ||
137 | out: | |
da3dd6c0 DW |
138 | error = ptcounter_add(icount, 1); |
139 | if (error) { | |
140 | str_liberror(ctx, error, | |
141 | _("incrementing scanned inode counter")); | |
142 | return false; | |
143 | } | |
ed60d210 | 144 | progress_add(1); |
ee310b0c | 145 | xfs_action_list_defer(ctx, agno, &alist); |
6c05cc5d DW |
146 | if (fd >= 0) { |
147 | error = close(fd); | |
148 | if (error) | |
149 | xfs_scrub_inode_vfs_error(ctx, bstat); | |
150 | } | |
fa16b376 DW |
151 | if (!moveon) |
152 | ictx->moveon = false; | |
153 | return ictx->moveon ? 0 : XFS_ITERATE_INODES_ABORT; | |
154 | } | |
155 | ||
156 | /* Verify all the inodes in a filesystem. */ | |
157 | bool | |
158 | xfs_scan_inodes( | |
159 | struct scrub_ctx *ctx) | |
160 | { | |
161 | struct scrub_inode_ctx ictx; | |
da3dd6c0 DW |
162 | uint64_t val; |
163 | int err; | |
fa16b376 DW |
164 | |
165 | ictx.moveon = true; | |
da3dd6c0 DW |
166 | err = ptcounter_alloc(scrub_nproc(ctx), &ictx.icount); |
167 | if (err) { | |
168 | str_liberror(ctx, err, _("creating scanned inode counter")); | |
fa16b376 DW |
169 | return false; |
170 | } | |
171 | ||
59f79e0a DW |
172 | err = scrub_scan_all_inodes(ctx, xfs_scrub_inode, &ictx); |
173 | if (err) | |
fa16b376 DW |
174 | ictx.moveon = false; |
175 | if (!ictx.moveon) | |
176 | goto free; | |
177 | xfs_scrub_report_preen_triggers(ctx); | |
da3dd6c0 DW |
178 | err = ptcounter_value(ictx.icount, &val); |
179 | if (err) { | |
180 | str_liberror(ctx, err, _("summing scanned inode counter")); | |
181 | return false; | |
182 | } | |
183 | ctx->inodes_checked = val; | |
fa16b376 DW |
184 | free: |
185 | ptcounter_free(ictx.icount); | |
186 | return ictx.moveon; | |
187 | } | |
ed60d210 DW |
188 | |
189 | /* Estimate how much work we're going to do. */ | |
190 | bool | |
191 | xfs_estimate_inodes_work( | |
192 | struct scrub_ctx *ctx, | |
193 | uint64_t *items, | |
194 | unsigned int *nr_threads, | |
195 | int *rshift) | |
196 | { | |
197 | *items = ctx->mnt_sv.f_files - ctx->mnt_sv.f_ffree; | |
198 | *nr_threads = scrub_nproc(ctx); | |
199 | *rshift = 0; | |
200 | return true; | |
201 | } |