blob: 77d5378ec3fee760902db1aca607d4fac20c37f8 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-or-later
* Copyright (C) 2019-2023 Oracle. All Rights Reserved.
* Author: Darrick J. Wong <>
#include "xfs.h"
#include <assert.h>
#include <sys/statvfs.h>
#include "platform_defs.h"
#include "input.h"
#include "libfrog/paths.h"
#include "libfrog/ptvar.h"
#include "xfs_scrub.h"
#include "common.h"
#include "descr.h"
* Deferred String Description Renderer
* ====================================
* There are many places in xfs_scrub where some event occurred and we'd like
* to be able to print some sort of message describing what happened, and
* where. However, we don't know whether we're going to need the description
* of where ahead of time and there's little point in spending any time looking
* up gettext strings and formatting buffers until we actually need to.
* This code provides enough of a function closure that we are able to record
* some information about the program status but defer rendering the textual
* description until we know that we need it. Once we've rendered the string
* we can skip it for subsequent calls. We use per-thread storage for the
* message buffer to amortize the memory allocation across calls.
* On a clean filesystem this can reduce the xfs_scrub runtime by 7-10% by
* avoiding unnecessary work.
static struct ptvar *descr_ptvar;
/* Global buffer for when we aren't running in threaded mode. */
static char global_dsc_buf[DESCR_BUFSZ];
* Render a textual description string using the function and location stored
* in the description context.
const char *
struct descr *dsc,
const char *file,
int line)
char *dsc_buf;
int ret;
if (descr_ptvar) {
dsc_buf = ptvar_get(descr_ptvar, &ret);
if (ret)
return _("error finding description buffer");
} else
dsc_buf = global_dsc_buf;
ret = dsc->fn(dsc->ctx, dsc_buf, DESCR_BUFSZ, dsc->where);
if (ret < 0) {
snprintf(dsc_buf, DESCR_BUFSZ,
_("error %d while rendering description at %s line %d\n"),
ret, file, line);
return dsc_buf;
* Set a new location context for this deferred-rendering string.
* The caller is responsible for freeing the old context, if any.
struct descr *dsc,
void *where)
dsc->where = where;
/* Allocate all the description string buffers. */
struct scrub_ctx *ctx,
unsigned int nr_threads)
int ret;
assert(descr_ptvar == NULL);
ret = -ptvar_alloc(nr_threads, DESCR_BUFSZ, &descr_ptvar);
if (ret)
str_liberror(ctx, ret, _("creating description buffer"));
return ret;
/* Free all the description string buffers. */
if (descr_ptvar)
descr_ptvar = NULL;