varnish-cache/lib/libvarnishapi/vsm.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
 * Author: Martin Blix Grydeland <martin@varnish-software.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
#include "config.h"
33
34
#include <sys/mman.h>
35
#include <sys/stat.h>
36
37
#include <fcntl.h>
38
#include <float.h>
39
#include <math.h>
40
#include <stdarg.h>
41
#include <stdint.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <string.h>
45
#include <unistd.h>
46
47
#include "vdef.h"
48
#include "vas.h"
49
#include "miniobj.h"
50
51
#include "vav.h"
52
#include "vin.h"
53
#include "vlu.h"
54
#include "vsb.h"
55
#include "vsm_priv.h"
56
#include "vqueue.h"
57
#include "vtim.h"
58
59
#include "vapi/vsig.h"
60
#include "vapi/vsm.h"
61
62
#ifndef MAP_HASSEMAPHORE
63
#  define MAP_HASSEMAPHORE 0 /* XXX Linux */
64
#endif
65
66
#ifndef MAP_NOSYNC
67
#  define MAP_NOSYNC 0 /* XXX Linux */
68
#endif
69
70
const struct vsm_valid VSM_invalid[1] = {{"invalid"}};
71
const struct vsm_valid VSM_valid[1] = {{"valid"}};
72
73
static vlu_f vsm_vlu_func;
74
75
#define VSM_PRIV_SHIFT                                                  \
76
        (sizeof (uint64_t) * 4)
77
#define VSM_PRIV_MASK                                                   \
78
        ((1ULL << VSM_PRIV_SHIFT) - 1)
79
#define VSM_PRIV_LOW(u)                                                 \
80
        ((uint64_t)(u) & VSM_PRIV_MASK)
81
#define VSM_PRIV_HIGH(u)                                                \
82
        (((uint64_t)(u) >> VSM_PRIV_SHIFT) & VSM_PRIV_MASK)
83
#define VSM_PRIV_MERGE(low, high)                                       \
84
        (VSM_PRIV_LOW(low) | (VSM_PRIV_LOW(high) << VSM_PRIV_SHIFT))
85
86
/*--------------------------------------------------------------------*/
87
88
struct vsm_set;
89
90
struct vsm_seg {
91
        unsigned                magic;
92
#define VSM_SEG_MAGIC           0xeb6c6dfd
93
        unsigned                flags;
94
#define VSM_FLAG_MARKSCAN       (1U<<1)
95
#define VSM_FLAG_STALE          (1U<<2)
96
#define VSM_FLAG_CLUSTER        (1U<<3)
97
        VTAILQ_ENTRY(vsm_seg)   list;
98
        VTAILQ_ENTRY(vsm_seg)   clist;
99
        struct vsm_set          *set;
100
        struct vsm_seg          *cluster;
101
        char                    **av;
102
        int                     refs;
103
        void                    *s;
104
        size_t                  sz;
105
        void                    *b;
106
        void                    *e;
107
        uint64_t                serial;
108
};
109
110
struct vsm_set {
111
        unsigned                magic;
112
#define VSM_SET_MAGIC           0xdee401b8
113
        const char              *dname;
114
        struct vsm              *vsm;
115
        VTAILQ_HEAD(,vsm_seg)   segs;
116
        VTAILQ_HEAD(,vsm_seg)   stale;
117
        VTAILQ_HEAD(,vsm_seg)   clusters;
118
119
        int                     dfd;
120
        struct stat             dst;
121
122
        int                     fd;
123
        struct stat             fst;
124
125
        uintmax_t               id1, id2;
126
127
        // _.index reading state
128
        struct vlu              *vlu;
129
        unsigned                retval;
130
        struct vsm_seg          *vg;
131
132
        unsigned                flag_running;
133
        unsigned                flag_changed;
134
        unsigned                flag_restarted;
135
};
136
137
struct vsm {
138
        unsigned                magic;
139
#define VSM_MAGIC               0x6e3bd69b
140
141
        struct vsb              *diag;
142
        uint64_t                serial;
143
144
        int                     wdfd;
145
        struct stat             wdst;
146
        char                    *wdname;
147
148
        struct vsm_set          *mgt;
149
        struct vsm_set          *child;
150
151
        int                     attached;
152
        double                  patience;
153
};
154
155
/*--------------------------------------------------------------------*/
156
157
static int
158 977
vsm_diag(struct vsm *vd, const char *fmt, ...)
159
{
160
        va_list ap;
161
162 977
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
163 977
        AN(fmt);
164
165 977
        if (vd->diag == NULL)
166 977
                vd->diag = VSB_new_auto();
167 977
        AN(vd->diag);
168 977
        VSB_clear(vd->diag);
169 977
        va_start(ap, fmt);
170 977
        VSB_vprintf(vd->diag, fmt, ap);
171 977
        va_end(ap);
172 977
        AZ(VSB_finish(vd->diag));
173 977
        return (-1);
174
}
175
176
/*--------------------------------------------------------------------*/
177
178
static int
179 128407
vsm_mapseg(struct vsm *vd, struct vsm_seg *vg)
180
{
181
        size_t of, off, sz, ps, len;
182
        struct vsb *vsb;
183
        int fd;
184
185 128407
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
186
187 128407
        if (vg->s != NULL)
188 2500
                return (0);
189
190 125907
        ps = getpagesize();
191
192 125907
        of = strtoul(vg->av[2], NULL, 10);
193 125907
        off = RDN2(of, ps);
194
195 125907
        if (vg->flags & VSM_FLAG_CLUSTER)
196 1851
                assert(of == 0);
197 125907
        assert(vg->cluster == NULL);
198
199 125907
        sz = strtoul(vg->av[3], NULL, 10);
200 125907
        assert(sz > 0);
201 125907
        assert(of >= off);
202 125907
        len = RUP2((of - off) + sz, ps);
203
204 125907
        vsb = VSB_new_auto();
205 125907
        AN(vsb);
206 125907
        VSB_printf(vsb, "%s/%s/%s", vd->wdname, vg->set->dname, vg->av[1]);
207 125907
        AZ(VSB_finish(vsb));
208
209 125907
        fd = open(VSB_data(vsb), O_RDONLY);     // XXX: openat
210 125907
        if (fd < 0) {
211 0
                VSB_destroy(&vsb);
212 0
                return (vsm_diag(vd, "Could not open segment"));
213
        }
214
215 251814
        vg->s = (void*)mmap(NULL, len,
216
            PROT_READ,
217
            MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED,
218 125907
            fd, (off_t)off);
219
220 125907
        VSB_destroy(&vsb);
221
222 125907
        closefd(&fd);
223 125907
        if (vg->s == MAP_FAILED)
224 0
                return (vsm_diag(vd, "Could not mmap segment"));
225
226 125907
        vg->b = (char*)(vg->s) + of - off;
227 125907
        vg->e = (char *)vg->b + sz;
228 125907
        vg->sz = len;
229
230 125907
        return (0);
231 128407
}
232
233
static void
234 111657
vsm_unmapseg(struct vsm_seg *vg)
235
{
236
237 111657
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
238
239 111657
        AN(vg->b);
240 111657
        AN(vg->e);
241 111657
        AZ(munmap(vg->s, vg->sz));
242 111657
        vg->s = vg->b = vg->e = NULL;
243 111657
        vg->sz = 0;
244 111657
}
245
246
/*--------------------------------------------------------------------*/
247
248
static void
249 1707393
vsm_delseg(struct vsm_seg *vg, int refsok)
250
{
251
252 1707393
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
253
254 1707393
        if (vg->set->vg == vg) {
255 172351
                AZ(vg->flags & VSM_FLAG_STALE);
256 172351
                vg->set->vg = VTAILQ_NEXT(vg, list);
257 172351
        }
258
259 1707393
        if (refsok && vg->refs) {
260 3701
                AZ(vg->flags & VSM_FLAG_STALE);
261 3701
                vg->flags |= VSM_FLAG_STALE;
262 3701
                VTAILQ_REMOVE(&vg->set->segs, vg, list);
263 3701
                VTAILQ_INSERT_TAIL(&vg->set->stale, vg, list);
264 3701
                return;
265
        }
266
267 1703692
        if (vg->s != NULL)
268 0
                vsm_unmapseg(vg);
269
270 1703692
        if (vg->flags & VSM_FLAG_CLUSTER) {
271 44975
                vg->flags &= ~VSM_FLAG_CLUSTER;
272 44975
                VTAILQ_REMOVE(&vg->set->clusters, vg, clist);
273 44975
        }
274
275 1703692
        if (vg->flags & VSM_FLAG_STALE)
276 3701
                VTAILQ_REMOVE(&vg->set->stale, vg, list);
277
        else
278 1699991
                VTAILQ_REMOVE(&vg->set->segs, vg, list);
279 1703692
        VAV_Free(vg->av);
280 1703692
        FREE_OBJ(vg);
281 1707393
}
282
283
/*--------------------------------------------------------------------*/
284
285
static struct vsm_set *
286 107850
vsm_newset(const char *dirname)
287
{
288
        struct vsm_set *vs;
289
290 107850
        ALLOC_OBJ(vs, VSM_SET_MAGIC);
291 107850
        AN(vs);
292 107850
        VTAILQ_INIT(&vs->segs);
293 107850
        VTAILQ_INIT(&vs->stale);
294 107850
        VTAILQ_INIT(&vs->clusters);
295 107850
        vs->dname = dirname;
296 107850
        vs->dfd = vs->fd = -1;
297 107850
        vs->vlu = VLU_New(vsm_vlu_func, vs, 0);
298 107850
        AN(vs->vlu);
299 107850
        return (vs);
300
}
301
302
static void
303 106550
vsm_delset(struct vsm_set **p)
304
{
305
        struct vsm_set *vs;
306
        struct vsm_seg *vg;
307
308 106550
        TAKE_OBJ_NOTNULL(vs, p, VSM_SET_MAGIC);
309
310 106550
        if (vs->fd >= 0)
311 64883
                closefd(&vs->fd);
312 106550
        if (vs->dfd >= 0)
313 87500
                closefd(&vs->dfd);
314 106550
        while ((vg = VTAILQ_FIRST(&vs->stale)) != NULL) {
315 0
                AN(vg->flags & VSM_FLAG_STALE);
316 0
                vsm_delseg(vg, 0);
317
        }
318 1714375
        while ((vg = VTAILQ_FIRST(&vs->segs)) != NULL) {
319 1607825
                AZ(vg->flags & VSM_FLAG_STALE);
320 1607825
                vsm_delseg(vg, 0);
321
        }
322 106550
        assert(VTAILQ_EMPTY(&vs->clusters));
323 106550
        VLU_Destroy(&vs->vlu);
324 106550
        FREE_OBJ(vs);
325 106550
}
326
327
static void
328 236792
vsm_wash_set(const struct vsm_set *vs, int all)
329
{
330
        struct vsm_seg *vg, *vg2;
331
332 1872366
        VTAILQ_FOREACH_SAFE(vg, &vs->segs, list, vg2) {
333 1635574
                if (all || (vg->flags & VSM_FLAG_MARKSCAN) == 0)
334 49997
                        vsm_delseg(vg, 1);
335 1635574
        }
336 236792
}
337
338
/*--------------------------------------------------------------------*/
339
340
struct vsm *
341 53925
VSM_New(void)
342
{
343
        struct vsm *vd;
344
345 53925
        ALLOC_OBJ(vd, VSM_MAGIC);
346 53925
        AN(vd);
347
348 53925
        vd->mgt = vsm_newset(VSM_MGT_DIRNAME);
349 53925
        vd->mgt->flag_running = VSM_MGT_RUNNING;
350 53925
        vd->mgt->flag_changed = VSM_MGT_CHANGED;
351 53925
        vd->mgt->flag_restarted = VSM_MGT_RESTARTED;
352
353 53925
        vd->child = vsm_newset(VSM_CHILD_DIRNAME);
354 53925
        vd->child->flag_running = VSM_WRK_RUNNING;
355 53925
        vd->child->flag_changed = VSM_WRK_CHANGED;
356 53925
        vd->child->flag_restarted = VSM_WRK_RESTARTED;
357
358 53925
        vd->mgt->vsm = vd;
359 53925
        vd->child->vsm = vd;
360 53925
        vd->wdfd = -1;
361 53925
        vd->patience = 5;
362 53925
        return (vd);
363
}
364
365
/*--------------------------------------------------------------------*/
366
367
int
368 54925
VSM_Arg(struct vsm *vd, char flag, const char *arg)
369
{
370 54925
        char *p = NULL;
371
372 54925
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
373
374 54925
        if (arg == NULL)
375 950
                return (1);
376 53975
        switch (flag) {
377
        case 't':
378 300
                if (!strcasecmp(arg, "off")) {
379 0
                        vd->patience = -1;
380 0
                } else {
381 300
                        vd->patience = strtod(arg, &p);
382 475
                        if ((p != NULL && *p != '\0') ||
383 175
                            !isfinite(vd->patience) || vd->patience < 0)
384 350
                                return (vsm_diag(vd,
385 175
                                    "-t: Invalid argument: %s", arg));
386
                }
387 125
                break;
388
        case 'n':
389 53675
                if (vd->wdname != NULL)
390 0
                        free(vd->wdname);
391 53675
                vd->wdname = VIN_n_Arg(arg);
392 53675
                if (vd->wdname == NULL)
393 0
                        return (vsm_diag(vd, "Invalid instance name: %s",
394 0
                            strerror(errno)));
395 53675
                break;
396
        default:
397 0
                return (vsm_diag(vd, "Unknown VSM_Arg('%c')", flag));
398
        }
399 53800
        return (1);
400 54925
}
401
402
/*--------------------------------------------------------------------*/
403
404
void
405 53275
VSM_Destroy(struct vsm **vdp)
406
{
407
        struct vsm *vd;
408
409 53275
        TAKE_OBJ_NOTNULL(vd, vdp, VSM_MAGIC);
410
411 53275
        VSM_ResetError(vd);
412 53275
        REPLACE(vd->wdname, NULL);
413 53275
        if (vd->diag != NULL)
414 0
                VSB_destroy(&vd->diag);
415 53275
        if (vd->wdfd >= 0)
416 53225
                closefd(&vd->wdfd);
417 53275
        vsm_delset(&vd->mgt);
418 53275
        vsm_delset(&vd->child);
419 53275
        FREE_OBJ(vd);
420 53275
}
421
422
/*--------------------------------------------------------------------*/
423
424
const char *
425 250
VSM_Error(const struct vsm *vd)
426
{
427
428 250
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
429
430 250
        if (vd->diag == NULL)
431 0
                return ("No VSM error");
432
        else
433 250
                return (VSB_data(vd->diag));
434 250
}
435
436
/*--------------------------------------------------------------------*/
437
438
void
439 107652
VSM_ResetError(struct vsm *vd)
440
{
441
442 107652
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
443
444 107652
        if (vd->diag == NULL)
445 106875
                return;
446 777
        VSB_destroy(&vd->diag);
447 107652
}
448
449
/*--------------------------------------------------------------------
450
 */
451
452
static int
453 3124267
vsm_cmp_av(char * const *a1, char * const *a2)
454
{
455
456 3317907
        while (1) {
457 3317907
                if (*a1 == NULL && *a2 == NULL)
458 47052
                        return (0);
459 3270855
                if (*a1 == NULL || *a2 == NULL)
460 0
                        return (1);
461 3270855
                if (strcmp(*a1, *a2))
462 3077215
                        return (1);
463 193640
                a1++;
464 193640
                a2++;
465
        }
466 3124267
}
467
468
static struct vsm_seg *
469 49400
vsm_findcluster(const struct vsm_set *vs, const char *cnam)
470
{
471
        struct vsm_seg *vg;
472 49400
        AN(vs);
473 49400
        AN(cnam);
474 68637
        VTAILQ_FOREACH(vg, &vs->clusters, clist) {
475 68637
                AN(vg->av[1]);
476 68637
                if (!strcmp(cnam, vg->av[1]))
477 49400
                        return (vg);
478 19237
        }
479 0
        return (NULL);
480 49400
}
481
482
static int
483 89572
vsm_vlu_hash(struct vsm *vd, struct vsm_set *vs, const char *line)
484
{
485
        int i;
486
        uintmax_t id1, id2;
487
488 89572
        (void)vd;
489
490 89572
        i = sscanf(line, "# %ju %ju", &id1, &id2);
491 89572
        if (i != 2) {
492 0
                vs->retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
493 0
                return (0);
494
        }
495 89572
        vs->retval |= VSM_MGT_RUNNING;
496 89572
        if (id1 != vs->id1 || id2 != vs->id2) {
497 89525
                vs->retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
498 89525
                vs->id1 = id1;
499 89525
                vs->id2 = id2;
500 89525
        }
501 89572
        return (0);
502 89572
}
503
504
static int
505 1724224
vsm_vlu_plus(struct vsm *vd, struct vsm_set *vs, const char *line)
506
{
507
        char **av;
508
        int ac;
509
        struct vsm_seg *vg;
510
511 1724224
        av = VAV_Parse(line + 1, &ac, 0);
512
513 1724224
        if (av[0] != NULL || ac < 4 || ac > 6) {
514 0
                (void)(vsm_diag(vd, "vsm_vlu_plus: bad index (%d/%s)",
515 0
                    ac, av[0]));
516 0
                VAV_Free(av);
517 0
                return (-1);
518
        }
519
520 1724224
        vg = vs->vg;
521 1724224
        CHECK_OBJ_ORNULL(vg, VSM_SEG_MAGIC);
522 1724224
        if (vg != NULL)
523 48628
                AZ(vg->flags & VSM_FLAG_STALE);
524 4453199
        while (vg != NULL && vsm_cmp_av(&vg->av[1], &av[1]))
525 2728975
                vg = VTAILQ_NEXT(vg, list);
526 1724224
        if (vg != NULL) {
527
                /* entry compared equal, so it survives */
528 1182
                CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
529 1182
                VAV_Free(av);
530 1182
                vg->flags |= VSM_FLAG_MARKSCAN;
531 1182
                vs->vg = VTAILQ_NEXT(vg, list);
532 1182
        } else {
533 1723042
                ALLOC_OBJ(vg, VSM_SEG_MAGIC);
534 1723042
                AN(vg);
535 1723042
                vg->av = av;
536 1723042
                vg->set = vs;
537 1723042
                vg->flags = VSM_FLAG_MARKSCAN;
538 1723042
                vg->serial = vd->serial;
539
540 1723042
                VTAILQ_INSERT_TAIL(&vs->segs, vg, list);
541 1723042
                if (ac == 4) {
542 45350
                        vg->flags |= VSM_FLAG_CLUSTER;
543 45350
                        VTAILQ_INSERT_TAIL(&vs->clusters, vg, clist);
544 1723042
                } else if (*vg->av[2] != '0') {
545 48125
                        vg->cluster = vsm_findcluster(vs, vg->av[1]);
546 48125
                        CHECK_OBJ_NOTNULL(vg->cluster, VSM_SEG_MAGIC);
547 48125
                }
548
        }
549 1724224
        return (0);
550 1724224
}
551
552
static int
553 45870
vsm_vlu_minus(struct vsm *vd, const struct vsm_set *vs, const char *line)
554
{
555
        char **av;
556
        int ac;
557
        struct vsm_seg *vg;
558
559 45870
        av = VAV_Parse(line + 1, &ac, 0);
560
561 45870
        if (av[0] != NULL || ac < 4 || ac > 6) {
562 0
                (void)(vsm_diag(vd, "vsm_vlu_minus: bad index (%d/%s)",
563 0
                    ac, av[0]));
564 0
                VAV_Free(av);
565 0
                return (-1);
566
        }
567
568
        /* Clustered segments cannot come before their cluster */
569 45870
        if (*av[2] != '0')
570 1275
                vg = vsm_findcluster(vs, av[1]);
571
        else
572 44595
                vg = VTAILQ_FIRST(&vs->segs);
573
574 394110
        for (;vg != NULL; vg = VTAILQ_NEXT(vg, list)) {
575 394110
                if (!vsm_cmp_av(&vg->av[1], &av[1])) {
576 45870
                        vsm_delseg(vg, 1);
577 45870
                        break;
578
                }
579 348240
        }
580 45870
        AN(vg);
581 45870
        VAV_Free(av);
582 45870
        return (0);
583 45870
}
584
585
static int v_matchproto_(vlu_f)
586 1859666
vsm_vlu_func(void *priv, const char *line)
587
{
588
        struct vsm *vd;
589
        struct vsm_set *vs;
590 1859666
        int i = 0;
591
592 1859666
        CAST_OBJ_NOTNULL(vs, priv, VSM_SET_MAGIC);
593 1859666
        vd = vs->vsm;
594 1859666
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
595 1859666
        AN(line);
596
597
        /* Up the serial counter. This wraps at UINTPTR_MAX/2
598
         * because thats the highest value we can store in struct
599
         * vsm_fantom. */
600 1859666
        vd->serial = VSM_PRIV_LOW(vd->serial + 1);
601
602 1859666
        switch (line[0]) {
603
        case '#':
604 89572
                i = vsm_vlu_hash(vd, vs, line);
605 140675
                VTAILQ_FOREACH(vs->vg, &vs->segs, list)
606 51103
                        vs->vg->flags &= ~VSM_FLAG_MARKSCAN;
607 89572
                if (!(vs->retval & vs->flag_restarted))
608 35972
                        vs->vg = VTAILQ_FIRST(&vs->segs);
609 89572
                break;
610
        case '+':
611 1724224
                i = vsm_vlu_plus(vd, vs, line);
612 1724224
                break;
613
        case '-':
614 45870
                i = vsm_vlu_minus(vd, vs, line);
615 45870
                break;
616
        default:
617 0
                break;
618
        }
619 1859666
        return (i);
620
}
621
622
static void
623 1345001
vsm_readlines(struct vsm_set *vs)
624
{
625
        int i;
626
627 1345001
        do {
628 1532809
                assert(vs->fd >= 0);
629 1532809
                i = VLU_Fd(vs->vlu, vs->fd);
630 1532809
        } while (!i);
631 1345001
        assert(i == -2);
632 1345001
}
633
634
static unsigned
635 1516682
vsm_refresh_set(struct vsm *vd, struct vsm_set *vs)
636
{
637
        struct stat st;
638
639 1516682
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
640 1516682
        CHECK_OBJ_NOTNULL(vs, VSM_SET_MAGIC);
641 1516682
        vs->retval = 0;
642 2796591
        if (vs->dfd >= 0 && (
643 1281182
            fstatat(vd->wdfd, vs->dname, &st, AT_SYMLINK_NOFOLLOW) ||
644 1281189
            st.st_ino != vs->dst.st_ino ||
645 1279917
            st.st_dev != vs->dst.st_dev ||
646 1279918
            st.st_mode != vs->dst.st_mode ||
647 1279909
            st.st_nlink == 0)) {
648 1323
                closefd(&vs->dfd);
649 1275
        }
650
651 1516660
        if (vs->dfd < 0) {
652 236745
                if (vs->fd >= 0)
653 1270
                        closefd(&vs->fd);
654 236745
                vs->dfd = openat(vd->wdfd, vs->dname, O_RDONLY);
655 236745
        }
656
657 1516660
        if (vs->dfd < 0) {
658 147220
                vs->id1 = vs->id2 = 0;
659 147220
                vsm_wash_set(vs, 1);
660 147220
                return (vs->retval | vs->flag_restarted);
661
        }
662
663 1369440
        AZ(fstat(vs->dfd, &vs->dst));
664
665 2624888
        if (vs->fd >= 0 && (
666 1278102
            fstatat(vs->dfd, "_.index", &st, AT_SYMLINK_NOFOLLOW) ||
667 1255496
            st.st_ino != vs->fst.st_ino ||
668 1255449
            st.st_dev != vs->fst.st_dev ||
669 1255449
            st.st_mode != vs->fst.st_mode ||
670 1255449
            st.st_size < vs->fst.st_size ||
671 1255448
            st.st_nlink < 1)) {
672 22669
                closefd(&vs->fd);
673 22669
        }
674
675 1369440
        if (vs->fd >= 0) {
676 1255444
                vs->vg = NULL;
677 1255444
                vsm_readlines(vs);
678 1255444
        } else {
679 283726
                VTAILQ_FOREACH(vs->vg, &vs->segs, list)
680 169730
                        vs->vg->flags &= ~VSM_FLAG_MARKSCAN;
681 113996
                vs->vg = VTAILQ_FIRST(&vs->segs);
682 113996
                vs->fd = openat(vs->dfd, "_.index", O_RDONLY);
683 113996
                if (vs->fd < 0)
684 24424
                        return (vs->retval | vs->flag_restarted);
685 89572
                VLU_Reset(vs->vlu);
686 89572
                AZ(fstat(vs->fd, &vs->fst));
687 89572
                vsm_readlines(vs);
688 89572
                vsm_wash_set(vs, 0);
689
        }
690
691 1345016
        vs->fst.st_size = lseek(vs->fd, 0L, SEEK_CUR);
692
693 1345016
        vs->retval |= vs->flag_running;
694 1345016
        return (vs->retval);
695 1516660
}
696
697
/*--------------------------------------------------------------------*/
698
699
unsigned
700 770390
VSM_Status(struct vsm *vd)
701
{
702 770390
        unsigned retval = 0;
703
        struct stat st;
704
705 770390
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
706
707
        /* See if the -n workdir changed */
708 770390
        if (vd->wdfd >= 0) {
709 716066
                AZ(fstat(vd->wdfd, &st));
710 1432130
                if (st.st_ino != vd->wdst.st_ino ||
711 716065
                    st.st_dev != vd->wdst.st_dev ||
712 716065
                    st.st_mode != vd->wdst.st_mode ||
713 716064
                    st.st_nlink == 0) {
714 2
                        closefd(&vd->wdfd);
715 0
                        vsm_wash_set(vd->mgt, 1);
716 0
                        vsm_wash_set(vd->child, 1);
717 0
                }
718 716064
        }
719
720
        /* Open workdir */
721 770388
        if (vd->wdfd < 0) {
722 54327
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
723 54327
                retval |= VSM_WRK_RESTARTED | VSM_MGT_CHANGED;
724 54327
                vd->wdfd = open(vd->wdname, O_RDONLY);
725 54327
                if (vd->wdfd < 0)
726 727
                        (void)vsm_diag(vd,
727
                            "VSM_Status: Cannot open workdir");
728
                else
729 53600
                        AZ(fstat(vd->wdfd, &vd->wdst));
730 54327
        }
731
732 770388
        if (vd->wdfd >= 0) {
733 769666
                retval |= vsm_refresh_set(vd, vd->mgt);
734 769666
                if (retval & VSM_MGT_RUNNING)
735 746998
                        retval |= vsm_refresh_set(vd, vd->child);
736 769666
        }
737 770388
        return (retval);
738
}
739
740
/*--------------------------------------------------------------------*/
741
742
int
743 53675
VSM_Attach(struct vsm *vd, int progress)
744
{
745
        double t0;
746
        unsigned u;
747 53675
        int i, n = 0;
748
749 53675
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
750
751 53675
        if (vd->patience < 0)
752 0
                t0 = DBL_MAX;
753
        else
754 53675
                t0 = VTIM_mono() + vd->patience;
755
756 53675
        if (vd->wdname == NULL) {
757
                /* Use default (hostname) */
758 0
                i = VSM_Arg(vd, 'n', "");
759 0
                if (i < 0)
760 0
                        return (i);
761 0
                AN(vd->wdname);
762 0
        }
763
764 53675
        AZ(vd->attached);
765 54402
        while (!VSIG_int && !VSIG_term) {
766 54377
                u = VSM_Status(vd);
767 54377
                VSM_ResetError(vd);
768 54377
                if (u & VSM_MGT_RUNNING) {
769 53600
                        if (progress >= 0 && n > 4)
770 0
                                (void)write(progress, "\n", 1);
771 53600
                        vd->attached = 1;
772 53600
                        return (0);
773
                }
774 777
                if (t0 < VTIM_mono()) {
775 50
                        if (progress >= 0 && n > 4)
776 25
                                (void)write(progress, "\n", 1);
777 50
                        return (vsm_diag(vd,
778
                            "Could not get hold of varnishd, is it running?"));
779
                }
780 727
                if (progress >= 0 && !(++n % 4))
781 152
                        (void)write(progress, ".", 1);
782 727
                VTIM_sleep(.25);
783
        }
784 25
        return (vsm_diag(vd, "Attach interrupted"));
785 53675
}
786
787
/*--------------------------------------------------------------------*/
788
789
static struct vsm_seg *
790 3016813
vsm_findseg(const struct vsm *vd, const struct vsm_fantom *vf)
791
{
792
        struct vsm_set *vs;
793
        struct vsm_seg *vg;
794
        uint64_t x;
795
796 3016813
        x = VSM_PRIV_HIGH(vf->priv);
797 3016813
        if (x == vd->serial) {
798 2975834
                vg = (struct vsm_seg *)vf->priv2;
799 2975834
                if (!VALID_OBJ(vg, VSM_SEG_MAGIC) ||
800 2975834
                    vg->serial != VSM_PRIV_LOW(vf->priv))
801 0
                        WRONG("Corrupt fantom");
802 2975834
                return (vg);
803
        }
804
805 40979
        x = VSM_PRIV_LOW(vf->priv);
806 40979
        vs = vd->mgt;
807 278527
        VTAILQ_FOREACH(vg, &vs->segs, list)
808 239216
                if (vg->serial == x)
809 1668
                        break;
810 40979
        if (vg == NULL) {
811 39311
                VTAILQ_FOREACH(vg, &vs->stale, list)
812 0
                        if (vg->serial == x)
813 0
                                break;
814 39311
        }
815 40979
        vs = vd->child;
816 40979
        if (vg == NULL) {
817 298081
                VTAILQ_FOREACH(vg, &vs->segs, list)
818 294381
                        if (vg->serial == x)
819 35611
                                break;
820 39311
        }
821 40979
        if (vg == NULL) {
822 3700
                VTAILQ_FOREACH(vg, &vs->stale, list)
823 3700
                        if (vg->serial == x)
824 3700
                                break;
825 3700
        }
826 40979
        if (vg == NULL)
827 0
                return (NULL);
828
829
        /* Update the fantom with the new priv so that lookups will be
830
         * fast on the next call. Note that this casts away the const. */
831 40979
        ((struct vsm_fantom *)TRUST_ME(vf))->priv =
832 40979
            VSM_PRIV_MERGE(vg->serial, vd->serial);
833 40979
        return (vg);
834 3016813
}
835
836
/*--------------------------------------------------------------------*/
837
838
void
839 166762
VSM__iter0(const struct vsm *vd, struct vsm_fantom *vf)
840
{
841
842 166762
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
843 166762
        AN(vf);
844
845 166762
        AN(vd->attached);
846 166762
        memset(vf, 0, sizeof *vf);
847 166762
}
848
849
int
850 1700102
VSM__itern(struct vsm *vd, struct vsm_fantom *vf)
851
{
852
        struct vsm_seg *vg;
853
854 1700102
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
855 1700102
        AN(vd->attached);
856 1700102
        AN(vf);
857
858 1700102
        if (vf->priv == 0) {
859 166762
                vg = VTAILQ_FIRST(&vd->mgt->segs);
860 166762
                if (vg == NULL)
861 1
                        return (0);
862 166761
        } else {
863 1533340
                vg = vsm_findseg(vd, vf);
864 1533340
                if (vg == NULL)
865 0
                        return (vsm_diag(vd, "VSM_FOREACH: inconsistency"));
866 1548029
                while (1) {
867 1548029
                        if (vg->set == vd->mgt && VTAILQ_NEXT(vg, list) == NULL)
868 164386
                                vg = VTAILQ_FIRST(&vd->child->segs);
869
                        else
870 1383643
                                vg = VTAILQ_NEXT(vg, list);
871 1548029
                        if (vg == NULL)
872 112736
                                return (0);
873 1435293
                        if (!(vg->flags & VSM_FLAG_CLUSTER))
874 1420604
                                break;
875
                }
876
        }
877 1587365
        memset(vf, 0, sizeof *vf);
878 1587365
        vf->priv = VSM_PRIV_MERGE(vg->serial, vd->serial);
879 1587365
        vf->priv2 = (uintptr_t)vg;
880 1587365
        vf->category = vg->av[4];
881 1587365
        vf->ident = vg->av[5];
882 1587365
        AN(vf->category);
883 1587365
        return (1);
884 1700102
}
885
886
/*--------------------------------------------------------------------*/
887
888
int
889 128407
VSM_Map(struct vsm *vd, struct vsm_fantom *vf)
890
{
891
        struct vsm_seg *vg, *vgc;
892
        size_t of, sz;
893
        int r;
894
895 128407
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
896 128407
        AN(vd->attached);
897 128407
        AN(vf);
898 128407
        vg = vsm_findseg(vd, vf);
899 128407
        if (vg == NULL)
900 0
                return (vsm_diag(vd, "VSM_Map: bad fantom"));
901
902 128407
        assert(vg->serial == VSM_PRIV_LOW(vf->priv));
903 128407
        assert(vg->av[4] == vf->category);
904 128407
        assert(vg->av[5] == vf->ident);
905
906 128407
        if (vg->b != NULL) {
907 0
                assert(vg->refs > 0);
908 0
                AN(vg->e);
909 0
                vf->b = vg->b;
910 0
                vf->e = vg->e;
911 0
                vg->refs++;
912 0
                return (0);
913
        }
914
915 128407
        assert(vg->refs == 0);
916
917 128407
        vgc = vg->cluster;
918
919 128407
        if (vgc == NULL) {
920 124056
                r = vsm_mapseg(vd, vg);
921 124056
                if (r)
922 0
                        return (r);
923 124056
                vf->b = vg->b;
924 124056
                vf->e = vg->e;
925
926 124056
                vg->refs++;
927
928 124056
                return (0);
929
        }
930
931 4351
        CHECK_OBJ_NOTNULL(vgc, VSM_SEG_MAGIC);
932 4351
        assert(vgc->flags & VSM_FLAG_CLUSTER);
933 4351
        assert(vg->s == NULL);
934 4351
        assert(vg->sz == 0);
935
936 4351
        r = vsm_mapseg(vd, vgc);
937 4351
        if (r)
938 0
                return (r);
939 4351
        vgc->refs++;
940
941 4351
        of = strtoul(vg->av[2], NULL, 10);
942 4351
        sz = strtoul(vg->av[3], NULL, 10);
943 4351
        assert(sz > 0);
944
945 4351
        assert(vgc->sz >= of + sz);
946 4351
        assert(vgc->s == vgc->b);
947 4351
        vg->b = (char *)vgc->b + of;
948 4351
        vg->e = (char *)vg->b + sz;
949
950 4351
        vf->b = vg->b;
951 4351
        vf->e = vg->e;
952
953 4351
        vg->refs++;
954
955 4351
        return (0);
956 128407
}
957
958
/*--------------------------------------------------------------------*/
959
960
int
961 111682
VSM_Unmap(struct vsm *vd, struct vsm_fantom *vf)
962
{
963
        struct vsm_seg *vg;
964
965 111682
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
966 111682
        AN(vd->attached);
967 111682
        AN(vf);
968 111682
        AN(vf->b);
969 111682
        vg = vsm_findseg(vd, vf);
970 111682
        if (vg == NULL)
971 0
                return (vsm_diag(vd, "VSM_Unmap: bad fantom"));
972 111682
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
973 111682
        assert(vg->refs > 0);
974 111682
        vg->refs--;
975 111682
        vf->b = NULL;
976 111682
        vf->e = NULL;
977 111682
        if (vg->refs > 0)
978 0
                return (0);
979
980 111682
        if (vg->cluster) {
981 1501
                CHECK_OBJ_NOTNULL(vg->cluster, VSM_SEG_MAGIC);
982 1501
                assert(vg->s == NULL);
983 1501
                assert(vg->sz == 0);
984 1501
                assert(vg->cluster->refs > 0);
985 1501
                if (--vg->cluster->refs == 0) {
986 1476
                        vsm_unmapseg(vg->cluster);
987 1476
                        if (vg->cluster->flags & VSM_FLAG_STALE) {
988 0
                                AN(vg->flags & VSM_FLAG_STALE);
989 0
                                vsm_delseg(vg->cluster, 0);
990 0
                        }
991 1476
                }
992 1501
                vg->b = vg->e = NULL;
993 1501
        } else {
994 110181
                vsm_unmapseg(vg);
995
        }
996 111682
        if (vg->flags & VSM_FLAG_STALE)
997 3701
                vsm_delseg(vg, 0);
998 111682
        return (0);
999 111682
}
1000
1001
/*--------------------------------------------------------------------*/
1002
1003
const struct vsm_valid *
1004 1243503
VSM_StillValid(const struct vsm *vd, const struct vsm_fantom *vf)
1005
{
1006
        struct vsm_seg *vg;
1007
1008 1243503
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
1009 1243503
        AN(vf);
1010 1243503
        vg = vsm_findseg(vd, vf);
1011 1243503
        if (vg == NULL || vg->flags & VSM_FLAG_STALE)
1012 1640
                return (VSM_invalid);
1013 1241863
        return (VSM_valid);
1014 1243503
}
1015
1016
/*--------------------------------------------------------------------*/
1017
1018
int
1019 135608
VSM_Get(struct vsm *vd, struct vsm_fantom *vf,
1020
    const char *category, const char *ident)
1021
{
1022
1023 135608
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
1024 135608
        AN(vd->attached);
1025 941720
        VSM_FOREACH(vf, vd) {
1026 836959
                if (strcmp(vf->category, category))
1027 806112
                        continue;
1028 30847
                if (ident != NULL && strcmp(vf->ident, ident))
1029 0
                        continue;
1030 30847
                return (1);
1031
        }
1032 104761
        memset(vf, 0, sizeof *vf);
1033 104761
        return (0);
1034 135608
}
1035
1036
/*--------------------------------------------------------------------*/
1037
1038
char *
1039 2250
VSM_Dup(struct vsm *vd, const char *category, const char *ident)
1040
{
1041
        struct vsm_fantom vf;
1042 2250
        char *p = NULL;
1043
1044 2250
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
1045 2250
        AN(vd->attached);
1046 9075
        VSM_FOREACH(&vf, vd) {
1047 9075
                if (strcmp(vf.category, category))
1048 3900
                        continue;
1049 5175
                if (ident != NULL && strcmp(vf.ident, ident))
1050 2925
                        continue;
1051 2250
                AZ(VSM_Map(vd, &vf));
1052 2250
                AN(vf.b);
1053 2250
                AN(vf.e);
1054 2250
                p = malloc((char*)vf.e - (char*)vf.b);
1055 2250
                AN(p);
1056 2250
                memcpy(p, vf.b, (char*)vf.e - (char*)vf.b);
1057 2250
                AZ(VSM_Unmap(vd, &vf));
1058 2250
                break;
1059
        }
1060 2250
        return (p);
1061
}