vinyl-cache/lib/libvinylapi/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                lineno;
130
        unsigned                retval;
131
        struct vsm_seg          *vg;
132
133
        unsigned                flag_running;
134
        unsigned                flag_changed;
135
        unsigned                flag_restarted;
136
137
        int                     couldkill;
138
};
139
140
struct vsm {
141
        unsigned                magic;
142
#define VSM_MAGIC               0x6e3bd69b
143
144
        struct vsb              *diag;
145
        uint64_t                serial;
146
147
        int                     wdfd;
148
        struct stat             wdst;
149
        char                    *wdname;
150
151
        struct vsm_set          *mgt;
152
        struct vsm_set          *child;
153
154
        int                     attached;
155
        double                  patience;
156
};
157
158
/*--------------------------------------------------------------------*/
159
160
static int
161 189
vsm_diag(struct vsm *vd, const char *fmt, ...)
162
{
163
        va_list ap;
164
165 189
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
166 189
        AN(fmt);
167
168 189
        if (vd->diag == NULL)
169 189
                vd->diag = VSB_new_auto();
170 189
        AN(vd->diag);
171 189
        VSB_clear(vd->diag);
172 189
        va_start(ap, fmt);
173 189
        VSB_vprintf(vd->diag, fmt, ap);
174 189
        va_end(ap);
175 189
        AZ(VSB_finish(vd->diag));
176 189
        return (-1);
177
}
178
179
/*--------------------------------------------------------------------*/
180
181
static int
182 28576
vsm_mapseg(struct vsm *vd, struct vsm_seg *vg)
183
{
184
        size_t of, off, sz, ps, len;
185
        struct vsb *vsb;
186
        void *s;
187
        int fd;
188
189 28576
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
190
191 28576
        if (vg->s != NULL)
192 404
                return (0);
193
194 28172
        ps = getpagesize();
195
196 28172
        of = strtoul(vg->av[2], NULL, 10);
197 28172
        off = RDN2(of, ps);
198
199 28172
        if (vg->flags & VSM_FLAG_CLUSTER)
200 180
                assert(of == 0);
201 28172
        assert(vg->cluster == NULL);
202
203 28172
        sz = strtoul(vg->av[3], NULL, 10);
204 28172
        assert(sz > 0);
205 28172
        assert(of >= off);
206 28172
        len = RUP2((of - off) + sz, ps);
207
208 28172
        vsb = VSB_new_auto();
209 28172
        AN(vsb);
210 28172
        VSB_printf(vsb, "%s/%s/%s", vd->wdname, vg->set->dname, vg->av[1]);
211 28172
        AZ(VSB_finish(vsb));
212
213 28172
        fd = open(VSB_data(vsb), O_RDONLY);     // XXX: openat
214 28172
        if (fd < 0) {
215 5
                VSB_destroy(&vsb);
216 5
                return (vsm_diag(vd, "Could not open segment"));
217
        }
218
219 56334
        s = (void*)mmap(NULL, len,
220
            PROT_READ,
221
            MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED,
222 28167
            fd, (off_t)off);
223
224 28167
        VSB_destroy(&vsb);
225
226 28167
        closefd(&fd);
227 28167
        if (s == MAP_FAILED)
228 0
                return (vsm_diag(vd, "Could not mmap segment"));
229
230 28167
        vg->s = s;
231 28167
        vg->b = (char*)(vg->s) + of - off;
232 28167
        vg->e = (char *)vg->b + sz;
233 28167
        vg->sz = len;
234
235 28167
        return (0);
236 28576
}
237
238
static void
239 25159
vsm_unmapseg(struct vsm_seg *vg)
240
{
241
242 25159
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
243
244 25159
        AN(vg->b);
245 25159
        AN(vg->e);
246 25159
        AZ(munmap(vg->s, vg->sz));
247 25159
        vg->s = vg->b = vg->e = NULL;
248 25159
        vg->sz = 0;
249 25159
}
250
251
/*--------------------------------------------------------------------*/
252
253
static void
254 369950
vsm_delseg(struct vsm_seg *vg, int refsok)
255
{
256
257 369950
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
258
259 369950
        if (vg->set->vg == vg) {
260 20683
                AZ(vg->flags & VSM_FLAG_STALE);
261 20683
                vg->set->vg = VTAILQ_NEXT(vg, list);
262 20683
        }
263
264 369950
        if (refsok && vg->refs) {
265 598
                AZ(vg->flags & VSM_FLAG_STALE);
266 598
                vg->flags |= VSM_FLAG_STALE;
267 598
                VTAILQ_REMOVE(&vg->set->segs, vg, list);
268 598
                VTAILQ_INSERT_TAIL(&vg->set->stale, vg, list);
269 598
                return;
270
        }
271
272 369352
        if (vg->s != NULL)
273 0
                vsm_unmapseg(vg);
274
275 369352
        if (vg->flags & VSM_FLAG_CLUSTER) {
276 8760
                vg->flags &= ~VSM_FLAG_CLUSTER;
277 8760
                VTAILQ_REMOVE(&vg->set->clusters, vg, clist);
278 8760
        }
279
280 369352
        if (vg->flags & VSM_FLAG_STALE)
281 598
                VTAILQ_REMOVE(&vg->set->stale, vg, list);
282
        else
283 368754
                VTAILQ_REMOVE(&vg->set->segs, vg, list);
284 369352
        VAV_Free(vg->av);
285 369352
        FREE_OBJ(vg);
286 369950
}
287
288
/*--------------------------------------------------------------------*/
289
290
static struct vsm_set *
291 19448
vsm_newset(const char *dirname)
292
{
293
        struct vsm_set *vs;
294
295 19448
        ALLOC_OBJ(vs, VSM_SET_MAGIC);
296 19448
        AN(vs);
297 19448
        VTAILQ_INIT(&vs->segs);
298 19448
        VTAILQ_INIT(&vs->stale);
299 19448
        VTAILQ_INIT(&vs->clusters);
300 19448
        vs->dname = dirname;
301 19448
        vs->dfd = vs->fd = -1;
302 19448
        vs->vlu = VLU_New(vsm_vlu_func, vs, 0);
303 19448
        AN(vs->vlu);
304 19448
        if (getenv("VSM_NOPID") != NULL)
305 0
                vs->couldkill = -1;
306 19448
        return (vs);
307
}
308
309
static void
310 19224
vsm_delset(struct vsm_set **p)
311
{
312
        struct vsm_set *vs;
313
        struct vsm_seg *vg;
314
315 19224
        TAKE_OBJ_NOTNULL(vs, p, VSM_SET_MAGIC);
316
317 19224
        if (vs->fd >= 0)
318 11888
                closefd(&vs->fd);
319 19224
        if (vs->dfd >= 0)
320 15860
                closefd(&vs->dfd);
321 19224
        while ((vg = VTAILQ_FIRST(&vs->stale)) != NULL) {
322 0
                AN(vg->flags & VSM_FLAG_STALE);
323 0
                vsm_delseg(vg, 0);
324
        }
325 360512
        while ((vg = VTAILQ_FIRST(&vs->segs)) != NULL) {
326 341288
                AZ(vg->flags & VSM_FLAG_STALE);
327 341288
                vsm_delseg(vg, 0);
328
        }
329 19224
        assert(VTAILQ_EMPTY(&vs->clusters));
330 19224
        VLU_Destroy(&vs->vlu);
331 19224
        FREE_OBJ(vs);
332 19224
}
333
334
static void
335 49775
vsm_wash_set(const struct vsm_set *vs, int all)
336
{
337
        struct vsm_seg *vg, *vg2;
338
339 408518
        VTAILQ_FOREACH_SAFE(vg, &vs->segs, list, vg2) {
340 358743
                if (all || (vg->flags & VSM_FLAG_MARKSCAN) == 0)
341 11812
                        vsm_delseg(vg, 1);
342 358743
        }
343 49775
}
344
345
/*--------------------------------------------------------------------*/
346
347
struct vsm *
348 9724
VSM_New(void)
349
{
350
        struct vsm *vd;
351
352 9724
        ALLOC_OBJ(vd, VSM_MAGIC);
353 9724
        AN(vd);
354
355 9724
        vd->mgt = vsm_newset(VSM_MGT_DIRNAME);
356 9724
        vd->mgt->flag_running = VSM_MGT_RUNNING;
357 9724
        vd->mgt->flag_changed = VSM_MGT_CHANGED;
358 9724
        vd->mgt->flag_restarted = VSM_MGT_RESTARTED;
359
360 9724
        vd->child = vsm_newset(VSM_CHILD_DIRNAME);
361 9724
        vd->child->flag_running = VSM_WRK_RUNNING;
362 9724
        vd->child->flag_changed = VSM_WRK_CHANGED;
363 9724
        vd->child->flag_restarted = VSM_WRK_RESTARTED;
364
365 9724
        vd->mgt->vsm = vd;
366 9724
        vd->child->vsm = vd;
367 9724
        vd->wdfd = -1;
368 9724
        vd->patience = 5;
369 9724
        return (vd);
370
}
371
372
/*--------------------------------------------------------------------*/
373
374
int
375 9892
VSM_Arg(struct vsm *vd, char flag, const char *arg)
376
{
377 9892
        char *p = NULL;
378
379 9892
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
380
381 9892
        if (arg == NULL)
382 156
                return (1);
383 9736
        switch (flag) {
384
        case 't':
385 52
                if (!strcasecmp(arg, "off")) {
386 0
                        vd->patience = -1;
387 0
                } else {
388 52
                        vd->patience = strtod(arg, &p);
389 84
                        if ((p != NULL && *p != '\0') ||
390 32
                            !isfinite(vd->patience) || vd->patience < 0)
391 56
                                return (vsm_diag(vd,
392 28
                                    "-t: Invalid argument: %s", arg));
393
                }
394 24
                break;
395
        case 'n':
396 9684
                if (vd->wdname != NULL)
397 0
                        free(vd->wdname);
398 9684
                vd->wdname = VIN_n_Arg(arg);
399 9684
                if (vd->wdname == NULL)
400 0
                        return (vsm_diag(vd, "Invalid instance name: %s",
401 0
                            strerror(errno)));
402 9684
                break;
403
        default:
404 0
                return (vsm_diag(vd, "Unknown VSM_Arg('%c')", flag));
405
        }
406 9708
        return (1);
407 9892
}
408
409
/*--------------------------------------------------------------------*/
410
411
void
412 9612
VSM_Destroy(struct vsm **vdp)
413
{
414
        struct vsm *vd;
415
416 9612
        TAKE_OBJ_NOTNULL(vd, vdp, VSM_MAGIC);
417
418 9612
        VSM_ResetError(vd);
419 9612
        REPLACE(vd->wdname, NULL);
420 9612
        if (vd->diag != NULL)
421 0
                VSB_destroy(&vd->diag);
422 9612
        if (vd->wdfd >= 0)
423 9604
                closefd(&vd->wdfd);
424 9612
        vsm_delset(&vd->mgt);
425 9612
        vsm_delset(&vd->child);
426 9612
        FREE_OBJ(vd);
427 9612
}
428
429
/*--------------------------------------------------------------------*/
430
431
const char *
432 49
VSM_Error(const struct vsm *vd)
433
{
434
435 49
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
436
437 49
        if (vd->diag == NULL)
438 0
                return ("No VSM error");
439
        else
440 49
                return (VSB_data(vd->diag));
441 49
}
442
443
/*--------------------------------------------------------------------*/
444
445
void
446 19428
VSM_ResetError(struct vsm *vd)
447
{
448
449 19428
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
450
451 19428
        if (vd->diag == NULL)
452 19275
                return;
453 153
        VSB_destroy(&vd->diag);
454 19428
}
455
456
/*--------------------------------------------------------------------
457
 */
458
459
static int
460 397715
vsm_cmp_av(char * const *a1, char * const *a2)
461
{
462
463 471784
        while (1) {
464 471784
                if (*a1 == NULL && *a2 == NULL)
465 16468
                        return (0);
466 455316
                if (*a1 == NULL || *a2 == NULL)
467 0
                        return (1);
468 455316
                if (vstrcmp(*a1, *a2))
469 381247
                        return (1);
470 74069
                a1++;
471 74069
                a2++;
472
        }
473 397715
}
474
475
static struct vsm_seg *
476 8566
vsm_findcluster(const struct vsm_set *vs, const char *cnam)
477
{
478
        struct vsm_seg *vg;
479 8566
        AN(vs);
480 8566
        AN(cnam);
481 12008
        VTAILQ_FOREACH(vg, &vs->clusters, clist) {
482 12008
                AN(vg->av[1]);
483 12008
                if (!vstrcmp(cnam, vg->av[1]))
484 8566
                        return (vg);
485 3442
        }
486 0
        return (NULL);
487 8566
}
488
489
static unsigned
490 324736
vsm_running(struct vsm_set *vs, pid_t pid)
491
{
492
493 324736
        AN(vs);
494
495 324736
        if (pid == 0)
496 0
                return (0);
497
498 324736
        if (kill(pid, 0) == 0) {
499 314735
                vs->couldkill = 1;
500 314735
                return (1);
501
        }
502 10001
        if (errno == EPERM)     /* a process exists, assume running */
503 0
                return (1);
504 10001
        assert(errno != EINVAL);
505 10001
        return (0);
506 324736
}
507
508
static int
509 16248
vsm_vlu_hash(struct vsm_set *vs, const char *line)
510
{
511
        int i;
512
        uintmax_t id1, id2;
513
514 16248
        i = sscanf(line, "# %ju %ju", &id1, &id2);
515 16248
        if (i != 2) {
516 0
                vs->retval |= vs->flag_restarted;
517 0
                return (0);
518
        }
519 16248
        if (vs->couldkill >= 0 && vsm_running(vs, id1)) {
520
                /* nothing to do */
521 16248
        } else if (vs->couldkill > 0 && errno == ESRCH) {
522 0
                vs->retval |= vs->flag_restarted | VSM_MGT_CHANGED;
523 0
                return (0);
524
        }
525 16248
        vs->retval |= VSM_MGT_RUNNING;
526 16248
        if (id1 != vs->id1 || id2 != vs->id2) {
527 16240
                vs->retval |= vs->flag_restarted;
528 16240
                vs->id1 = id1;
529 16240
                vs->id2 = id2;
530 16240
        }
531 16248
        return (0);
532 16248
}
533
534
static int
535 0
vsm_bad_index(struct vsm *vd, const struct vsm_set *vs, const char *line,
536
    int ac, const char *err)
537
{
538
539
        /* av[0] is VAV_Parse's error slot, so ac is one more than the
540
         * number of fields on the line
541
         */
542 0
        if (err != NULL)
543 0
                return (vsm_diag(vd, "Malformed _.index line %u: %s: %s",
544 0
                    vs->lineno, err, line));
545 0
        if (ac > 6)
546 0
                return (vsm_diag(vd, "Malformed _.index line %u: %d fields, "
547
                    "expected 3 to 5.  Whitespace in a segment name or ident "
548 0
                    "splits it into extra fields: %s", vs->lineno, ac - 1,
549 0
                    line));
550 0
        return (vsm_diag(vd, "Malformed _.index line %u: %d fields, "
551 0
            "expected 3 to 5: %s", vs->lineno, ac - 1, line));
552 0
}
553
554
static int
555 373420
vsm_vlu_plus(struct vsm *vd, struct vsm_set *vs, const char *line)
556
{
557
        char **av;
558
        int ac;
559
        struct vsm_seg *vg;
560
561 373420
        av = VAV_Parse(line + 1, &ac, 0);
562
563 373420
        if (av[0] != NULL || ac < 4 || ac > 6) {
564 0
                (void)vsm_bad_index(vd, vs, line, ac, av[0]);
565 0
                VAV_Free(av);
566 0
                return (-1);
567
        }
568
569 373420
        vg = vs->vg;
570 373420
        CHECK_OBJ_ORNULL(vg, VSM_SEG_MAGIC);
571 373420
        if (vg != NULL)
572 216
                AZ(vg->flags & VSM_FLAG_STALE);
573 373420
        while (vg != NULL && vsm_cmp_av(&vg->av[1], &av[1]))
574 0
                vg = VTAILQ_NEXT(vg, list);
575 373420
        if (vg != NULL) {
576
                /* entry compared equal, so it survives */
577 216
                CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
578 216
                VAV_Free(av);
579 216
                vg->flags |= VSM_FLAG_MARKSCAN;
580 216
                vs->vg = VTAILQ_NEXT(vg, list);
581 216
        } else {
582 373204
                ALLOC_OBJ(vg, VSM_SEG_MAGIC);
583 373204
                AN(vg);
584 373204
                vg->av = av;
585 373204
                vg->set = vs;
586 373204
                vg->flags = VSM_FLAG_MARKSCAN;
587 373204
                vg->serial = vd->serial;
588
589 373204
                VTAILQ_INSERT_TAIL(&vs->segs, vg, list);
590 373204
                if (ac == 4) {
591 8824
                        vg->flags |= VSM_FLAG_CLUSTER;
592 8824
                        VTAILQ_INSERT_TAIL(&vs->clusters, vg, clist);
593 373204
                } else if (*vg->av[2] != '0') {
594 8356
                        vg->cluster = vsm_findcluster(vs, vg->av[1]);
595 8356
                        CHECK_OBJ_NOTNULL(vg->cluster, VSM_SEG_MAGIC);
596 8356
                }
597 373204
                vs->retval |= vs->flag_changed;
598
        }
599 373420
        return (0);
600 373420
}
601
602
static int
603 16252
vsm_vlu_minus(struct vsm *vd, struct vsm_set *vs, const char *line)
604
{
605
        char **av;
606
        int ac;
607
        struct vsm_seg *vg;
608
609 16252
        av = VAV_Parse(line + 1, &ac, 0);
610
611 16252
        if (av[0] != NULL || ac < 4 || ac > 6) {
612 0
                (void)vsm_bad_index(vd, vs, line, ac, av[0]);
613 0
                VAV_Free(av);
614 0
                return (-1);
615
        }
616
617
        /* Clustered segments cannot come before their cluster */
618 16252
        if (*av[2] != '0')
619 210
                vg = vsm_findcluster(vs, av[1]);
620
        else
621 16042
                vg = VTAILQ_FIRST(&vs->segs);
622
623 397499
        for (;vg != NULL; vg = VTAILQ_NEXT(vg, list)) {
624 397499
                if (!vsm_cmp_av(&vg->av[1], &av[1])) {
625 16252
                        vs->retval |= vs->flag_changed;
626 16252
                        vsm_delseg(vg, 1);
627 16252
                        break;
628
                }
629 381247
        }
630 16252
        AN(vg);
631 16252
        VAV_Free(av);
632 16252
        return (0);
633 16252
}
634
635
static int v_matchproto_(vlu_f)
636 405920
vsm_vlu_func(void *priv, const char *line)
637
{
638
        struct vsm *vd;
639
        struct vsm_set *vs;
640 405920
        int i = 0;
641
642 405920
        CAST_OBJ_NOTNULL(vs, priv, VSM_SET_MAGIC);
643 405920
        vd = vs->vsm;
644 405920
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
645 405920
        AN(line);
646
647 405920
        vs->lineno++;
648
649
        /* Up the serial counter. This wraps at UINTPTR_MAX/2
650
         * because thats the highest value we can store in struct
651
         * vsm_fantom. */
652 405920
        vd->serial = VSM_PRIV_LOW(vd->serial + 1);
653
654 405920
        switch (line[0]) {
655
        case '#':
656 16248
                i = vsm_vlu_hash(vs, line);
657 28276
                VTAILQ_FOREACH(vs->vg, &vs->segs, list)
658 12028
                        vs->vg->flags &= ~VSM_FLAG_MARKSCAN;
659 16248
                if (!(vs->retval & vs->flag_restarted))
660 8
                        vs->vg = VTAILQ_FIRST(&vs->segs);
661 16248
                break;
662
        case '+':
663 373420
                i = vsm_vlu_plus(vd, vs, line);
664 373420
                break;
665
        case '-':
666 16252
                i = vsm_vlu_minus(vd, vs, line);
667 16252
                break;
668
        default:
669 0
                break;
670
        }
671 405920
        return (i);
672
}
673
674
static void
675 308488
vsm_readlines(struct vsm_set *vs)
676
{
677
        struct vsm *vd;
678
        int i;
679
680 308488
        vd = vs->vsm;
681 308488
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
682
683 308488
        do {
684 352046
                assert(vs->fd >= 0);
685 352046
                i = VLU_Fd(vs->vlu, vs->fd);
686 352046
        } while (!i);
687 308488
        if (i != -2) {
688
                /* The line handler left the reason in the diag */
689 0
                AN(vd->diag);
690 0
                WRONG(VSB_data(vd->diag));
691 0
        }
692 308488
}
693
694
static unsigned
695 349657
vsm_refresh_set(struct vsm *vd, struct vsm_set *vs)
696
{
697 349657
        unsigned restarted = 0;
698
        struct stat st;
699
700 349657
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
701 349657
        CHECK_OBJ_NOTNULL(vs, VSM_SET_MAGIC);
702 349657
        vs->retval = 0;
703 649547
        if (vs->dfd >= 0 && (
704 300142
            fstatat(vd->wdfd, vs->dname, &st, AT_SYMLINK_NOFOLLOW) ||
705 300142
            st.st_ino != vs->dst.st_ino ||
706 299890
            st.st_dev != vs->dst.st_dev ||
707 299890
            st.st_mode != vs->dst.st_mode ||
708 299890
            st.st_nlink == 0)) {
709 252
                closefd(&vs->dfd);
710 252
                restarted = vs->flag_restarted;
711 252
        }
712
713 349657
        if (vs->dfd < 0) {
714 49767
                if (vs->fd >= 0)
715 250
                        closefd(&vs->fd);
716 49767
                vs->dfd = openat(vd->wdfd, vs->dname, O_RDONLY);
717 49767
        }
718
719 349657
        if (vs->dfd < 0) {
720 33527
                vs->id1 = vs->id2 = 0;
721 33527
                vsm_wash_set(vs, 1);
722 33527
                return (vs->retval | restarted);
723
        }
724
725 316130
        AZ(fstat(vs->dfd, &vs->dst));
726
727 608370
        if (vs->fd >= 0 && (
728 296222
            fstatat(vs->dfd, "_.index", &st, AT_SYMLINK_NOFOLLOW) ||
729 292248
            st.st_ino != vs->fst.st_ino ||
730 292240
            st.st_dev != vs->fst.st_dev ||
731 292240
            st.st_mode != vs->fst.st_mode ||
732 292240
            st.st_size < vs->fst.st_size ||
733 292240
            st.st_nlink < 1)) {
734 3982
                closefd(&vs->fd);
735 3982
                vs->retval |= vs->flag_changed;
736 3982
        }
737
738 316130
        if (vs->fd >= 0) {
739 292240
                vs->vg = NULL;
740 292240
                vsm_readlines(vs);
741 292240
        } else {
742 74039
                VTAILQ_FOREACH(vs->vg, &vs->segs, list)
743 50149
                        vs->vg->flags &= ~VSM_FLAG_MARKSCAN;
744 23890
                vs->vg = VTAILQ_FIRST(&vs->segs);
745 23890
                vs->fd = openat(vs->dfd, "_.index", O_RDONLY);
746 23890
                if (vs->fd < 0)
747 7642
                        return (vs->retval | restarted);
748 16248
                VLU_Reset(vs->vlu);
749 16248
                vs->lineno = 0;
750 16248
                AZ(fstat(vs->fd, &vs->fst));
751 16248
                vsm_readlines(vs);
752 16248
                vsm_wash_set(vs, 0);
753
        }
754
755 308488
        vs->fst.st_size = lseek(vs->fd, 0L, SEEK_CUR);
756
757 308488
        if (vs->couldkill < 0 || vsm_running(vs, vs->id1))
758 298500
                vs->retval |= vs->flag_running;
759 308488
        return (vs->retval);
760 349657
}
761
762
/*--------------------------------------------------------------------*/
763
764
unsigned
765 178672
VSM_Status(struct vsm *vd)
766
{
767 178672
        unsigned retval = 0;
768
        struct stat st;
769
770 178672
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
771
772
        /* See if the -n workdir changed */
773 178672
        if (vd->wdfd >= 0) {
774 168864
                AZ(fstat(vd->wdfd, &st));
775 337728
                if (st.st_ino != vd->wdst.st_ino ||
776 168864
                    st.st_dev != vd->wdst.st_dev ||
777 168864
                    st.st_mode != vd->wdst.st_mode ||
778 168864
                    st.st_nlink == 0) {
779 0
                        closefd(&vd->wdfd);
780 0
                        vsm_wash_set(vd->mgt, 1);
781 0
                        vsm_wash_set(vd->child, 1);
782 0
                }
783 168864
        }
784
785
        /* Open workdir */
786 178672
        if (vd->wdfd < 0) {
787 9808
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
788 9808
                retval |= VSM_WRK_RESTARTED | VSM_WRK_CHANGED;
789 9808
                vd->wdfd = open(vd->wdname, O_RDONLY);
790 9808
                if (vd->wdfd < 0)
791 140
                        (void)vsm_diag(vd,
792
                            "VSM_Status: Cannot open workdir");
793
                else
794 9668
                        AZ(fstat(vd->wdfd, &vd->wdst));
795 9808
        }
796
797 178672
        if (vd->wdfd >= 0) {
798 178532
                retval |= vsm_refresh_set(vd, vd->mgt);
799 178532
                if (vd->mgt->couldkill > 0 && (retval & VSM_MGT_RESTARTED))
800 9668
                        vd->mgt->couldkill = 0;
801 178532
                if (retval & VSM_MGT_RUNNING)
802 171125
                        retval |= vsm_refresh_set(vd, vd->child);
803 178532
                if (vd->child->couldkill > 0 && (retval & VSM_WRK_RESTARTED))
804 6563
                        vd->child->couldkill = 0;
805 178532
        }
806 178672
        return (retval);
807
}
808
809
/*--------------------------------------------------------------------*/
810
811
int
812 9684
VSM_Attach(struct vsm *vd, int progress)
813
{
814
        const char *def;
815
        double t0;
816
        unsigned u;
817 9684
        int i, n = 0;
818
819 9684
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
820
821 9684
        if (vd->patience < 0)
822 0
                t0 = DBL_MAX;
823
        else
824 9684
                t0 = VTIM_mono() + vd->patience;
825
826 9684
        if (vd->wdname == NULL) {
827 28
                def = getenv("VINYL_DEFAULT_N");
828 28
                if (def == NULL)
829 0
                        def = ""; /* Use default (hostname) */
830 28
                i = VSM_Arg(vd, 'n', def);
831 28
                if (i < 0)
832 0
                        return (i);
833 28
                AN(vd->wdname);
834 28
        }
835
836 9684
        AZ(vd->attached);
837 9820
        while (!VSIG_int && !VSIG_term) {
838 9816
                u = VSM_Status(vd);
839 9816
                VSM_ResetError(vd);
840 9816
                if (u & VSM_MGT_RUNNING) {
841 9668
                        if (progress >= 0 && n > 4)
842 0
                                (void)write(progress, "\n", 1);
843 9668
                        vd->attached = 1;
844 9668
                        return (0);
845
                }
846 148
                if (t0 < VTIM_mono()) {
847 12
                        if (progress >= 0 && n > 4)
848 4
                                (void)write(progress, "\n", 1);
849 12
                        return (vsm_diag(vd,
850
                            "Could not get hold of vinyld, is it running?"));
851
                }
852 136
                if (progress >= 0 && !(++n % 4))
853 32
                        (void)write(progress, ".", 1);
854 136
                VTIM_sleep(.25);
855
        }
856 4
        return (vsm_diag(vd, "Attach interrupted"));
857 9684
}
858
859
/*--------------------------------------------------------------------*/
860
861
static struct vsm_seg *
862 34610
vsm_set_findseg(const struct vsm_set *vs, uintptr_t serial)
863
{
864
        struct vsm_seg *vg;
865
866 414329
        VTAILQ_FOREACH(vg, &vs->segs, list) {
867 394199
                if (vg->serial == serial)
868 14480
                        return (vg);
869 379719
        }
870 35963
        VTAILQ_FOREACH(vg, &vs->stale, list) {
871 16423
                if (vg->serial == serial)
872 590
                        return (vg);
873 15833
        }
874 19540
        return (NULL);
875 34610
}
876
877
static struct vsm_seg *
878 984093
vsm_findseg(const struct vsm *vd, const struct vsm_fantom *vf)
879
{
880
        struct vsm_seg *vg;
881
        uint64_t x;
882
883 984093
        x = VSM_PRIV_HIGH(vf->priv);
884 984093
        if (x == vd->serial) {
885 966623
                vg = (struct vsm_seg *)vf->priv2;
886 966623
                if (!VALID_OBJ(vg, VSM_SEG_MAGIC) ||
887 966623
                    vg->serial != VSM_PRIV_LOW(vf->priv))
888 0
                        WRONG("Corrupt fantom");
889 966623
                return (vg);
890
        }
891
892 17470
        x = VSM_PRIV_LOW(vf->priv);
893 17470
        vg = vsm_set_findseg(vd->mgt, x);
894 17470
        if (vg == NULL)
895 17140
                vg = vsm_set_findseg(vd->child, x);
896 17470
        if (vg == NULL)
897 2400
                return (NULL);
898
899
        /* Update the fantom with the new priv so that lookups will be
900
         * fast on the next call. Note that this casts away the const. */
901 15070
        ((struct vsm_fantom *)TRUST_ME(vf))->priv =
902 15070
            VSM_PRIV_MERGE(vg->serial, vd->serial);
903 15070
        return (vg);
904 984093
}
905
906
/*--------------------------------------------------------------------*/
907
908
void
909 44225
VSM__iter0(const struct vsm *vd, struct vsm_fantom *vf)
910
{
911
912 44225
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
913 44225
        AN(vf);
914
915 44225
        AN(vd->attached);
916 44225
        memset(vf, 0, sizeof *vf);
917 44225
}
918
919
int
920 577534
VSM__itern(struct vsm *vd, struct vsm_fantom *vf)
921
{
922
        struct vsm_seg *vg;
923
924 577534
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
925 577534
        AN(vd->attached);
926 577534
        AN(vf);
927
928 577534
        if (vf->priv == 0) {
929 44225
                vg = VTAILQ_FIRST(&vd->mgt->segs);
930 44225
                if (vg == NULL)
931 0
                        return (0);
932 44225
        } else {
933 533309
                vg = vsm_findseg(vd, vf);
934 533309
                if (vg == NULL)
935 0
                        return (vsm_diag(vd, "VSM_FOREACH: inconsistency"));
936 540443
                while (1) {
937 540443
                        if (vg->set == vd->mgt && VTAILQ_NEXT(vg, list) == NULL)
938 43861
                                vg = VTAILQ_FIRST(&vd->child->segs);
939
                        else
940 496582
                                vg = VTAILQ_NEXT(vg, list);
941 540443
                        if (vg == NULL)
942 31635
                                return (0);
943 508808
                        if (!(vg->flags & VSM_FLAG_CLUSTER))
944 501674
                                break;
945
                }
946
        }
947 545899
        memset(vf, 0, sizeof *vf);
948 545899
        vf->priv = VSM_PRIV_MERGE(vg->serial, vd->serial);
949 545899
        vf->priv2 = (uintptr_t)vg;
950 545899
        vf->category = vg->av[4];
951 545899
        vf->ident = vg->av[5];
952 545899
        AN(vf->category);
953 545899
        return (1);
954 577534
}
955
956
/*--------------------------------------------------------------------*/
957
958
int
959 28576
VSM_Map(struct vsm *vd, struct vsm_fantom *vf)
960
{
961
        struct vsm_seg *vg, *vgc;
962
        size_t of, sz;
963
        int r;
964
965 28576
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
966 28576
        AN(vd->attached);
967 28576
        AN(vf);
968 28576
        vg = vsm_findseg(vd, vf);
969 28576
        if (vg == NULL)
970 0
                return (vsm_diag(vd, "VSM_Map: bad fantom"));
971
972 28576
        assert(vg->serial == VSM_PRIV_LOW(vf->priv));
973 28576
        assert(vg->av[4] == vf->category);
974 28576
        assert(vg->av[5] == vf->ident);
975
976 28576
        if (vg->b != NULL) {
977 0
                assert(vg->refs > 0);
978 0
                AN(vg->e);
979 0
                vf->b = vg->b;
980 0
                vf->e = vg->e;
981 0
                vg->refs++;
982 0
                return (0);
983
        }
984
985 28576
        assert(vg->refs == 0);
986
987 28576
        vgc = vg->cluster;
988
989 28576
        if (vgc == NULL) {
990 27992
                r = vsm_mapseg(vd, vg);
991 27992
                if (r)
992 5
                        return (r);
993 27987
                vf->b = vg->b;
994 27987
                vf->e = vg->e;
995
996 27987
                vg->refs++;
997
998 27987
                return (0);
999
        }
1000
1001 584
        CHECK_OBJ(vgc, VSM_SEG_MAGIC);
1002 584
        assert(vgc->flags & VSM_FLAG_CLUSTER);
1003 584
        assert(vg->s == NULL);
1004 584
        assert(vg->sz == 0);
1005
1006 584
        r = vsm_mapseg(vd, vgc);
1007 584
        if (r)
1008 0
                return (r);
1009 584
        vgc->refs++;
1010
1011 584
        of = strtoul(vg->av[2], NULL, 10);
1012 584
        sz = strtoul(vg->av[3], NULL, 10);
1013 584
        assert(sz > 0);
1014
1015 584
        assert(vgc->sz >= of + sz);
1016 584
        assert(vgc->s == vgc->b);
1017 584
        vg->b = (char *)vgc->b + of;
1018 584
        vg->e = (char *)vg->b + sz;
1019
1020 584
        vf->b = vg->b;
1021 584
        vf->e = vg->e;
1022
1023 584
        vg->refs++;
1024
1025 584
        return (0);
1026 28576
}
1027
1028
/*--------------------------------------------------------------------*/
1029
1030
int
1031 25167
VSM_Unmap(struct vsm *vd, struct vsm_fantom *vf)
1032
{
1033
        struct vsm_seg *vg;
1034
1035 25167
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
1036 25167
        AN(vd->attached);
1037 25167
        AN(vf);
1038 25167
        AN(vf->b);
1039 25167
        vg = vsm_findseg(vd, vf);
1040 25167
        if (vg == NULL)
1041 0
                return (vsm_diag(vd, "VSM_Unmap: bad fantom"));
1042 25167
        CHECK_OBJ(vg, VSM_SEG_MAGIC);
1043 25167
        assert(vg->refs > 0);
1044 25167
        vg->refs--;
1045 25167
        vf->b = NULL;
1046 25167
        vf->e = NULL;
1047 25167
        if (vg->refs > 0)
1048 0
                return (0);
1049
1050 25167
        if (vg->cluster) {
1051 124
                CHECK_OBJ_NOTNULL(vg->cluster, VSM_SEG_MAGIC);
1052 124
                assert(vg->s == NULL);
1053 124
                assert(vg->sz == 0);
1054 124
                assert(vg->cluster->refs > 0);
1055 124
                if (--vg->cluster->refs == 0) {
1056 116
                        vsm_unmapseg(vg->cluster);
1057 116
                        if (vg->cluster->flags & VSM_FLAG_STALE) {
1058 8
                                AN(vg->flags & VSM_FLAG_STALE);
1059 8
                                vsm_delseg(vg->cluster, 0);
1060 8
                        }
1061 116
                }
1062 124
                vg->b = vg->e = NULL;
1063 124
        } else {
1064 25043
                vsm_unmapseg(vg);
1065
        }
1066 25167
        if (vg->flags & VSM_FLAG_STALE)
1067 590
                vsm_delseg(vg, 0);
1068 25167
        return (0);
1069 25167
}
1070
1071
/*--------------------------------------------------------------------*/
1072
1073
const struct vsm_valid *
1074 397038
VSM_StillValid(const struct vsm *vd, const struct vsm_fantom *vf)
1075
{
1076
        struct vsm_seg *vg;
1077
1078 397038
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
1079 397038
        AN(vf);
1080 397038
        vg = vsm_findseg(vd, vf);
1081 397038
        if (vg == NULL || vg->flags & VSM_FLAG_STALE)
1082 2963
                return (VSM_invalid);
1083 394075
        return (VSM_valid);
1084 397038
}
1085
1086
/*--------------------------------------------------------------------*/
1087
1088
int
1089 38123
VSM_Get(struct vsm *vd, struct vsm_fantom *vf,
1090
    const char *category, const char *ident)
1091
{
1092
1093 38123
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
1094 38123
        AN(vd->attached);
1095 265055
        VSM_FOREACH(vf, vd) {
1096 239158
                if (vstrcmp(vf->category, category))
1097 226932
                        continue;
1098 12226
                if (ident != NULL && vstrcmp(vf->ident, ident))
1099 0
                        continue;
1100 12226
                return (1);
1101
        }
1102 25897
        memset(vf, 0, sizeof *vf);
1103 25897
        return (0);
1104 38123
}
1105
1106
/*--------------------------------------------------------------------*/
1107
1108
char *
1109 364
VSM_Dup(struct vsm *vd, const char *category, const char *ident)
1110
{
1111
        struct vsm_fantom vf;
1112 364
        char *p = NULL;
1113
1114 364
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
1115 364
        AN(vd->attached);
1116 1456
        VSM_FOREACH(&vf, vd) {
1117 1456
                if (vstrcmp(vf.category, category))
1118 624
                        continue;
1119 832
                if (ident != NULL && vstrcmp(vf.ident, ident))
1120 468
                        continue;
1121 364
                AZ(VSM_Map(vd, &vf));
1122 364
                AN(vf.b);
1123 364
                AN(vf.e);
1124 364
                p = malloc((char*)vf.e - (char*)vf.b);
1125 364
                AN(p);
1126 364
                vmemcpy(p, vf.b, (char *)vf.e - (char *)vf.b);
1127 364
                AZ(VSM_Unmap(vd, &vf));
1128 364
                break;
1129
        }
1130 364
        return (p);
1131
}