varnish-cache/bin/varnishd/cache/cache_vrt_priv.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2021 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 * Runtime support for compiled VCL programs: private variables
31
 */
32
33
#include "config.h"
34
35
36
#include <stdlib.h>
37
38
#include "cache_varnishd.h"
39
#include "vcl.h"
40
#include "vcc_interface.h"
41
42
struct vrt_priv {
43
        unsigned                        magic;
44
#define VRT_PRIV_MAGIC                  0x24157a52
45
        VRBT_ENTRY(vrt_priv)            entry;
46
        struct vmod_priv                priv[1];
47
        uintptr_t                       vmod_id;
48
};
49
50
struct vrt_privs cli_task_privs[1];
51
52
static inline int vrt_priv_dyncmp(const struct vrt_priv *,
53
    const struct vrt_priv *);
54
55 110875
VRBT_GENERATE_INSERT_COLOR(vrt_privs, vrt_priv, entry, static)
56 2528265525
VRBT_GENERATE_FIND(vrt_privs, vrt_priv, entry, vrt_priv_dyncmp, static)
57 33475
VRBT_GENERATE_INSERT_FINISH(vrt_privs, vrt_priv, entry, static)
58 304725
VRBT_GENERATE_INSERT(vrt_privs, vrt_priv, entry, vrt_priv_dyncmp, static)
59 293388
VRBT_GENERATE_MINMAX(vrt_privs, vrt_priv, entry, static)
60 59850
VRBT_GENERATE_NEXT(vrt_privs, vrt_priv, entry, static)
61
62
/*--------------------------------------------------------------------
63
 */
64
65
void
66 250
pan_privs(struct vsb *vsb, const struct vrt_privs *privs)
67
{
68
        struct vrt_priv *vp;
69
        const struct vmod_priv *p;
70
        const struct vmod_priv_methods *m;
71
72 250
        if (privs == NULL) {
73 0
                VSB_cat(vsb, "privs = NULL\n");
74 0
                return;
75
        }
76 250
        VSB_printf(vsb, "privs = %p {\n", privs);
77 250
        VSB_indent(vsb, 2);
78 250
        VRBT_FOREACH(vp, vrt_privs, privs) {
79 0
                if (PAN_dump_oneline(vsb, vp, VRT_PRIV_MAGIC, "priv"))
80 0
                        continue;
81 0
                p = vp->priv;
82
                //lint -e{774}
83 0
                if (p == NULL) {
84
                        // should never happen
85 0
                        VSB_printf(vsb, "NULL vmod %jx},\n",
86 0
                            (uintmax_t)vp->vmod_id);
87 0
                        continue;
88
                }
89 0
                m = p->methods;
90 0
                VSB_printf(vsb,
91
                    "{p %p l %ld m %p t \"%s\"} vmod %jx},\n",
92 0
                    p->priv, p->len, m,
93 0
                    m != NULL ? m->type : "",
94 0
                    (uintmax_t)vp->vmod_id
95
                );
96 0
        }
97 250
        VSB_indent(vsb, -2);
98 250
        VSB_cat(vsb, "},\n");
99 250
}
100
101
/*--------------------------------------------------------------------
102
 */
103
104
static void
105 286373
VRTPRIV_init(struct vrt_privs *privs)
106
{
107
108 286373
        VRBT_INIT(privs);
109 286373
}
110
111
static inline int
112 2528531275
vrt_priv_dyncmp(const struct vrt_priv *vp1, const struct vrt_priv *vp2)
113
{
114 2528531275
        if (vp1->vmod_id < vp2->vmod_id)
115 1200043125
                return (-1);
116 1328488150
        if (vp1->vmod_id > vp2->vmod_id)
117 1050724225
                return (1);
118 277763925
        return (0);
119 2528531275
}
120
121
static struct vmod_priv *
122 277760775
vrt_priv_dynamic_get(const struct vrt_privs *privs, uintptr_t vmod_id)
123
{
124
        struct vrt_priv *vp;
125
126 277760775
        const struct vrt_priv needle = {.vmod_id = vmod_id};
127
128 277760775
        vp = VRBT_FIND(vrt_privs, privs, &needle);
129 277760775
        if (vp == NULL)
130 5500
                return (NULL);
131
132 277755275
        CHECK_OBJ(vp, VRT_PRIV_MAGIC);
133 277755275
        assert(vp->vmod_id == vmod_id);
134 277755275
        return (vp->priv);
135 277760775
}
136
137
static struct vmod_priv *
138 43750
vrt_priv_dynamic(struct ws *ws, struct vrt_privs *privs, uintptr_t vmod_id)
139
{
140
        struct vrt_priv *vp, *ovp;
141
142 43750
        AN(vmod_id);
143
144
        /* even if ws is full, return any existing priv */
145 43750
        if (WS_ReserveSize(ws, sizeof *vp) == 0)
146 1625
                return (vrt_priv_dynamic_get(privs, vmod_id));
147
148 42125
        vp = WS_Reservation(ws);
149 42125
        INIT_OBJ(vp, VRT_PRIV_MAGIC);
150 42125
        vp->vmod_id = vmod_id;
151 42125
        ovp = VRBT_INSERT(vrt_privs, privs, vp);
152 42125
        if (ovp == NULL) {
153 33475
                WS_Release(ws, sizeof *vp);
154 33475
                return (vp->priv);
155
        }
156 8650
        WS_Release(ws, 0);
157 8650
        return (ovp->priv);
158 43750
}
159
160
static struct vrt_privs *
161 277802125
vrt_priv_task_context(VRT_CTX)
162
{
163
164 277802125
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
165
166
        /* In pipe mode, both req and bo are set. We use req */
167
168 277802125
        assert(ctx->req == NULL || ctx->bo == NULL ||
169
            ctx->method == VCL_MET_PIPE || ctx->method == 0);
170
171 277802125
        if (ctx->req) {
172 277790275
                CHECK_OBJ(ctx->req, REQ_MAGIC);
173 277790275
                return (ctx->req->privs);
174
        }
175 11850
        if (ctx->bo) {
176 7825
                CHECK_OBJ(ctx->bo, BUSYOBJ_MAGIC);
177 7825
                return (ctx->bo->privs);
178
        }
179 4025
        ASSERT_CLI();
180 4025
        return (cli_task_privs);
181 277802125
}
182
183
struct vmod_priv *
184 277758900
VRT_priv_task_get(VRT_CTX, const void *vmod_id)
185
{
186 277758900
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
187
188 277758900
        return (vrt_priv_dynamic_get(
189 277758900
            vrt_priv_task_context(ctx),
190 277758900
            (uintptr_t)vmod_id));
191
}
192
193
struct vmod_priv *
194 43225
VRT_priv_task(VRT_CTX, const void *vmod_id)
195
{
196
197 43225
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
198
199 43225
        return (vrt_priv_dynamic(
200 43225
            ctx->ws,
201 43225
            vrt_priv_task_context(ctx),
202 43225
            (uintptr_t)vmod_id));
203
}
204
205
/*
206
 * XXX #3498 on VRT_fail(): Would be better to move the PRIV_TOP check to VCC
207
 *
208
 * This will fail in the preamble of any VCL SUB containing a call to a vmod
209
 * function with a PRIV_TOP argument, which might not exactly be pola
210
 */
211
212
#define VRT_PRIV_TOP_PREP(ctx, req, sp, top)    do {                    \
213
                CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);                  \
214
                req = (ctx)->req;                                       \
215
                if (req == NULL) {                                      \
216
                        VRT_fail(ctx, "PRIV_TOP is only accessible "    \
217
                            "in client VCL context");                   \
218
                        return (NULL);                                  \
219
                }                                                       \
220
                CHECK_OBJ(req, REQ_MAGIC);                              \
221
                sp = (ctx)->sp;                                         \
222
                CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);                      \
223
                top = (req)->top;                                       \
224
                CHECK_OBJ_NOTNULL(top, REQTOP_MAGIC);                   \
225
                req = (top)->topreq;                                    \
226
                CHECK_OBJ_NOTNULL(req, REQ_MAGIC);                      \
227
        } while(0)
228
229
struct vmod_priv *
230 250
VRT_priv_top_get(VRT_CTX, const void *vmod_id)
231
{
232
        struct req *req;
233
        struct sess *sp;
234
        struct reqtop *top;
235
        struct vmod_priv *priv;
236
237 250
        VRT_PRIV_TOP_PREP(ctx, req, sp, top);
238
239 250
        Lck_Lock(&sp->mtx);
240 250
        priv = vrt_priv_dynamic_get(top->privs, (uintptr_t)vmod_id);
241 250
        Lck_Unlock(&sp->mtx);
242 250
        return (priv);
243 250
}
244
245
struct vmod_priv *
246 525
VRT_priv_top(VRT_CTX, const void *vmod_id)
247
{
248
        struct req *req;
249
        struct sess *sp;
250
        struct reqtop *top;
251
        struct vmod_priv *priv;
252
253 525
        VRT_PRIV_TOP_PREP(ctx, req, sp, top);
254
255 525
        Lck_Lock(&sp->mtx);
256 525
        priv = vrt_priv_dynamic(req->ws, top->privs, (uintptr_t)vmod_id);
257 525
        Lck_Unlock(&sp->mtx);
258 525
        return (priv);
259 525
}
260
261
/*--------------------------------------------------------------------
262
 */
263
264
void
265 35697
VRT_priv_fini(VRT_CTX, const struct vmod_priv *p)
266
{
267
        const struct vmod_priv_methods *m;
268
269 35697
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
270
271 35697
        m = p->methods;
272 35697
        if (m == NULL)
273 28949
                return;
274
275 6748
        CHECK_OBJ(m, VMOD_PRIV_METHODS_MAGIC);
276 6748
        if (p->priv == NULL || m->fini == NULL)
277 0
                return;
278
279
        // XXX remove me after soak in
280 6748
        VRT_CTX_Assert(ctx);
281
282 6748
        m->fini(ctx, p->priv);
283 6748
        assert(ctx->vpi->handling == 0 || ctx->vpi->handling == VCL_RET_FAIL);
284 35697
}
285
286
/*--------------------------------------------------------------------*/
287
288
void
289 286373
VCL_TaskEnter(struct vrt_privs *privs)
290
{
291
292 286373
        VRTPRIV_init(privs);
293 286373
}
294
295
void
296 286036
VCL_TaskLeave(VRT_CTX, struct vrt_privs *privs)
297
{
298
        struct vrt_priv *vp, *vp1;
299
300 286036
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
301 286036
        AN(ctx->vpi);
302 286036
        assert(ctx->vpi->handling == 0 || ctx->vpi->handling == VCL_RET_FAIL);
303
304
        /*
305
         * NB: We don't bother removing entries as we finish them because it's
306
         * a costly operation. Instead we safely walk the whole tree and clear
307
         * the head at the very end.
308
         */
309 319511
        VRBT_FOREACH_SAFE(vp, vrt_privs, privs, vp1) {
310 33475
                CHECK_OBJ(vp, VRT_PRIV_MAGIC);
311 33475
                VRT_priv_fini(ctx, vp->priv);
312 33475
        }
313 286036
        ZERO_OBJ(privs, sizeof *privs);
314 286036
}