1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
10 #include <sys/statvfs.h>
12 #include "libfrog/paths.h"
13 #include "libfrog/workqueue.h"
14 #include "xfs_scrub.h"
18 #ifndef AT_NO_AUTOMOUNT
19 # define AT_NO_AUTOMOUNT 0x800
23 * Helper functions to assist in traversing a directory tree using regular
27 /* Scan a filesystem tree. */
31 pthread_cond_t wakeup
;
34 scan_fs_tree_dir_fn dir_fn
;
35 scan_fs_tree_dirent_fn dirent_fn
;
39 /* Per-work-item scan context. */
40 struct scan_fs_tree_dir
{
42 struct scan_fs_tree
*sft
;
46 static void scan_fs_dir(struct workqueue
*wq
, xfs_agnumber_t agno
, void *arg
);
48 /* Increment the number of directories that are queued for processing. */
51 struct scan_fs_tree
*sft
)
53 pthread_mutex_lock(&sft
->lock
);
55 pthread_mutex_unlock(&sft
->lock
);
59 * Decrement the number of directories that are queued for processing and if
60 * we ran out of dirs to process, wake up anyone who was waiting for processing
65 struct scan_fs_tree
*sft
)
67 pthread_mutex_lock(&sft
->lock
);
69 if (sft
->nr_dirs
== 0)
70 pthread_cond_signal(&sft
->wakeup
);
71 pthread_mutex_unlock(&sft
->lock
);
74 /* Queue a directory for scanning. */
77 struct scrub_ctx
*ctx
,
78 struct scan_fs_tree
*sft
,
83 struct scan_fs_tree_dir
*new_sftd
;
86 new_sftd
= malloc(sizeof(struct scan_fs_tree_dir
));
88 str_errno(ctx
, _("creating directory scan context"));
92 new_sftd
->path
= strdup(path
);
93 if (!new_sftd
->path
) {
94 str_errno(ctx
, _("creating directory scan path"));
99 new_sftd
->rootdir
= is_rootdir
;
102 error
= workqueue_add(wq
, scan_fs_dir
, 0, new_sftd
);
105 str_liberror(ctx
, error
, _("queueing directory scan work"));
111 free(new_sftd
->path
);
117 /* Scan a directory sub tree. */
120 struct workqueue
*wq
,
124 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
125 struct scan_fs_tree_dir
*sftd
= arg
;
126 struct scan_fs_tree
*sft
= sftd
->sft
;
128 struct dirent
*dirent
;
129 char newpath
[PATH_MAX
];
134 /* Open the directory. */
135 dir_fd
= open(sftd
->path
, O_RDONLY
| O_NOATIME
| O_NOFOLLOW
| O_NOCTTY
);
138 str_errno(ctx
, sftd
->path
);
142 /* Caller-specific directory checks. */
143 if (!sft
->dir_fn(ctx
, sftd
->path
, dir_fd
, sft
->arg
)) {
145 error
= close(dir_fd
);
147 str_errno(ctx
, sftd
->path
);
151 /* Iterate the directory entries. */
152 dir
= fdopendir(dir_fd
);
154 str_errno(ctx
, sftd
->path
);
159 for (dirent
= readdir(dir
); dirent
!= NULL
; dirent
= readdir(dir
)) {
160 snprintf(newpath
, PATH_MAX
, "%s/%s", sftd
->path
,
163 /* Get the stat info for this directory entry. */
164 error
= fstatat(dir_fd
, dirent
->d_name
, &sb
,
165 AT_NO_AUTOMOUNT
| AT_SYMLINK_NOFOLLOW
);
167 str_errno(ctx
, newpath
);
171 /* Ignore files on other filesystems. */
172 if (sb
.st_dev
!= sft
->root_sb
.st_dev
)
175 /* Caller-specific directory entry function. */
176 if (!sft
->dirent_fn(ctx
, newpath
, dir_fd
, dirent
, &sb
,
182 if (xfs_scrub_excessive_errors(ctx
)) {
187 /* If directory, call ourselves recursively. */
188 if (S_ISDIR(sb
.st_mode
) && strcmp(".", dirent
->d_name
) &&
189 strcmp("..", dirent
->d_name
)) {
190 sft
->moveon
= queue_subdir(ctx
, sft
, wq
, newpath
,
197 /* Close dir, go away. */
198 error
= closedir(dir
);
200 str_errno(ctx
, sftd
->path
);
208 /* Scan the entire filesystem. */
211 struct scrub_ctx
*ctx
,
212 scan_fs_tree_dir_fn dir_fn
,
213 scan_fs_tree_dirent_fn dirent_fn
,
217 struct scan_fs_tree sft
;
222 sft
.root_sb
= ctx
->mnt_sb
;
224 sft
.dirent_fn
= dirent_fn
;
226 pthread_mutex_init(&sft
.lock
, NULL
);
227 pthread_cond_init(&sft
.wakeup
, NULL
);
229 ret
= workqueue_create(&wq
, (struct xfs_mount
*)ctx
,
230 scrub_nproc_workqueue(ctx
));
232 str_info(ctx
, ctx
->mntpoint
, _("Could not create workqueue."));
236 sft
.moveon
= queue_subdir(ctx
, &sft
, &wq
, ctx
->mntpoint
, true);
241 * Wait for the wakeup to trigger, which should only happen when the
242 * last worker thread decrements nr_dirs to zero. Once the worker
243 * triggers the wakeup and unlocks the sft lock, it's no longer safe
244 * for any worker thread to access sft, as we now own the lock and are
245 * about to tear everything down.
247 pthread_mutex_lock(&sft
.lock
);
249 pthread_cond_wait(&sft
.wakeup
, &sft
.lock
);
250 assert(sft
.nr_dirs
== 0);
251 pthread_mutex_unlock(&sft
.lock
);
254 workqueue_destroy(&wq
);
259 struct fstrim_range
{
264 #define FITRIM _IOWR('X', 121, struct fstrim_range) /* Trim */
267 /* Call FITRIM to trim all the unused space in a filesystem. */
270 struct scrub_ctx
*ctx
)
272 struct fstrim_range range
= {0};
275 range
.len
= ULLONG_MAX
;
276 error
= ioctl(ctx
->mnt
.fd
, FITRIM
, &range
);
277 if (error
&& errno
!= EOPNOTSUPP
&& errno
!= ENOTTY
)