#include <sys/statvfs.h>
#include <syslog.h>
#include "platform_defs.h"
-#include "path.h"
+#include "libfrog/paths.h"
#include "xfs_scrub.h"
#include "common.h"
#include "progress.h"
/* Too many errors? Bail out. */
bool
-xfs_scrub_excessive_errors(
+scrub_excessive_errors(
struct scrub_ctx *ctx)
{
- bool ret;
+ unsigned long long errors_seen;
+
+ /*
+ * We only set max_errors at the start of the program, so it's safe to
+ * access it locklessly.
+ */
+ if (ctx->max_errors == 0)
+ return false;
pthread_mutex_lock(&ctx->lock);
- ret = ctx->max_errors > 0 && ctx->errors_found >= ctx->max_errors;
+ errors_seen = ctx->corruptions_found + ctx->unfixable_errors;
pthread_mutex_unlock(&ctx->lock);
- return ret;
+ return errors_seen >= ctx->max_errors;
}
static struct {
const char *string;
int loglevel;
} err_levels[] = {
- [S_ERROR] = { .string = "Error", .loglevel = LOG_ERR },
- [S_WARN] = { .string = "Warning", .loglevel = LOG_WARNING },
- [S_REPAIR] = { .string = "Repaired", .loglevel = LOG_WARNING },
- [S_INFO] = { .string = "Info", .loglevel = LOG_INFO },
- [S_PREEN] = { .string = "Optimized", .loglevel = LOG_INFO }
+ [S_ERROR] = {
+ .string = "Error",
+ .loglevel = LOG_ERR,
+ },
+ [S_CORRUPT] = {
+ .string = "Corruption",
+ .loglevel = LOG_ERR,
+ },
+ [S_UNFIXABLE] = {
+ .string = "Unfixable Error",
+ .loglevel = LOG_ERR,
+ },
+ [S_WARN] = {
+ .string = "Warning",
+ .loglevel = LOG_WARNING,
+ },
+ [S_INFO] = {
+ .string = "Info",
+ .loglevel = LOG_INFO,
+ },
+ [S_REPAIR] = {
+ .string = "Repaired",
+ .loglevel = LOG_INFO,
+ },
+ [S_PREEN] = {
+ .string = "Optimized",
+ .loglevel = LOG_INFO,
+ },
};
/* If stream is a tty, clear to end of line to clean up progress bar. */
fflush(stream);
out_record:
- if (error) /* A syscall failed */
+ if (error || level == S_ERROR) /* A syscall failed */
ctx->runtime_errors++;
- else if (level == S_ERROR)
- ctx->errors_found++;
+ else if (level == S_CORRUPT)
+ ctx->corruptions_found++;
+ else if (level == S_UNFIXABLE)
+ ctx->unfixable_errors++;
else if (level == S_WARN)
ctx->warnings_found++;
else if (level == S_REPAIR)
double
auto_units(
unsigned long long number,
- char **units)
+ char **units,
+ int *precision)
{
if (debug > 1)
goto no_prefix;
+ *precision = 1;
if (number > 1000000000000ULL) {
*units = "T";
return number / 1000000000000.0;
no_prefix:
*units = "";
+ *precision = 0;
return number;
}
scrub_nproc(
struct scrub_ctx *ctx)
{
- if (nr_threads)
- return nr_threads;
+ if (force_nr_threads)
+ return force_nr_threads;
return ctx->nr_io_threads;
}
}
/*
- * Sleep for 100ms * however many -b we got past the initial one.
+ * Sleep for 100us * however many -b we got past the initial one.
* This is an (albeit clumsy) way to throttle scrub activity.
*/
void
background_sleep(void)
{
- unsigned long long time;
+ unsigned long long time_ns;
struct timespec tv;
if (bg_mode < 2)
return;
- time = 100000ULL * (bg_mode - 1);
- tv.tv_sec = time / 1000000;
- tv.tv_nsec = time % 1000000;
+ time_ns = 100 * NSEC_PER_USEC * (bg_mode - 1);
+ tv.tv_sec = time_ns / NSEC_PER_SEC;
+ tv.tv_nsec = time_ns % NSEC_PER_SEC;
nanosleep(&tv, NULL);
}
return true;
}
+
+/*
+ * Render an inode number into a buffer in a format suitable for use in
+ * log messages. The buffer will be filled with:
+ * "inode <inode number> (<ag number>/<ag inode number>)"
+ * If the @format argument is non-NULL, it will be rendered into the buffer
+ * after the inode representation and a single space.
+ */
+int
+scrub_render_ino_descr(
+ const struct scrub_ctx *ctx,
+ char *buf,
+ size_t buflen,
+ uint64_t ino,
+ uint32_t gen,
+ const char *format,
+ ...)
+{
+ va_list args;
+ uint32_t agno;
+ uint32_t agino;
+ int ret;
+
+ agno = cvt_ino_to_agno(&ctx->mnt, ino);
+ agino = cvt_ino_to_agino(&ctx->mnt, ino);
+ ret = snprintf(buf, buflen, _("inode %"PRIu64" (%"PRIu32"/%"PRIu32")%s"),
+ ino, agno, agino, format ? " " : "");
+ if (ret < 0 || ret >= buflen || format == NULL)
+ return ret;
+
+ va_start(args, format);
+ ret += vsnprintf(buf + ret, buflen - ret, format, args);
+ va_end(args);
+ return ret;
+}