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 32224379
WS_Assert(const struct ws *ws)
43
{
44
45 32224379
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
46 32224379
        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 32224379
        assert(ws->s != NULL);
51 32224379
        assert(PAOK(ws->s));
52 32224379
        assert(ws->e != NULL);
53 32224379
        assert(PAOK(ws->e));
54 32224379
        assert(ws->s < ws->e);
55 32224379
        assert(ws->f >= ws->s);
56 32224379
        assert(ws->f <= ws->e);
57 32224379
        assert(PAOK(ws->f));
58 32224379
        if (ws->r) {
59 10598050
                assert(ws->r >= ws->f);
60 10598050
                assert(ws->r <= ws->e);
61 10598050
        }
62 32224379
        assert(*ws->e == WS_REDZONE_END);
63 32224379
}
64
65
int
66 2007046
WS_Allocated(const struct ws *ws, const void *ptr, ssize_t len)
67
{
68 2007046
        const char *p = ptr;
69
70 2007046
        WS_Assert(ws);
71 2007046
        if (len < 0)
72 10880
                len = strlen(p) + 1;
73 2007046
        assert(!(p > ws->f && p <= ws->e));
74 2007046
        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 1071284
WS_Init(struct ws *ws, const char *id, void *space, unsigned len)
84
{
85
        unsigned l;
86
87 1071284
        DSLb(DBG_WORKSPACE,
88
            "WS_Init(%s, %p, %p, %u)", id, ws, space, len);
89 1071284
        assert(space != NULL);
90 1071284
        INIT_OBJ(ws, WS_MAGIC);
91 1071284
        ws->s = space;
92 1071284
        assert(PAOK(space));
93 1071284
        l = PRNDDN(len - 1);
94 1071284
        ws->e = ws->s + l;
95 1071284
        memset(ws->e, WS_REDZONE_END, len - l);
96 1071284
        ws->f = ws->s;
97 1071284
        assert(id[0] & 0x20);           // cheesy islower()
98 1071284
        bstrcpy(ws->id, id);
99 1071284
        WS_Assert(ws);
100 1071284
}
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 1725649
WS_Reset(struct ws *ws, uintptr_t pp)
113
{
114
        char *p;
115
116 1725649
        WS_Assert(ws);
117 1725649
        AN(pp);
118 1725649
        if (pp == snap_overflowed) {
119 40
                DSLb(DBG_WORKSPACE, "WS_Reset(%s, %p, overflowed)", ws->id, ws);
120 40
                AN(WS_Overflowed(ws));
121 40
                return;
122
        }
123 1725609
        p = (char *)pp;
124 1725609
        DSLb(DBG_WORKSPACE, "WS_Reset(%s, %p, %p)", ws->id, ws, p);
125 1725609
        assert(ws->r == NULL);
126 1725609
        assert(p >= ws->s);
127 1725609
        assert(p <= ws->e);
128 1725609
        ws->f = p;
129 1725609
        WS_Assert(ws);
130 1725649
}
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
int
138 319683
WS_Pipeline(struct ws *ws, const void *b, const void *e, unsigned rollback)
139
{
140
        unsigned r, l;
141
142 319683
        WS_Assert(ws);
143
144 319683
        if (rollback)
145 238297
                WS_Rollback(ws, 0);
146
147 319683
        r = WS_ReserveAll(ws);
148
149 319683
        if (b == NULL) {
150 306372
                AZ(e);
151 306372
                return (0);
152
        }
153
154 13311
        AN(e);
155 13311
        l = pdiff(b, e);
156 13311
        if (l > r)
157 0
                return (-1);
158 13311
        memmove(ws->f, b, l);
159 13311
        return (l);
160 319683
}
161
162
void *
163 692656
WS_Alloc(struct ws *ws, unsigned bytes)
164
{
165
        char *r;
166
167 692656
        WS_Assert(ws);
168 692656
        assert(bytes > 0);
169 692656
        bytes = PRNDUP(bytes);
170
171 692656
        assert(ws->r == NULL);
172 692656
        if (ws->f + bytes > ws->e) {
173 13760
                WS_MarkOverflow(ws);
174 13760
                return (NULL);
175
        }
176 678896
        r = ws->f;
177 678896
        ws->f += bytes;
178 678896
        DSLb(DBG_WORKSPACE, "WS_Alloc(%s, %p, %u) = %p", ws->id, ws, bytes, r);
179 678896
        WS_Assert(ws);
180 678896
        return (r);
181 692656
}
182
183
void *
184 648538
WS_Copy(struct ws *ws, const void *str, int len)
185
{
186
        char *r;
187
        unsigned bytes;
188
189 648538
        WS_Assert(ws);
190 648538
        assert(ws->r == NULL);
191
192 648538
        if (len == -1)
193 12433
                len = strlen(str) + 1;
194 648538
        assert(len > 0);
195
196 648538
        bytes = PRNDUP((unsigned)len);
197 648538
        if (ws->f + bytes > ws->e) {
198 120
                WS_MarkOverflow(ws);
199 120
                return (NULL);
200
        }
201 648418
        r = ws->f;
202 648418
        ws->f += bytes;
203 648418
        memcpy(r, str, len);
204 648418
        DSLb(DBG_WORKSPACE, "WS_Copy(%s, %p, %d) = %p", ws->id, ws, len, r);
205 648418
        WS_Assert(ws);
206 648418
        return (r);
207 648538
}
208
209
uintptr_t
210 1964474
WS_Snapshot(struct ws *ws)
211
{
212
213 1964474
        WS_Assert(ws);
214 1964474
        assert(ws->r == NULL);
215 1964474
        if (WS_Overflowed(ws)) {
216 120
                DSLb(DBG_WORKSPACE, "WS_Snapshot(%s, %p) = overflowed",
217
                    ws->id, ws);
218 120
                return (snap_overflowed);
219
        }
220 1964354
        DSLb(DBG_WORKSPACE, "WS_Snapshot(%s, %p) = %p", ws->id, ws, ws->f);
221 1964354
        return ((uintptr_t)ws->f);
222 1964474
}
223
224
/*
225
 * WS_Release() must be called in all cases
226
 */
227
unsigned
228 2175807
WS_ReserveAll(struct ws *ws)
229
{
230
        unsigned b;
231
232 2175807
        WS_Assert(ws);
233 2175807
        assert(ws->r == NULL);
234
235 2175807
        ws->r = ws->e;
236 2175807
        b = pdiff(ws->f, ws->r);
237
238 2175807
        WS_Assert(ws);
239 2175807
        DSLb(DBG_WORKSPACE, "WS_ReserveAll(%s, %p) = %u", ws->id, ws, b);
240
241 2175807
        return (b);
242
}
243
244
/*
245
 * WS_Release() must be called for retval > 0 only
246
 */
247
unsigned
248 593253
WS_ReserveSize(struct ws *ws, unsigned bytes)
249
{
250
        unsigned l;
251
252 593253
        WS_Assert(ws);
253 593253
        assert(ws->r == NULL);
254 593253
        assert(bytes > 0);
255
256 593253
        l = pdiff(ws->f, ws->e);
257 593253
        if (bytes > l) {
258 2680
                WS_MarkOverflow(ws);
259 2680
                return (0);
260
        }
261 590573
        ws->r = ws->f + bytes;
262 590573
        DSLb(DBG_WORKSPACE, "WS_ReserveSize(%s, %p, %u/%u) = %u", ws->id,
263
            ws, bytes, l, bytes);
264 590573
        WS_Assert(ws);
265 590573
        return (bytes);
266 593253
}
267
268
void
269 2256169
WS_Release(struct ws *ws, unsigned bytes)
270
{
271 2256169
        WS_Assert(ws);
272 2256169
        assert(bytes <= ws->e - ws->f);
273 2256169
        DSLb(DBG_WORKSPACE, "WS_Release(%s, %p, %u)", ws->id, ws, bytes);
274 2256169
        assert(ws->r != NULL);
275 2256169
        assert(ws->f + bytes <= ws->r);
276 2256169
        ws->f += PRNDUP(bytes);
277 2256169
        ws->r = NULL;
278 2256169
        WS_Assert(ws);
279 2256169
}
280
281
void
282 509905
WS_ReleaseP(struct ws *ws, const char *ptr)
283
{
284 509905
        WS_Assert(ws);
285 509905
        DSLb(DBG_WORKSPACE, "WS_ReleaseP(%s, %p, %p (%zd))", ws->id, ws, ptr,
286
            ptr - ws->f);
287 509905
        assert(ws->r != NULL);
288 509905
        assert(ptr >= ws->f);
289 509905
        assert(ptr <= ws->r);
290 509905
        ws->f += PRNDUP(ptr - ws->f);
291 509905
        ws->r = NULL;
292 509905
        WS_Assert(ws);
293 509905
}
294
295
void *
296 1304758
WS_AtOffset(const struct ws *ws, unsigned off, unsigned len)
297
{
298
        char *ptr;
299
300 1304758
        WS_Assert(ws);
301 1304758
        ptr = ws->s + off;
302 1304758
        AN(WS_Allocated(ws, ptr, len));
303 1304758
        return (ptr);
304
}
305
306
unsigned
307 420053
WS_ReservationOffset(const struct ws *ws)
308
{
309
310 420053
        AN(ws->r);
311 420053
        return (ws->f - ws->s);
312
}
313
314
/*--------------------------------------------------------------------*/
315
316
unsigned
317 477
WS_Dump(const struct ws *ws, char where, size_t off, void *buf, size_t len)
318
{
319
        char *b, *p;
320
        size_t l;
321
322 477
        WS_Assert(ws);
323 477
        AN(buf);
324 477
        AN(len);
325
326 477
        switch (where) {
327 0
        case 's': p = ws->s; break;
328 477
        case 'f': p = ws->f; break;
329 0
        case 'r': p = ws->r; break;
330
        default:
331 0
                errno = EINVAL;
332 0
                return (0);
333
        }
334
335 477
        if (p == NULL) {
336 1
                errno = EAGAIN;
337 1
                return (0);
338
        }
339
340 478
        p += off;
341 478
        if (p >= ws->e) {
342 0
                errno = EFAULT;
343 0
                return (0);
344
        }
345
346 478
        l = pdiff(p, ws->e);
347 478
        if (len <= l) {
348 478
                memcpy(buf, p, len);
349 478
                return (len);
350
        }
351
352 0
        b = buf;
353 0
        memcpy(b, p, l);
354 0
        memset(b + l, WS_REDZONE_END, len - l);
355 0
        return (l);
356 479
}
357
358
/*--------------------------------------------------------------------*/
359
360
static inline void
361 2520
ws_printptr(struct vsb *vsb, const char *s, const char *p)
362
{
363 2520
        if (p >= s)
364 1680
                VSB_printf(vsb, ", +%ld", (long) (p - s));
365
        else
366 840
                VSB_printf(vsb, ", %p", p);
367 2520
}
368
369
void
370 1520
WS_Panic(struct vsb *vsb, const struct ws *ws)
371
{
372
373 1520
        if (PAN_dump_struct(vsb, ws, WS_MAGIC, "ws"))
374 680
                return;
375 840
        if (ws->id[0] != '\0' && (!(ws->id[0] & 0x20))) // cheesy islower()
376 0
                VSB_cat(vsb, "OVERFLOWED ");
377 840
        VSB_printf(vsb, "id = \"%s\",\n", ws->id);
378 840
        VSB_printf(vsb, "{s, f, r, e} = {%p", ws->s);
379 840
        ws_printptr(vsb, ws->s, ws->f);
380 840
        ws_printptr(vsb, ws->s, ws->r);
381 840
        ws_printptr(vsb, ws->s, ws->e);
382 840
        VSB_cat(vsb, "},\n");
383 840
        VSB_indent(vsb, -2);
384 840
        VSB_cat(vsb, "},\n");
385 1520
}