]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - scrub/vfs.c
libfrog: move crc32c.h to libfrog/
[thirdparty/xfsprogs-dev.git] / scrub / vfs.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0+
b364a9c0
DW
2/*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
b364a9c0 4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
b364a9c0 5 */
a440f877 6#include "xfs.h"
b364a9c0 7#include <stdint.h>
b364a9c0
DW
8#include <dirent.h>
9#include <sys/types.h>
10#include <sys/statvfs.h>
b364a9c0
DW
11#include "handle.h"
12#include "path.h"
56598728 13#include "libfrog/workqueue.h"
b364a9c0
DW
14#include "xfs_scrub.h"
15#include "common.h"
16#include "vfs.h"
17
18#ifndef AT_NO_AUTOMOUNT
19# define AT_NO_AUTOMOUNT 0x800
20#endif
21
22/*
23 * Helper functions to assist in traversing a directory tree using regular
24 * VFS calls.
25 */
26
27/* Scan a filesystem tree. */
28struct scan_fs_tree {
29 unsigned int nr_dirs;
30 pthread_mutex_t lock;
31 pthread_cond_t wakeup;
32 struct stat root_sb;
33 bool moveon;
34 scan_fs_tree_dir_fn dir_fn;
35 scan_fs_tree_dirent_fn dirent_fn;
36 void *arg;
37};
38
39/* Per-work-item scan context. */
40struct scan_fs_tree_dir {
41 char *path;
42 struct scan_fs_tree *sft;
43 bool rootdir;
44};
45
46/* Scan a directory sub tree. */
47static void
48scan_fs_dir(
49 struct workqueue *wq,
50 xfs_agnumber_t agno,
51 void *arg)
52{
53 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
54 struct scan_fs_tree_dir *sftd = arg;
55 struct scan_fs_tree *sft = sftd->sft;
56 DIR *dir;
57 struct dirent *dirent;
58 char newpath[PATH_MAX];
59 struct scan_fs_tree_dir *new_sftd;
60 struct stat sb;
61 int dir_fd;
62 int error;
63
64 /* Open the directory. */
65 dir_fd = open(sftd->path, O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY);
66 if (dir_fd < 0) {
67 if (errno != ENOENT)
68 str_errno(ctx, sftd->path);
69 goto out;
70 }
71
72 /* Caller-specific directory checks. */
73 if (!sft->dir_fn(ctx, sftd->path, dir_fd, sft->arg)) {
74 sft->moveon = false;
6c05cc5d
DW
75 error = close(dir_fd);
76 if (error)
77 str_errno(ctx, sftd->path);
b364a9c0
DW
78 goto out;
79 }
80
81 /* Iterate the directory entries. */
82 dir = fdopendir(dir_fd);
83 if (!dir) {
84 str_errno(ctx, sftd->path);
e91c285f 85 close(dir_fd);
b364a9c0
DW
86 goto out;
87 }
88 rewinddir(dir);
89 for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir)) {
90 snprintf(newpath, PATH_MAX, "%s/%s", sftd->path,
91 dirent->d_name);
92
93 /* Get the stat info for this directory entry. */
94 error = fstatat(dir_fd, dirent->d_name, &sb,
95 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW);
96 if (error) {
97 str_errno(ctx, newpath);
98 continue;
99 }
100
101 /* Ignore files on other filesystems. */
102 if (sb.st_dev != sft->root_sb.st_dev)
103 continue;
104
105 /* Caller-specific directory entry function. */
106 if (!sft->dirent_fn(ctx, newpath, dir_fd, dirent, &sb,
107 sft->arg)) {
108 sft->moveon = false;
109 break;
110 }
111
112 if (xfs_scrub_excessive_errors(ctx)) {
113 sft->moveon = false;
114 break;
115 }
116
117 /* If directory, call ourselves recursively. */
118 if (S_ISDIR(sb.st_mode) && strcmp(".", dirent->d_name) &&
119 strcmp("..", dirent->d_name)) {
120 new_sftd = malloc(sizeof(struct scan_fs_tree_dir));
121 if (!new_sftd) {
122 str_errno(ctx, newpath);
123 sft->moveon = false;
124 break;
125 }
126 new_sftd->path = strdup(newpath);
127 new_sftd->sft = sft;
128 new_sftd->rootdir = false;
129 pthread_mutex_lock(&sft->lock);
130 sft->nr_dirs++;
131 pthread_mutex_unlock(&sft->lock);
132 error = workqueue_add(wq, scan_fs_dir, 0, new_sftd);
133 if (error) {
82377bde 134 str_info(ctx, ctx->mntpoint,
b364a9c0
DW
135_("Could not queue subdirectory scan work."));
136 sft->moveon = false;
137 break;
138 }
139 }
140 }
141
142 /* Close dir, go away. */
143 error = closedir(dir);
144 if (error)
145 str_errno(ctx, sftd->path);
146
147out:
148 pthread_mutex_lock(&sft->lock);
149 sft->nr_dirs--;
150 if (sft->nr_dirs == 0)
151 pthread_cond_signal(&sft->wakeup);
152 pthread_mutex_unlock(&sft->lock);
153
154 free(sftd->path);
155 free(sftd);
156}
157
158/* Scan the entire filesystem. */
159bool
160scan_fs_tree(
161 struct scrub_ctx *ctx,
162 scan_fs_tree_dir_fn dir_fn,
163 scan_fs_tree_dirent_fn dirent_fn,
164 void *arg)
165{
166 struct workqueue wq;
167 struct scan_fs_tree sft;
168 struct scan_fs_tree_dir *sftd;
169 int ret;
170
171 sft.moveon = true;
172 sft.nr_dirs = 1;
173 sft.root_sb = ctx->mnt_sb;
174 sft.dir_fn = dir_fn;
175 sft.dirent_fn = dirent_fn;
176 sft.arg = arg;
177 pthread_mutex_init(&sft.lock, NULL);
178 pthread_cond_init(&sft.wakeup, NULL);
179
180 sftd = malloc(sizeof(struct scan_fs_tree_dir));
181 if (!sftd) {
182 str_errno(ctx, ctx->mntpoint);
183 return false;
184 }
185 sftd->path = strdup(ctx->mntpoint);
186 sftd->sft = &sft;
187 sftd->rootdir = true;
188
189 ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
190 scrub_nproc_workqueue(ctx));
191 if (ret) {
82377bde 192 str_info(ctx, ctx->mntpoint, _("Could not create workqueue."));
b364a9c0
DW
193 goto out_free;
194 }
195 ret = workqueue_add(&wq, scan_fs_dir, 0, sftd);
196 if (ret) {
82377bde 197 str_info(ctx, ctx->mntpoint,
b364a9c0 198_("Could not queue directory scan work."));
224df902 199 goto out_wq;
b364a9c0
DW
200 }
201
202 pthread_mutex_lock(&sft.lock);
203 pthread_cond_wait(&sft.wakeup, &sft.lock);
204 assert(sft.nr_dirs == 0);
205 pthread_mutex_unlock(&sft.lock);
206 workqueue_destroy(&wq);
207
208 return sft.moveon;
224df902
DW
209out_wq:
210 workqueue_destroy(&wq);
b364a9c0
DW
211out_free:
212 free(sftd->path);
213 free(sftd);
214 return false;
215}
7e36bc0f
DW
216
217#ifndef FITRIM
218struct fstrim_range {
219 __u64 start;
220 __u64 len;
221 __u64 minlen;
222};
223#define FITRIM _IOWR('X', 121, struct fstrim_range) /* Trim */
224#endif
225
226/* Call FITRIM to trim all the unused space in a filesystem. */
227void
228fstrim(
229 struct scrub_ctx *ctx)
230{
231 struct fstrim_range range = {0};
232 int error;
233
234 range.len = ULLONG_MAX;
3f9efb2e 235 error = ioctl(ctx->mnt.fd, FITRIM, &range);
7e36bc0f
DW
236 if (error && errno != EOPNOTSUPP && errno != ENOTTY)
237 perror(_("fstrim"));
238}