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
        VTAILQ_ENTRY(vsm_seg)   list;
80
        int                     markscan;
81
        int                     stale;
82
        struct vsm_set          *set;
83
        char                    **av;
84
        int                     refs;
85
        void                    *b;
86
        void                    *e;
87
        size_t                  sz;
88
        uintptr_t               serial;
89
};
90
91
struct vsm_set {
92
        unsigned                magic;
93
#define VSM_SET_MAGIC           0xdee401b8
94
        const char              *dname;
95
        VTAILQ_HEAD(,vsm_seg)   segs;
96
        VTAILQ_HEAD(,vsm_seg)   stale;
97
98
        int                     dfd;
99
        struct stat             dst;
100
101
        int                     fd;
102
        struct stat             fst;
103
104
        uintmax_t               id1, id2;
105
};
106
107
struct vsm {
108
        unsigned                magic;
109
#define VSM_MAGIC               0x6e3bd69b
110
111
        struct vsb              *diag;
112
        uintptr_t               serial;
113
114
        int                     dfd;
115
        struct stat             dst;
116
        char                    *dname;
117
118
        struct vsm_set          *mgt;
119
        struct vsm_set          *child;
120
121
        int                     attached;
122
        double                  patience;
123
124
        int                     couldkill;
125
};
126
127
/*--------------------------------------------------------------------*/
128
129
static int
130 242
vsm_diag(struct vsm *vd, const char *fmt, ...)
131
{
132
        va_list ap;
133
134 242
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
135 242
        AN(fmt);
136
137 242
        if (vd->diag == NULL)
138 58
                vd->diag = VSB_new_auto();
139 242
        AN(vd->diag);
140 242
        VSB_clear(vd->diag);
141 242
        va_start(ap, fmt);
142 242
        VSB_vprintf(vd->diag, fmt, ap);
143 242
        va_end(ap);
144 242
        AZ(VSB_finish(vd->diag));
145 242
        return (-1);
146
}
147
148
/*--------------------------------------------------------------------*/
149
150
static void
151 12843
vsm_unmapseg(struct vsm_seg *vg)
152
{
153
        size_t sz, ps, len;
154
155 12843
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
156
157 12843
        AN(vg->b);
158 12843
        AN(vg->e);
159 12843
        sz = strtoul(vg->av[2], NULL, 10);
160 12843
        assert(sz > 0);
161 12843
        ps = getpagesize();
162 12843
        len = RUP2(sz, ps);
163 12843
        AZ(munmap(vg->b, len));
164 12843
        vg->b = vg->e = NULL;
165 12843
}
166
167
/*--------------------------------------------------------------------*/
168
169
static void
170 64392
vsm_delseg(struct vsm_seg *vg)
171
{
172
173 64392
        CHECK_OBJ_NOTNULL(vg, VSM_SEG_MAGIC);
174
175 64392
        if (vg->b != NULL)
176 0
                vsm_unmapseg(vg);
177
178 64392
        if (vg->stale)
179 20
                VTAILQ_REMOVE(&vg->set->stale, vg, list);
180
        else
181 64372
                VTAILQ_REMOVE(&vg->set->segs, vg, list);
182 64392
        VAV_Free(vg->av);
183 64392
        FREE_OBJ(vg);
184 64392
}
185
186
/*--------------------------------------------------------------------*/
187
188
static struct vsm_set *
189 5508
vsm_newset(const char *dirname)
190
{
191
        struct vsm_set *vs;
192
193 5508
        ALLOC_OBJ(vs, VSM_SET_MAGIC);
194 5508
        AN(vs);
195 5508
        VTAILQ_INIT(&vs->segs);
196 5508
        VTAILQ_INIT(&vs->stale);
197 5508
        vs->dname = dirname;
198 5508
        vs->dfd = vs->fd = -1;
199 5508
        return (vs);
200
}
201
202
static void
203 5436
vsm_delset(struct vsm_set **p)
204
{
205
        struct vsm_set *vs;
206
207 5436
        AN(p);
208 5436
        vs = *p;
209 5436
        *p = NULL;
210 5436
        if (vs->fd >= 0)
211 3130
                closefd(&vs->fd);
212 5436
        if (vs->dfd >= 0)
213 4372
                closefd(&vs->dfd);
214 10872
        while (!VTAILQ_EMPTY(&vs->stale))
215 0
                vsm_delseg(VTAILQ_FIRST(&vs->stale));
216 75244
        while (!VTAILQ_EMPTY(&vs->segs))
217 64372
                vsm_delseg(VTAILQ_FIRST(&vs->segs));
218 5436
        FREE_OBJ(vs);
219 5436
}
220
221
/*--------------------------------------------------------------------*/
222
223
struct vsm *
224 2754
VSM_New(void)
225
{
226
        struct vsm *vd;
227
228 2754
        ALLOC_OBJ(vd, VSM_MAGIC);
229 2754
        AN(vd);
230
231 2754
        vd->mgt = vsm_newset(VSM_MGT_DIRNAME);
232 2754
        vd->child = vsm_newset(VSM_CHILD_DIRNAME);
233 2754
        vd->dfd = -1;
234 2754
        vd->patience = 5;
235 2754
        if (getenv("VSM_NOPID") != NULL)
236 0
                vd->couldkill = -1;
237 2754
        return (vd);
238
}
239
240
/*--------------------------------------------------------------------*/
241
242
int
243 2770
VSM_Arg(struct vsm *vd, char flag, const char *arg)
244
{
245 2770
        char *p = NULL;
246
247 2770
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
248
249 2770
        if (arg == NULL)
250 20
                return (1);
251 2750
        switch (flag) {
252
        case 't':
253 14
                if (!strcasecmp(arg, "off")) {
254 0
                        vd->patience = -1;
255
                } else {
256 14
                        vd->patience = strtod(arg, &p);
257 24
                        if ((p != NULL && *p != '\0') ||
258 16
                            !isfinite(vd->patience) || vd->patience < 0)
259 12
                                return (vsm_diag(vd,
260
                                    "-t: Invalid argument: %s", arg));
261
                }
262 2
                break;
263
        case 'n':
264 2736
                if (VIN_n_Arg(arg, &p))
265 0
                        return (vsm_diag(vd, "Invalid instance name: %s",
266 0
                            strerror(errno)));
267 2736
                AN(p);
268 2736
                REPLACE(vd->dname, p);
269 2736
                free(p);
270 2736
                break;
271
        default:
272 0
                return (vsm_diag(vd, "Unknown VSM_Arg('%c')", flag));
273
        }
274 2738
        return (1);
275
}
276
277
/*--------------------------------------------------------------------*/
278
279
void
280 2718
VSM_Destroy(struct vsm **vdp)
281
{
282
        struct vsm *vd;
283
284 2718
        TAKE_OBJ_NOTNULL(vd, vdp, VSM_MAGIC);
285
286 2718
        VSM_ResetError(vd);
287 2718
        REPLACE(vd->dname, NULL);
288 2718
        if (vd->diag != NULL)
289 0
                VSB_destroy(&vd->diag);
290 2718
        if (vd->dfd >= 0)
291 2718
                closefd(&vd->dfd);
292 2718
        vsm_delset(&vd->mgt);
293 2718
        vsm_delset(&vd->child);
294 2718
        FREE_OBJ(vd);
295 2718
}
296
297
/*--------------------------------------------------------------------*/
298
299
const char *
300 232
VSM_Error(const struct vsm *vd)
301
{
302
303 232
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
304
305 232
        if (vd->diag == NULL)
306 0
                return ("No VSM error");
307
        else
308 232
                return (VSB_data(vd->diag));
309
}
310
311
/*--------------------------------------------------------------------*/
312
313
void
314 5462
VSM_ResetError(struct vsm *vd)
315
{
316
317 5462
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
318
319 5462
        if (vd->diag == NULL)
320 10880
                return;
321 44
        VSB_destroy(&vd->diag);
322
}
323
324
/*--------------------------------------------------------------------
325
 */
326
327
#define VSM_NUKE_ALL    (1U << 16)
328
329
static int
330 128422
vsm_cmp_av(char * const *a1, char * const *a2)
331
{
332
333
        while (1) {
334 128422
                if (*a1 == NULL && *a2 == NULL)
335 25705
                        return (0);
336 102717
                if (*a1 == NULL || *a2 == NULL)
337 0
                        return (1);
338 102717
                if (strcmp(*a1, *a2))
339 77
                        return (1);
340 102640
                a1++;
341 102640
                a2++;
342 102640
        }
343
}
344
345
static unsigned
346 205263
vsm_refresh_set2(struct vsm *vd, struct vsm_set *vs, struct vsb *vsb)
347
{
348 205263
        unsigned retval = 0;
349
        struct stat st;
350
        char buf[BUFSIZ];
351
        ssize_t sz;
352
        int i, ac;
353
        char *p, *e;
354
        uintmax_t id1, id2;
355
        char **av;
356
        struct vsm_seg *vg, *vg2;
357
358 205263
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
359 205263
        CHECK_OBJ_NOTNULL(vs, VSM_SET_MAGIC);
360 205263
        if (vs->dfd >= 0) {
361 158814
                if (fstatat(vd->dfd, vs->dname, &st, AT_SYMLINK_NOFOLLOW)) {
362 0
                        closefd(&vs->dfd);
363 -8
                        vs->id1 = vs->id2 = 0;
364 -8
                        return (VSM_MGT_RESTARTED|VSM_NUKE_ALL);
365
                }
366 317572
                if (st.st_ino != vs->dst.st_ino ||
367 317511
                    st.st_dev != vs->dst.st_dev ||
368 158756
                    st.st_mode != vs->dst.st_mode) {
369 64
                        closefd(&vs->dfd);
370 64
                        vs->id1 = vs->id2 = 0;
371
                }
372
        }
373
374 205266
        if (vs->dfd < 0) {
375 46531
                if (vs->fd >= 0)
376 62
                        closefd(&vs->fd);
377 46531
                vs->dfd = openat(vd->dfd, vs->dname, O_RDONLY);
378 46531
                retval |= VSM_MGT_RESTARTED;
379 46531
                if (vs->dfd < 0) {
380 42063
                        vs->id1 = vs->id2 = 0;
381 42063
                        return (retval|VSM_NUKE_ALL);
382
                }
383 4468
                AZ(fstat(vs->dfd, &vs->dst));
384
        }
385
386 304996
        if (vs->fd >= 0 && (
387 282341
            fstatat(vs->dfd, "_.index", &st, AT_SYMLINK_NOFOLLOW) ||
388 281026
            st.st_ino != vs->fst.st_ino ||
389 280947
            st.st_dev != vs->fst.st_dev ||
390 280944
            st.st_mode != vs->fst.st_mode ||
391 278717
            st.st_size != vs->fst.st_size ||
392 276492
            st.st_nlink < 1 ||
393 138246
            memcmp(&st.st_mtime, &vs->fst.st_mtime, sizeof st.st_mtime))) {
394 3550
                closefd(&vs->fd);
395
        }
396
397 163207
        if (vs->fd >= 0) {
398 138228
                if (vd->couldkill < 1 || !kill(vs->id1, 0))
399 131906
                        retval |= VSM_MGT_RUNNING;
400 138231
                return (retval);
401
        }
402
403 24979
        retval |= VSM_MGT_CHANGED;
404 24979
        vs->fd = openat(vs->dfd, "_.index", O_RDONLY);
405 24979
        if (vs->fd < 0)
406 18205
                return (retval|VSM_MGT_RESTARTED);
407
408 6774
        AZ(fstat(vs->fd, &vs->fst));
409
410 6774
        VSB_clear(vsb);
411
        do {
412 15787
                sz = read(vs->fd, buf, sizeof buf);
413 15787
                if (sz > 0)
414 9013
                        VSB_bcat(vsb, buf, sz);
415 15787
        } while (sz > 0);
416 6774
        AZ(VSB_finish(vsb));
417
418 6774
        vs->fst.st_size = VSB_len(vsb);
419
420 6774
        if (VSB_len(vsb) == 0)
421 0
                return (retval|VSM_NUKE_ALL);
422
423
        /*
424
         * Examine the ident line
425
         * XXX: for now ignore that one of the ID's is a pid which could
426
         * XXX: be kill(pid,0)'ed for more rapid abandonment detection.
427
         */
428 6774
        i = sscanf(VSB_data(vsb), "# %ju %ju\n%n", &id1, &id2, &ac);
429 6774
        if (i != 2) {
430 0
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
431 0
                return (retval);
432
        }
433 6774
        if (vd->couldkill >= 0 && !kill(id1, 0)) {
434 6772
                vd->couldkill = 1;
435 2
        } else if (vd->couldkill > 0 && errno == ESRCH) {
436 2
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
437 2
                return (retval);
438
        }
439 6772
        retval |= VSM_MGT_RUNNING;
440 6772
        if (id1 != vs->id1 || id2 != vs->id2) {
441 4466
                retval |= VSM_MGT_RESTARTED | VSM_MGT_CHANGED;
442 4466
                vs->id1 = id1;
443 4466
                vs->id2 = id2;
444
        }
445 6772
        p = VSB_data(vsb) + ac;
446
447 34429
        VTAILQ_FOREACH(vg, &vs->segs, list)
448 27657
                vg->markscan = 0;
449
450
        /*
451
         * Efficient comparison walking the two lists side-by-side is ok because
452
         * segment inserts always happen at the tail (VSMW_Allocv()). So, as
453
         * soon as vg is exhausted, we only insert.
454
         *
455
         * For restarts, we require a tabula rasa
456
         */
457
458 6772
        if (retval & VSM_MGT_RESTARTED)
459 4466
                vg = NULL;
460
        else
461 2306
                vg = VTAILQ_FIRST(&vs->segs);
462
463 106151
        while (p != NULL && *p != '\0') {
464 92607
                e = strchr(p, '\n');
465 92607
                if (e == NULL)
466 0
                        break;
467 92607
                *e = '\0';
468 92607
                av = VAV_Parse(p, &ac, 0);
469 92607
                p = e + 1;
470
471 92607
                if (av[0] != NULL || ac < 4 || ac > 5) {
472 0
                        (void)(vsm_diag(vd,
473
                            "vsm_refresh_set2: bad index (%d/%s)",
474
                            ac, av[0]));
475 0
                        VAV_Free(av);
476 0
                        break;
477
                }
478
479 92607
                if (vg == NULL) {
480 66900
                        ALLOC_OBJ(vg2, VSM_SEG_MAGIC);
481 66900
                        AN(vg2);
482 66900
                        vg2->av = av;
483 66900
                        vg2->set = vs;
484 66900
                        vg2->markscan = 1;
485 66900
                        vg2->serial = ++vd->serial;
486 66900
                        VTAILQ_INSERT_TAIL(&vs->segs, vg2, list);
487 66900
                        continue;
488
                }
489
490 51491
                while (vg != NULL && vsm_cmp_av(&vg->av[1], &av[1])) {
491 77
                        vg = VTAILQ_NEXT(vg, list);
492
                }
493
494 25707
                VAV_Free(av);
495
496 25707
                if (vg == NULL)
497 2
                        continue;
498
499
                /* entry compared equal, so it survives */
500 25705
                vg->markscan = 1;
501 25705
                vg = VTAILQ_NEXT(vg, list);
502
        }
503 6772
        return (retval);
504
}
505
506
static unsigned
507 205282
vsm_refresh_set(struct vsm *vd, struct vsm_set *vs, struct vsb *vsb)
508
{
509
        unsigned retval;
510
        struct vsm_seg *vg, *vg2;
511
512 205282
        retval = vsm_refresh_set2(vd, vs, vsb);
513 205252
        if (retval & VSM_NUKE_ALL)
514 42063
                retval |= VSM_MGT_CHANGED;
515 2261395
        VTAILQ_FOREACH_SAFE(vg, &vs->segs, list, vg2) {
516 2056111
                if (!vg->markscan || (retval & VSM_NUKE_ALL)) {
517 1920
                        VTAILQ_REMOVE(&vs->segs, vg, list);
518 1920
                        if (vg->refs) {
519 20
                                vg->stale = 1;
520 20
                                VTAILQ_INSERT_TAIL(&vs->stale, vg, list);
521
                        } else {
522 1900
                                VAV_Free(vg->av);
523 1932
                                FREE_OBJ(vg);
524
                        }
525
                }
526
        }
527 205284
        return (retval & ~VSM_NUKE_ALL);
528
}
529
530
/*--------------------------------------------------------------------*/
531
532
unsigned
533 109101
VSM_Status(struct vsm *vd)
534
{
535 109101
        unsigned retval = 0, u;
536
        struct stat st;
537
        struct vsb *vsb;
538
539 109101
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
540
541
        /* See if the -n workdir changed */
542 109101
        if (vd->dfd >= 0) {
543 106359
                AZ(fstat(vd->dfd, &st));
544 212720
                if (st.st_ino != vd->dst.st_ino ||
545 212722
                    st.st_dev != vd->dst.st_dev ||
546 212718
                    st.st_mode != vd->dst.st_mode ||
547 106357
                    st.st_nlink == 0) {
548 0
                        closefd(&vd->dfd);
549 0
                        retval |= VSM_MGT_CHANGED;
550 0
                        retval |= VSM_WRK_CHANGED;
551
                }
552
        }
553
554
        /* Open workdir */
555 109101
        if (vd->dfd < 0) {
556 2744
                vd->dfd = open(vd->dname, O_RDONLY);
557 2744
                if (vd->dfd < 0)
558 10
                        (void)vsm_diag(vd,
559
                            "VSM_Status: Cannot open workdir");
560
                else
561 2734
                        AZ(fstat(vd->dfd, &vd->dst));
562
        }
563
564 109101
        vsb = VSB_new_auto();
565 109099
        AN(vsb);
566
567 109099
        u = vsm_refresh_set(vd, vd->mgt, vsb);
568 109104
        retval |= u;
569 109104
        if (u & VSM_MGT_RUNNING)
570 96182
                retval |= vsm_refresh_set(vd, vd->child, vsb) << 8;
571 109103
        VSB_destroy(&vsb);
572 109097
        return (retval);
573
}
574
575
/*--------------------------------------------------------------------*/
576
577
int
578 2736
VSM_Attach(struct vsm *vd, int progress)
579
{
580
        double t0;
581
        unsigned u;
582 2736
        int i, n = 0;
583
584 2736
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
585
586 2736
        if (vd->patience < 0)
587 0
                t0 = DBL_MAX;
588
        else
589 2736
                t0 = VTIM_mono() + vd->patience;
590
591 2736
        if (vd->dname == NULL) {
592
                /* Use default (hostname) */
593 0
                i = VSM_Arg(vd, 'n', "");
594 0
                if (i < 0)
595 0
                        return (i);
596 0
                AN(vd->dname);
597
        }
598
599 2736
        AZ(vd->attached);
600
        while (1) {
601 2744
                u = VSM_Status(vd);
602 2744
                VSM_ResetError(vd);
603 2744
                if (u & VSM_MGT_RUNNING) {
604 2734
                        if (progress >= 0 && n > 4)
605 0
                                (void)write(progress, "\n", 1);
606 2734
                        vd->attached = 1;
607 2734
                        return (0);
608
                }
609 10
                if (t0 < VTIM_mono()) {
610 2
                        if (progress >= 0 && n > 4)
611 0
                                (void)write(progress, "\n", 1);
612 2
                        return (vsm_diag(vd,
613
                            "Could not get hold of varnishd, is it running?"));
614
                }
615 8
                if (progress >= 0 && !(++n % 4))
616 2
                        (void)write(progress, ".", 1);
617 8
                VTIM_sleep(.25);
618 8
        }
619
}
620
621
/*--------------------------------------------------------------------*/
622
623
static struct vsm_seg *
624 424596
vsm_findseg(const struct vsm *vd, const struct vsm_fantom *vf)
625
{
626
        struct vsm_set *vs;
627
        struct vsm_seg *vg;
628
        uintptr_t x;
629
630 424596
        x = vf->priv;
631 424596
        vs = vd->mgt;
632 1889605
        VTAILQ_FOREACH(vg, &vs->segs, list)
633 1733258
                if (vg->serial == x)
634 268249
                        return (vg);
635 156347
        VTAILQ_FOREACH(vg, &vs->stale, list)
636 0
                if (vg->serial == x)
637 0
                        return (vg);
638 156347
        vs = vd->child;
639 1074486
        VTAILQ_FOREACH(vg, &vs->segs, list)
640 1074456
                if (vg->serial == x)
641 156317
                        return (vg);
642 30
        VTAILQ_FOREACH(vg, &vs->stale, list)
643 30
                if (vg->serial == x)
644 30
                        return (vg);
645 0
        return (NULL);
646
}
647
648
/*--------------------------------------------------------------------*/
649
650
void
651 57386
VSM__iter0(const struct vsm *vd, struct vsm_fantom *vf)
652
{
653
654 57386
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
655 57386
        AN(vf);
656
657 57386
        AN(vd->attached);
658 57386
        memset(vf, 0, sizeof *vf);
659 57386
}
660
661
int
662 362916
VSM__itern(struct vsm *vd, struct vsm_fantom *vf)
663
{
664
        struct vsm_seg *vg, *vg2;
665
666 362916
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
667 362916
        AN(vd->attached);
668 362916
        AN(vf);
669
670 362916
        if (vf->priv == 0) {
671 57418
                vg2 = VTAILQ_FIRST(&vd->mgt->segs);
672
        } else {
673 305498
                vg = vsm_findseg(vd, vf);
674 305487
                if (vg == NULL)
675 0
                        return (vsm_diag(vd, "VSM_FOREACH: inconsistency"));
676 305487
                vg2 = VTAILQ_NEXT(vg, list);
677 305487
                if (vg2 == NULL && vg->set == vd->mgt)
678 57351
                        vg2 = VTAILQ_FIRST(&vd->child->segs);
679
        }
680 362905
        if (vg2 == NULL)
681 45653
                return (0);
682 317252
        memset(vf, 0, sizeof *vf);
683 317252
        vf->priv = vg2->serial;
684 317252
        vf->class = vg2->av[3];
685 317252
        vf->ident = vg2->av[4];
686 317252
        return (1);
687
}
688
689
/*--------------------------------------------------------------------*/
690
691
int
692 13541
VSM_Map(struct vsm *vd, struct vsm_fantom *vf)
693
{
694
        struct vsm_seg *vg;
695
        size_t sz, ps, len;
696
        struct vsb *vsb;
697
        int fd;
698
699 13541
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
700 13541
        AN(vd->attached);
701 13541
        AN(vf);
702 13541
        vg = vsm_findseg(vd, vf);
703 13538
        if (vg == NULL)
704 0
                return (vsm_diag(vd, "VSM_Map: bad fantom"));
705
706 13538
        assert(vg->serial == vf->priv);
707 13538
        assert(vg->av[3] == vf->class);
708 13538
        assert(vg->av[4] == vf->ident);
709
710 13538
        if (vg->b != NULL) {
711 0
                assert(vg->refs > 0);
712 0
                AN(vg->e);
713 0
                vf->b = vg->b;
714 0
                vf->e = vg->e;
715 0
                vg->refs++;
716 0
                return (0);
717
        }
718
719 13538
        sz = strtoul(vg->av[2], NULL, 10);
720 13540
        assert(sz > 0);
721 13540
        ps = getpagesize();
722 13539
        len = RUP2(sz, ps);
723
724 13539
        vsb = VSB_new_auto();
725 13540
        AN(vsb);
726 13540
        VSB_printf(vsb, "%s/%s/%s", vd->dname, vg->set->dname, vg->av[1]);
727 13540
        AZ(VSB_finish(vsb));
728
729 13539
        fd = open(VSB_data(vsb), O_RDONLY);     // XXX: openat
730 13541
        if (fd < 0) {
731 218
                VSB_destroy(&vsb);
732 218
                return (vsm_diag(vd, "Could not open segment"));
733
        }
734
735 13323
        vg->b = (void*)mmap(NULL, len,
736
            PROT_READ,
737
            MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED,
738
            fd, 0);
739
740 13323
        VSB_destroy(&vsb);
741
742
743 13323
        closefd(&fd);
744 13323
        if (vg->b == MAP_FAILED)
745 0
                return (vsm_diag(vd, "Could not mmap segment"));
746 13323
        vg->e = (char *)vg->b + sz;
747 13323
        vg->sz = len;
748
749 13323
        vf->b = vg->b;
750 13323
        vf->e = vg->e;
751
752 13323
        vg->refs++;
753
754 13323
        return (0);
755
}
756
757
/*--------------------------------------------------------------------*/
758
759
int
760 12843
VSM_Unmap(struct vsm *vd, struct vsm_fantom *vf)
761
{
762
        struct vsm_seg *vg;
763
764 12843
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
765 12843
        AN(vd->attached);
766 12843
        AN(vf);
767 12843
        AN(vf->b);
768 12843
        vg = vsm_findseg(vd, vf);
769 12843
        if (vg == NULL)
770 0
                return (vsm_diag(vd, "VSM_Unmap: bad fantom"));
771 12843
        assert(vg->refs > 0);
772 12843
        vg->refs--;
773 12843
        vf->b = NULL;
774 12843
        vf->e = NULL;
775 12843
        if (vg->refs > 0)
776 0
                return(0);
777 12843
        vsm_unmapseg(vg);
778 12843
        if (vg->stale)
779 20
                vsm_delseg(vg);
780 12843
        return (0);
781
}
782
783
/*--------------------------------------------------------------------*/
784
785
const struct vsm_valid *
786 92723
VSM_StillValid(const struct vsm *vd, const struct vsm_fantom *vf)
787
{
788
        struct vsm_seg *vg;
789
790 92723
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
791 92723
        AN(vf);
792 92723
        vg = vsm_findseg(vd, vf);
793 92727
        if (vg == NULL || vg->stale)
794 10
                return (VSM_invalid);
795 92717
        return (VSM_valid);
796
}
797
798
/*--------------------------------------------------------------------*/
799
800
int
801 55604
VSM_Get(struct vsm *vd, struct vsm_fantom *vf,
802
    const char *class, const char *ident)
803
{
804
805 55604
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
806 55604
        AN(vd->attached);
807 377463
        VSM_FOREACH(vf, vd) {
808 276849
                if (strcmp(vf->class, class))
809 266249
                        continue;
810 10600
                if (ident != NULL && strcmp(vf->ident, ident))
811 0
                        continue;
812 10600
                return (1);
813
        }
814 45017
        memset(vf, 0, sizeof *vf);
815 45017
        return (0);
816
}
817
818
/*--------------------------------------------------------------------*/
819
820
char *
821 42
VSM_Dup(struct vsm *vd, const char *class, const char *ident)
822
{
823
        struct vsm_fantom vf;
824 42
        char *p = NULL;
825
826 42
        CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
827 42
        AN(vd->attached);
828 184
        VSM_FOREACH(&vf, vd) {
829 142
                if (strcmp(vf.class, class))
830 40
                        continue;
831 102
                if (ident != NULL && strcmp(vf.ident, ident))
832 60
                        continue;
833 42
                AZ(VSM_Map(vd, &vf));
834 42
                AN(vf.b);
835 42
                AN(vf.e);
836 42
                p = malloc((char*)vf.e - (char*)vf.b);
837 42
                AN(p);
838 42
                memcpy(p, vf.b, (char*)vf.e - (char*)vf.b);
839 42
                AZ(VSM_Unmap(vd, &vf));
840 42
                break;
841
        }
842 42
        return (p);
843
}