2 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
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.
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.
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.
22 #include <sys/types.h>
24 #include <sys/resource.h>
25 #include <sys/statvfs.h>
31 #include "workqueue.h"
38 #include "xfs_scrub.h"
43 /* Phase 1: Find filesystem geometry (and clean up after) */
45 /* Shut down the filesystem. */
48 struct scrub_ctx
*ctx
)
52 flag
= XFS_FSOP_GOING_FLAGS_LOGFLUSH
;
53 str_info(ctx
, ctx
->mntpoint
, _("Shutting down filesystem!"));
54 if (ioctl(ctx
->mnt_fd
, XFS_IOC_GOINGDOWN
, &flag
))
55 str_errno(ctx
, ctx
->mntpoint
);
58 /* Clean up the XFS-specific state data. */
61 struct scrub_ctx
*ctx
)
64 free_handle(ctx
->fshandle
, ctx
->fshandle_len
);
66 disk_close(ctx
->rtdev
);
68 disk_close(ctx
->logdev
);
70 disk_close(ctx
->datadev
);
79 * Bind to the mountpoint, read the XFS geometry, bind to the block devices.
80 * Anything we've already built will be cleaned up by xfs_cleanup_fs.
84 struct scrub_ctx
*ctx
)
90 * Open the directory with O_NOATIME. For mountpoints owned
91 * by root, this should be sufficient to ensure that we have
92 * CAP_SYS_ADMIN, which we probably need to do anything fancy
93 * with the (XFS driver) kernel.
95 ctx
->mnt_fd
= open(ctx
->mntpoint
, O_RDONLY
| O_NOATIME
| O_DIRECTORY
);
96 if (ctx
->mnt_fd
< 0) {
98 str_info(ctx
, ctx
->mntpoint
,
99 _("Must be root to run scrub."));
101 str_errno(ctx
, ctx
->mntpoint
);
105 error
= fstat(ctx
->mnt_fd
, &ctx
->mnt_sb
);
107 str_errno(ctx
, ctx
->mntpoint
);
110 error
= fstatvfs(ctx
->mnt_fd
, &ctx
->mnt_sv
);
112 str_errno(ctx
, ctx
->mntpoint
);
115 error
= fstatfs(ctx
->mnt_fd
, &ctx
->mnt_sf
);
117 str_errno(ctx
, ctx
->mntpoint
);
121 ctx
->nr_io_threads
= nproc
;
123 fprintf(stdout
, _("%s: using %d threads to scrub.\n"),
124 ctx
->mntpoint
, scrub_nproc(ctx
));
128 if (!platform_test_xfs_fd(ctx
->mnt_fd
)) {
129 str_info(ctx
, ctx
->mntpoint
,
130 _("Does not appear to be an XFS filesystem!"));
135 * Flush everything out to disk before we start checking.
136 * This seems to reduce the incidence of stale file handle
137 * errors when we open things by handle.
139 error
= syncfs(ctx
->mnt_fd
);
141 str_errno(ctx
, ctx
->mntpoint
);
145 /* Retrieve XFS geometry. */
146 error
= ioctl(ctx
->mnt_fd
, XFS_IOC_FSGEOMETRY
, &ctx
->geo
);
148 str_errno(ctx
, ctx
->mntpoint
);
152 ctx
->agblklog
= log2_roundup(ctx
->geo
.agblocks
);
153 ctx
->blocklog
= highbit32(ctx
->geo
.blocksize
);
154 ctx
->inodelog
= highbit32(ctx
->geo
.inodesize
);
155 ctx
->inopblog
= ctx
->blocklog
- ctx
->inodelog
;
157 error
= path_to_fshandle(ctx
->mntpoint
, &ctx
->fshandle
,
160 str_errno(ctx
, _("getting fshandle"));
164 /* Do we have kernel-assisted metadata scrubbing? */
165 if (!xfs_can_scrub_fs_metadata(ctx
) || !xfs_can_scrub_inode(ctx
) ||
166 !xfs_can_scrub_bmap(ctx
) || !xfs_can_scrub_dir(ctx
) ||
167 !xfs_can_scrub_attr(ctx
) || !xfs_can_scrub_symlink(ctx
) ||
168 !xfs_can_scrub_parent(ctx
)) {
169 str_info(ctx
, ctx
->mntpoint
,
170 _("Kernel metadata scrubbing facility is not available."));
174 /* Do we need kernel-assisted metadata repair? */
175 if (ctx
->mode
!= SCRUB_MODE_DRY_RUN
&& !xfs_can_repair(ctx
)) {
176 str_info(ctx
, ctx
->mntpoint
,
177 _("Kernel metadata repair facility is not available. Use -n to scrub."));
181 /* Go find the XFS devices if we have a usable fsmap. */
182 fs_table_initialise(0, NULL
, 0, NULL
);
184 fsp
= fs_table_lookup(ctx
->mntpoint
, FS_MOUNT_POINT
);
186 str_info(ctx
, ctx
->mntpoint
,
187 _("Unable to find XFS information."));
190 memcpy(&ctx
->fsinfo
, fsp
, sizeof(struct fs_path
));
192 /* Did we find the log and rt devices, if they're present? */
193 if (ctx
->geo
.logstart
== 0 && ctx
->fsinfo
.fs_log
== NULL
) {
194 str_info(ctx
, ctx
->mntpoint
,
195 _("Unable to find log device path."));
198 if (ctx
->geo
.rtblocks
&& ctx
->fsinfo
.fs_rt
== NULL
) {
199 str_info(ctx
, ctx
->mntpoint
,
200 _("Unable to find realtime device path."));
204 /* Open the raw devices. */
205 ctx
->datadev
= disk_open(ctx
->fsinfo
.fs_name
);
207 str_errno(ctx
, ctx
->fsinfo
.fs_name
);
211 if (ctx
->fsinfo
.fs_log
) {
212 ctx
->logdev
= disk_open(ctx
->fsinfo
.fs_log
);
214 str_errno(ctx
, ctx
->fsinfo
.fs_name
);
218 if (ctx
->fsinfo
.fs_rt
) {
219 ctx
->rtdev
= disk_open(ctx
->fsinfo
.fs_rt
);
221 str_errno(ctx
, ctx
->fsinfo
.fs_name
);
227 * Everything's set up, which means any failures recorded after
228 * this point are most probably corruption errors (as opposed to
229 * purely setup errors).
231 log_info(ctx
, _("Invoking online scrub."), ctx
);
232 ctx
->scrub_setup_succeeded
= true;