]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/common.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
8 #include <sys/statvfs.h>
10 #include "platform_defs.h"
11 #include "libfrog/paths.h"
12 #include "xfs_scrub.h"
16 extern char *progname
;
19 * Reporting Status to the Console
21 * We aim for a roughly standard reporting format -- the severity of the
22 * status being reported, a textual description of the object being
23 * reported, and whatever the status happens to be.
25 * Errors are the most severe and reflect filesystem corruption.
26 * Warnings indicate that something is amiss and needs the attention of
27 * the administrator, but does not constitute a corruption. Information
31 /* Too many errors? Bail out. */
33 xfs_scrub_excessive_errors(
34 struct scrub_ctx
*ctx
)
38 pthread_mutex_lock(&ctx
->lock
);
39 ret
= ctx
->max_errors
> 0 && ctx
->errors_found
>= ctx
->max_errors
;
40 pthread_mutex_unlock(&ctx
->lock
);
55 .loglevel
= LOG_WARNING
,
66 .string
= "Optimized",
71 /* If stream is a tty, clear to end of line to clean up progress bar. */
72 static inline const char *stream_start(FILE *stream
)
75 return stderr_isatty
? CLEAR_EOL
: "";
76 return stdout_isatty
? CLEAR_EOL
: "";
79 /* Print a warning string and some warning text. */
82 struct scrub_ctx
*ctx
,
84 enum error_level level
,
91 FILE *stream
= stderr
;
93 char buf
[DESCR_BUFSZ
];
95 /* print strerror or format of choice but not both */
96 assert(!(error
&& format
));
101 pthread_mutex_lock(&ctx
->lock
);
103 /* We only want to hear about optimizing when in debug/verbose mode. */
104 if (level
== S_PREEN
&& !debug
&& !verbose
)
107 fprintf(stream
, "%s%s: %s: ", stream_start(stream
),
108 _(err_levels
[level
].string
), descr
);
110 fprintf(stream
, _("%s."), strerror_r(error
, buf
, DESCR_BUFSZ
));
112 va_start(args
, format
);
113 vfprintf(stream
, format
, args
);
118 fprintf(stream
, _(" (%s line %d)"), file
, line
);
119 fprintf(stream
, "\n");
120 if (stream
== stdout
)
124 if (error
) /* A syscall failed */
125 ctx
->runtime_errors
++;
126 else if (level
== S_ERROR
)
128 else if (level
== S_WARN
)
129 ctx
->warnings_found
++;
130 else if (level
== S_REPAIR
)
132 else if (level
== S_PREEN
)
135 pthread_mutex_unlock(&ctx
->lock
);
138 /* Log a message to syslog. */
139 #define LOG_BUFSZ 4096
140 #define LOGNAME_BUFSZ 256
143 struct scrub_ctx
*ctx
,
144 enum error_level level
,
149 char logname
[LOGNAME_BUFSZ
];
153 /* We only want to hear about optimizing when in debug/verbose mode. */
154 if (level
== S_PREEN
&& !debug
&& !verbose
)
158 * Skip logging if we're being run as a service (presumably the
159 * service will log stdout/stderr); if we're being run in a non
160 * interactive manner (assume we're a service); or if we're in
163 if (is_service
|| !isatty(fileno(stdin
)) || debug
)
166 snprintf(logname
, LOGNAME_BUFSZ
, "%s@%s", progname
, ctx
->mntpoint
);
167 openlog(logname
, LOG_PID
, LOG_DAEMON
);
169 sz
= snprintf(buf
, LOG_BUFSZ
, "%s: ", _(err_levels
[level
].string
));
170 va_start(args
, format
);
171 vsnprintf(buf
+ sz
, LOG_BUFSZ
- sz
, format
, args
);
173 syslog(err_levels
[level
].loglevel
, "%s", buf
);
183 return ((tv1
->tv_sec
- tv2
->tv_sec
) +
184 ((float) (tv1
->tv_usec
- tv2
->tv_usec
)) / 1000000);
187 /* Produce human readable disk space output. */
190 unsigned long long bytes
,
195 if (bytes
> (1ULL << 40)) {
197 return (double)bytes
/ (1ULL << 40);
198 } else if (bytes
> (1ULL << 30)) {
200 return (double)bytes
/ (1ULL << 30);
201 } else if (bytes
> (1ULL << 20)) {
203 return (double)bytes
/ (1ULL << 20);
204 } else if (bytes
> (1ULL << 10)) {
206 return (double)bytes
/ (1ULL << 10);
214 /* Produce human readable discrete number output. */
217 unsigned long long number
,
224 if (number
> 1000000000000ULL) {
226 return number
/ 1000000000000.0;
227 } else if (number
> 1000000000ULL) {
229 return number
/ 1000000000.0;
230 } else if (number
> 1000000ULL) {
232 return number
/ 1000000.0;
233 } else if (number
> 1000ULL) {
235 return number
/ 1000.0;
244 /* How many threads to kick off? */
247 struct scrub_ctx
*ctx
)
249 if (force_nr_threads
)
250 return force_nr_threads
;
251 return ctx
->nr_io_threads
;
255 * How many threads to kick off for a workqueue? If we only want one
256 * thread, save ourselves the overhead and just run it in the main thread.
259 scrub_nproc_workqueue(
260 struct scrub_ctx
*ctx
)
264 x
= scrub_nproc(ctx
);
271 * Sleep for 100us * however many -b we got past the initial one.
272 * This is an (albeit clumsy) way to throttle scrub activity.
274 #define NSEC_PER_SEC 1000000000ULL
275 #define NSEC_PER_USEC 1000ULL
277 background_sleep(void)
279 unsigned long long time_ns
;
285 time_ns
= 100 * NSEC_PER_USEC
* (bg_mode
- 1);
286 tv
.tv_sec
= time_ns
/ NSEC_PER_SEC
;
287 tv
.tv_nsec
= time_ns
% NSEC_PER_SEC
;
288 nanosleep(&tv
, NULL
);
292 * Return the input string with non-printing bytes escaped.
293 * Caller must free the buffer.
304 str
= malloc(strlen(in
) * 4);
307 for (p
= in
, q
= str
; *p
!= '\0'; p
++) {
312 x
= sprintf(q
, "\\x%02x", *p
);
321 * Record another naming warning, and decide if it's worth
325 should_warn_about_name(
326 struct scrub_ctx
*ctx
)
331 pthread_mutex_lock(&ctx
->lock
);
332 ctx
->naming_warnings
++;
333 whine
= ctx
->naming_warnings
== TOO_MANY_NAME_WARNINGS
;
334 res
= ctx
->naming_warnings
< TOO_MANY_NAME_WARNINGS
;
335 pthread_mutex_unlock(&ctx
->lock
);
337 if (whine
&& !(debug
|| verbose
))
338 str_info(ctx
, ctx
->mntpoint
,
339 _("More than %u naming warnings, shutting up."),
340 TOO_MANY_NAME_WARNINGS
);
342 return debug
|| verbose
|| res
;
345 /* Decide if a value is within +/- (n/d) of a desired value. */
348 struct scrub_ctx
*ctx
,
349 unsigned long long value
,
350 unsigned long long desired
,
351 unsigned long long abs_threshold
,
358 /* Don't complain if difference does not exceed an absolute value. */
359 if (value
< desired
&& desired
- value
< abs_threshold
)
361 if (value
> desired
&& value
- desired
< abs_threshold
)
364 /* Complain if the difference exceeds a certain percentage. */
365 if (value
< desired
* (d
- n
) / d
)
367 if (value
> desired
* (d
+ n
) / d
)
374 * Render an inode number into a buffer in a format suitable for use in
375 * log messages. The buffer will be filled with:
376 * "inode <inode number> (<ag number>/<ag inode number>)"
377 * If the @format argument is non-NULL, it will be rendered into the buffer
378 * after the inode representation and a single space.
381 scrub_render_ino_descr(
382 const struct scrub_ctx
*ctx
,
395 agno
= cvt_ino_to_agno(&ctx
->mnt
, ino
);
396 agino
= cvt_ino_to_agino(&ctx
->mnt
, ino
);
397 ret
= snprintf(buf
, buflen
, _("inode %"PRIu64
" (%"PRIu32
"/%"PRIu32
")%s"),
398 ino
, agno
, agino
, format
? " " : "");
399 if (ret
< 0 || ret
>= buflen
|| format
== NULL
)
402 va_start(args
, format
);
403 ret
+= vsnprintf(buf
+ ret
, buflen
- ret
, format
, args
);