]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/descr.c
xfs_scrub: implement deferred description string rendering
[thirdparty/xfsprogs-dev.git] / scrub / descr.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2019 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 */
6 #include "xfs.h"
7 #include <assert.h>
8 #include <sys/statvfs.h>
9 #include "platform_defs.h"
10 #include "input.h"
11 #include "libfrog/paths.h"
12 #include "libfrog/ptvar.h"
13 #include "xfs_scrub.h"
14 #include "common.h"
15 #include "descr.h"
16
17 /*
18 * Deferred String Description Renderer
19 * ====================================
20 * There are many places in xfs_scrub where some event occurred and we'd like
21 * to be able to print some sort of message describing what happened, and
22 * where. However, we don't know whether we're going to need the description
23 * of where ahead of time and there's little point in spending any time looking
24 * up gettext strings and formatting buffers until we actually need to.
25 *
26 * This code provides enough of a function closure that we are able to record
27 * some information about the program status but defer rendering the textual
28 * description until we know that we need it. Once we've rendered the string
29 * we can skip it for subsequent calls. We use per-thread storage for the
30 * message buffer to amortize the memory allocation across calls.
31 *
32 * On a clean filesystem this can reduce the xfs_scrub runtime by 7-10% by
33 * avoiding unnecessary work.
34 */
35
36 static struct ptvar *descr_ptvar;
37
38 /* Global buffer for when we aren't running in threaded mode. */
39 static char global_dsc_buf[DESCR_BUFSZ];
40
41 /*
42 * Render a textual description string using the function and location stored
43 * in the description context.
44 */
45 const char *
46 __descr_render(
47 struct descr *dsc,
48 const char *file,
49 int line)
50 {
51 char *dsc_buf;
52 int ret;
53
54 if (descr_ptvar) {
55 dsc_buf = ptvar_get(descr_ptvar, &ret);
56 if (ret)
57 return _("error finding description buffer");
58 } else
59 dsc_buf = global_dsc_buf;
60
61 ret = dsc->fn(dsc->ctx, dsc_buf, DESCR_BUFSZ, dsc->where);
62 if (ret < 0) {
63 snprintf(dsc_buf, DESCR_BUFSZ,
64 _("error %d while rendering description at %s line %d\n"),
65 ret, file, line);
66 }
67
68 return dsc_buf;
69 }
70
71 /*
72 * Set a new location context for this deferred-rendering string.
73 * The caller is responsible for freeing the old context, if any.
74 */
75 void
76 descr_set(
77 struct descr *dsc,
78 void *where)
79 {
80 dsc->where = where;
81 }
82
83 /* Allocate all the description string buffers. */
84 int
85 descr_init_phase(
86 struct scrub_ctx *ctx,
87 unsigned int nr_threads)
88 {
89 int ret;
90
91 assert(descr_ptvar == NULL);
92 ret = ptvar_alloc(nr_threads, DESCR_BUFSZ, &descr_ptvar);
93 if (ret)
94 str_liberror(ctx, ret, _("creating description buffer"));
95
96 return ret;
97 }
98
99 /* Free all the description string buffers. */
100 void
101 descr_end_phase(void)
102 {
103 if (descr_ptvar)
104 ptvar_free(descr_ptvar);
105 descr_ptvar = NULL;
106 }