]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/common.c
9227b57626e358d6ab6cb45b2c1a3172971d91a4
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
);
49 [S_ERROR
] = { .string
= "Error", .loglevel
= LOG_ERR
},
50 [S_WARN
] = { .string
= "Warning", .loglevel
= LOG_WARNING
},
51 [S_INFO
] = { .string
= "Info", .loglevel
= LOG_INFO
},
52 [S_REPAIR
] = { .string
= "Repaired", .loglevel
= LOG_INFO
},
53 [S_PREEN
] = { .string
= "Optimized", .loglevel
= LOG_INFO
}
56 /* If stream is a tty, clear to end of line to clean up progress bar. */
57 static inline const char *stream_start(FILE *stream
)
60 return stderr_isatty
? CLEAR_EOL
: "";
61 return stdout_isatty
? CLEAR_EOL
: "";
64 /* Print a warning string and some warning text. */
67 struct scrub_ctx
*ctx
,
69 enum error_level level
,
76 FILE *stream
= stderr
;
78 char buf
[DESCR_BUFSZ
];
80 /* print strerror or format of choice but not both */
81 assert(!(error
&& format
));
86 pthread_mutex_lock(&ctx
->lock
);
88 /* We only want to hear about optimizing when in debug/verbose mode. */
89 if (level
== S_PREEN
&& !debug
&& !verbose
)
92 fprintf(stream
, "%s%s: %s: ", stream_start(stream
),
93 _(err_levels
[level
].string
), descr
);
95 fprintf(stream
, _("%s."), strerror_r(error
, buf
, DESCR_BUFSZ
));
97 va_start(args
, format
);
98 vfprintf(stream
, format
, args
);
103 fprintf(stream
, _(" (%s line %d)"), file
, line
);
104 fprintf(stream
, "\n");
105 if (stream
== stdout
)
109 if (error
) /* A syscall failed */
110 ctx
->runtime_errors
++;
111 else if (level
== S_ERROR
)
113 else if (level
== S_WARN
)
114 ctx
->warnings_found
++;
115 else if (level
== S_REPAIR
)
117 else if (level
== S_PREEN
)
120 pthread_mutex_unlock(&ctx
->lock
);
123 /* Log a message to syslog. */
124 #define LOG_BUFSZ 4096
125 #define LOGNAME_BUFSZ 256
128 struct scrub_ctx
*ctx
,
129 enum error_level level
,
134 char logname
[LOGNAME_BUFSZ
];
138 /* We only want to hear about optimizing when in debug/verbose mode. */
139 if (level
== S_PREEN
&& !debug
&& !verbose
)
143 * Skip logging if we're being run as a service (presumably the
144 * service will log stdout/stderr); if we're being run in a non
145 * interactive manner (assume we're a service); or if we're in
148 if (is_service
|| !isatty(fileno(stdin
)) || debug
)
151 snprintf(logname
, LOGNAME_BUFSZ
, "%s@%s", progname
, ctx
->mntpoint
);
152 openlog(logname
, LOG_PID
, LOG_DAEMON
);
154 sz
= snprintf(buf
, LOG_BUFSZ
, "%s: ", _(err_levels
[level
].string
));
155 va_start(args
, format
);
156 vsnprintf(buf
+ sz
, LOG_BUFSZ
- sz
, format
, args
);
158 syslog(err_levels
[level
].loglevel
, "%s", buf
);
168 return ((tv1
->tv_sec
- tv2
->tv_sec
) +
169 ((float) (tv1
->tv_usec
- tv2
->tv_usec
)) / 1000000);
172 /* Produce human readable disk space output. */
175 unsigned long long bytes
,
180 if (bytes
> (1ULL << 40)) {
182 return (double)bytes
/ (1ULL << 40);
183 } else if (bytes
> (1ULL << 30)) {
185 return (double)bytes
/ (1ULL << 30);
186 } else if (bytes
> (1ULL << 20)) {
188 return (double)bytes
/ (1ULL << 20);
189 } else if (bytes
> (1ULL << 10)) {
191 return (double)bytes
/ (1ULL << 10);
199 /* Produce human readable discrete number output. */
202 unsigned long long number
,
209 if (number
> 1000000000000ULL) {
211 return number
/ 1000000000000.0;
212 } else if (number
> 1000000000ULL) {
214 return number
/ 1000000000.0;
215 } else if (number
> 1000000ULL) {
217 return number
/ 1000000.0;
218 } else if (number
> 1000ULL) {
220 return number
/ 1000.0;
229 /* How many threads to kick off? */
232 struct scrub_ctx
*ctx
)
234 if (force_nr_threads
)
235 return force_nr_threads
;
236 return ctx
->nr_io_threads
;
240 * How many threads to kick off for a workqueue? If we only want one
241 * thread, save ourselves the overhead and just run it in the main thread.
244 scrub_nproc_workqueue(
245 struct scrub_ctx
*ctx
)
249 x
= scrub_nproc(ctx
);
256 * Sleep for 100us * however many -b we got past the initial one.
257 * This is an (albeit clumsy) way to throttle scrub activity.
259 #define NSEC_PER_SEC 1000000000ULL
260 #define NSEC_PER_USEC 1000ULL
262 background_sleep(void)
264 unsigned long long time_ns
;
270 time_ns
= 100 * NSEC_PER_USEC
* (bg_mode
- 1);
271 tv
.tv_sec
= time_ns
/ NSEC_PER_SEC
;
272 tv
.tv_nsec
= time_ns
% NSEC_PER_SEC
;
273 nanosleep(&tv
, NULL
);
277 * Return the input string with non-printing bytes escaped.
278 * Caller must free the buffer.
289 str
= malloc(strlen(in
) * 4);
292 for (p
= in
, q
= str
; *p
!= '\0'; p
++) {
297 x
= sprintf(q
, "\\x%02x", *p
);
306 * Record another naming warning, and decide if it's worth
310 should_warn_about_name(
311 struct scrub_ctx
*ctx
)
316 pthread_mutex_lock(&ctx
->lock
);
317 ctx
->naming_warnings
++;
318 whine
= ctx
->naming_warnings
== TOO_MANY_NAME_WARNINGS
;
319 res
= ctx
->naming_warnings
< TOO_MANY_NAME_WARNINGS
;
320 pthread_mutex_unlock(&ctx
->lock
);
322 if (whine
&& !(debug
|| verbose
))
323 str_info(ctx
, ctx
->mntpoint
,
324 _("More than %u naming warnings, shutting up."),
325 TOO_MANY_NAME_WARNINGS
);
327 return debug
|| verbose
|| res
;
330 /* Decide if a value is within +/- (n/d) of a desired value. */
333 struct scrub_ctx
*ctx
,
334 unsigned long long value
,
335 unsigned long long desired
,
336 unsigned long long abs_threshold
,
343 /* Don't complain if difference does not exceed an absolute value. */
344 if (value
< desired
&& desired
- value
< abs_threshold
)
346 if (value
> desired
&& value
- desired
< abs_threshold
)
349 /* Complain if the difference exceeds a certain percentage. */
350 if (value
< desired
* (d
- n
) / d
)
352 if (value
> desired
* (d
+ n
) / d
)
359 * Render an inode number into a buffer in a format suitable for use in
360 * log messages. The buffer will be filled with:
361 * "inode <inode number> (<ag number>/<ag inode number>)"
362 * If the @format argument is non-NULL, it will be rendered into the buffer
363 * after the inode representation and a single space.
366 scrub_render_ino_descr(
367 const struct scrub_ctx
*ctx
,
380 agno
= cvt_ino_to_agno(&ctx
->mnt
, ino
);
381 agino
= cvt_ino_to_agino(&ctx
->mnt
, ino
);
382 ret
= snprintf(buf
, buflen
, _("inode %"PRIu64
" (%"PRIu32
"/%"PRIu32
")%s"),
383 ino
, agno
, agino
, format
? " " : "");
384 if (ret
< 0 || ret
>= buflen
|| format
== NULL
)
387 va_start(args
, format
);
388 ret
+= vsnprintf(buf
+ ret
, buflen
- ret
, format
, args
);