varnish-cache/bin/varnishd/cache/cache_ws.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
 * Author: Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
7
 *
8
 * SPDX-License-Identifier: BSD-2-Clause
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 *
31
 */
32
33
#include "config.h"
34
35
#include "cache_varnishd.h"
36
37
#define WS_REDZONE_END          '\x15'
38
39
static const uintptr_t snap_overflowed = (uintptr_t)&snap_overflowed;
40
41
void
42 19325820
WS_Assert(const struct ws *ws)
43
{
44
45 19325820
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
46 19325820
        DSLb(DBG_WORKSPACE, "WS(%s, %p) = {%p %zu %zu %zu}",
47
            ws->id, ws, ws->s, pdiff(ws->s, ws->f),
48
            ws->r == NULL ? 0 : pdiff(ws->f, ws->r),
49
            pdiff(ws->s, ws->e));
50 19325820
        assert(ws->s != NULL);
51 19325820
        assert(PAOK(ws->s));
52 19325820
        assert(ws->e != NULL);
53 19325820
        assert(PAOK(ws->e));
54 19325820
        assert(ws->s < ws->e);
55 19325820
        assert(ws->f >= ws->s);
56 19325820
        assert(ws->f <= ws->e);
57 19325820
        assert(PAOK(ws->f));
58 19325820
        if (ws->r) {
59 6372436
                assert(ws->r >= ws->f);
60 6372436
                assert(ws->r <= ws->e);
61 6372436
        }
62 19325820
        assert(*ws->e == WS_REDZONE_END);
63 19325820
}
64
65
int
66 1212413
WS_Allocated(const struct ws *ws, const void *ptr, ssize_t len)
67
{
68 1212413
        const char *p = ptr;
69
70 1212413
        WS_Assert(ws);
71 1212413
        if (len < 0)
72 5250
                len = strlen(p) + 1;
73 1212413
        assert(!(p > ws->f && p <= ws->e));
74 1212413
        return (p >= ws->s && (p + len) <= ws->f);
75
}
76
77
/*
78
 * NB: The id must be max 3 char and lower-case.
79
 * (upper-case the first char to indicate overflow)
80
 */
81
82
void
83 649258
WS_Init(struct ws *ws, const char *id, void *space, unsigned len)
84
{
85
        unsigned l;
86
87 649258
        DSLb(DBG_WORKSPACE,
88
            "WS_Init(%s, %p, %p, %u)", id, ws, space, len);
89 649258
        assert(space != NULL);
90 649258
        INIT_OBJ(ws, WS_MAGIC);
91 649258
        ws->s = space;
92 649258
        assert(PAOK(space));
93 649258
        l = PRNDDN(len - 1);
94 649258
        ws->e = ws->s + l;
95 649258
        memset(ws->e, WS_REDZONE_END, len - l);
96 649258
        ws->f = ws->s;
97 649258
        assert(id[0] & 0x20);           // cheesy islower()
98 649258
        bstrcpy(ws->id, id);
99 649258
        WS_Assert(ws);
100 649258
}
101
102
/*
103
 * Reset a WS to a cookie from WS_Snapshot
104
 *
105
 * for use by any code using cache.h
106
 *
107
 * does not reset the overflow bit and asserts that, if WS_Snapshot had found
108
 * the workspace overflown, the marker is intact
109
 */
110
111
void
112 1042874
WS_Reset(struct ws *ws, uintptr_t pp)
113
{
114
        char *p;
115
116 1042874
        WS_Assert(ws);
117 1042874
        AN(pp);
118 1042874
        if (pp == snap_overflowed) {
119 25
                DSLb(DBG_WORKSPACE, "WS_Reset(%s, %p, overflowed)", ws->id, ws);
120 25
                AN(WS_Overflowed(ws));
121 25
                return;
122
        }
123 1042849
        p = (char *)pp;
124 1042849
        DSLb(DBG_WORKSPACE, "WS_Reset(%s, %p, %p)", ws->id, ws, p);
125 1042849
        assert(ws->r == NULL);
126 1042849
        assert(p >= ws->s);
127 1042849
        assert(p <= ws->e);
128 1042849
        ws->f = p;
129 1042849
        WS_Assert(ws);
130 1042874
}
131
132
/*
133
 * Make a reservation and optionally pipeline a memory region that may or
134
 * may not originate from the same workspace.
135
 */
136
137
unsigned
138 191639
WS_ReqPipeline(struct ws *ws, const void *b, const void *e)
139
{
140
        unsigned r, l;
141
142 191639
        WS_Assert(ws);
143
144 191639
        if (!strcasecmp(ws->id, "req"))
145 141389
                WS_Rollback(ws, 0);
146
        else
147 50250
                AZ(b);
148
149 191639
        r = WS_ReserveAll(ws);
150
151 191639
        if (b == NULL) {
152 183422
                AZ(e);
153 183422
                return (0);
154
        }
155
156 8217
        AN(e);
157 8217
        l = pdiff(b, e);
158 8217
        assert(l <= r);
159 8217
        memmove(ws->f, b, l);
160 8217
        return (l);
161 191639
}
162
163
void *
164 367470
WS_Alloc(struct ws *ws, unsigned bytes)
165
{
166
        char *r;
167
168 367470
        WS_Assert(ws);
169 367470
        assert(bytes > 0);
170 367470
        bytes = PRNDUP(bytes);
171
172 367470
        assert(ws->r == NULL);
173 367470
        if (ws->f + bytes > ws->e) {
174 7175
                WS_MarkOverflow(ws);
175 7175
                return (NULL);
176
        }
177 360295
        r = ws->f;
178 360295
        ws->f += bytes;
179 360295
        DSLb(DBG_WORKSPACE, "WS_Alloc(%s, %p, %u) = %p", ws->id, ws, bytes, r);
180 360295
        WS_Assert(ws);
181 360295
        return (r);
182 367470
}
183
184
void *
185 395700
WS_Copy(struct ws *ws, const void *str, int len)
186
{
187
        char *r;
188
        unsigned bytes;
189
190 395700
        WS_Assert(ws);
191 395700
        assert(ws->r == NULL);
192
193 395700
        if (len == -1)
194 7666
                len = strlen(str) + 1;
195 395700
        assert(len > 0);
196
197 395700
        bytes = PRNDUP((unsigned)len);
198 395700
        if (ws->f + bytes > ws->e) {
199 25
                WS_MarkOverflow(ws);
200 25
                return (NULL);
201
        }
202 395675
        r = ws->f;
203 395675
        ws->f += bytes;
204 395675
        memcpy(r, str, len);
205 395675
        DSLb(DBG_WORKSPACE, "WS_Copy(%s, %p, %d) = %p", ws->id, ws, len, r);
206 395675
        WS_Assert(ws);
207 395675
        return (r);
208 395700
}
209
210
uintptr_t
211 1190092
WS_Snapshot(struct ws *ws)
212
{
213
214 1190092
        WS_Assert(ws);
215 1190092
        assert(ws->r == NULL);
216 1190092
        if (WS_Overflowed(ws)) {
217 25
                DSLb(DBG_WORKSPACE, "WS_Snapshot(%s, %p) = overflowed",
218
                    ws->id, ws);
219 25
                return (snap_overflowed);
220
        }
221 1190067
        DSLb(DBG_WORKSPACE, "WS_Snapshot(%s, %p) = %p", ws->id, ws, ws->f);
222 1190067
        return ((uintptr_t)ws->f);
223 1190092
}
224
225
/*
226
 * WS_Release() must be called in all cases
227
 */
228
unsigned
229 1312971
WS_ReserveAll(struct ws *ws)
230
{
231
        unsigned b;
232
233 1312971
        WS_Assert(ws);
234 1312971
        assert(ws->r == NULL);
235
236 1312971
        ws->r = ws->e;
237 1312971
        b = pdiff(ws->f, ws->r);
238
239 1312971
        WS_Assert(ws);
240 1312971
        DSLb(DBG_WORKSPACE, "WS_ReserveAll(%s, %p) = %u", ws->id, ws, b);
241
242 1312971
        return (b);
243
}
244
245
/*
246
 * WS_Release() must be called for retval > 0 only
247
 */
248
unsigned
249 348725
WS_ReserveSize(struct ws *ws, unsigned bytes)
250
{
251
        unsigned l;
252
253 348725
        WS_Assert(ws);
254 348725
        assert(ws->r == NULL);
255 348725
        assert(bytes > 0);
256
257 348725
        l = pdiff(ws->f, ws->e);
258 348725
        if (bytes > l) {
259 1675
                WS_MarkOverflow(ws);
260 1675
                return (0);
261
        }
262 347050
        ws->r = ws->f + bytes;
263 347050
        DSLb(DBG_WORKSPACE, "WS_ReserveSize(%s, %p, %u/%u) = %u", ws->id,
264
            ws, bytes, l, bytes);
265 347050
        WS_Assert(ws);
266 347050
        return (bytes);
267 348725
}
268
269
void
270 1354864
WS_Release(struct ws *ws, unsigned bytes)
271
{
272 1354864
        WS_Assert(ws);
273 1354864
        assert(bytes <= ws->e - ws->f);
274 1354864
        DSLb(DBG_WORKSPACE, "WS_Release(%s, %p, %u)", ws->id, ws, bytes);
275 1354864
        assert(ws->r != NULL);
276 1354864
        assert(ws->f + bytes <= ws->r);
277 1354864
        ws->f += PRNDUP(bytes);
278 1354864
        ws->r = NULL;
279 1354864
        WS_Assert(ws);
280 1354864
}
281
282
void
283 304923
WS_ReleaseP(struct ws *ws, const char *ptr)
284
{
285 304923
        WS_Assert(ws);
286 304923
        DSLb(DBG_WORKSPACE, "WS_ReleaseP(%s, %p, %p (%zd))", ws->id, ws, ptr,
287
            ptr - ws->f);
288 304923
        assert(ws->r != NULL);
289 304923
        assert(ptr >= ws->f);
290 304923
        assert(ptr <= ws->r);
291 304923
        ws->f += PRNDUP(ptr - ws->f);
292 304923
        ws->r = NULL;
293 304923
        WS_Assert(ws);
294 304923
}
295
296
void *
297 785118
WS_AtOffset(const struct ws *ws, unsigned off, unsigned len)
298
{
299
        char *ptr;
300
301 785118
        WS_Assert(ws);
302 785118
        ptr = ws->s + off;
303 785118
        AN(WS_Allocated(ws, ptr, len));
304 785118
        return (ptr);
305
}
306
307
unsigned
308 250807
WS_ReservationOffset(const struct ws *ws)
309
{
310
311 250807
        AN(ws->r);
312 250807
        return (ws->f - ws->s);
313
}
314
315
/*--------------------------------------------------------------------*/
316
317
unsigned
318 298
WS_Dump(const struct ws *ws, char where, size_t off, void *buf, size_t len)
319
{
320
        char *b, *p;
321
        size_t l;
322
323 298
        WS_Assert(ws);
324 298
        AN(buf);
325 298
        AN(len);
326
327 298
        switch (where) {
328 0
        case 's': p = ws->s; break;
329 298
        case 'f': p = ws->f; break;
330 0
        case 'r': p = ws->r; break;
331
        default:
332 0
                errno = EINVAL;
333 0
                return (0);
334
        }
335
336 298
        if (p == NULL) {
337 1
                errno = EAGAIN;
338 1
                return (0);
339
        }
340
341 299
        p += off;
342 299
        if (p >= ws->e) {
343 0
                errno = EFAULT;
344 0
                return (0);
345
        }
346
347 299
        l = pdiff(p, ws->e);
348 299
        if (len <= l) {
349 299
                memcpy(buf, p, len);
350 299
                return (len);
351
        }
352
353 0
        b = buf;
354 0
        memcpy(b, p, l);
355 0
        memset(b + l, WS_REDZONE_END, len - l);
356 0
        return (l);
357 300
}
358
359
/*--------------------------------------------------------------------*/
360
361
static inline void
362 1350
ws_printptr(struct vsb *vsb, const char *s, const char *p)
363
{
364 1350
        if (p >= s)
365 900
                VSB_printf(vsb, ", +%ld", (long) (p - s));
366
        else
367 450
                VSB_printf(vsb, ", %p", p);
368 1350
}
369
370
void
371 800
WS_Panic(struct vsb *vsb, const struct ws *ws)
372
{
373
374 800
        if (PAN_dump_struct(vsb, ws, WS_MAGIC, "ws"))
375 350
                return;
376 450
        if (ws->id[0] != '\0' && (!(ws->id[0] & 0x20))) // cheesy islower()
377 0
                VSB_cat(vsb, "OVERFLOWED ");
378 450
        VSB_printf(vsb, "id = \"%s\",\n", ws->id);
379 450
        VSB_printf(vsb, "{s, f, r, e} = {%p", ws->s);
380 450
        ws_printptr(vsb, ws->s, ws->f);
381 450
        ws_printptr(vsb, ws->s, ws->r);
382 450
        ws_printptr(vsb, ws->s, ws->e);
383 450
        VSB_cat(vsb, "},\n");
384 450
        VSB_indent(vsb, -2);
385 450
        VSB_cat(vsb, "},\n");
386 800
}