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 <djwong@kernel.org>
*/
#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 *
__descr_render(
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.
*/
void
descr_set(
struct descr *dsc,
void *where)
{
dsc->where = where;
}
/* Allocate all the description string buffers. */
int
descr_init_phase(
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. */
void
descr_end_phase(void)
{
if (descr_ptvar)
ptvar_free(descr_ptvar);
descr_ptvar = NULL;
}