varnish-cache/lib/libvarnishapi/vsm.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 * Author: Martin Blix Grydeland <martin@varnish-software.com>
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
#include "config.h"
32
33
#include <sys/mman.h>
34
#include <sys/stat.h>
35
36
#include <errno.h>
37
#include <fcntl.h>
38
#include <float.h>
39
#include <math.h>
40
#include <signal.h>
41
#include <stdarg.h>
42
#include <stdint.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <unistd.h>
47
48
#include "vdef.h"
49
#include "vas.h"
50
#include "miniobj.h"
51
52
#include "vav.h"
53
#include "vin.h"
54
#include "vsb.h"
55
#include "vsm_priv.h"
56
#include "vqueue.h"
57
#include "vtim.h"
58
59
#include "vapi/vsm.h"
60
61
#ifndef MAP_HASSEMAPHORE
62
#  define MAP_HASSEMAPHORE 0 /* XXX Linux */
63
#endif
64
65
#ifndef MAP_NOSYNC
66
#  define MAP_NOSYNC 0 /* XXX Linux */
67
#endif
68
69
const struct vsm_valid VSM_invalid[1] = {{"invalid"}};
70
const struct vsm_valid VSM_valid[1] = {{"valid"}};
71
72
/*--------------------------------------------------------------------*/
73
74
struct vsm_set;
75
76
struct vsm_seg {
77
        unsigned                magic;
78
#define VSM_SEG_MAGIC           0xeb6c6dfd
79
        unsigned                flags;
80
#define VSM_FLAG_MARKSCAN       (1U<<1)
81
#define VSM_FLAG_STALE          (1U<<2)
82
#define VSM_FLAG_CLUSTER        (1U<<3)
83
        VTAILQ_ENTRY(vsm_seg)   list;
84
        struct vsm_set          *set;
85
        struct vsm_seg          *cluster;
86
        char                    **av;
87
        int                     refs;
88
        void                    *s;
89
        size_t                  sz;
90
        void                    *b;
91
        void                    *e;
92
        uintptr_t               serial;
93
};
94
95
struct vsm_set {
96
        unsigned                magic;
97
#define VSM_SET_MAGIC           0xdee401b8
98
        const char              *dname;
99
        VTAILQ_HEAD(,vsm_seg)   segs;
100
        VTAILQ_HEAD(,vsm_seg)   stale;
101
        VTAILQ_HEAD(,vsm_seg)   clusters;
102
103
        int                     dfd;
104
        struct stat             dst;
105
106
        int                     fd;
107
        struct stat             fst;
108
109
        uintmax_t               id1, id2;
110
};
111
112
struct vsm {
113
        unsigned                magic;
114
#define VSM_MAGIC               0x6e3bd69b
115
116
        struct vsb              *diag;
117
        uintptr_t               serial;
118
119
        int                     dfd;
120
        struct stat             dst;
121
        char                    *dname;
122
123
        struct vsm_set          *mgt;
124
        struct vsm_set          *child;
125
126
        int                     attached;
127
        double                  patience;
128
129
        int                     couldkill;
130
};
131
132
/*--------------------------------------------------------------------*/
133
134
static int
135 284
vsm_diag(struct vsm *vd, const char *fmt, ...)
136
{
137
        va_list ap;
138
139 284
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
140 284
        AN(fmt);
141
142 284
        if (vd->diag == NULL)
143 102
                vd->diag = VSB_new_auto();
144 284
        AN(vd->diag);
145 284
        VSB_clear(vd->diag);
146 284
        va_start(ap, fmt);
147 284
        VSB_vprintf(vd->diag, fmt, ap);
148 284
        va_end(ap);
149 284
        AZ(VSB_finish(vd->diag));
150 284
        return (-1);
151
}
152
153
/*--------------------------------------------------------------------*/
154
155
static int
156 11590
vsm_mapseg(struct vsm *vd, struct vsm_seg *vg)
157
{
158
        size_t of, off, sz, ps, len;
159
        struct vsb *vsb;
160
        int fd;
161
162 11590
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
163
164 11590
        if (vg->s != NULL)
165 198
                return (0);
166
167 11392
        ps = getpagesize();
168
169 11392
        of = strtoul(vg->av[2], NULL, 10);
170 11392
        off = RDN2(of, ps);
171
172 11392
        if (vg->flags & VSM_FLAG_CLUSTER)
173 52
                assert(of == 0);
174 11392
        assert(vg->cluster == NULL);
175
176 11392
        sz = strtoul(vg->av[3], NULL, 10);
177 11392
        assert(sz > 0);
178 11392
        assert(of >= off);
179 11392
        len = RUP2((of - off) + sz, ps);
180
181 11392
        vsb = VSB_new_auto();
182 11392
        AN(vsb);
183 11392
        VSB_printf(vsb, "%s/%s/%s", vd->dname, vg->set->dname, vg->av[1]);
184 11392
        AZ(VSB_finish(vsb));
185
186 11392
        fd = open(VSB_data(vsb), O_RDONLY);     // XXX: openat
187 11392
        if (fd < 0) {
188 216
                VSB_destroy(&vsb);
189 216
                return (vsm_diag(vd, "Could not open segment"));
190
        }
191
192 11176
        vg->s = (void*)mmap(NULL, len,
193
            PROT_READ,
194
            MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED,
195
            fd, (off_t)off);
196
197 11176
        VSB_destroy(&vsb);
198
199 11176
        closefd(&fd);
200 11176
        if (vg->s == MAP_FAILED)
201 0
                return (vsm_diag(vd, "Could not mmap segment"));
202
203 11176
        vg->b = (char*)(vg->s) + of - off;
204 11176
        vg->e = (char *)vg->b + sz;
205 11176
        vg->sz = len;
206
207 11176
        return (0);
208
}
209
210
static void
211 10528
vsm_unmapseg(struct vsm_seg *vg)
212
{
213
214 10528
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
215
216 10528
        AN(vg->b);
217 10528
        AN(vg->e);
218 10528
        AZ(munmap(vg->s, vg->sz));
219 10528
        vg->s = vg->b = vg->e = NULL;
220 10528
        vg->sz = 0;
221 10528
}
222
223
/*--------------------------------------------------------------------*/
224
225
static void
226 92294
vsm_delseg(struct vsm_seg *vg)
227
{
228
229 92294
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
230
231 92294
        if (vg->s != NULL)
232 0
                vsm_unmapseg(vg);
233
234 92294
        if (vg->flags & VSM_FLAG_STALE)
235 30
                VTAILQ_REMOVE(&vg->set->stale, vg, list);
236 92264
        else if (vg->flags & VSM_FLAG_CLUSTER)
237 3022
                VTAILQ_REMOVE(&vg->set->clusters, vg, list);
238
        else
239 89242
                VTAILQ_REMOVE(&vg->set->segs, vg, list);
240 92294
        VAV_Free(vg->av);
241 92294
        FREE_OBJ(vg);
242 92294
}
243
244
/*--------------------------------------------------------------------*/
245
246
static struct vsm_set *
247 6384
vsm_newset(const char *dirname)
248
{
249
        struct vsm_set *vs;
250
251 6384
        ALLOC_OBJ(vs, VSM_SET_MAGIC);
252 6384
        AN(vs);
253 6384
        VTAILQ_INIT(&vs->segs);
254 6384
        VTAILQ_INIT(&vs->stale);
255 6384
        VTAILQ_INIT(&vs->clusters);
256 6384
        vs->dname = dirname;
257 6384
        vs->dfd = vs->fd = -1;
258 6384
        return (vs);
259
}
260
261
static void
262 6308
vsm_delset(struct vsm_set **p)
263
{
264
        struct vsm_set *vs;
265
266 6308
        AN(p);
267 6308
        vs = *p;
268 6308
        *p = NULL;
269 6308
        if (vs->fd >= 0)
270 3718
                closefd(&vs->fd);
271 6308
        if (vs->dfd >= 0)
272 5114
                closefd(&vs->dfd);
273 12616
        while (!VTAILQ_EMPTY(&vs->stale))
274 0
                vsm_delseg(VTAILQ_FIRST(&vs->stale));
275 101858
        while (!VTAILQ_EMPTY(&vs->segs))
276 89242
                vsm_delseg(VTAILQ_FIRST(&vs->segs));
277 15638
        while (!VTAILQ_EMPTY(&vs->clusters))
278 3022
                vsm_delseg(VTAILQ_FIRST(&vs->clusters));
279 6308
        FREE_OBJ(vs);
280 6308
}
281
282
/*--------------------------------------------------------------------*/
283
284
struct vsm *
285 3192
VSM_New(void)
286
{
287
        struct vsm *vd;
288
289 3192
        ALLOC_OBJ(vd, VSM_MAGIC);
290 3192
        AN(vd);
291
292 3192
        vd->mgt = vsm_newset(VSM_MGT_DIRNAME);
293 3192
        vd->child = vsm_newset(VSM_CHILD_DIRNAME);
294 3192
        vd->dfd = -1;
295 3192
        vd->patience = 5;
296 3192
        if (getenv("VSM_NOPID") != NULL)
297 0
                vd->couldkill = -1;
298 3192
        return (vd);
299
}
300
301
/*--------------------------------------------------------------------*/
302
303
int
304 3216
VSM_Arg(struct vsm *vd, char flag, const char *arg)
305
{
306 3216
        char *p = NULL;
307
308 3216
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
309
310 3216
        if (arg == NULL)
311 28
                return (1);
312 3188
        switch (flag) {
313
        case 't':
314 14
                if (!strcasecmp(arg, "off")) {
315 0
                        vd->patience = -1;
316
                } else {
317 14
                        vd->patience = strtod(arg, &p);
318 24
                        if ((p != NULL && *p != '\0') ||
319 16
                            !isfinite(vd->patience) || vd->patience < 0)
320 12
                                return (vsm_diag(vd,
321
                                    "-t: Invalid argument: %s", arg));
322
                }
323 2
                break;
324
        case 'n':
325 3174
                if (VIN_n_Arg(arg, &p))
326 0
                        return (vsm_diag(vd, "Invalid instance name: %s",
327 0
                            strerror(errno)));
328 3174
                AN(p);
329 3174
                REPLACE(vd->dname, p);
330 3174
                free(p);
331 3174
                break;
332
        default:
333 0
                return (vsm_diag(vd, "Unknown VSM_Arg('%c')", flag));
334
        }
335 3176
        return (1);
336
}
337
338
/*--------------------------------------------------------------------*/
339
340
void
341 3154
VSM_Destroy(struct vsm **vdp)
342
{
343
        struct vsm *vd;
344
345 3154
        TAKE_OBJ_NOTNULL(vd, vdp, VSM_MAGIC);
346
347 3154
        VSM_ResetError(vd);
348 3154
        REPLACE(vd->dname, NULL);
349 3154
        if (vd->diag != NULL)
350 0
                VSB_destroy(&vd->diag);
351 3154
        if (vd->dfd >= 0)
352 3152
                closefd(&vd->dfd);
353 3154
        vsm_delset(&vd->mgt);
354 3154
        vsm_delset(&vd->child);
355 3154
        FREE_OBJ(vd);
356 3154
}
357
358
/*--------------------------------------------------------------------*/
359
360
const char *
361 232
VSM_Error(const struct vsm *vd)
362
{
363
364 232
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
365
366 232
        if (vd->diag == NULL)
367 0
                return ("No VSM error");
368
        else
369 232
                return (VSB_data(vd->diag));
370
}
371
372
/*--------------------------------------------------------------------*/
373
374
void
375 6376
VSM_ResetError(struct vsm *vd)
376
{
377
378 6376
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
379
380 6376
        if (vd->diag == NULL)
381 6288
                return;
382 88
        VSB_destroy(&vd->diag);
383
}
384
385
/*--------------------------------------------------------------------
386
 */
387
388
#define VSM_NUKE_ALL    (1U << 16)
389
390
static int
391 224530
vsm_cmp_av(char * const *a1, char * const *a2)
392
{
393
394
        while (1) {
395 410329
                if (*a1 == NULL && *a2 == NULL)
396 36939
                        return (0);
397 187591
                if (*a1 == NULL || *a2 == NULL)
398 437
                        return (1);
399 187154
                if (strcmp(*a1, *a2))
400 1355
                        return (1);
401 185799
                a1++;
402 185799
                a2++;
403
        }
404
}
405
406
static struct vsm_seg *
407 94164
vsm_findcluster(const struct vsm_seg *vga)
408
{
409 94164
        const struct vsm_set *vs = vga->set;
410
        struct vsm_seg *vg;
411 94164
        AN(vs);
412 94164
        AN(vga->av[1]);
413 113528
        VTAILQ_FOREACH(vg, &vs->clusters, list) {
414 23435
                AN(vg->av[1]);
415 23435
                if (!strcmp(vga->av[1], vg->av[1]))
416 4071
                        return (vg);
417
        }
418 90093
        return (NULL);
419
}
420
421
static unsigned
422 237768
vsm_refresh_set2(struct vsm *vd, struct vsm_set *vs, struct vsb *vsb)
423
{
424 237768
        unsigned retval = 0;
425
        struct stat st;
426
        char buf[BUFSIZ];
427
        ssize_t sz;
428
        int i, ac;
429
        char *p, *e;
430
        uintmax_t id1, id2;
431
        char **av;
432
        struct vsm_seg *vg, *vg2;
433
434 237768
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
435 237768
        CHECK_OBJ_NOTNULL(vs, VSM_SET_MAGIC);
436 237768
        if (vs->dfd >= 0) {
437 186687
                if (fstatat(vd->dfd, vs->dname, &st, AT_SYMLINK_NOFOLLOW)) {
438 0
                        closefd(&vs->dfd);
439 0
                        vs->id1 = vs->id2 = 0;
440 0
                        return (VSM_MGT_RESTARTED|VSM_NUKE_ALL);
441
                }
442 373311
                if (st.st_ino != vs->dst.st_ino ||
443 373246
                    st.st_dev != vs->dst.st_dev ||
444 186623
                    st.st_mode != vs->dst.st_mode) {
445 64
                        closefd(&vs->dfd);
446 64
                        vs->id1 = vs->id2 = 0;
447
                }
448
        }
449
450 237769
        if (vs->dfd < 0) {
451 51151
                if (vs->fd >= 0)
452 63
                        closefd(&vs->fd);
453 51151
                vs->dfd = openat(vd->dfd, vs->dname, O_RDONLY);
454 51151
                retval |= VSM_MGT_RESTARTED;
455 51151
                if (vs->dfd < 0) {
456 45937
                        vs->id1 = vs->id2 = 0;
457 45937
                        return (retval|VSM_NUKE_ALL);
458
                }
459 5214
                AZ(fstat(vs->dfd, &vs->dst));
460
        }
461
462 371416
        if (vs->fd >= 0 && (
463 357768
            fstatat(vs->dfd, "_.index", &st, AT_SYMLINK_NOFOLLOW) ||
464 356247
            st.st_ino != vs->fst.st_ino ||
465 356118
            st.st_dev != vs->fst.st_dev ||
466 356118
            st.st_mode != vs->fst.st_mode ||
467 353429
            st.st_size != vs->fst.st_size ||
468 350740
            st.st_nlink < 1 ||
469 175370
            memcmp(&st.st_mtime, &vs->fst.st_mtime, sizeof st.st_mtime))) {
470 4216
                closefd(&vs->fd);
471
        }
472
473 191836
        if (vs->fd >= 0) {
474 175365
                if (vd->couldkill < 1 || !kill(vs->id1, 0))
475 167193
                        retval |= VSM_MGT_RUNNING;
476 175365
                return (retval);
477
        }
478
479 16471
        retval |= VSM_MGT_CHANGED;
480 16471
        vs->fd = openat(vs->dfd, "_.index", O_RDONLY);
481 16471
        if (vs->fd < 0)
482 8438
                return (retval|VSM_MGT_RESTARTED);
483
484 8033
        AZ(fstat(vs->fd, &vs->fst));
485
486 8033
        VSB_clear(vsb);
487
        do {
488 19083
                sz = read(vs->fd, buf, sizeof buf);
489 19083
                if (sz > 0)
490 11050
                        VSB_bcat(vsb, buf, sz);
491 19083
        } while (sz > 0);
492 8033
        AZ(VSB_finish(vsb));
493
494 8033
        vs->fst.st_size = VSB_len(vsb);
495
496 8033
        if (VSB_len(vsb) == 0)
497 0
                return (retval|VSM_NUKE_ALL);
498
499
        /*
500
         * First line is ident comment
501
         */
502 8033
        i = sscanf(VSB_data(vsb), "# %ju %ju\n%n", &id1, &id2, &ac);
503 8033
        if (i != 2) {
504 0
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
505 0
                return (retval);
506
        }
507 8033
        if (vd->couldkill >= 0 && !kill(id1, 0)) {
508 8031
                vd->couldkill = 1;
509 2
        } else if (vd->couldkill > 0 && errno == ESRCH) {
510 2
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
511 2
                return (retval);
512
        }
513 8031
        retval |= VSM_MGT_RUNNING;
514 8031
        if (id1 != vs->id1 || id2 != vs->id2) {
515 5212
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
516 5212
                vs->id1 = id1;
517 5212
                vs->id2 = id2;
518
        }
519 8031
        p = VSB_data(vsb) + ac;
520
521 48938
        VTAILQ_FOREACH(vg, &vs->segs, list)
522 40907
                vg->flags &= ~VSM_FLAG_MARKSCAN;
523
524
        /*
525
         * Efficient comparison by walking the two lists side-by-side because
526
         * segment inserts always happen at the tail (VSMW_Allocv()). So, as
527
         * soon as vg is exhausted, we only insert.
528
         *
529
         * For restarts, we require a tabula rasa
530
         */
531
532 8031
        if (retval & VSM_MGT_RESTARTED)
533 5212
                vg = NULL;
534
        else
535 2819
                vg = VTAILQ_FIRST(&vs->segs);
536
537 150655
        while (p != NULL && *p != '\0') {
538 134593
                e = strchr(p, '\n');
539 134593
                if (e == NULL)
540 0
                        break;
541 134593
                *e = '\0';
542 134593
                av = VAV_Parse(p, &ac, 0);
543 134593
                p = e + 1;
544
545 134593
                if (av[0] != NULL || ac < 4 || ac > 6) {
546 0
                        (void)(vsm_diag(vd,
547
                            "vsm_refresh_set2: bad index (%d/%s)",
548
                            ac, av[0]));
549 0
                        VAV_Free(av);
550 0
                        break;
551
                }
552
553 134593
                if (vg == NULL) {
554 97204
                        ALLOC_OBJ(vg2, VSM_SEG_MAGIC);
555 97204
                        AN(vg2);
556 97204
                        vg2->av = av;
557 97204
                        vg2->set = vs;
558 97204
                        vg2->flags = VSM_FLAG_MARKSCAN;
559 97204
                        vg2->serial = ++vd->serial;
560 97204
                        if (ac == 4) {
561 3040
                                vg2->flags |= VSM_FLAG_CLUSTER;
562 3040
                                VTAILQ_INSERT_TAIL(&vs->clusters, vg2, list);
563
                        } else {
564 94164
                                VTAILQ_INSERT_TAIL(&vs->segs, vg2, list);
565 94164
                                vg2->cluster = vsm_findcluster(vg2);
566
                        }
567 97204
                        continue;
568
                }
569
570 76570
                while (vg != NULL && vsm_cmp_av(&vg->av[1], &av[1]))
571 1792
                        vg = VTAILQ_NEXT(vg, list);
572
573 37389
                VAV_Free(av);
574
575 37389
                if (vg == NULL)
576 450
                        continue;
577
578
                /* entry compared equal, so it survives */
579 36939
                vg->flags |= VSM_FLAG_MARKSCAN;
580 36939
                vg = VTAILQ_NEXT(vg, list);
581
        }
582 8031
        return (retval);
583
}
584
585
static unsigned
586 237774
vsm_refresh_set(struct vsm *vd, struct vsm_set *vs, struct vsb *vsb)
587
{
588
        unsigned retval;
589
        struct vsm_seg *vg, *vg2;
590
591 237774
        retval = vsm_refresh_set2(vd, vs, vsb);
592 237814
        if (retval & VSM_NUKE_ALL)
593 45937
                retval |= VSM_MGT_CHANGED;
594 3320204
        VTAILQ_FOREACH_SAFE(vg, &vs->segs, list, vg2) {
595 6160858
                if ((vg->flags & VSM_FLAG_MARKSCAN) == 0 ||
596 3078430
                    (retval & VSM_NUKE_ALL)) {
597 4006
                        VTAILQ_REMOVE(&vs->segs, vg, list);
598 4006
                        if (vg->refs) {
599 30
                                vg->flags |= VSM_FLAG_STALE;
600 30
                                VTAILQ_INSERT_TAIL(&vs->stale, vg, list);
601
                        } else {
602 3976
                                VAV_Free(vg->av);
603 3938
                                FREE_OBJ(vg);
604
                        }
605
                }
606
        }
607 237776
        return (retval & ~VSM_NUKE_ALL);
608
}
609
610
/*--------------------------------------------------------------------*/
611
612
unsigned
613 120280
VSM_Status(struct vsm *vd)
614
{
615 120280
        unsigned retval = 0, u;
616
        struct stat st;
617
        struct vsb *vsb;
618
619 120280
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
620
621
        /* See if the -n workdir changed */
622 120280
        if (vd->dfd >= 0) {
623 117058
                AZ(fstat(vd->dfd, &st));
624 234114
                if (st.st_ino != vd->dst.st_ino ||
625 234115
                    st.st_dev != vd->dst.st_dev ||
626 234115
                    st.st_mode != vd->dst.st_mode ||
627 117057
                    st.st_nlink == 0) {
628 0
                        closefd(&vd->dfd);
629 0
                        retval |= VSM_MGT_CHANGED;
630 0
                        retval |= VSM_WRK_CHANGED;
631
                }
632
        }
633
634
        /* Open workdir */
635 120279
        if (vd->dfd < 0) {
636 3222
                vd->dfd = open(vd->dname, O_RDONLY);
637 3222
                if (vd->dfd < 0)
638 52
                        (void)vsm_diag(vd,
639
                            "VSM_Status: Cannot open workdir");
640
                else
641 3170
                        AZ(fstat(vd->dfd, &vd->dst));
642
        }
643
644 120279
        vsb = VSB_new_auto();
645 120280
        AN(vsb);
646
647 120280
        u = vsm_refresh_set(vd, vd->mgt, vsb);
648 120280
        retval |= u;
649 120280
        if (u & VSM_MGT_RUNNING)
650 117498
                retval |= vsm_refresh_set(vd, vd->child, vsb) << 8;
651 120280
        VSB_destroy(&vsb);
652 120280
        return (retval);
653
}
654
655
/*--------------------------------------------------------------------*/
656
657
int
658 3174
VSM_Attach(struct vsm *vd, int progress)
659
{
660
        double t0;
661
        unsigned u;
662 3174
        int i, n = 0;
663
664 3174
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
665
666 3174
        if (vd->patience < 0)
667 0
                t0 = DBL_MAX;
668
        else
669 3174
                t0 = VTIM_mono() + vd->patience;
670
671 3174
        if (vd->dname == NULL) {
672
                /* Use default (hostname) */
673 0
                i = VSM_Arg(vd, 'n', "");
674 0
                if (i < 0)
675 0
                        return (i);
676 0
                AN(vd->dname);
677
        }
678
679 3174
        AZ(vd->attached);
680
        while (1) {
681 48
                u = VSM_Status(vd);
682 3222
                VSM_ResetError(vd);
683 3222
                if (u & VSM_MGT_RUNNING) {
684 3170
                        if (progress >= 0 && n > 4)
685 0
                                (void)write(progress, "\n", 1);
686 3170
                        vd->attached = 1;
687 3170
                        return (0);
688
                }
689 52
                if (t0 < VTIM_mono()) {
690 4
                        if (progress >= 0 && n > 4)
691 2
                                (void)write(progress, "\n", 1);
692 4
                        return (vsm_diag(vd,
693
                            "Could not get hold of varnishd, is it running?"));
694
                }
695 48
                if (progress >= 0 && !(++n % 4))
696 12
                        (void)write(progress, ".", 1);
697 48
                VTIM_sleep(.25);
698
        }
699
}
700
701
/*--------------------------------------------------------------------*/
702
703
static struct vsm_seg *
704 499280
vsm_findseg(const struct vsm *vd, const struct vsm_fantom *vf)
705
{
706
        struct vsm_set *vs;
707
        struct vsm_seg *vg;
708
        uintptr_t x;
709
710 499280
        x = vf->priv;
711 499280
        vs = vd->mgt;
712 2506703
        VTAILQ_FOREACH(vg, &vs->segs, list)
713 2328086
                if (vg->serial == x)
714 320663
                        return (vg);
715 178617
        VTAILQ_FOREACH(vg, &vs->stale, list)
716 0
                if (vg->serial == x)
717 0
                        return (vg);
718 178617
        vs = vd->child;
719 1620780
        VTAILQ_FOREACH(vg, &vs->segs, list)
720 1620736
                if (vg->serial == x)
721 178573
                        return (vg);
722 44
        VTAILQ_FOREACH(vg, &vs->stale, list)
723 44
                if (vg->serial == x)
724 44
                        return (vg);
725 0
        return (NULL);
726
}
727
728
/*--------------------------------------------------------------------*/
729
730
void
731 57316
VSM__iter0(const struct vsm *vd, struct vsm_fantom *vf)
732
{
733
734 57316
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
735 57316
        AN(vf);
736
737 57316
        AN(vd->attached);
738 57316
        memset(vf, 0, sizeof *vf);
739 57316
}
740
741
int
742 423380
VSM__itern(struct vsm *vd, struct vsm_fantom *vf)
743
{
744
        struct vsm_seg *vg, *vg2;
745
746 423380
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
747 423380
        AN(vd->attached);
748 423380
        AN(vf);
749
750 423380
        if (vf->priv == 0) {
751 57320
                vg2 = VTAILQ_FIRST(&vd->mgt->segs);
752
        } else {
753 366060
                vg = vsm_findseg(vd, vf);
754 366062
                if (vg == NULL)
755 0
                        return (vsm_diag(vd, "VSM_FOREACH: inconsistency"));
756 366062
                vg2 = VTAILQ_NEXT(vg, list);
757 366062
                if (vg2 == NULL && vg->set == vd->mgt)
758 57238
                        vg2 = VTAILQ_FIRST(&vd->child->segs);
759
        }
760 423382
        if (vg2 == NULL)
761 49275
                return (0);
762 374107
        memset(vf, 0, sizeof *vf);
763 374107
        vf->priv = vg2->serial;
764 374107
        vf->class = vg2->av[4];
765 374107
        vf->ident = vg2->av[5];
766 374107
        return (1);
767
}
768
769
/*--------------------------------------------------------------------*/
770
771
int
772 11590
VSM_Map(struct vsm *vd, struct vsm_fantom *vf)
773
{
774
        struct vsm_seg *vg, *vgc;
775
        size_t of, sz;
776
        int r;
777
778 11590
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
779 11590
        AN(vd->attached);
780 11590
        AN(vf);
781 11590
        vg = vsm_findseg(vd, vf);
782 11590
        if (vg == NULL)
783 0
                return (vsm_diag(vd, "VSM_Map: bad fantom"));
784
785 11590
        assert(vg->serial == vf->priv);
786 11590
        assert(vg->av[4] == vf->class);
787 11590
        assert(vg->av[5] == vf->ident);
788
789 11590
        if (vg->b != NULL) {
790 0
                assert(vg->refs > 0);
791 0
                AN(vg->e);
792 0
                vf->b = vg->b;
793 0
                vf->e = vg->e;
794 0
                vg->refs++;
795 0
                return (0);
796
        }
797
798 11590
        assert(vg->refs == 0);
799
800 11590
        vgc = vg->cluster;
801
802 11590
        if (vgc == NULL) {
803 11340
                r = vsm_mapseg(vd, vg);
804 11340
                if (r)
805 216
                        return (r);
806 11124
                vf->b = vg->b;
807 11124
                vf->e = vg->e;
808
809 11124
                vg->refs++;
810
811 11124
                return (0);
812
        }
813
814 250
        assert(vgc->flags & VSM_FLAG_CLUSTER);
815 250
        assert(vg->s == NULL);
816 250
        assert(vg->sz == 0);
817
818 250
        r = vsm_mapseg(vd, vgc);
819 250
        if (r)
820 0
                return (r);
821 250
        vgc->refs++;
822
823 250
        of = strtoul(vg->av[2], NULL, 10);
824 250
        sz = strtoul(vg->av[3], NULL, 10);
825 250
        assert(sz > 0);
826
827 250
        assert(vgc->sz >= of + sz);
828 250
        assert(vgc->s == vgc->b);
829 250
        vg->b = (char *)vgc->b + of;
830 250
        vg->e = (char *)vg->b + sz;
831
832 250
        vf->b = vg->b;
833 250
        vf->e = vg->e;
834
835 250
        vg->refs++;
836
837 250
        return (0);
838
}
839
840
/*--------------------------------------------------------------------*/
841
842
int
843 10528
VSM_Unmap(struct vsm *vd, struct vsm_fantom *vf)
844
{
845
        struct vsm_seg *vg;
846
847 10528
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
848 10528
        AN(vd->attached);
849 10528
        AN(vf);
850 10528
        AN(vf->b);
851 10528
        vg = vsm_findseg(vd, vf);
852 10528
        if (vg == NULL)
853 0
                return (vsm_diag(vd, "VSM_Unmap: bad fantom"));
854 10528
        assert(vg->refs > 0);
855 10528
        vg->refs--;
856 10528
        vf->b = NULL;
857 10528
        vf->e = NULL;
858 10528
        if (vg->refs > 0)
859 0
                return(0);
860
861 10528
        if (vg->cluster) {
862 34
                assert(vg->s == NULL);
863 34
                assert(vg->sz == 0);
864 34
                assert(vg->cluster->refs > 0);
865 34
                if (--vg->cluster->refs == 0)
866 34
                        vsm_unmapseg(vg->cluster);
867 34
                vg->b = vg->e = NULL;
868
        } else {
869 10494
                vsm_unmapseg(vg);
870
        }
871 10528
        if (vg->flags & VSM_FLAG_STALE)
872 30
                vsm_delseg(vg);
873 10528
        return (0);
874
}
875
876
/*--------------------------------------------------------------------*/
877
878
const struct vsm_valid *
879 111113
VSM_StillValid(const struct vsm *vd, const struct vsm_fantom *vf)
880
{
881
        struct vsm_seg *vg;
882
883 111113
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
884 111113
        AN(vf);
885 111113
        vg = vsm_findseg(vd, vf);
886 111114
        if (vg == NULL || vg->flags & VSM_FLAG_STALE)
887 14
                return (VSM_invalid);
888 111100
        return (VSM_valid);
889
}
890
891
/*--------------------------------------------------------------------*/
892
893
int
894 55339
VSM_Get(struct vsm *vd, struct vsm_fantom *vf,
895
    const char *class, const char *ident)
896
{
897
898 55339
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
899 55339
        AN(vd->attached);
900 426704
        VSM_FOREACH(vf, vd) {
901 322748
                if (strcmp(vf->class, class))
902 316026
                        continue;
903 6722
                if (ident != NULL && strcmp(vf->ident, ident))
904 0
                        continue;
905 6722
                return (1);
906
        }
907 48617
        memset(vf, 0, sizeof *vf);
908 48617
        return (0);
909
}
910
911
/*--------------------------------------------------------------------*/
912
913
char *
914 72
VSM_Dup(struct vsm *vd, const char *class, const char *ident)
915
{
916
        struct vsm_fantom vf;
917 72
        char *p = NULL;
918
919 72
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
920 72
        AN(vd->attached);
921 326
        VSM_FOREACH(&vf, vd) {
922 254
                if (strcmp(vf.class, class))
923 104
                        continue;
924 150
                if (ident != NULL && strcmp(vf.ident, ident))
925 78
                        continue;
926 72
                AZ(VSM_Map(vd, &vf));
927 72
                AN(vf.b);
928 72
                AN(vf.e);
929 72
                p = malloc((char*)vf.e - (char*)vf.b);
930 72
                AN(p);
931 72
                memcpy(p, vf.b, (char*)vf.e - (char*)vf.b);
932 72
                AZ(VSM_Unmap(vd, &vf));
933 72
                break;
934
        }
935 72
        return (p);
936
}