| | 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 |
} |