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
)
89 * Open the directory with O_NOATIME. For mountpoints owned
90 * by root, this should be sufficient to ensure that we have
91 * CAP_SYS_ADMIN, which we probably need to do anything fancy
92 * with the (XFS driver) kernel.
94 ctx
->mnt_fd
= open(ctx
->mntpoint
, O_RDONLY
| O_NOATIME
| O_DIRECTORY
);
95 if (ctx
->mnt_fd
< 0) {
97 str_info(ctx
, ctx
->mntpoint
,
98 _("Must be root to run scrub."));
100 str_errno(ctx
, ctx
->mntpoint
);
104 error
= fstat(ctx
->mnt_fd
, &ctx
->mnt_sb
);
106 str_errno(ctx
, ctx
->mntpoint
);
109 error
= fstatvfs(ctx
->mnt_fd
, &ctx
->mnt_sv
);
111 str_errno(ctx
, ctx
->mntpoint
);
114 error
= fstatfs(ctx
->mnt_fd
, &ctx
->mnt_sf
);
116 str_errno(ctx
, ctx
->mntpoint
);
120 ctx
->nr_io_threads
= nproc
;
122 fprintf(stdout
, _("%s: using %d threads to scrub.\n"),
123 ctx
->mntpoint
, scrub_nproc(ctx
));
127 if (!platform_test_xfs_fd(ctx
->mnt_fd
)) {
128 str_info(ctx
, ctx
->mntpoint
,
129 _("Does not appear to be an XFS filesystem!"));
134 * Flush everything out to disk before we start checking.
135 * This seems to reduce the incidence of stale file handle
136 * errors when we open things by handle.
138 error
= syncfs(ctx
->mnt_fd
);
140 str_errno(ctx
, ctx
->mntpoint
);
144 /* Retrieve XFS geometry. */
145 error
= ioctl(ctx
->mnt_fd
, XFS_IOC_FSGEOMETRY
, &ctx
->geo
);
147 str_errno(ctx
, ctx
->mntpoint
);
151 ctx
->agblklog
= log2_roundup(ctx
->geo
.agblocks
);
152 ctx
->blocklog
= highbit32(ctx
->geo
.blocksize
);
153 ctx
->inodelog
= highbit32(ctx
->geo
.inodesize
);
154 ctx
->inopblog
= ctx
->blocklog
- ctx
->inodelog
;
156 error
= path_to_fshandle(ctx
->mntpoint
, &ctx
->fshandle
,
159 str_errno(ctx
, _("getting fshandle"));
163 /* Do we have kernel-assisted metadata scrubbing? */
164 if (!xfs_can_scrub_fs_metadata(ctx
) || !xfs_can_scrub_inode(ctx
) ||
165 !xfs_can_scrub_bmap(ctx
) || !xfs_can_scrub_dir(ctx
) ||
166 !xfs_can_scrub_attr(ctx
) || !xfs_can_scrub_symlink(ctx
) ||
167 !xfs_can_scrub_parent(ctx
)) {
168 str_info(ctx
, ctx
->mntpoint
,
169 _("Kernel metadata scrubbing facility is not available."));
173 /* Do we need kernel-assisted metadata repair? */
174 if (ctx
->mode
!= SCRUB_MODE_DRY_RUN
&& !xfs_can_repair(ctx
)) {
175 str_info(ctx
, ctx
->mntpoint
,
176 _("Kernel metadata repair facility is not available. Use -n to scrub."));
180 /* Did we find the log and rt devices, if they're present? */
181 if (ctx
->geo
.logstart
== 0 && ctx
->fsinfo
.fs_log
== NULL
) {
182 str_info(ctx
, ctx
->mntpoint
,
183 _("Unable to find log device path."));
186 if (ctx
->geo
.rtblocks
&& ctx
->fsinfo
.fs_rt
== NULL
) {
187 str_info(ctx
, ctx
->mntpoint
,
188 _("Unable to find realtime device path."));
192 /* Open the raw devices. */
193 ctx
->datadev
= disk_open(ctx
->fsinfo
.fs_name
);
195 str_errno(ctx
, ctx
->fsinfo
.fs_name
);
199 if (ctx
->fsinfo
.fs_log
) {
200 ctx
->logdev
= disk_open(ctx
->fsinfo
.fs_log
);
202 str_errno(ctx
, ctx
->fsinfo
.fs_name
);
206 if (ctx
->fsinfo
.fs_rt
) {
207 ctx
->rtdev
= disk_open(ctx
->fsinfo
.fs_rt
);
209 str_errno(ctx
, ctx
->fsinfo
.fs_name
);
215 * Everything's set up, which means any failures recorded after
216 * this point are most probably corruption errors (as opposed to
217 * purely setup errors).
219 log_info(ctx
, _("Invoking online scrub."), ctx
);
220 ctx
->scrub_setup_succeeded
= true;