]>
Commit | Line | Data |
---|---|---|
b3f76f94 DW |
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 | } |