| | 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 |
32440424 |
WS_Assert(const struct ws *ws) |
43 |
|
{ |
44 |
|
|
45 |
32440424 |
CHECK_OBJ_NOTNULL(ws, WS_MAGIC); |
46 |
32440424 |
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 |
32440424 |
assert(ws->s != NULL); |
51 |
32440424 |
assert(PAOK(ws->s)); |
52 |
32440424 |
assert(ws->e != NULL); |
53 |
32440424 |
assert(PAOK(ws->e)); |
54 |
32440424 |
assert(ws->s < ws->e); |
55 |
32440424 |
assert(ws->f >= ws->s); |
56 |
32440424 |
assert(ws->f <= ws->e); |
57 |
32440424 |
assert(PAOK(ws->f)); |
58 |
32440424 |
if (ws->r) { |
59 |
10665677 |
assert(ws->r >= ws->f); |
60 |
10665677 |
assert(ws->r <= ws->e); |
61 |
10665677 |
} |
62 |
32440424 |
assert(*ws->e == WS_REDZONE_END); |
63 |
32440424 |
} |
64 |
|
|
65 |
|
int |
66 |
2021196 |
WS_Allocated(const struct ws *ws, const void *ptr, ssize_t len) |
67 |
|
{ |
68 |
2021196 |
const char *p = ptr; |
69 |
|
|
70 |
2021196 |
WS_Assert(ws); |
71 |
2021196 |
if (len < 0) |
72 |
11520 |
len = strlen(p) + 1; |
73 |
2021196 |
assert(!(p > ws->f && p <= ws->e)); |
74 |
2021196 |
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 |
1073627 |
WS_Init(struct ws *ws, const char *id, void *space, unsigned len) |
84 |
|
{ |
85 |
|
unsigned l; |
86 |
|
|
87 |
1073627 |
DSLb(DBG_WORKSPACE, |
88 |
|
"WS_Init(%s, %p, %p, %u)", id, ws, space, len); |
89 |
1073627 |
assert(space != NULL); |
90 |
1073627 |
INIT_OBJ(ws, WS_MAGIC); |
91 |
1073627 |
ws->s = space; |
92 |
1073627 |
assert(PAOK(space)); |
93 |
1073627 |
l = PRNDDN(len - 1); |
94 |
1073627 |
ws->e = ws->s + l; |
95 |
1073627 |
memset(ws->e, WS_REDZONE_END, len - l); |
96 |
1073627 |
ws->f = ws->s; |
97 |
1073627 |
assert(id[0] & 0x20); // cheesy islower() |
98 |
1073627 |
bstrcpy(ws->id, id); |
99 |
1073627 |
WS_Assert(ws); |
100 |
1073627 |
} |
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 |
1737809 |
WS_Reset(struct ws *ws, uintptr_t pp) |
113 |
|
{ |
114 |
|
char *p; |
115 |
|
|
116 |
1737809 |
WS_Assert(ws); |
117 |
1737809 |
AN(pp); |
118 |
1737809 |
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 |
1737769 |
p = (char *)pp; |
124 |
1737769 |
DSLb(DBG_WORKSPACE, "WS_Reset(%s, %p, %p)", ws->id, ws, p); |
125 |
1737769 |
assert(ws->r == NULL); |
126 |
1737769 |
assert(p >= ws->s); |
127 |
1737769 |
assert(p <= ws->e); |
128 |
1737769 |
ws->f = p; |
129 |
1737769 |
WS_Assert(ws); |
130 |
1737809 |
} |
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 |
321084 |
WS_Pipeline(struct ws *ws, const void *b, const void *e, unsigned rollback) |
139 |
|
{ |
140 |
|
unsigned r, l; |
141 |
|
|
142 |
321084 |
WS_Assert(ws); |
143 |
|
|
144 |
321084 |
if (rollback) |
145 |
239650 |
WS_Rollback(ws, 0); |
146 |
|
|
147 |
321084 |
r = WS_ReserveAll(ws); |
148 |
|
|
149 |
321084 |
if (b == NULL) { |
150 |
307795 |
AZ(e); |
151 |
307795 |
return (0); |
152 |
|
} |
153 |
|
|
154 |
13289 |
AN(e); |
155 |
13289 |
l = pdiff(b, e); |
156 |
13289 |
if (l > r) |
157 |
0 |
return (-1); |
158 |
13289 |
memmove(ws->f, b, l); |
159 |
13289 |
return (l); |
160 |
321084 |
} |
161 |
|
|
162 |
|
void * |
163 |
700143 |
WS_Alloc(struct ws *ws, unsigned bytes) |
164 |
|
{ |
165 |
|
char *r; |
166 |
|
|
167 |
700143 |
WS_Assert(ws); |
168 |
700143 |
assert(bytes > 0); |
169 |
700143 |
bytes = PRNDUP(bytes); |
170 |
|
|
171 |
700143 |
assert(ws->r == NULL); |
172 |
700143 |
if (ws->f + bytes > ws->e) { |
173 |
13760 |
WS_MarkOverflow(ws); |
174 |
13760 |
return (NULL); |
175 |
|
} |
176 |
686383 |
r = ws->f; |
177 |
686383 |
ws->f += bytes; |
178 |
686383 |
DSLb(DBG_WORKSPACE, "WS_Alloc(%s, %p, %u) = %p", ws->id, ws, bytes, r); |
179 |
686383 |
WS_Assert(ws); |
180 |
686383 |
return (r); |
181 |
700143 |
} |
182 |
|
|
183 |
|
void * |
184 |
648799 |
WS_Copy(struct ws *ws, const void *str, int len) |
185 |
|
{ |
186 |
|
char *r; |
187 |
|
unsigned bytes; |
188 |
|
|
189 |
648799 |
WS_Assert(ws); |
190 |
648799 |
assert(ws->r == NULL); |
191 |
|
|
192 |
648799 |
if (len == -1) |
193 |
12423 |
len = strlen(str) + 1; |
194 |
648799 |
assert(len > 0); |
195 |
|
|
196 |
648799 |
bytes = PRNDUP((unsigned)len); |
197 |
648799 |
if (ws->f + bytes > ws->e) { |
198 |
160 |
WS_MarkOverflow(ws); |
199 |
160 |
return (NULL); |
200 |
|
} |
201 |
648639 |
r = ws->f; |
202 |
648639 |
ws->f += bytes; |
203 |
648639 |
memcpy(r, str, len); |
204 |
648639 |
DSLb(DBG_WORKSPACE, "WS_Copy(%s, %p, %d) = %p", ws->id, ws, len, r); |
205 |
648639 |
WS_Assert(ws); |
206 |
648639 |
return (r); |
207 |
648799 |
} |
208 |
|
|
209 |
|
uintptr_t |
210 |
1981745 |
WS_Snapshot(struct ws *ws) |
211 |
|
{ |
212 |
|
|
213 |
1981745 |
WS_Assert(ws); |
214 |
1981745 |
assert(ws->r == NULL); |
215 |
1981745 |
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 |
1981625 |
DSLb(DBG_WORKSPACE, "WS_Snapshot(%s, %p) = %p", ws->id, ws, ws->f); |
221 |
1981625 |
return ((uintptr_t)ws->f); |
222 |
1981745 |
} |
223 |
|
|
224 |
|
/* |
225 |
|
* WS_Release() must be called in all cases |
226 |
|
*/ |
227 |
|
unsigned |
228 |
2193157 |
WS_ReserveAll(struct ws *ws) |
229 |
|
{ |
230 |
|
unsigned b; |
231 |
|
|
232 |
2193157 |
WS_Assert(ws); |
233 |
2193157 |
assert(ws->r == NULL); |
234 |
|
|
235 |
2193157 |
ws->r = ws->e; |
236 |
2193157 |
b = pdiff(ws->f, ws->r); |
237 |
|
|
238 |
2193157 |
WS_Assert(ws); |
239 |
2193157 |
DSLb(DBG_WORKSPACE, "WS_ReserveAll(%s, %p) = %u", ws->id, ws, b); |
240 |
|
|
241 |
2193157 |
return (b); |
242 |
|
} |
243 |
|
|
244 |
|
/* |
245 |
|
* WS_Release() must be called for retval > 0 only |
246 |
|
*/ |
247 |
|
unsigned |
248 |
593774 |
WS_ReserveSize(struct ws *ws, unsigned bytes) |
249 |
|
{ |
250 |
|
unsigned l; |
251 |
|
|
252 |
593774 |
WS_Assert(ws); |
253 |
593774 |
assert(ws->r == NULL); |
254 |
593774 |
assert(bytes > 0); |
255 |
|
|
256 |
593774 |
l = pdiff(ws->f, ws->e); |
257 |
593774 |
if (bytes > l) { |
258 |
2680 |
WS_MarkOverflow(ws); |
259 |
2680 |
return (0); |
260 |
|
} |
261 |
591094 |
ws->r = ws->f + bytes; |
262 |
591094 |
DSLb(DBG_WORKSPACE, "WS_ReserveSize(%s, %p, %u/%u) = %u", ws->id, |
263 |
|
ws, bytes, l, bytes); |
264 |
591094 |
WS_Assert(ws); |
265 |
591094 |
return (bytes); |
266 |
593774 |
} |
267 |
|
|
268 |
|
void |
269 |
2272424 |
WS_Release(struct ws *ws, unsigned bytes) |
270 |
|
{ |
271 |
2272424 |
WS_Assert(ws); |
272 |
2272424 |
assert(bytes <= ws->e - ws->f); |
273 |
2272424 |
DSLb(DBG_WORKSPACE, "WS_Release(%s, %p, %u)", ws->id, ws, bytes); |
274 |
2272424 |
assert(ws->r != NULL); |
275 |
2272424 |
assert(ws->f + bytes <= ws->r); |
276 |
2272424 |
ws->f += PRNDUP(bytes); |
277 |
2272424 |
ws->r = NULL; |
278 |
2272424 |
WS_Assert(ws); |
279 |
2272424 |
} |
280 |
|
|
281 |
|
void |
282 |
511300 |
WS_ReleaseP(struct ws *ws, const char *ptr) |
283 |
|
{ |
284 |
511300 |
WS_Assert(ws); |
285 |
511300 |
DSLb(DBG_WORKSPACE, "WS_ReleaseP(%s, %p, %p (%zd))", ws->id, ws, ptr, |
286 |
|
ptr - ws->f); |
287 |
511300 |
assert(ws->r != NULL); |
288 |
511300 |
assert(ptr >= ws->f); |
289 |
511300 |
assert(ptr <= ws->r); |
290 |
511300 |
ws->f += PRNDUP(ptr - ws->f); |
291 |
511300 |
ws->r = NULL; |
292 |
511300 |
WS_Assert(ws); |
293 |
511300 |
} |
294 |
|
|
295 |
|
void * |
296 |
1317990 |
WS_AtOffset(const struct ws *ws, unsigned off, unsigned len) |
297 |
|
{ |
298 |
|
char *ptr; |
299 |
|
|
300 |
1317990 |
WS_Assert(ws); |
301 |
1317990 |
ptr = ws->s + off; |
302 |
1317990 |
AN(WS_Allocated(ws, ptr, len)); |
303 |
1317990 |
return (ptr); |
304 |
|
} |
305 |
|
|
306 |
|
unsigned |
307 |
420460 |
WS_ReservationOffset(const struct ws *ws) |
308 |
|
{ |
309 |
|
|
310 |
420460 |
AN(ws->r); |
311 |
420460 |
return (ws->f - ws->s); |
312 |
|
} |
313 |
|
|
314 |
|
/*--------------------------------------------------------------------*/ |
315 |
|
|
316 |
|
unsigned |
317 |
478 |
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 |
478 |
WS_Assert(ws); |
323 |
478 |
AN(buf); |
324 |
478 |
AN(len); |
325 |
|
|
326 |
478 |
switch (where) { |
327 |
0 |
case 's': p = ws->s; break; |
328 |
478 |
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 |
478 |
if (p == NULL) { |
336 |
1 |
errno = EAGAIN; |
337 |
1 |
return (0); |
338 |
|
} |
339 |
|
|
340 |
479 |
p += off; |
341 |
479 |
if (p >= ws->e) { |
342 |
0 |
errno = EFAULT; |
343 |
0 |
return (0); |
344 |
|
} |
345 |
|
|
346 |
479 |
l = pdiff(p, ws->e); |
347 |
479 |
if (len <= l) { |
348 |
479 |
memcpy(buf, p, len); |
349 |
479 |
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 |
480 |
} |
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 |
} |