| | varnish-cache/bin/varnishd/cache/cache_ban.c |
| 0 |
|
/*- |
| 1 |
|
* Copyright (c) 2006 Verdens Gang AS |
| 2 |
|
* Copyright (c) 2006-2015 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 |
|
*/ |
| 31 |
|
|
| 32 |
|
#include "config.h" |
| 33 |
|
|
| 34 |
|
#include <stdlib.h> |
| 35 |
|
#include <stdio.h> |
| 36 |
|
|
| 37 |
|
#include "cache_varnishd.h" |
| 38 |
|
#include "cache_ban.h" |
| 39 |
|
#include "cache_objhead.h" |
| 40 |
|
|
| 41 |
|
#include "vcli_serve.h" |
| 42 |
|
#include "vend.h" |
| 43 |
|
#include "vmb.h" |
| 44 |
|
|
| 45 |
|
/* cache_ban_build.c */ |
| 46 |
|
void BAN_Build_Init(void); |
| 47 |
|
void BAN_Build_Fini(void); |
| 48 |
|
|
| 49 |
|
struct lock ban_mtx; |
| 50 |
|
int ban_shutdown; |
| 51 |
|
struct banhead_s ban_head = VTAILQ_HEAD_INITIALIZER(ban_head); |
| 52 |
|
struct ban * volatile ban_start; |
| 53 |
|
|
| 54 |
|
static pthread_t ban_thread; |
| 55 |
|
static int ban_holds; |
| 56 |
|
uint64_t bans_persisted_bytes; |
| 57 |
|
uint64_t bans_persisted_fragmentation; |
| 58 |
|
|
| 59 |
|
struct ban_test { |
| 60 |
|
uint8_t oper; |
| 61 |
|
uint8_t arg1; |
| 62 |
|
const char *arg1_spec; |
| 63 |
|
const char *arg2; |
| 64 |
|
double arg2_double; |
| 65 |
|
const void *arg2_spec; |
| 66 |
|
}; |
| 67 |
|
|
| 68 |
|
static const char * const arg_name[BAN_ARGARRSZ + 1] = { |
| 69 |
|
#define PVAR(a, b, c) [BAN_ARGIDX(c)] = (a), |
| 70 |
|
#include "tbl/ban_vars.h" |
| 71 |
|
[BAN_ARGARRSZ] = NULL |
| 72 |
|
}; |
| 73 |
|
|
| 74 |
|
/*-------------------------------------------------------------------- |
| 75 |
|
* Storage handling of bans |
| 76 |
|
*/ |
| 77 |
|
|
| 78 |
|
static struct ban * |
| 79 |
1040 |
ban_alloc(void) |
| 80 |
|
{ |
| 81 |
|
struct ban *b; |
| 82 |
|
|
| 83 |
1040 |
ALLOC_OBJ(b, BAN_MAGIC); |
| 84 |
1040 |
if (b != NULL) |
| 85 |
1040 |
VTAILQ_INIT(&b->objcore); |
| 86 |
1040 |
return (b); |
| 87 |
|
} |
| 88 |
|
|
| 89 |
|
void |
| 90 |
2881 |
BAN_Free(struct ban *b) |
| 91 |
|
{ |
| 92 |
|
|
| 93 |
2881 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
| 94 |
2881 |
AZ(b->refcount); |
| 95 |
2881 |
assert(VTAILQ_EMPTY(&b->objcore)); |
| 96 |
|
|
| 97 |
2881 |
if (b->spec != NULL) |
| 98 |
2881 |
free(b->spec); |
| 99 |
2881 |
FREE_OBJ(b); |
| 100 |
2881 |
} |
| 101 |
|
|
| 102 |
|
/*-------------------------------------------------------------------- |
| 103 |
|
* Get/release holds which prevent the ban_lurker from starting. |
| 104 |
|
* Holds are held while stevedores load zombie objects. |
| 105 |
|
*/ |
| 106 |
|
|
| 107 |
|
void |
| 108 |
1520 |
BAN_Hold(void) |
| 109 |
|
{ |
| 110 |
|
|
| 111 |
1520 |
Lck_Lock(&ban_mtx); |
| 112 |
|
/* Once holds are released, we allow no more */ |
| 113 |
1520 |
assert(ban_holds > 0); |
| 114 |
1520 |
ban_holds++; |
| 115 |
1520 |
Lck_Unlock(&ban_mtx); |
| 116 |
1520 |
} |
| 117 |
|
|
| 118 |
|
void |
| 119 |
39456 |
BAN_Release(void) |
| 120 |
|
{ |
| 121 |
|
|
| 122 |
39456 |
Lck_Lock(&ban_mtx); |
| 123 |
39456 |
assert(ban_holds > 0); |
| 124 |
39456 |
ban_holds--; |
| 125 |
39456 |
Lck_Unlock(&ban_mtx); |
| 126 |
39456 |
if (ban_holds == 0) { |
| 127 |
37936 |
BANIDX_fini(); |
| 128 |
37936 |
WRK_BgThread(&ban_thread, "ban-lurker", ban_lurker, NULL); |
| 129 |
37936 |
} |
| 130 |
39456 |
} |
| 131 |
|
|
| 132 |
|
/*-------------------------------------------------------------------- |
| 133 |
|
* Extract time and length from ban-spec |
| 134 |
|
*/ |
| 135 |
|
|
| 136 |
|
vtim_real |
| 137 |
38080 |
ban_time(const uint8_t *banspec) |
| 138 |
|
{ |
| 139 |
|
vtim_real t; |
| 140 |
|
uint64_t u; |
| 141 |
|
|
| 142 |
38080 |
assert(sizeof t == sizeof u); |
| 143 |
38080 |
assert(sizeof t == (BANS_LENGTH - BANS_TIMESTAMP)); |
| 144 |
38080 |
u = vbe64dec(banspec + BANS_TIMESTAMP); |
| 145 |
38080 |
memcpy(&t, &u, sizeof t); |
| 146 |
38080 |
return (t); |
| 147 |
|
} |
| 148 |
|
|
| 149 |
|
unsigned |
| 150 |
243505 |
ban_len(const uint8_t *banspec) |
| 151 |
|
{ |
| 152 |
|
unsigned u; |
| 153 |
|
|
| 154 |
243505 |
u = vbe32dec(banspec + BANS_LENGTH); |
| 155 |
243505 |
return (u); |
| 156 |
|
} |
| 157 |
|
|
| 158 |
|
int |
| 159 |
10960 |
ban_equal(const uint8_t *bs1, const uint8_t *bs2) |
| 160 |
|
{ |
| 161 |
|
unsigned u; |
| 162 |
|
|
| 163 |
|
/* |
| 164 |
|
* Compare two ban-strings. |
| 165 |
|
*/ |
| 166 |
10960 |
u = ban_len(bs1); |
| 167 |
10960 |
if (u != ban_len(bs2)) |
| 168 |
4120 |
return (0); |
| 169 |
6840 |
if (bs1[BANS_FLAGS] & BANS_FLAG_NODEDUP) |
| 170 |
120 |
return (0); |
| 171 |
|
|
| 172 |
6720 |
return (!memcmp(bs1 + BANS_LENGTH, bs2 + BANS_LENGTH, u - BANS_LENGTH)); |
| 173 |
10960 |
} |
| 174 |
|
|
| 175 |
|
void |
| 176 |
39976 |
ban_mark_completed(struct ban *b) |
| 177 |
|
{ |
| 178 |
|
unsigned ln; |
| 179 |
|
|
| 180 |
39976 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
| 181 |
39976 |
Lck_AssertHeld(&ban_mtx); |
| 182 |
|
|
| 183 |
39976 |
AN(b->spec); |
| 184 |
39976 |
if (!(b->flags & BANS_FLAG_COMPLETED)) { |
| 185 |
39976 |
ln = ban_len(b->spec); |
| 186 |
39976 |
b->flags |= BANS_FLAG_COMPLETED; |
| 187 |
39976 |
b->spec[BANS_FLAGS] |= BANS_FLAG_COMPLETED; |
| 188 |
39976 |
VWMB(); |
| 189 |
39976 |
vbe32enc(b->spec + BANS_LENGTH, BANS_HEAD_LEN); |
| 190 |
39976 |
VSC_C_main->bans_completed++; |
| 191 |
39976 |
bans_persisted_fragmentation += ln - ban_len(b->spec); |
| 192 |
39976 |
VSC_C_main->bans_persisted_fragmentation = |
| 193 |
39976 |
bans_persisted_fragmentation; |
| 194 |
39976 |
} |
| 195 |
39976 |
} |
| 196 |
|
|
| 197 |
|
/*-------------------------------------------------------------------- |
| 198 |
|
* Access a lump of bytes in a ban test spec |
| 199 |
|
*/ |
| 200 |
|
|
| 201 |
|
static const void * |
| 202 |
16520 |
ban_get_lump(const uint8_t **bs) |
| 203 |
|
{ |
| 204 |
|
const void *r; |
| 205 |
|
unsigned ln; |
| 206 |
|
|
| 207 |
101640 |
while (**bs == 0xff) |
| 208 |
85120 |
*bs += 1; |
| 209 |
16520 |
ln = vbe32dec(*bs); |
| 210 |
16520 |
*bs += PRNDUP(sizeof(uint32_t)); |
| 211 |
16520 |
assert(PAOK(*bs)); |
| 212 |
16520 |
r = (const void*)*bs; |
| 213 |
16520 |
*bs += ln; |
| 214 |
16520 |
return (r); |
| 215 |
|
} |
| 216 |
|
|
| 217 |
|
/*-------------------------------------------------------------------- |
| 218 |
|
* Pick a test apart from a spec string |
| 219 |
|
*/ |
| 220 |
|
|
| 221 |
|
static void |
| 222 |
14520 |
ban_iter(const uint8_t **bs, struct ban_test *bt) |
| 223 |
|
{ |
| 224 |
|
const void *lump; |
| 225 |
|
uint64_t dtmp; |
| 226 |
|
|
| 227 |
14520 |
memset(bt, 0, sizeof *bt); |
| 228 |
14520 |
bt->arg2_double = nan(""); |
| 229 |
14520 |
bt->arg1 = *(*bs)++; |
| 230 |
14520 |
if (BANS_HAS_ARG1_SPEC(bt->arg1)) { |
| 231 |
4080 |
bt->arg1_spec = (const char *)*bs; |
| 232 |
4080 |
(*bs) += (*bs)[0] + 2; |
| 233 |
4080 |
} |
| 234 |
14520 |
lump = ban_get_lump(bs); |
| 235 |
14520 |
bt->oper = *(*bs)++; |
| 236 |
14520 |
if (BANS_HAS_ARG2_DOUBLE(bt->arg1)) { |
| 237 |
6280 |
dtmp = vbe64dec(lump); |
| 238 |
6280 |
memcpy(&bt->arg2_double, &dtmp, sizeof dtmp); |
| 239 |
6280 |
return; |
| 240 |
|
} |
| 241 |
8240 |
bt->arg2 = lump; |
| 242 |
8240 |
if (BANS_HAS_ARG2_SPEC(bt->oper)) |
| 243 |
2000 |
bt->arg2_spec = ban_get_lump(bs); |
| 244 |
14520 |
} |
| 245 |
|
|
| 246 |
|
/*-------------------------------------------------------------------- |
| 247 |
|
* A new object is created, grab a reference to the newest ban |
| 248 |
|
*/ |
| 249 |
|
|
| 250 |
|
void |
| 251 |
58000 |
BAN_NewObjCore(struct objcore *oc) |
| 252 |
|
{ |
| 253 |
|
|
| 254 |
58000 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
| 255 |
58000 |
AZ(oc->ban); |
| 256 |
58000 |
AN(oc->objhead); |
| 257 |
58000 |
Lck_Lock(&ban_mtx); |
| 258 |
58000 |
oc->ban = ban_start; |
| 259 |
58000 |
ban_start->refcount++; |
| 260 |
58000 |
VTAILQ_INSERT_TAIL(&ban_start->objcore, oc, ban_list); |
| 261 |
58000 |
Lck_Unlock(&ban_mtx); |
| 262 |
58000 |
} |
| 263 |
|
|
| 264 |
|
/*-------------------------------------------------------------------- |
| 265 |
|
* An object is destroyed, release its ban reference |
| 266 |
|
*/ |
| 267 |
|
|
| 268 |
|
void |
| 269 |
75404 |
BAN_DestroyObj(struct objcore *oc) |
| 270 |
|
{ |
| 271 |
|
|
| 272 |
75404 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
| 273 |
75404 |
if (oc->ban == NULL) |
| 274 |
60021 |
return; |
| 275 |
15383 |
Lck_Lock(&ban_mtx); |
| 276 |
15383 |
CHECK_OBJ_ORNULL(oc->ban, BAN_MAGIC); |
| 277 |
15383 |
if (oc->ban != NULL) { |
| 278 |
15383 |
assert(oc->ban->refcount > 0); |
| 279 |
15383 |
oc->ban->refcount--; |
| 280 |
15383 |
VTAILQ_REMOVE(&oc->ban->objcore, oc, ban_list); |
| 281 |
15383 |
oc->ban = NULL; |
| 282 |
15383 |
} |
| 283 |
15383 |
Lck_Unlock(&ban_mtx); |
| 284 |
75404 |
} |
| 285 |
|
|
| 286 |
|
/*-------------------------------------------------------------------- |
| 287 |
|
* Find a ban based on a timestamp. |
| 288 |
|
* Assume we have a BAN_Hold, so list traversal is safe. |
| 289 |
|
*/ |
| 290 |
|
|
| 291 |
|
struct ban * |
| 292 |
680 |
BAN_FindBan(vtim_real t0) |
| 293 |
|
{ |
| 294 |
|
struct ban *b; |
| 295 |
|
vtim_real t1; |
| 296 |
|
|
| 297 |
680 |
assert(ban_holds > 0); |
| 298 |
680 |
b = BANIDX_lookup(t0); |
| 299 |
680 |
VTAILQ_FOREACH_FROM(b, &ban_head, list) { |
| 300 |
680 |
t1 = ban_time(b->spec); |
| 301 |
680 |
if (t1 == t0) |
| 302 |
680 |
return (b); |
| 303 |
0 |
if (t1 < t0) |
| 304 |
0 |
break; |
| 305 |
0 |
} |
| 306 |
0 |
return (NULL); |
| 307 |
680 |
} |
| 308 |
|
|
| 309 |
|
/*-------------------------------------------------------------------- |
| 310 |
|
* Grab a reference to a ban and associate the objcore with that ban. |
| 311 |
|
* Assume we have a BAN_Hold, so list traversal is safe. |
| 312 |
|
*/ |
| 313 |
|
|
| 314 |
|
void |
| 315 |
680 |
BAN_RefBan(struct objcore *oc, struct ban *b) |
| 316 |
|
{ |
| 317 |
|
|
| 318 |
680 |
Lck_Lock(&ban_mtx); |
| 319 |
680 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
| 320 |
680 |
AZ(oc->ban); |
| 321 |
680 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
| 322 |
680 |
assert(ban_holds > 0); |
| 323 |
680 |
b->refcount++; |
| 324 |
680 |
VTAILQ_INSERT_TAIL(&b->objcore, oc, ban_list); |
| 325 |
680 |
oc->ban = b; |
| 326 |
680 |
Lck_Unlock(&ban_mtx); |
| 327 |
680 |
} |
| 328 |
|
|
| 329 |
|
/*-------------------------------------------------------------------- |
| 330 |
|
* Compile a full ban list and export this area to the stevedores for |
| 331 |
|
* persistence. |
| 332 |
|
*/ |
| 333 |
|
|
| 334 |
|
static void |
| 335 |
75456 |
ban_export(void) |
| 336 |
|
{ |
| 337 |
|
struct ban *b; |
| 338 |
|
struct vsb *vsb; |
| 339 |
|
unsigned ln; |
| 340 |
|
|
| 341 |
75456 |
Lck_AssertHeld(&ban_mtx); |
| 342 |
75456 |
ln = bans_persisted_bytes - bans_persisted_fragmentation; |
| 343 |
75456 |
vsb = VSB_new_auto(); |
| 344 |
75456 |
AN(vsb); |
| 345 |
154111 |
VTAILQ_FOREACH_REVERSE(b, &ban_head, banhead_s, list) |
| 346 |
78655 |
AZ(VSB_bcat(vsb, b->spec, ban_len(b->spec))); |
| 347 |
75456 |
AZ(VSB_finish(vsb)); |
| 348 |
75456 |
assert(VSB_len(vsb) == ln); |
| 349 |
75456 |
STV_BanExport((const uint8_t *)VSB_data(vsb), VSB_len(vsb)); |
| 350 |
75456 |
VSB_destroy(&vsb); |
| 351 |
75456 |
VSC_C_main->bans_persisted_bytes = |
| 352 |
75456 |
bans_persisted_bytes = ln; |
| 353 |
75456 |
VSC_C_main->bans_persisted_fragmentation = |
| 354 |
75456 |
bans_persisted_fragmentation = 0; |
| 355 |
75456 |
} |
| 356 |
|
|
| 357 |
|
/* |
| 358 |
|
* For both of these we do a full export on info failure to remove |
| 359 |
|
* holes in the exported list. |
| 360 |
|
* XXX: we should keep track of the size of holes in the last exported list |
| 361 |
|
* XXX: check if the ban_export should be batched in ban_cleantail |
| 362 |
|
*/ |
| 363 |
|
void |
| 364 |
41936 |
ban_info_new(const uint8_t *ban, unsigned len) |
| 365 |
|
{ |
| 366 |
|
/* XXX martin pls review if ban_mtx needs to be held */ |
| 367 |
41936 |
Lck_AssertHeld(&ban_mtx); |
| 368 |
41936 |
if (STV_BanInfoNew(ban, len)) |
| 369 |
0 |
ban_export(); |
| 370 |
41936 |
} |
| 371 |
|
|
| 372 |
|
void |
| 373 |
2881 |
ban_info_drop(const uint8_t *ban, unsigned len) |
| 374 |
|
{ |
| 375 |
|
/* XXX martin pls review if ban_mtx needs to be held */ |
| 376 |
2881 |
Lck_AssertHeld(&ban_mtx); |
| 377 |
2881 |
if (STV_BanInfoDrop(ban, len)) |
| 378 |
0 |
ban_export(); |
| 379 |
2881 |
} |
| 380 |
|
|
| 381 |
|
/*-------------------------------------------------------------------- |
| 382 |
|
* Put a skeleton ban in the list, unless there is an identical, |
| 383 |
|
* time & condition, ban already in place. |
| 384 |
|
* |
| 385 |
|
* If a newer ban has same condition, mark the inserted ban COMPLETED, |
| 386 |
|
* also mark any older bans, with the same condition COMPLETED. |
| 387 |
|
*/ |
| 388 |
|
|
| 389 |
|
static void |
| 390 |
1360 |
ban_reload(const uint8_t *ban, unsigned len) |
| 391 |
|
{ |
| 392 |
|
struct ban *b, *b2; |
| 393 |
1360 |
int duplicate = 0; |
| 394 |
1360 |
vtim_real t0, t1, t2 = 9e99; |
| 395 |
1360 |
ASSERT_CLI(); |
| 396 |
1360 |
Lck_AssertHeld(&ban_mtx); |
| 397 |
1360 |
assert(ban_holds > 0); |
| 398 |
|
|
| 399 |
1360 |
t0 = ban_time(ban); |
| 400 |
1360 |
assert(len == ban_len(ban)); |
| 401 |
|
|
| 402 |
1360 |
b = BANIDX_lookup(t0); |
| 403 |
2400 |
VTAILQ_FOREACH_FROM(b, &ban_head, list) { |
| 404 |
1760 |
t1 = ban_time(b->spec); |
| 405 |
1760 |
assert(t1 < t2); |
| 406 |
1760 |
t2 = t1; |
| 407 |
1760 |
if (t1 == t0) |
| 408 |
320 |
return; |
| 409 |
1440 |
if (t1 < t0) |
| 410 |
400 |
break; |
| 411 |
1040 |
if (ban_equal(b->spec, ban)) |
| 412 |
720 |
duplicate = 1; |
| 413 |
1040 |
} |
| 414 |
|
|
| 415 |
1040 |
VSC_C_main->bans++; |
| 416 |
1040 |
VSC_C_main->bans_added++; |
| 417 |
|
|
| 418 |
1040 |
b2 = ban_alloc(); |
| 419 |
1040 |
AN(b2); |
| 420 |
1040 |
b2->spec = malloc(len); |
| 421 |
1040 |
AN(b2->spec); |
| 422 |
1040 |
memcpy(b2->spec, ban, len); |
| 423 |
1040 |
if (ban[BANS_FLAGS] & BANS_FLAG_REQ) { |
| 424 |
200 |
VSC_C_main->bans_req++; |
| 425 |
200 |
b2->flags |= BANS_FLAG_REQ; |
| 426 |
200 |
} |
| 427 |
1040 |
if (duplicate) |
| 428 |
720 |
VSC_C_main->bans_dups++; |
| 429 |
1040 |
if (duplicate || (ban[BANS_FLAGS] & BANS_FLAG_COMPLETED)) |
| 430 |
760 |
ban_mark_completed(b2); |
| 431 |
1040 |
if (b == NULL) |
| 432 |
640 |
VTAILQ_INSERT_TAIL(&ban_head, b2, list); |
| 433 |
|
else |
| 434 |
400 |
VTAILQ_INSERT_BEFORE(b, b2, list); |
| 435 |
1040 |
bans_persisted_bytes += len; |
| 436 |
1040 |
VSC_C_main->bans_persisted_bytes = bans_persisted_bytes; |
| 437 |
|
|
| 438 |
|
/* Hunt down older duplicates */ |
| 439 |
1640 |
for (b = VTAILQ_NEXT(b2, list); b != NULL; b = VTAILQ_NEXT(b, list)) { |
| 440 |
600 |
if (b->flags & BANS_FLAG_COMPLETED) |
| 441 |
560 |
continue; |
| 442 |
40 |
if (ban_equal(b->spec, ban)) { |
| 443 |
0 |
ban_mark_completed(b); |
| 444 |
0 |
VSC_C_main->bans_dups++; |
| 445 |
0 |
} |
| 446 |
40 |
} |
| 447 |
1360 |
} |
| 448 |
|
|
| 449 |
|
/*-------------------------------------------------------------------- |
| 450 |
|
* Reload a series of persisted ban specs |
| 451 |
|
*/ |
| 452 |
|
|
| 453 |
|
void |
| 454 |
1520 |
BAN_Reload(const uint8_t *ptr, unsigned len) |
| 455 |
|
{ |
| 456 |
|
const uint8_t *pe; |
| 457 |
|
unsigned l; |
| 458 |
|
|
| 459 |
1520 |
AZ(ban_shutdown); |
| 460 |
1520 |
pe = ptr + len; |
| 461 |
1520 |
Lck_Lock(&ban_mtx); |
| 462 |
2880 |
while (ptr < pe) { |
| 463 |
|
/* XXX: This can be optimized by traversing the live |
| 464 |
|
* ban list together with the reload list (combining |
| 465 |
|
* the loops in BAN_Reload and ban_reload). */ |
| 466 |
1360 |
l = ban_len(ptr); |
| 467 |
1360 |
assert(ptr + l <= pe); |
| 468 |
1360 |
ban_reload(ptr, l); |
| 469 |
1360 |
ptr += l; |
| 470 |
|
} |
| 471 |
1520 |
Lck_Unlock(&ban_mtx); |
| 472 |
1520 |
} |
| 473 |
|
|
| 474 |
|
/*-------------------------------------------------------------------- |
| 475 |
|
* Get a bans timestamp |
| 476 |
|
*/ |
| 477 |
|
|
| 478 |
|
vtim_real |
| 479 |
2800 |
BAN_Time(const struct ban *b) |
| 480 |
|
{ |
| 481 |
|
|
| 482 |
2800 |
if (b == NULL) |
| 483 |
880 |
return (0.0); |
| 484 |
|
|
| 485 |
1920 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
| 486 |
1920 |
return (ban_time(b->spec)); |
| 487 |
2800 |
} |
| 488 |
|
|
| 489 |
|
/*-------------------------------------------------------------------- |
| 490 |
|
* Evaluate ban-spec |
| 491 |
|
*/ |
| 492 |
|
|
| 493 |
|
int |
| 494 |
3600 |
ban_evaluate(struct worker *wrk, const uint8_t *bsarg, struct objcore *oc, |
| 495 |
|
const struct http *reqhttp, unsigned *tests) |
| 496 |
|
{ |
| 497 |
|
struct ban_test bt; |
| 498 |
|
const uint8_t *bs, *be; |
| 499 |
|
const char *p; |
| 500 |
|
const char *arg1; |
| 501 |
|
double darg1, darg2; |
| 502 |
|
hdr_t hdr; |
| 503 |
|
int rv; |
| 504 |
|
|
| 505 |
|
/* |
| 506 |
|
* for ttl, age and last_hit, fix the point in time such that banning |
| 507 |
|
* refers to the same point in time when the ban is evaluated |
| 508 |
|
* |
| 509 |
|
* for grace/keep, we assume that the absolute values are pola and that |
| 510 |
|
* users will most likely also specify a ttl criterion if they want to |
| 511 |
|
* fix a point in time (such as "obj.ttl > 5h && obj.keep > 3h") |
| 512 |
|
*/ |
| 513 |
|
|
| 514 |
3600 |
bs = bsarg; |
| 515 |
3600 |
be = bs + ban_len(bs); |
| 516 |
3600 |
bs += BANS_HEAD_LEN; |
| 517 |
6000 |
while (bs < be) { |
| 518 |
4160 |
(*tests)++; |
| 519 |
4160 |
ban_iter(&bs, &bt); |
| 520 |
4160 |
arg1 = NULL; |
| 521 |
4160 |
darg1 = darg2 = nan(""); |
| 522 |
4160 |
switch (bt.arg1) { |
| 523 |
|
case BANS_ARG_URL: |
| 524 |
1080 |
AN(reqhttp); |
| 525 |
1080 |
arg1 = reqhttp->hd[HTTP_HDR_URL].b; |
| 526 |
1080 |
break; |
| 527 |
|
case BANS_ARG_REQHTTP: |
| 528 |
360 |
AN(reqhttp); |
| 529 |
360 |
CAST_HDR(hdr, bt.arg1_spec); |
| 530 |
360 |
(void)http_GetHdr(reqhttp, hdr, &p); |
| 531 |
360 |
arg1 = p; |
| 532 |
360 |
break; |
| 533 |
|
case BANS_ARG_OBJHTTP: |
| 534 |
1280 |
CAST_HDR(hdr, bt.arg1_spec); |
| 535 |
1280 |
arg1 = HTTP_GetHdrPack(wrk, oc, hdr); |
| 536 |
1280 |
break; |
| 537 |
|
case BANS_ARG_OBJSTATUS: |
| 538 |
560 |
arg1 = HTTP_GetHdrPack(wrk, oc, H__Status); |
| 539 |
560 |
break; |
| 540 |
|
case BANS_ARG_OBJTTL: |
| 541 |
200 |
darg1 = oc->ttl + oc->t_origin; |
| 542 |
200 |
darg2 = bt.arg2_double + ban_time(bsarg); |
| 543 |
200 |
break; |
| 544 |
|
case BANS_ARG_OBJAGE: |
| 545 |
200 |
darg1 = 0.0 - oc->t_origin; |
| 546 |
200 |
darg2 = 0.0 - (ban_time(bsarg) - bt.arg2_double); |
| 547 |
200 |
break; |
| 548 |
|
case BANS_ARG_OBJGRACE: |
| 549 |
120 |
darg1 = oc->grace; |
| 550 |
120 |
darg2 = bt.arg2_double; |
| 551 |
120 |
break; |
| 552 |
|
case BANS_ARG_OBJKEEP: |
| 553 |
280 |
darg1 = oc->keep; |
| 554 |
280 |
darg2 = bt.arg2_double; |
| 555 |
280 |
break; |
| 556 |
|
case BANS_ARG_OBJLASTHIT: |
| 557 |
80 |
if (isnan(oc->last_lru)) |
| 558 |
0 |
return (0); |
| 559 |
80 |
darg1 = 0.0 - oc->last_lru; |
| 560 |
80 |
darg2 = 0.0 - (ban_time(bsarg) - bt.arg2_double); |
| 561 |
80 |
break; |
| 562 |
|
default: |
| 563 |
0 |
WRONG("Wrong BAN_ARG code"); |
| 564 |
0 |
} |
| 565 |
|
|
| 566 |
4160 |
switch (bt.oper) { |
| 567 |
|
case BANS_OPER_EQ: |
| 568 |
2240 |
if (arg1 == NULL) { |
| 569 |
440 |
if (isnan(darg1) || darg1 != darg2) |
| 570 |
200 |
return (0); |
| 571 |
2040 |
} else if (strcmp(arg1, bt.arg2)) { |
| 572 |
840 |
return (0); |
| 573 |
|
} |
| 574 |
1200 |
break; |
| 575 |
|
case BANS_OPER_NEQ: |
| 576 |
480 |
if (arg1 == NULL) { |
| 577 |
280 |
if (! isnan(darg1) && darg1 == darg2) |
| 578 |
160 |
return (0); |
| 579 |
320 |
} else if (!strcmp(arg1, bt.arg2)) { |
| 580 |
80 |
return (0); |
| 581 |
|
} |
| 582 |
240 |
break; |
| 583 |
|
case BANS_OPER_MATCH: |
| 584 |
960 |
if (arg1 == NULL) |
| 585 |
40 |
return (0); |
| 586 |
920 |
rv = VRE_match(bt.arg2_spec, arg1, 0, 0, NULL); |
| 587 |
920 |
xxxassert(rv >= -1); |
| 588 |
920 |
if (rv < 0) |
| 589 |
80 |
return (0); |
| 590 |
840 |
break; |
| 591 |
|
case BANS_OPER_NMATCH: |
| 592 |
0 |
if (arg1 == NULL) |
| 593 |
0 |
return (0); |
| 594 |
0 |
rv = VRE_match(bt.arg2_spec, arg1, 0, 0, NULL); |
| 595 |
0 |
xxxassert(rv >= -1); |
| 596 |
0 |
if (rv >= 0) |
| 597 |
0 |
return (0); |
| 598 |
0 |
break; |
| 599 |
|
case BANS_OPER_GT: |
| 600 |
320 |
AZ(arg1); |
| 601 |
320 |
assert(! isnan(darg1)); |
| 602 |
320 |
if (!(darg1 > darg2)) |
| 603 |
320 |
return (0); |
| 604 |
0 |
break; |
| 605 |
|
case BANS_OPER_GTE: |
| 606 |
0 |
AZ(arg1); |
| 607 |
0 |
assert(! isnan(darg1)); |
| 608 |
0 |
if (!(darg1 >= darg2)) |
| 609 |
0 |
return (0); |
| 610 |
0 |
break; |
| 611 |
|
case BANS_OPER_LT: |
| 612 |
120 |
AZ(arg1); |
| 613 |
120 |
assert(! isnan(darg1)); |
| 614 |
120 |
if (!(darg1 < darg2)) |
| 615 |
40 |
return (0); |
| 616 |
80 |
break; |
| 617 |
|
case BANS_OPER_LTE: |
| 618 |
40 |
AZ(arg1); |
| 619 |
40 |
assert(! isnan(darg1)); |
| 620 |
40 |
if (!(darg1 <= darg2)) |
| 621 |
0 |
return (0); |
| 622 |
40 |
break; |
| 623 |
|
default: |
| 624 |
0 |
WRONG("Wrong BAN_OPER code"); |
| 625 |
0 |
} |
| 626 |
|
} |
| 627 |
1840 |
return (1); |
| 628 |
3600 |
} |
| 629 |
|
|
| 630 |
|
/*-------------------------------------------------------------------- |
| 631 |
|
* Check an object against all applicable bans |
| 632 |
|
* |
| 633 |
|
* Return: |
| 634 |
|
* -1 not all bans checked, but none of the checked matched |
| 635 |
|
* Only if !has_req |
| 636 |
|
* 0 No bans matched, object moved to ban_start. |
| 637 |
|
* 1 Ban matched, object removed from ban list. |
| 638 |
|
*/ |
| 639 |
|
|
| 640 |
|
int |
| 641 |
50415 |
BAN_CheckObject(struct worker *wrk, struct objcore *oc, struct req *req) |
| 642 |
|
{ |
| 643 |
|
struct ban *b; |
| 644 |
|
struct vsl_log *vsl; |
| 645 |
|
struct ban *b0, *bn; |
| 646 |
|
unsigned tests; |
| 647 |
|
|
| 648 |
50415 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
| 649 |
50415 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
| 650 |
50415 |
CHECK_OBJ_NOTNULL(req, REQ_MAGIC); |
| 651 |
50415 |
Lck_AssertHeld(&oc->objhead->mtx); |
| 652 |
50415 |
assert(oc->refcnt > 0); |
| 653 |
|
|
| 654 |
50415 |
vsl = req->vsl; |
| 655 |
|
|
| 656 |
50415 |
CHECK_OBJ_NOTNULL(oc->ban, BAN_MAGIC); |
| 657 |
|
|
| 658 |
|
/* First do an optimistic unlocked check */ |
| 659 |
50415 |
b0 = ban_start; |
| 660 |
50415 |
CHECK_OBJ_NOTNULL(b0, BAN_MAGIC); |
| 661 |
|
|
| 662 |
50415 |
if (b0 == oc->ban) |
| 663 |
47975 |
return (0); |
| 664 |
|
|
| 665 |
|
/* If that fails, make a safe check */ |
| 666 |
2440 |
Lck_Lock(&ban_mtx); |
| 667 |
2440 |
b0 = ban_start; |
| 668 |
2440 |
bn = oc->ban; |
| 669 |
2440 |
if (b0 != bn) |
| 670 |
2440 |
bn->refcount++; |
| 671 |
2440 |
Lck_Unlock(&ban_mtx); |
| 672 |
|
|
| 673 |
2440 |
AN(bn); |
| 674 |
|
|
| 675 |
2440 |
if (b0 == bn) |
| 676 |
0 |
return (0); |
| 677 |
|
|
| 678 |
2440 |
AN(b0); |
| 679 |
2440 |
AN(bn); |
| 680 |
|
|
| 681 |
|
/* |
| 682 |
|
* This loop is safe without locks, because we know we hold |
| 683 |
|
* a refcount on a ban somewhere in the list and we do not |
| 684 |
|
* inspect the list past that ban. |
| 685 |
|
*/ |
| 686 |
2440 |
tests = 0; |
| 687 |
4160 |
for (b = b0; b != bn; b = VTAILQ_NEXT(b, list)) { |
| 688 |
3080 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
| 689 |
3080 |
if (b->flags & BANS_FLAG_COMPLETED) |
| 690 |
800 |
continue; |
| 691 |
2280 |
if (ban_evaluate(wrk, b->spec, oc, req->http, &tests)) |
| 692 |
1360 |
break; |
| 693 |
920 |
} |
| 694 |
|
|
| 695 |
2440 |
Lck_Lock(&ban_mtx); |
| 696 |
2440 |
bn->refcount--; |
| 697 |
2440 |
VSC_C_main->bans_tested++; |
| 698 |
2440 |
VSC_C_main->bans_tests_tested += tests; |
| 699 |
|
|
| 700 |
2440 |
if (b == bn) { |
| 701 |
|
/* not banned */ |
| 702 |
1080 |
oc->ban->refcount--; |
| 703 |
1080 |
VTAILQ_REMOVE(&oc->ban->objcore, oc, ban_list); |
| 704 |
1080 |
VTAILQ_INSERT_TAIL(&b0->objcore, oc, ban_list); |
| 705 |
1080 |
b0->refcount++; |
| 706 |
1080 |
oc->ban = b0; |
| 707 |
1080 |
b = NULL; |
| 708 |
1080 |
} |
| 709 |
2440 |
if (b != NULL) |
| 710 |
1360 |
VSC_C_main->bans_obj_killed++; |
| 711 |
|
|
| 712 |
2440 |
if (VTAILQ_LAST(&ban_head, banhead_s)->refcount == 0) |
| 713 |
880 |
ban_kick_lurker(); |
| 714 |
|
|
| 715 |
2440 |
Lck_Unlock(&ban_mtx); |
| 716 |
|
|
| 717 |
2440 |
if (b == NULL) { |
| 718 |
|
/* not banned */ |
| 719 |
1080 |
ObjSendEvent(wrk, oc, OEV_BANCHG); |
| 720 |
1080 |
return (0); |
| 721 |
|
} else { |
| 722 |
2720 |
VSLb(vsl, SLT_ExpBan, |
| 723 |
1360 |
"%ju banned lookup", VXID(ObjGetXID(wrk, oc))); |
| 724 |
1360 |
return (1); |
| 725 |
|
} |
| 726 |
50415 |
} |
| 727 |
|
|
| 728 |
|
/*-------------------------------------------------------------------- |
| 729 |
|
* CLI functions to add bans |
| 730 |
|
*/ |
| 731 |
|
|
| 732 |
|
static void v_matchproto_(cli_func_t) |
| 733 |
3680 |
ccf_ban(struct cli *cli, const char * const *av, void *priv) |
| 734 |
|
{ |
| 735 |
|
int narg, i; |
| 736 |
|
struct ban_proto *bp; |
| 737 |
3680 |
const char *err = NULL; |
| 738 |
|
|
| 739 |
3680 |
(void)priv; |
| 740 |
|
|
| 741 |
|
/* First do some cheap checks on the arguments */ |
| 742 |
16520 |
for (narg = 0; av[narg + 2] != NULL; narg++) |
| 743 |
12840 |
continue; |
| 744 |
3680 |
if ((narg % 4) != 3) { |
| 745 |
80 |
VCLI_Out(cli, "Wrong number of arguments"); |
| 746 |
80 |
VCLI_SetResult(cli, CLIS_PARAM); |
| 747 |
80 |
return; |
| 748 |
|
} |
| 749 |
3960 |
for (i = 3; i < narg; i += 4) { |
| 750 |
400 |
if (strcmp(av[i + 2], "&&")) { |
| 751 |
40 |
VCLI_Out(cli, "Found \"%s\" expected &&", av[i + 2]); |
| 752 |
40 |
VCLI_SetResult(cli, CLIS_PARAM); |
| 753 |
40 |
return; |
| 754 |
|
} |
| 755 |
360 |
} |
| 756 |
|
|
| 757 |
3560 |
bp = BAN_Build(); |
| 758 |
3560 |
if (bp == NULL) { |
| 759 |
0 |
VCLI_Out(cli, "Out of Memory"); |
| 760 |
0 |
VCLI_SetResult(cli, CLIS_CANT); |
| 761 |
0 |
return; |
| 762 |
|
} |
| 763 |
7200 |
for (i = 0; i < narg; i += 4) { |
| 764 |
3920 |
err = BAN_AddTest(bp, av[i + 2], av[i + 3], av[i + 4]); |
| 765 |
3920 |
if (err) |
| 766 |
280 |
break; |
| 767 |
3640 |
} |
| 768 |
|
|
| 769 |
3560 |
if (err == NULL) { |
| 770 |
|
// XXX racy - grab wstat lock? |
| 771 |
3280 |
err = BAN_Commit(bp); |
| 772 |
3280 |
} |
| 773 |
|
|
| 774 |
3560 |
if (err != NULL) { |
| 775 |
280 |
VCLI_Out(cli, "%s", err); |
| 776 |
280 |
BAN_Abandon(bp); |
| 777 |
280 |
VCLI_SetResult(cli, CLIS_PARAM); |
| 778 |
280 |
} |
| 779 |
3680 |
} |
| 780 |
|
|
| 781 |
|
#define Ms 60 |
| 782 |
|
#define Hs (Ms * 60) |
| 783 |
|
#define Ds (Hs * 24) |
| 784 |
|
#define Ws (Ds * 7) |
| 785 |
|
#define Ys (Ds * 365) |
| 786 |
|
|
| 787 |
|
#define Xfmt(buf, var, s, unit) \ |
| 788 |
|
((var) >= s && (var) % s == 0) \ |
| 789 |
|
bprintf((buf), "%ju" unit, (var) / s) |
| 790 |
|
|
| 791 |
|
// XXX move to VTIM? |
| 792 |
|
#define vdur_render(buf, dur) do { \ |
| 793 |
|
uintmax_t dec = (uintmax_t)floor(dur); \ |
| 794 |
|
uintmax_t frac = (uintmax_t)floor((dur) * 1e3) % UINTMAX_C(1000); \ |
| 795 |
|
if (dec == 0 && frac == 0) \ |
| 796 |
|
(void) strncpy(buf, "0s", sizeof(buf)); \ |
| 797 |
|
else if (dec == 0) \ |
| 798 |
|
bprintf((buf), "%jums", frac); \ |
| 799 |
|
else if (frac != 0) \ |
| 800 |
|
bprintf((buf), "%ju.%03jus", dec, frac); \ |
| 801 |
|
else if Xfmt(buf, dec, Ys, "y"); \ |
| 802 |
|
else if Xfmt(buf, dec, Ws, "w"); \ |
| 803 |
|
else if Xfmt(buf, dec, Ds, "d"); \ |
| 804 |
|
else if Xfmt(buf, dec, Hs, "h"); \ |
| 805 |
|
else if Xfmt(buf, dec, Ms, "m"); \ |
| 806 |
|
else \ |
| 807 |
|
bprintf((buf), "%jus", dec); \ |
| 808 |
|
} while (0) |
| 809 |
|
|
| 810 |
|
static void |
| 811 |
12960 |
ban_render(struct cli *cli, const uint8_t *bs, int quote) |
| 812 |
|
{ |
| 813 |
|
struct ban_test bt; |
| 814 |
|
const uint8_t *be; |
| 815 |
|
char buf[64]; |
| 816 |
|
|
| 817 |
12960 |
be = bs + ban_len(bs); |
| 818 |
12960 |
bs += BANS_HEAD_LEN; |
| 819 |
23320 |
while (bs < be) { |
| 820 |
10360 |
ban_iter(&bs, &bt); |
| 821 |
10360 |
ASSERT_BAN_ARG(bt.arg1); |
| 822 |
10360 |
ASSERT_BAN_OPER(bt.oper); |
| 823 |
|
|
| 824 |
10360 |
if (BANS_HAS_ARG1_SPEC(bt.arg1)) |
| 825 |
4880 |
VCLI_Out(cli, "%s%.*s", |
| 826 |
2440 |
arg_name[BAN_ARGIDX(bt.arg1)], |
| 827 |
2440 |
bt.arg1_spec[0] - 1, bt.arg1_spec + 1); |
| 828 |
|
else |
| 829 |
7920 |
VCLI_Out(cli, "%s", arg_name[BAN_ARGIDX(bt.arg1)]); |
| 830 |
|
|
| 831 |
10360 |
VCLI_Out(cli, " %s ", ban_oper[BAN_OPERIDX(bt.oper)]); |
| 832 |
|
|
| 833 |
10360 |
if (BANS_HAS_ARG2_DOUBLE(bt.arg1)) { |
| 834 |
10440 |
vdur_render(buf, bt.arg2_double); |
| 835 |
5400 |
VCLI_Out(cli, "%s", buf); |
| 836 |
10360 |
} else if (quote) { |
| 837 |
520 |
VCLI_Quote(cli, bt.arg2); |
| 838 |
520 |
} else { |
| 839 |
4440 |
VCLI_Out(cli, "%s", bt.arg2); |
| 840 |
|
} |
| 841 |
|
|
| 842 |
10360 |
if (bs < be) |
| 843 |
1000 |
VCLI_Out(cli, " && "); |
| 844 |
|
} |
| 845 |
12960 |
} |
| 846 |
|
|
| 847 |
|
static void |
| 848 |
2920 |
ban_list(struct cli *cli, struct ban *bl) |
| 849 |
|
{ |
| 850 |
|
struct ban *b; |
| 851 |
|
int64_t o; |
| 852 |
|
|
| 853 |
2920 |
VCLI_Out(cli, "Present bans:\n"); |
| 854 |
14880 |
VTAILQ_FOREACH(b, &ban_head, list) { |
| 855 |
11960 |
o = bl == b ? 1 : 0; |
| 856 |
23920 |
VCLI_Out(cli, "%10.6f %5ju %s", ban_time(b->spec), |
| 857 |
11960 |
(intmax_t)(b->refcount - o), |
| 858 |
11960 |
b->flags & BANS_FLAG_COMPLETED ? "C" : "-"); |
| 859 |
11960 |
if (DO_DEBUG(DBG_LURKER)) { |
| 860 |
3760 |
VCLI_Out(cli, "%s%s %p ", |
| 861 |
1880 |
b->flags & BANS_FLAG_REQ ? "R" : "-", |
| 862 |
1880 |
b->flags & BANS_FLAG_OBJ ? "O" : "-", |
| 863 |
1880 |
b); |
| 864 |
1880 |
} |
| 865 |
11960 |
VCLI_Out(cli, " "); |
| 866 |
11960 |
ban_render(cli, b->spec, 0); |
| 867 |
11960 |
VCLI_Out(cli, "\n"); |
| 868 |
11960 |
if (VCLI_Overflow(cli)) |
| 869 |
0 |
break; |
| 870 |
11960 |
if (DO_DEBUG(DBG_LURKER)) { |
| 871 |
1880 |
Lck_Lock(&ban_mtx); |
| 872 |
|
struct objcore *oc; |
| 873 |
3160 |
VTAILQ_FOREACH(oc, &b->objcore, ban_list) |
| 874 |
1280 |
VCLI_Out(cli, " oc = %p\n", oc); |
| 875 |
1880 |
Lck_Unlock(&ban_mtx); |
| 876 |
1880 |
} |
| 877 |
11960 |
} |
| 878 |
2920 |
} |
| 879 |
|
|
| 880 |
|
static void |
| 881 |
240 |
ban_list_json(struct cli *cli, const char * const *av, struct ban *bl) |
| 882 |
|
{ |
| 883 |
|
struct ban *b; |
| 884 |
|
int64_t o; |
| 885 |
240 |
int n = 0; |
| 886 |
|
int ocs; |
| 887 |
|
|
| 888 |
240 |
VCLI_JSON_begin(cli, 2, av); |
| 889 |
240 |
VCLI_Out(cli, ",\n"); |
| 890 |
1240 |
VTAILQ_FOREACH(b, &ban_head, list) { |
| 891 |
1000 |
o = bl == b ? 1 : 0; |
| 892 |
1000 |
VCLI_Out(cli, "%s", n ? ",\n" : ""); |
| 893 |
1000 |
n++; |
| 894 |
1000 |
VCLI_Out(cli, "{\n"); |
| 895 |
1000 |
VSB_indent(cli->sb, 2); |
| 896 |
1000 |
VCLI_Out(cli, "\"time\": %.6f,\n", ban_time(b->spec)); |
| 897 |
1000 |
VCLI_Out(cli, "\"refs\": %ju,\n", (intmax_t)(b->refcount - o)); |
| 898 |
2000 |
VCLI_Out(cli, "\"completed\": %s,\n", |
| 899 |
1000 |
b->flags & BANS_FLAG_COMPLETED ? "true" : "false"); |
| 900 |
1000 |
VCLI_Out(cli, "\"spec\": \""); |
| 901 |
1000 |
ban_render(cli, b->spec, 1); |
| 902 |
1000 |
VCLI_Out(cli, "\""); |
| 903 |
|
|
| 904 |
1000 |
if (DO_DEBUG(DBG_LURKER)) { |
| 905 |
240 |
VCLI_Out(cli, ",\n"); |
| 906 |
480 |
VCLI_Out(cli, "\"req_tests\": %s,\n", |
| 907 |
240 |
b->flags & BANS_FLAG_REQ ? "true" : "false"); |
| 908 |
480 |
VCLI_Out(cli, "\"obj_tests\": %s,\n", |
| 909 |
240 |
b->flags & BANS_FLAG_OBJ ? "true" : "false"); |
| 910 |
240 |
VCLI_Out(cli, "\"pointer\": \"%p\",\n", b); |
| 911 |
240 |
if (VCLI_Overflow(cli)) |
| 912 |
0 |
break; |
| 913 |
|
|
| 914 |
240 |
ocs = 0; |
| 915 |
240 |
VCLI_Out(cli, "\"objcores\": [\n"); |
| 916 |
240 |
VSB_indent(cli->sb, 2); |
| 917 |
240 |
Lck_Lock(&ban_mtx); |
| 918 |
|
struct objcore *oc; |
| 919 |
240 |
VTAILQ_FOREACH(oc, &b->objcore, ban_list) { |
| 920 |
0 |
if (ocs) |
| 921 |
0 |
VCLI_Out(cli, ",\n"); |
| 922 |
0 |
VCLI_Out(cli, "%p", oc); |
| 923 |
0 |
ocs++; |
| 924 |
0 |
} |
| 925 |
240 |
Lck_Unlock(&ban_mtx); |
| 926 |
240 |
VSB_indent(cli->sb, -2); |
| 927 |
240 |
VCLI_Out(cli, "\n]"); |
| 928 |
240 |
} |
| 929 |
1000 |
VSB_indent(cli->sb, -2); |
| 930 |
1000 |
VCLI_Out(cli, "\n}"); |
| 931 |
1000 |
} |
| 932 |
240 |
VCLI_JSON_end(cli); |
| 933 |
240 |
} |
| 934 |
|
|
| 935 |
|
static void v_matchproto_(cli_func_t) |
| 936 |
3160 |
ccf_ban_list(struct cli *cli, const char * const *av, void *priv) |
| 937 |
|
{ |
| 938 |
|
struct ban *bl; |
| 939 |
|
|
| 940 |
3160 |
(void)priv; |
| 941 |
|
|
| 942 |
|
/* Get a reference so we are safe to traverse the list */ |
| 943 |
3160 |
Lck_Lock(&ban_mtx); |
| 944 |
3160 |
bl = VTAILQ_LAST(&ban_head, banhead_s); |
| 945 |
3160 |
bl->refcount++; |
| 946 |
3160 |
Lck_Unlock(&ban_mtx); |
| 947 |
|
|
| 948 |
3160 |
if (av[2] != NULL && strcmp(av[2], "-j") == 0) |
| 949 |
240 |
ban_list_json(cli, av, bl); |
| 950 |
|
else |
| 951 |
2920 |
ban_list(cli, bl); |
| 952 |
|
|
| 953 |
3160 |
Lck_Lock(&ban_mtx); |
| 954 |
3160 |
bl->refcount--; |
| 955 |
3160 |
ban_kick_lurker(); // XXX: Mostly for testcase b00009.vtc |
| 956 |
3160 |
Lck_Unlock(&ban_mtx); |
| 957 |
3160 |
} |
| 958 |
|
|
| 959 |
|
static struct cli_proto ban_cmds[] = { |
| 960 |
|
{ CLICMD_BAN, "", ccf_ban }, |
| 961 |
|
{ CLICMD_BAN_LIST, "", ccf_ban_list, |
| 962 |
|
ccf_ban_list }, |
| 963 |
|
{ NULL } |
| 964 |
|
}; |
| 965 |
|
|
| 966 |
|
/*-------------------------------------------------------------------- |
| 967 |
|
*/ |
| 968 |
|
|
| 969 |
|
void |
| 970 |
37936 |
BAN_Compile(void) |
| 971 |
|
{ |
| 972 |
|
struct ban *b; |
| 973 |
|
|
| 974 |
|
/* |
| 975 |
|
* All bans have been read from all persistent stevedores. Export |
| 976 |
|
* the compiled list |
| 977 |
|
*/ |
| 978 |
|
|
| 979 |
37936 |
ASSERT_CLI(); |
| 980 |
37936 |
AZ(ban_shutdown); |
| 981 |
|
|
| 982 |
37936 |
Lck_Lock(&ban_mtx); |
| 983 |
|
|
| 984 |
|
/* Report the place-holder ban */ |
| 985 |
37936 |
b = VTAILQ_FIRST(&ban_head); |
| 986 |
37936 |
ban_info_new(b->spec, ban_len(b->spec)); |
| 987 |
|
|
| 988 |
37936 |
ban_export(); |
| 989 |
|
|
| 990 |
37936 |
Lck_Unlock(&ban_mtx); |
| 991 |
|
|
| 992 |
37936 |
ban_start = VTAILQ_FIRST(&ban_head); |
| 993 |
37936 |
BAN_Release(); |
| 994 |
37936 |
} |
| 995 |
|
|
| 996 |
|
void |
| 997 |
38016 |
BAN_Init(void) |
| 998 |
|
{ |
| 999 |
|
struct ban_proto *bp; |
| 1000 |
|
|
| 1001 |
38016 |
BAN_Build_Init(); |
| 1002 |
38016 |
Lck_New(&ban_mtx, lck_ban); |
| 1003 |
38016 |
CLI_AddFuncs(ban_cmds); |
| 1004 |
|
|
| 1005 |
38016 |
ban_holds = 1; |
| 1006 |
|
|
| 1007 |
|
/* Add a placeholder ban */ |
| 1008 |
38016 |
bp = BAN_Build(); |
| 1009 |
38016 |
AN(bp); |
| 1010 |
38016 |
PTOK(pthread_cond_init(&ban_lurker_cond, NULL)); |
| 1011 |
38016 |
AZ(BAN_Commit(bp)); |
| 1012 |
38016 |
Lck_Lock(&ban_mtx); |
| 1013 |
38016 |
ban_mark_completed(VTAILQ_FIRST(&ban_head)); |
| 1014 |
38016 |
Lck_Unlock(&ban_mtx); |
| 1015 |
38016 |
} |
| 1016 |
|
|
| 1017 |
|
/*-------------------------------------------------------------------- |
| 1018 |
|
* Shutdown of the ban system. |
| 1019 |
|
* |
| 1020 |
|
* When this function returns, no new bans will be accepted, and no |
| 1021 |
|
* bans will be dropped (ban lurker thread stopped), so that no |
| 1022 |
|
* STV_BanInfo calls will be executed. |
| 1023 |
|
*/ |
| 1024 |
|
|
| 1025 |
|
void |
| 1026 |
37520 |
BAN_Shutdown(void) |
| 1027 |
|
{ |
| 1028 |
|
void *status; |
| 1029 |
|
|
| 1030 |
37520 |
Lck_Lock(&ban_mtx); |
| 1031 |
37520 |
ban_shutdown = 1; |
| 1032 |
37520 |
ban_kick_lurker(); |
| 1033 |
37520 |
Lck_Unlock(&ban_mtx); |
| 1034 |
|
|
| 1035 |
37520 |
PTOK(pthread_join(ban_thread, &status)); |
| 1036 |
37520 |
AZ(status); |
| 1037 |
|
|
| 1038 |
37520 |
Lck_Lock(&ban_mtx); |
| 1039 |
|
/* Export the ban list to compact it */ |
| 1040 |
37520 |
ban_export(); |
| 1041 |
37520 |
Lck_Unlock(&ban_mtx); |
| 1042 |
|
|
| 1043 |
37520 |
BAN_Build_Fini(); |
| 1044 |
37520 |
} |