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 114
vsm_diag(struct vsm *vd, const char *fmt, ...)
136
{
137
        va_list ap;
138
139 114
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
140 114
        AN(fmt);
141
142 114
        if (vd->diag == NULL)
143 29
                vd->diag = VSB_new_auto();
144 114
        AN(vd->diag);
145 114
        VSB_clear(vd->diag);
146 114
        va_start(ap, fmt);
147 114
        VSB_vprintf(vd->diag, fmt, ap);
148 114
        va_end(ap);
149 114
        AZ(VSB_finish(vd->diag));
150 114
        return (-1);
151
}
152
153
/*--------------------------------------------------------------------*/
154
155
static int
156 5728
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 5728
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
163
164 5728
        if (vg->s != NULL)
165 99
                return (0);
166
167 5629
        ps = getpagesize();
168
169 5629
        of = strtoul(vg->av[2], NULL, 10);
170 5629
        off = RDN2(of, ps);
171
172 5629
        if (vg->flags & VSM_FLAG_CLUSTER)
173 27
                assert(of == 0);
174 5629
        assert(vg->cluster == NULL);
175
176 5629
        sz = strtoul(vg->av[3], NULL, 10);
177 5629
        assert(sz > 0);
178 5629
        assert(of >= off);
179 5629
        len = RUP2((of - off) + sz, ps);
180
181 5629
        vsb = VSB_new_auto();
182 5629
        AN(vsb);
183 5629
        VSB_printf(vsb, "%s/%s/%s", vd->dname, vg->set->dname, vg->av[1]);
184 5629
        AZ(VSB_finish(vsb));
185
186 5629
        fd = open(VSB_data(vsb), O_RDONLY);     // XXX: openat
187 5629
        if (fd < 0) {
188 102
                VSB_destroy(&vsb);
189 102
                return (vsm_diag(vd, "Could not open segment"));
190
        }
191
192 5527
        vg->s = (void*)mmap(NULL, len,
193
            PROT_READ,
194
            MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED,
195
            fd, (off_t)off);
196
197 5527
        VSB_destroy(&vsb);
198
199 5527
        closefd(&fd);
200 5527
        if (vg->s == MAP_FAILED)
201 0
                return (vsm_diag(vd, "Could not mmap segment"));
202
203 5527
        vg->b = (char*)(vg->s) + of - off;
204 5527
        vg->e = (char *)vg->b + sz;
205 5527
        vg->sz = len;
206
207 5527
        return (0);
208
}
209
210
static void
211 5203
vsm_unmapseg(struct vsm_seg *vg)
212
{
213
214 5203
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
215
216 5203
        AN(vg->b);
217 5203
        AN(vg->e);
218 5203
        AZ(munmap(vg->s, vg->sz));
219 5203
        vg->s = vg->b = vg->e = NULL;
220 5203
        vg->sz = 0;
221 5203
}
222
223
/*--------------------------------------------------------------------*/
224
225
static void
226 45546
vsm_delseg(struct vsm_seg *vg)
227
{
228
229 45546
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
230
231 45546
        if (vg->s != NULL)
232 0
                vsm_unmapseg(vg);
233
234 45546
        if (vg->flags & VSM_FLAG_STALE)
235 15
                VTAILQ_REMOVE(&vg->set->stale, vg, list);
236 45531
        else if (vg->flags & VSM_FLAG_CLUSTER)
237 1487
                VTAILQ_REMOVE(&vg->set->clusters, vg, list);
238
        else
239 44044
                VTAILQ_REMOVE(&vg->set->segs, vg, list);
240 45546
        VAV_Free(vg->av);
241 45546
        FREE_OBJ(vg);
242 45546
}
243
244
/*--------------------------------------------------------------------*/
245
246
static struct vsm_set *
247 3168
vsm_newset(const char *dirname)
248
{
249
        struct vsm_set *vs;
250
251 3168
        ALLOC_OBJ(vs, VSM_SET_MAGIC);
252 3168
        AN(vs);
253 3168
        VTAILQ_INIT(&vs->segs);
254 3168
        VTAILQ_INIT(&vs->stale);
255 3168
        VTAILQ_INIT(&vs->clusters);
256 3168
        vs->dname = dirname;
257 3168
        vs->dfd = vs->fd = -1;
258 3168
        return (vs);
259
}
260
261
static void
262 3130
vsm_delset(struct vsm_set **p)
263
{
264
        struct vsm_set *vs;
265
266 3130
        AN(p);
267 3130
        vs = *p;
268 3130
        *p = NULL;
269 3130
        if (vs->fd >= 0)
270 1843
                closefd(&vs->fd);
271 3130
        if (vs->dfd >= 0)
272 2532
                closefd(&vs->dfd);
273 6260
        while (!VTAILQ_EMPTY(&vs->stale))
274 0
                vsm_delseg(VTAILQ_FIRST(&vs->stale));
275 50304
        while (!VTAILQ_EMPTY(&vs->segs))
276 44044
                vsm_delseg(VTAILQ_FIRST(&vs->segs));
277 7747
        while (!VTAILQ_EMPTY(&vs->clusters))
278 1487
                vsm_delseg(VTAILQ_FIRST(&vs->clusters));
279 3130
        FREE_OBJ(vs);
280 3130
}
281
282
/*--------------------------------------------------------------------*/
283
284
struct vsm *
285 1584
VSM_New(void)
286
{
287
        struct vsm *vd;
288
289 1584
        ALLOC_OBJ(vd, VSM_MAGIC);
290 1584
        AN(vd);
291
292 1584
        vd->mgt = vsm_newset(VSM_MGT_DIRNAME);
293 1584
        vd->child = vsm_newset(VSM_CHILD_DIRNAME);
294 1584
        vd->dfd = -1;
295 1584
        vd->patience = 5;
296 1584
        if (getenv("VSM_NOPID") != NULL)
297 0
                vd->couldkill = -1;
298 1584
        return (vd);
299
}
300
301
/*--------------------------------------------------------------------*/
302
303
int
304 1594
VSM_Arg(struct vsm *vd, char flag, const char *arg)
305
{
306 1594
        char *p = NULL;
307
308 1594
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
309
310 1594
        if (arg == NULL)
311 12
                return (1);
312 1582
        switch (flag) {
313
        case 't':
314 7
                if (!strcasecmp(arg, "off")) {
315 0
                        vd->patience = -1;
316
                } else {
317 7
                        vd->patience = strtod(arg, &p);
318 12
                        if ((p != NULL && *p != '\0') ||
319 8
                            !isfinite(vd->patience) || vd->patience < 0)
320 6
                                return (vsm_diag(vd,
321
                                    "-t: Invalid argument: %s", arg));
322
                }
323 1
                break;
324
        case 'n':
325 1575
                if (VIN_n_Arg(arg, &p))
326 0
                        return (vsm_diag(vd, "Invalid instance name: %s",
327 0
                            strerror(errno)));
328 1575
                AN(p);
329 1575
                REPLACE(vd->dname, p);
330 1575
                free(p);
331 1575
                break;
332
        default:
333 0
                return (vsm_diag(vd, "Unknown VSM_Arg('%c')", flag));
334
        }
335 1576
        return (1);
336
}
337
338
/*--------------------------------------------------------------------*/
339
340
void
341 1565
VSM_Destroy(struct vsm **vdp)
342
{
343
        struct vsm *vd;
344
345 1565
        TAKE_OBJ_NOTNULL(vd, vdp, VSM_MAGIC);
346
347 1565
        VSM_ResetError(vd);
348 1565
        REPLACE(vd->dname, NULL);
349 1565
        if (vd->diag != NULL)
350 0
                VSB_destroy(&vd->diag);
351 1565
        if (vd->dfd >= 0)
352 1565
                closefd(&vd->dfd);
353 1565
        vsm_delset(&vd->mgt);
354 1565
        vsm_delset(&vd->child);
355 1565
        FREE_OBJ(vd);
356 1565
}
357
358
/*--------------------------------------------------------------------*/
359
360
const char *
361 109
VSM_Error(const struct vsm *vd)
362
{
363
364 109
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
365
366 109
        if (vd->diag == NULL)
367 0
                return ("No VSM error");
368
        else
369 109
                return (VSB_data(vd->diag));
370
}
371
372
/*--------------------------------------------------------------------*/
373
374
void
375 3144
VSM_ResetError(struct vsm *vd)
376
{
377
378 3144
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
379
380 3144
        if (vd->diag == NULL)
381 3122
                return;
382 22
        VSB_destroy(&vd->diag);
383
}
384
385
/*--------------------------------------------------------------------
386
 */
387
388
#define VSM_NUKE_ALL    (1U << 16)
389
390
static int
391 124898
vsm_cmp_av(char * const *a1, char * const *a2)
392
{
393
394
        while (1) {
395 228323
                if (*a1 == NULL && *a2 == NULL)
396 20581
                        return (0);
397 104317
                if (*a1 == NULL || *a2 == NULL)
398 211
                        return (1);
399 104106
                if (strcmp(*a1, *a2))
400 681
                        return (1);
401 103425
                a1++;
402 103425
                a2++;
403
        }
404
}
405
406
static struct vsm_seg *
407 46501
vsm_findcluster(const struct vsm_seg *vga)
408
{
409 46501
        const struct vsm_set *vs = vga->set;
410
        struct vsm_seg *vg;
411 46501
        AN(vs);
412 46501
        AN(vga->av[1]);
413 56706
        VTAILQ_FOREACH(vg, &vs->clusters, list) {
414 12212
                AN(vg->av[1]);
415 12212
                if (!strcmp(vga->av[1], vg->av[1]))
416 2007
                        return (vg);
417
        }
418 44494
        return (NULL);
419
}
420
421
static unsigned
422 113763
vsm_refresh_set2(struct vsm *vd, struct vsm_set *vs, struct vsb *vsb)
423
{
424 113763
        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 113763
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
435 113763
        CHECK_OBJ_NOTNULL(vs, VSM_SET_MAGIC);
436 113763
        if (vs->dfd >= 0) {
437 88999
                if (fstatat(vd->dfd, vs->dname, &st, AT_SYMLINK_NOFOLLOW)) {
438 0
                        closefd(&vs->dfd);
439 -2
                        vs->id1 = vs->id2 = 0;
440 -2
                        return (VSM_MGT_RESTARTED|VSM_NUKE_ALL);
441
                }
442 177967
                if (st.st_ino != vs->dst.st_ino ||
443 177938
                    st.st_dev != vs->dst.st_dev ||
444 88969
                    st.st_mode != vs->dst.st_mode) {
445 32
                        closefd(&vs->dfd);
446 32
                        vs->id1 = vs->id2 = 0;
447
                }
448
        }
449
450 113762
        if (vs->dfd < 0) {
451 24793
                if (vs->fd >= 0)
452 32
                        closefd(&vs->fd);
453 24793
                vs->dfd = openat(vd->dfd, vs->dname, O_RDONLY);
454 24793
                retval |= VSM_MGT_RESTARTED;
455 24793
                if (vs->dfd < 0) {
456 22211
                        vs->id1 = vs->id2 = 0;
457 22211
                        return (retval|VSM_NUKE_ALL);
458
                }
459 2582
                AZ(fstat(vs->dfd, &vs->dst));
460
        }
461
462 177065
        if (vs->fd >= 0 && (
463 170340
            fstatat(vs->dfd, "_.index", &st, AT_SYMLINK_NOFOLLOW) ||
464 169585
            st.st_ino != vs->fst.st_ino ||
465 169519
            st.st_dev != vs->fst.st_dev ||
466 169518
            st.st_mode != vs->fst.st_mode ||
467 168029
            st.st_size != vs->fst.st_size ||
468 166540
            st.st_nlink < 1 ||
469 83270
            memcmp(&st.st_mtime, &vs->fst.st_mtime, sizeof st.st_mtime))) {
470 2245
                closefd(&vs->fd);
471
        }
472
473 91550
        if (vs->fd >= 0) {
474 83270
                if (vd->couldkill < 1 || !kill(vs->id1, 0))
475 79243
                        retval |= VSM_MGT_RUNNING;
476 83269
                return (retval);
477
        }
478
479 8280
        retval |= VSM_MGT_CHANGED;
480 8280
        vs->fd = openat(vs->dfd, "_.index", O_RDONLY);
481 8280
        if (vs->fd < 0)
482 4142
                return (retval|VSM_MGT_RESTARTED);
483
484 4138
        AZ(fstat(vs->fd, &vs->fst));
485
486 4138
        VSB_clear(vsb);
487
        do {
488 9815
                sz = read(vs->fd, buf, sizeof buf);
489 9815
                if (sz > 0)
490 5677
                        VSB_bcat(vsb, buf, sz);
491 9815
        } while (sz > 0);
492 4138
        AZ(VSB_finish(vsb));
493
494 4138
        vs->fst.st_size = VSB_len(vsb);
495
496 4138
        if (VSB_len(vsb) == 0)
497 0
                return (retval|VSM_NUKE_ALL);
498
499
        /*
500
         * First line is ident comment
501
         */
502 4138
        i = sscanf(VSB_data(vsb), "# %ju %ju\n%n", &id1, &id2, &ac);
503 4138
        if (i != 2) {
504 0
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
505 0
                return (retval);
506
        }
507 4138
        if (vd->couldkill >= 0 && !kill(id1, 0)) {
508 4137
                vd->couldkill = 1;
509 1
        } else if (vd->couldkill > 0 && errno == ESRCH) {
510 1
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
511 1
                return (retval);
512
        }
513 4137
        retval |= VSM_MGT_RUNNING;
514 4137
        if (id1 != vs->id1 || id2 != vs->id2) {
515 2581
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
516 2581
                vs->id1 = id1;
517 2581
                vs->id2 = id2;
518
        }
519 4137
        p = VSB_data(vsb) + ac;
520
521 26698
        VTAILQ_FOREACH(vg, &vs->segs, list)
522 22561
                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 4137
        if (retval & VSM_MGT_RESTARTED)
533 2581
                vg = NULL;
534
        else
535 1556
                vg = VTAILQ_FIRST(&vs->segs);
536
537 77071
        while (p != NULL && *p != '\0') {
538 68797
                e = strchr(p, '\n');
539 68797
                if (e == NULL)
540 0
                        break;
541 68797
                *e = '\0';
542 68797
                av = VAV_Parse(p, &ac, 0);
543 68797
                p = e + 1;
544
545 68797
                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 68797
                if (vg == NULL) {
554 47997
                        ALLOC_OBJ(vg2, VSM_SEG_MAGIC);
555 47997
                        AN(vg2);
556 47997
                        vg2->av = av;
557 47997
                        vg2->set = vs;
558 47997
                        vg2->flags = VSM_FLAG_MARKSCAN;
559 47997
                        vg2->serial = ++vd->serial;
560 47997
                        if (ac == 4) {
561 1496
                                vg2->flags |= VSM_FLAG_CLUSTER;
562 1496
                                VTAILQ_INSERT_TAIL(&vs->clusters, vg2, list);
563
                        } else {
564 46501
                                VTAILQ_INSERT_TAIL(&vs->segs, vg2, list);
565 46501
                                vg2->cluster = vsm_findcluster(vg2);
566
                        }
567 47997
                        continue;
568
                }
569
570 42492
                while (vg != NULL && vsm_cmp_av(&vg->av[1], &av[1]))
571 892
                        vg = VTAILQ_NEXT(vg, list);
572
573 20800
                VAV_Free(av);
574
575 20800
                if (vg == NULL)
576 219
                        continue;
577
578
                /* entry compared equal, so it survives */
579 20581
                vg->flags |= VSM_FLAG_MARKSCAN;
580 20581
                vg = VTAILQ_NEXT(vg, list);
581
        }
582 4137
        return (retval);
583
}
584
585
static unsigned
586 113758
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 113758
        retval = vsm_refresh_set2(vd, vs, vsb);
592 113761
        if (retval & VSM_NUKE_ALL)
593 22211
                retval |= VSM_MGT_CHANGED;
594 1571403
        VTAILQ_FOREACH_SAFE(vg, &vs->segs, list, vg2) {
595 2913294
                if ((vg->flags & VSM_FLAG_MARKSCAN) == 0 ||
596 1455652
                    (retval & VSM_NUKE_ALL)) {
597 1980
                        VTAILQ_REMOVE(&vs->segs, vg, list);
598 1980
                        if (vg->refs) {
599 15
                                vg->flags |= VSM_FLAG_STALE;
600 15
                                VTAILQ_INSERT_TAIL(&vs->stale, vg, list);
601
                        } else {
602 1965
                                VAV_Free(vg->av);
603 1965
                                FREE_OBJ(vg);
604
                        }
605
                }
606
        }
607 113761
        return (retval & ~VSM_NUKE_ALL);
608
}
609
610
/*--------------------------------------------------------------------*/
611
612
unsigned
613 57556
VSM_Status(struct vsm *vd)
614
{
615 57556
        unsigned retval = 0, u;
616
        struct stat st;
617
        struct vsb *vsb;
618
619 57556
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
620
621
        /* See if the -n workdir changed */
622 57556
        if (vd->dfd >= 0) {
623 55977
                AZ(fstat(vd->dfd, &st));
624 111952
                if (st.st_ino != vd->dst.st_ino ||
625 111952
                    st.st_dev != vd->dst.st_dev ||
626 111952
                    st.st_mode != vd->dst.st_mode ||
627 55976
                    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 57555
        if (vd->dfd < 0) {
636 1579
                vd->dfd = open(vd->dname, O_RDONLY);
637 1579
                if (vd->dfd < 0)
638 5
                        (void)vsm_diag(vd,
639
                            "VSM_Status: Cannot open workdir");
640
                else
641 1574
                        AZ(fstat(vd->dfd, &vd->dst));
642
        }
643
644 57555
        vsb = VSB_new_auto();
645 57554
        AN(vsb);
646
647 57554
        u = vsm_refresh_set(vd, vd->mgt, vsb);
648 57556
        retval |= u;
649 57556
        if (u & VSM_MGT_RUNNING)
650 56206
                retval |= vsm_refresh_set(vd, vd->child, vsb) << 8;
651 57556
        VSB_destroy(&vsb);
652 57556
        return (retval);
653
}
654
655
/*--------------------------------------------------------------------*/
656
657
int
658 1575
VSM_Attach(struct vsm *vd, int progress)
659
{
660
        double t0;
661
        unsigned u;
662 1575
        int i, n = 0;
663
664 1575
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
665
666 1575
        if (vd->patience < 0)
667 0
                t0 = DBL_MAX;
668
        else
669 1575
                t0 = VTIM_mono() + vd->patience;
670
671 1575
        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 1575
        AZ(vd->attached);
680
        while (1) {
681 4
                u = VSM_Status(vd);
682 1579
                VSM_ResetError(vd);
683 1579
                if (u & VSM_MGT_RUNNING) {
684 1574
                        if (progress >= 0 && n > 4)
685 0
                                (void)write(progress, "\n", 1);
686 1574
                        vd->attached = 1;
687 1574
                        return (0);
688
                }
689 5
                if (t0 < VTIM_mono()) {
690 1
                        if (progress >= 0 && n > 4)
691 0
                                (void)write(progress, "\n", 1);
692 1
                        return (vsm_diag(vd,
693
                            "Could not get hold of varnishd, is it running?"));
694
                }
695 4
                if (progress >= 0 && !(++n % 4))
696 1
                        (void)write(progress, ".", 1);
697 4
                VTIM_sleep(.25);
698
        }
699
}
700
701
/*--------------------------------------------------------------------*/
702
703
static struct vsm_seg *
704 242152
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 242152
        x = vf->priv;
711 242152
        vs = vd->mgt;
712 1214277
        VTAILQ_FOREACH(vg, &vs->segs, list)
713 1128096
                if (vg->serial == x)
714 155971
                        return (vg);
715 86181
        VTAILQ_FOREACH(vg, &vs->stale, list)
716 0
                if (vg->serial == x)
717 0
                        return (vg);
718 86181
        vs = vd->child;
719 803113
        VTAILQ_FOREACH(vg, &vs->segs, list)
720 803091
                if (vg->serial == x)
721 86159
                        return (vg);
722 22
        VTAILQ_FOREACH(vg, &vs->stale, list)
723 22
                if (vg->serial == x)
724 22
                        return (vg);
725 0
        return (NULL);
726
}
727
728
/*--------------------------------------------------------------------*/
729
730
void
731 27837
VSM__iter0(const struct vsm *vd, struct vsm_fantom *vf)
732
{
733
734 27837
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
735 27837
        AN(vf);
736
737 27837
        AN(vd->attached);
738 27837
        memset(vf, 0, sizeof *vf);
739 27837
}
740
741
int
742 206474
VSM__itern(struct vsm *vd, struct vsm_fantom *vf)
743
{
744
        struct vsm_seg *vg, *vg2;
745
746 206474
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
747 206474
        AN(vd->attached);
748 206474
        AN(vf);
749
750 206474
        if (vf->priv == 0) {
751 27840
                vg2 = VTAILQ_FIRST(&vd->mgt->segs);
752
        } else {
753 178634
                vg = vsm_findseg(vd, vf);
754 178633
                if (vg == NULL)
755 0
                        return (vsm_diag(vd, "VSM_FOREACH: inconsistency"));
756 178633
                vg2 = VTAILQ_NEXT(vg, list);
757 178633
                if (vg2 == NULL && vg->set == vd->mgt)
758 27802
                        vg2 = VTAILQ_FIRST(&vd->child->segs);
759
        }
760 206473
        if (vg2 == NULL)
761 23880
                return (0);
762 182593
        memset(vf, 0, sizeof *vf);
763 182593
        vf->priv = vg2->serial;
764 182593
        vf->class = vg2->av[4];
765 182593
        vf->ident = vg2->av[5];
766 182593
        return (1);
767
}
768
769
/*--------------------------------------------------------------------*/
770
771
int
772 5728
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 5728
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
779 5728
        AN(vd->attached);
780 5728
        AN(vf);
781 5728
        vg = vsm_findseg(vd, vf);
782 5728
        if (vg == NULL)
783 0
                return (vsm_diag(vd, "VSM_Map: bad fantom"));
784
785 5728
        assert(vg->serial == vf->priv);
786 5728
        assert(vg->av[4] == vf->class);
787 5728
        assert(vg->av[5] == vf->ident);
788
789 5728
        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 5728
        assert(vg->refs == 0);
799
800 5728
        vgc = vg->cluster;
801
802 5728
        if (vgc == NULL) {
803 5602
                r = vsm_mapseg(vd, vg);
804 5602
                if (r)
805 102
                        return (r);
806 5500
                vf->b = vg->b;
807 5500
                vf->e = vg->e;
808
809 5500
                vg->refs++;
810
811 5500
                return (0);
812
        }
813
814 126
        assert(vgc->flags & VSM_FLAG_CLUSTER);
815 126
        assert(vg->s == NULL);
816 126
        assert(vg->sz == 0);
817
818 126
        r = vsm_mapseg(vd, vgc);
819 126
        if (r)
820 0
                return (r);
821 126
        vgc->refs++;
822
823 126
        of = strtoul(vg->av[2], NULL, 10);
824 126
        sz = strtoul(vg->av[3], NULL, 10);
825 126
        assert(sz > 0);
826
827 126
        assert(vgc->sz >= of + sz);
828 126
        assert(vgc->s == vgc->b);
829 126
        vg->b = (char *)vgc->b + of;
830 126
        vg->e = (char *)vg->b + sz;
831
832 126
        vf->b = vg->b;
833 126
        vf->e = vg->e;
834
835 126
        vg->refs++;
836
837 126
        return (0);
838
}
839
840
/*--------------------------------------------------------------------*/
841
842
int
843 5203
VSM_Unmap(struct vsm *vd, struct vsm_fantom *vf)
844
{
845
        struct vsm_seg *vg;
846
847 5203
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
848 5203
        AN(vd->attached);
849 5203
        AN(vf);
850 5203
        AN(vf->b);
851 5203
        vg = vsm_findseg(vd, vf);
852 5203
        if (vg == NULL)
853 0
                return (vsm_diag(vd, "VSM_Unmap: bad fantom"));
854 5203
        assert(vg->refs > 0);
855 5203
        vg->refs--;
856 5203
        vf->b = NULL;
857 5203
        vf->e = NULL;
858 5203
        if (vg->refs > 0)
859 0
                return(0);
860
861 5203
        if (vg->cluster) {
862 18
                assert(vg->s == NULL);
863 18
                assert(vg->sz == 0);
864 18
                assert(vg->cluster->refs > 0);
865 18
                if (--vg->cluster->refs == 0)
866 18
                        vsm_unmapseg(vg->cluster);
867 18
                vg->b = vg->e = NULL;
868
        } else {
869 5185
                vsm_unmapseg(vg);
870
        }
871 5203
        if (vg->flags & VSM_FLAG_STALE)
872 15
                vsm_delseg(vg);
873 5203
        return (0);
874
}
875
876
/*--------------------------------------------------------------------*/
877
878
const struct vsm_valid *
879 52597
VSM_StillValid(const struct vsm *vd, const struct vsm_fantom *vf)
880
{
881
        struct vsm_seg *vg;
882
883 52597
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
884 52597
        AN(vf);
885 52597
        vg = vsm_findseg(vd, vf);
886 52597
        if (vg == NULL || vg->flags & VSM_FLAG_STALE)
887 7
                return (VSM_invalid);
888 52590
        return (VSM_valid);
889
}
890
891
/*--------------------------------------------------------------------*/
892
893
int
894 26858
VSM_Get(struct vsm *vd, struct vsm_fantom *vf,
895
    const char *class, const char *ident)
896
{
897
898 26858
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
899 26858
        AN(vd->attached);
900 207350
        VSM_FOREACH(vf, vd) {
901 156941
                if (strcmp(vf->class, class))
902 153634
                        continue;
903 3307
                if (ident != NULL && strcmp(vf->ident, ident))
904 0
                        continue;
905 3307
                return (1);
906
        }
907 23551
        memset(vf, 0, sizeof *vf);
908 23551
        return (0);
909
}
910
911
/*--------------------------------------------------------------------*/
912
913
char *
914 32
VSM_Dup(struct vsm *vd, const char *class, const char *ident)
915
{
916
        struct vsm_fantom vf;
917 32
        char *p = NULL;
918
919 32
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
920 32
        AN(vd->attached);
921 148
        VSM_FOREACH(&vf, vd) {
922 116
                if (strcmp(vf.class, class))
923 48
                        continue;
924 68
                if (ident != NULL && strcmp(vf.ident, ident))
925 36
                        continue;
926 32
                AZ(VSM_Map(vd, &vf));
927 32
                AN(vf.b);
928 32
                AN(vf.e);
929 32
                p = malloc((char*)vf.e - (char*)vf.b);
930 32
                AN(p);
931 32
                memcpy(p, vf.b, (char*)vf.e - (char*)vf.b);
932 32
                AZ(VSM_Unmap(vd, &vf));
933 32
                break;
934
        }
935 32
        return (p);
936
}