]>
Commit | Line | Data |
---|---|---|
fa16b376 DW |
1 | /* |
2 | * Copyright (C) 2018 Oracle. All Rights Reserved. | |
3 | * | |
4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version 2 | |
9 | * of the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it would be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write the Free Software Foundation, | |
18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | */ | |
20 | #include <stdio.h> | |
21 | #include <stdint.h> | |
22 | #include <stdbool.h> | |
23 | #include <sys/types.h> | |
24 | #include <sys/stat.h> | |
25 | #include <sys/statvfs.h> | |
26 | #include "xfs.h" | |
27 | #include "path.h" | |
28 | #include "workqueue.h" | |
29 | #include "xfs_scrub.h" | |
30 | #include "common.h" | |
31 | #include "counter.h" | |
32 | #include "inodes.h" | |
ed60d210 | 33 | #include "progress.h" |
fa16b376 DW |
34 | #include "scrub.h" |
35 | ||
36 | /* Phase 3: Scan all inodes. */ | |
37 | ||
38 | /* | |
39 | * Run a per-file metadata scanner. We use the ino/gen interface to | |
40 | * ensure that the inode we're checking matches what the inode scan | |
41 | * told us to look at. | |
42 | */ | |
43 | static bool | |
44 | xfs_scrub_fd( | |
45 | struct scrub_ctx *ctx, | |
46 | bool (*fn)(struct scrub_ctx *, uint64_t, | |
47 | uint32_t, int), | |
48 | struct xfs_bstat *bs) | |
49 | { | |
50 | return fn(ctx, bs->bs_ino, bs->bs_gen, ctx->mnt_fd); | |
51 | } | |
52 | ||
53 | struct scrub_inode_ctx { | |
54 | struct ptcounter *icount; | |
55 | bool moveon; | |
56 | }; | |
57 | ||
58 | /* Verify the contents, xattrs, and extent maps of an inode. */ | |
59 | static int | |
60 | xfs_scrub_inode( | |
61 | struct scrub_ctx *ctx, | |
62 | struct xfs_handle *handle, | |
63 | struct xfs_bstat *bstat, | |
64 | void *arg) | |
65 | { | |
66 | struct scrub_inode_ctx *ictx = arg; | |
67 | struct ptcounter *icount = ictx->icount; | |
68 | bool moveon = true; | |
69 | int fd = -1; | |
70 | ||
71 | background_sleep(); | |
72 | ||
73 | /* Try to open the inode to pin it. */ | |
74 | if (S_ISREG(bstat->bs_mode)) { | |
75 | fd = xfs_open_handle(handle); | |
76 | /* Stale inode means we scan the whole cluster again. */ | |
77 | if (fd < 0 && errno == ESTALE) | |
78 | return ESTALE; | |
79 | } | |
80 | ||
81 | /* Scrub the inode. */ | |
82 | moveon = xfs_scrub_fd(ctx, xfs_scrub_inode_fields, bstat); | |
83 | if (!moveon) | |
84 | goto out; | |
85 | ||
86 | /* Scrub all block mappings. */ | |
87 | moveon = xfs_scrub_fd(ctx, xfs_scrub_data_fork, bstat); | |
88 | if (!moveon) | |
89 | goto out; | |
90 | moveon = xfs_scrub_fd(ctx, xfs_scrub_attr_fork, bstat); | |
91 | if (!moveon) | |
92 | goto out; | |
93 | moveon = xfs_scrub_fd(ctx, xfs_scrub_cow_fork, bstat); | |
94 | if (!moveon) | |
95 | goto out; | |
96 | ||
97 | if (S_ISLNK(bstat->bs_mode)) { | |
98 | /* Check symlink contents. */ | |
99 | moveon = xfs_scrub_symlink(ctx, bstat->bs_ino, | |
100 | bstat->bs_gen, ctx->mnt_fd); | |
101 | } else if (S_ISDIR(bstat->bs_mode)) { | |
102 | /* Check the directory entries. */ | |
103 | moveon = xfs_scrub_fd(ctx, xfs_scrub_dir, bstat); | |
104 | } | |
105 | if (!moveon) | |
106 | goto out; | |
107 | ||
108 | /* Check all the extended attributes. */ | |
109 | moveon = xfs_scrub_fd(ctx, xfs_scrub_attr, bstat); | |
110 | if (!moveon) | |
111 | goto out; | |
112 | ||
113 | /* Check parent pointers. */ | |
114 | moveon = xfs_scrub_fd(ctx, xfs_scrub_parent, bstat); | |
115 | if (!moveon) | |
116 | goto out; | |
117 | ||
118 | out: | |
119 | ptcounter_add(icount, 1); | |
ed60d210 | 120 | progress_add(1); |
fa16b376 DW |
121 | if (fd >= 0) |
122 | close(fd); | |
123 | if (!moveon) | |
124 | ictx->moveon = false; | |
125 | return ictx->moveon ? 0 : XFS_ITERATE_INODES_ABORT; | |
126 | } | |
127 | ||
128 | /* Verify all the inodes in a filesystem. */ | |
129 | bool | |
130 | xfs_scan_inodes( | |
131 | struct scrub_ctx *ctx) | |
132 | { | |
133 | struct scrub_inode_ctx ictx; | |
134 | bool ret; | |
135 | ||
136 | ictx.moveon = true; | |
137 | ictx.icount = ptcounter_init(scrub_nproc(ctx)); | |
138 | if (!ictx.icount) { | |
139 | str_error(ctx, ctx->mntpoint, _("Could not create counter.")); | |
140 | return false; | |
141 | } | |
142 | ||
143 | ret = xfs_scan_all_inodes(ctx, xfs_scrub_inode, &ictx); | |
144 | if (!ret) | |
145 | ictx.moveon = false; | |
146 | if (!ictx.moveon) | |
147 | goto free; | |
148 | xfs_scrub_report_preen_triggers(ctx); | |
149 | ctx->inodes_checked = ptcounter_value(ictx.icount); | |
150 | ||
151 | free: | |
152 | ptcounter_free(ictx.icount); | |
153 | return ictx.moveon; | |
154 | } | |
ed60d210 DW |
155 | |
156 | /* Estimate how much work we're going to do. */ | |
157 | bool | |
158 | xfs_estimate_inodes_work( | |
159 | struct scrub_ctx *ctx, | |
160 | uint64_t *items, | |
161 | unsigned int *nr_threads, | |
162 | int *rshift) | |
163 | { | |
164 | *items = ctx->mnt_sv.f_files - ctx->mnt_sv.f_ffree; | |
165 | *nr_threads = scrub_nproc(ctx); | |
166 | *rshift = 0; | |
167 | return true; | |
168 | } |