source: bin/varnishd/storage_persistent.c @ f88445

Revision f88445, 33.6 KB checked in by Poul-Henning Kamp <phk@…>, 5 years ago (diff)

Elide empty segments when writing the segment list.

Take due care to not confuse unloaded segments with empty segments
in this respect.

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@4268 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2008-2009 Linpro AS
3 * All rights reserved.
4 *
5 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * Persistent storage method
29 *
30 * XXX: Before we start the client or maybe after it stops, we should give the
31 * XXX: stevedores a chance to examine their storage for consistency.
32 */
33
34#include "config.h"
35
36#include "svnid.h"
37SVNID("$Id$")
38
39#include <errno.h>
40#include <math.h>
41#include <stdio.h>
42#include <stddef.h>
43#include <stdint.h>
44#include <stdlib.h>
45#include <string.h>
46#include <sys/param.h>
47#include <sys/mman.h>
48
49#include "cache.h"
50#include "stevedore.h"
51#include "hash_slinger.h"
52#include "vsha256.h"
53
54#include "persistent.h"
55
56#ifndef MAP_NOCORE
57#define MAP_NOCORE 0 /* XXX Linux */
58#endif
59
60#ifndef MAP_NOSYNC
61#define MAP_NOSYNC 0 /* XXX Linux */
62#endif
63
64#define ASSERT_SILO_THREAD(sc) \
65    do {assert(pthread_self() == (sc)->thread);} while (0)
66
67/*
68 * Context for a signature.
69 *
70 * A signature is a sequence of bytes in the silo, signed by a SHA256 hash
71 * which follows the bytes.
72 *
73 * The context structure allows us to append to a signature without
74 * recalculating the entire SHA256 hash.
75 */
76
77struct smp_signctx {
78        struct smp_sign         *ss;
79        struct SHA256Context    ctx;
80        uint32_t                unique;
81        const char              *id;
82};
83
84struct smp_sc;
85
86/* XXX: name confusion with on-media version ? */
87struct smp_seg {
88        unsigned                magic;
89#define SMP_SEG_MAGIC           0x45c61895
90
91        struct smp_sc           *sc;
92        struct lru              *lru;
93
94        VTAILQ_ENTRY(smp_seg)   list;           /* on smp_sc.smp_segments */
95
96        uint64_t                offset;         /* coordinates in silo */
97        uint64_t                length;
98
99        struct smp_segment      segment;        /* Copy of on-disk desc. */
100
101        uint32_t                nalloc;         /* How many alloc objects */
102        uint32_t                nfilled;        /* How many live objects */
103        uint32_t                nfixed;         /* How many fixed objects */
104
105        /* Only for open segment */
106        uint32_t                maxobj;         /* Max number of objects */
107        struct smp_object       *objs;          /* objdesc copy */
108        uint64_t                next_addr;      /* next write address */
109
110        struct smp_signctx      ctx[1];
111};
112
113VTAILQ_HEAD(smp_seghead, smp_seg);
114
115struct smp_sc {
116        unsigned                magic;
117#define SMP_SC_MAGIC            0x7b73af0a
118        struct stevedore        *parent;
119
120        unsigned                flags;
121#define SMP_F_LOADED            (1 << 0)
122
123        int                     fd;
124        const char              *filename;
125        off_t                   mediasize;
126        unsigned                granularity;
127        uint32_t                unique;
128
129        uint8_t                 *ptr;
130
131        struct smp_ident        *ident;
132
133        struct smp_seghead      segments;
134        struct smp_seg          *cur_seg;
135        uint64_t                free_offset;
136
137        uint64_t                objreserv;
138        pthread_t               thread;
139
140        VTAILQ_ENTRY(smp_sc)    list;
141
142        struct smp_signctx      idn;
143        struct smp_signctx      ban1;
144        struct smp_signctx      ban2;
145        struct smp_signctx      seg1;
146        struct smp_signctx      seg2;
147
148        struct ban              *tailban;
149
150        struct lock             mtx;
151
152        /* Cleaner metrics */
153
154        unsigned                min_nseg;
155        unsigned                aim_nseg;
156        unsigned                max_nseg;
157
158        unsigned                aim_nobj;
159
160        uint64_t                min_segl;
161        uint64_t                aim_segl;
162        uint64_t                max_segl;
163
164        uint64_t                free_reserve;
165};
166
167/*
168 * silos is unlocked, it only changes during startup when we are
169 * single-threaded
170 */
171static VTAILQ_HEAD(,smp_sc)     silos = VTAILQ_HEAD_INITIALIZER(silos);
172
173/*********************************************************************
174 * SIGNATURE functions
175 * The signature is SHA256 over:
176 *    1. The smp_sign struct up to but not including the length field.
177 *    2. smp_sign->length bytes, starting after the smp_sign structure
178 *    3. The smp-sign->length field.
179 * The signature is stored after the byte-range from step 2.
180 */
181
182#define SIGN_DATA(ctx)  ((void *)((ctx)->ss + 1))
183#define SIGN_END(ctx)   ((void *)((int8_t *)SIGN_DATA(ctx) + (ctx)->ss->length))
184
185/*--------------------------------------------------------------------
186 * Define a signature by location and identifier.
187 */
188
189static void
190smp_def_sign(const struct smp_sc *sc, struct smp_signctx *ctx, uint64_t off, const char *id)
191{
192
193        AZ(off & 7);                    /* Alignment */
194        assert(strlen(id) < sizeof ctx->ss->ident);
195
196        memset(ctx, 0, sizeof ctx);
197        ctx->ss = (void*)(sc->ptr + off);
198        ctx->unique = sc->unique;
199        ctx->id = id;
200}
201
202/*--------------------------------------------------------------------
203 * Check that a signature is good, leave state ready for append
204 */
205static int
206smp_chk_sign(struct smp_signctx *ctx)
207{
208        struct SHA256Context cx;
209        unsigned char sign[SHA256_LEN];
210        int r = 0;
211
212        if (strcmp(ctx->id, ctx->ss->ident))
213                r = 1;
214        else if (ctx->unique != ctx->ss->unique)
215                r = 2;
216        else if ((uintptr_t)ctx->ss != ctx->ss->mapped)
217                r = 3;
218        else {
219                SHA256_Init(&ctx->ctx);
220                SHA256_Update(&ctx->ctx, ctx->ss,
221                    offsetof(struct smp_sign, length));
222                SHA256_Update(&ctx->ctx, SIGN_DATA(ctx), ctx->ss->length);
223                cx = ctx->ctx;
224                SHA256_Update(&cx, &ctx->ss->length, sizeof(ctx->ss->length));
225                SHA256_Final(sign, &cx);
226                if (memcmp(sign, SIGN_END(ctx), sizeof sign))
227                        r = 4;
228        } 
229        if (r) {
230                fprintf(stderr, "CHK(%p %p %s) = %d\n",
231                    ctx, ctx->ss, ctx->ss->ident, r);
232                fprintf(stderr, "%p {%s %x %p %ju}\n",
233                    ctx, ctx->id, ctx->unique, ctx->ss, ctx->ss->length);
234        }
235        return (r);
236}
237
238/*--------------------------------------------------------------------
239 * Append data to a signature
240 */
241static void
242smp_append_sign(struct smp_signctx *ctx, const void *ptr, uint32_t len)
243{
244        struct SHA256Context cx;
245        unsigned char sign[SHA256_LEN];
246
247        if (len != 0) {
248                SHA256_Update(&ctx->ctx, ptr, len);
249                ctx->ss->length += len;
250        }
251        cx = ctx->ctx;
252        SHA256_Update(&cx, &ctx->ss->length, sizeof(ctx->ss->length));
253        SHA256_Final(sign, &cx);
254        memcpy(SIGN_END(ctx), sign, sizeof sign);
255XXXAZ(smp_chk_sign(ctx));
256}
257
258/*--------------------------------------------------------------------
259 * Reset a signature to empty, prepare for appending.
260 */
261
262static void
263smp_reset_sign(struct smp_signctx *ctx)
264{
265
266        memset(ctx->ss, 0, sizeof *ctx->ss);
267        strcpy(ctx->ss->ident, ctx->id);
268        ctx->ss->unique = ctx->unique;
269        ctx->ss->mapped = (uintptr_t)ctx->ss;
270        SHA256_Init(&ctx->ctx);
271        SHA256_Update(&ctx->ctx, ctx->ss,
272            offsetof(struct smp_sign, length));
273        smp_append_sign(ctx, NULL, 0);
274}
275
276/*--------------------------------------------------------------------
277 * Force a write of a signature block to the backing store.
278 */
279
280static void
281smp_sync_sign(const struct smp_signctx *ctx)
282{
283        int i;
284
285        /* XXX: round to pages */
286        i = msync(ctx->ss, ctx->ss->length + SHA256_LEN, MS_SYNC);
287        if (i && 0)
288                fprintf(stderr, "SyncSign(%p %s) = %d %s\n",
289                    ctx->ss, ctx->id, i, strerror(errno));
290}
291
292/*--------------------------------------------------------------------
293 * Create and force a new signature to backing store
294 */
295
296static void
297smp_new_sign(const struct smp_sc *sc, struct smp_signctx *ctx, uint64_t off, const char *id)
298{
299        smp_def_sign(sc, ctx, off, id);
300        smp_reset_sign(ctx);
301        smp_sync_sign(ctx);
302}
303
304/*--------------------------------------------------------------------
305 * Caculate payload of some stuff
306 */
307
308static uint64_t
309smp_stuff_len(const struct smp_sc *sc, unsigned stuff)
310{
311        uint64_t l;
312
313        assert(stuff < SMP_END_STUFF);
314        l = sc->ident->stuff[stuff + 1] - sc->ident->stuff[stuff];
315        l -= SMP_SIGN_SPACE;
316        return (l);
317}
318
319/*--------------------------------------------------------------------
320 * Initialize a Silo with a valid but empty structure.
321 *
322 * XXX: more intelligent sizing of things.
323 */
324
325static void
326smp_newsilo(struct smp_sc *sc)
327{
328        struct smp_ident        *si;
329
330        ASSERT_MGT();
331        assert(strlen(SMP_IDENT_STRING) < sizeof si->ident);
332
333        /* Choose a new random number */
334        sc->unique = random();
335
336        smp_reset_sign(&sc->idn);
337        si = sc->ident;
338
339        memset(si, 0, sizeof *si);
340        strcpy(si->ident, SMP_IDENT_STRING);
341        si->byte_order = 0x12345678;
342        si->size = sizeof *si;
343        si->major_version = 1;
344        si->minor_version = 1;
345        si->unique = sc->unique;
346        si->mediasize = sc->mediasize;
347        si->granularity = sc->granularity;
348
349        si->stuff[SMP_BAN1_STUFF] = sc->granularity;
350        si->stuff[SMP_BAN2_STUFF] = si->stuff[SMP_BAN1_STUFF] + 1024*1024;
351        si->stuff[SMP_SEG1_STUFF] = si->stuff[SMP_BAN2_STUFF] + 1024*1024;
352        si->stuff[SMP_SEG2_STUFF] = si->stuff[SMP_SEG1_STUFF] + 1024*1024;
353        si->stuff[SMP_SPC_STUFF] = si->stuff[SMP_SEG2_STUFF] + 1024*1024;
354        si->stuff[SMP_END_STUFF] = si->mediasize;
355        assert(si->stuff[SMP_SPC_STUFF] < si->stuff[SMP_END_STUFF]);
356
357        smp_new_sign(sc, &sc->ban1, si->stuff[SMP_BAN1_STUFF], "BAN 1");
358        smp_new_sign(sc, &sc->ban2, si->stuff[SMP_BAN2_STUFF], "BAN 2");
359        smp_new_sign(sc, &sc->seg1, si->stuff[SMP_SEG1_STUFF], "SEG 1");
360        smp_new_sign(sc, &sc->seg2, si->stuff[SMP_SEG2_STUFF], "SEG 2");
361
362        smp_append_sign(&sc->idn, si, sizeof *si);
363        smp_sync_sign(&sc->idn);
364}
365
366/*--------------------------------------------------------------------
367 * Check if a silo is valid.
368 */
369
370static int
371smp_valid_silo(struct smp_sc *sc)
372{
373        struct smp_ident        *si;
374        int i, j;
375
376        assert(strlen(SMP_IDENT_STRING) < sizeof si->ident);
377
378        if (smp_chk_sign(&sc->idn))
379                return (1);
380
381        si = sc->ident;
382        if (strcmp(si->ident, SMP_IDENT_STRING))
383                return (2);
384        if (si->byte_order != 0x12345678)
385                return (3);
386        if (si->size != sizeof *si)
387                return (4);
388        if (si->major_version != 1)
389                return (5);
390        if (si->minor_version != 1)
391                return (6);
392        if (si->mediasize != sc->mediasize)
393                return (7);
394        if (si->granularity != sc->granularity)
395                return (8);
396        sc->unique = si->unique;
397
398        /* XXX: Sanity check stuff[6] */
399
400        assert(si->stuff[SMP_BAN1_STUFF] > sizeof *si + SHA256_LEN);
401        assert(si->stuff[SMP_BAN2_STUFF] > si->stuff[SMP_BAN1_STUFF]);
402        assert(si->stuff[SMP_SEG1_STUFF] > si->stuff[SMP_BAN2_STUFF]);
403        assert(si->stuff[SMP_SEG2_STUFF] > si->stuff[SMP_SEG1_STUFF]);
404        assert(si->stuff[SMP_SPC_STUFF] > si->stuff[SMP_SEG2_STUFF]);
405        assert(si->stuff[SMP_END_STUFF] == sc->mediasize);
406
407        assert(smp_stuff_len(sc, SMP_SEG1_STUFF) > 65536);
408        assert(smp_stuff_len(sc, SMP_SEG1_STUFF) ==
409          smp_stuff_len(sc, SMP_SEG2_STUFF));
410
411        assert(smp_stuff_len(sc, SMP_BAN1_STUFF) > 65536);
412        assert(smp_stuff_len(sc, SMP_BAN1_STUFF) ==
413          smp_stuff_len(sc, SMP_BAN2_STUFF));
414
415        smp_def_sign(sc, &sc->ban1, si->stuff[SMP_BAN1_STUFF], "BAN 1");
416        smp_def_sign(sc, &sc->ban2, si->stuff[SMP_BAN2_STUFF], "BAN 2");
417        smp_def_sign(sc, &sc->seg1, si->stuff[SMP_SEG1_STUFF], "SEG 1");
418        smp_def_sign(sc, &sc->seg2, si->stuff[SMP_SEG2_STUFF], "SEG 2");
419
420        /* We must have one valid BAN table */
421        i = smp_chk_sign(&sc->ban1);
422        j = smp_chk_sign(&sc->ban2);
423        if (i && j)
424                return (100 + i * 10 + j);
425
426        /* We must have one valid SEG table */
427        i = smp_chk_sign(&sc->seg1);
428        j = smp_chk_sign(&sc->seg2);
429        if (i && j)
430                return (200 + i * 10 + j);
431        return (0);
432}
433
434/*--------------------------------------------------------------------
435 * Calculate cleaner metrics from silo dimensions
436 */
437
438static void
439smp_metrics(struct smp_sc *sc)
440{
441
442        /*
443         * We do not want to loose too big chunks of the silos
444         * content when we are forced to clean a segment.
445         *
446         * For now insist that a segment covers no more than 1% of the silo.
447         *
448         * XXX: This should possibly depend on the size of the silo so
449         * XXX: trivially small silos do not run into trouble along
450         * XXX: the lines of "one object per silo".
451         */
452
453        sc->min_nseg = 10;
454        sc->max_segl = smp_stuff_len(sc, SMP_SPC_STUFF) / sc->min_nseg;
455
456        fprintf(stderr, "min_nseg = %u, max_segl = %ju\n",
457            sc->min_nseg, (uintmax_t)sc->max_segl);
458
459        /*
460         * The number of segments are limited by the size of the segment
461         * table(s) and from that follows the minimum size of a segmement.
462         */
463
464        sc->max_nseg = smp_stuff_len(sc, SMP_SEG1_STUFF) / sc->min_nseg;
465        sc->min_segl = smp_stuff_len(sc, SMP_SPC_STUFF) / sc->max_nseg;
466
467        while (sc->min_segl < sizeof(struct object)) {
468                sc->max_nseg /= 2;
469                sc->min_segl = smp_stuff_len(sc, SMP_SPC_STUFF) / sc->max_nseg;
470        }
471
472        fprintf(stderr, "max_nseg = %u, min_segl = %ju\n",
473            sc->max_nseg, (uintmax_t)sc->min_segl);
474
475        /*
476         * Set our initial aim point at the exponential average of the
477         * two extremes.
478         *
479         * XXX: This is a pretty arbitrary choice, but having no idea
480         * XXX: object count, size distribution or ttl pattern at this
481         * XXX: point, we have to do something.
482         */
483
484        sc->aim_nseg =
485           (unsigned) exp((log(sc->min_nseg) + log(sc->max_nseg))*.5);
486        sc->aim_segl = smp_stuff_len(sc, SMP_SPC_STUFF) / sc->aim_nseg;
487
488        fprintf(stderr, "aim_nseg = %u, aim_segl = %ju\n",
489            sc->aim_nseg, (uintmax_t)sc->aim_segl);
490
491        /*
492         * Objects per segment
493         *
494         * XXX: calculate size of minimum object (workspace, http etc)
495         */
496
497        sc->aim_nobj = sc->max_segl / 4000;
498
499        fprintf(stderr, "aim_nobj = %u\n", sc->aim_nobj);
500
501        /*
502         * How much space in the free reserve pool ?
503         */
504        sc->free_reserve = sc->aim_segl * 10;
505
506        fprintf(stderr, "free_reserve = %ju\n", sc->free_reserve);
507}
508
509/*--------------------------------------------------------------------
510 * Set up persistent storage silo in the master process.
511 */
512
513static void
514smp_init(struct stevedore *parent, int ac, char * const *av)
515{
516        struct smp_sc           *sc;
517        int i;
518       
519        ASSERT_MGT();
520
521        AZ(av[ac]);
522#define SIZOF(foo)       fprintf(stderr, \
523    "sizeof(%s) = %zu = 0x%zx\n", #foo, sizeof(foo), sizeof(foo));
524        SIZOF(struct smp_ident);
525        SIZOF(struct smp_sign);
526        SIZOF(struct smp_segptr);
527        SIZOF(struct smp_object);
528#undef SIZOF
529
530        assert(sizeof(struct smp_ident) == SMP_IDENT_SIZE);
531
532        /* Allocate softc */
533        ALLOC_OBJ(sc, SMP_SC_MAGIC);
534        XXXAN(sc);
535        sc->parent = parent;
536        sc->fd = -1;
537        VTAILQ_INIT(&sc->segments);
538
539        /* Argument processing */
540        if (ac != 2)
541                ARGV_ERR("(-spersistent) wrong number of arguments\n");
542
543        i = STV_GetFile(av[0], &sc->fd, &sc->filename, "-spersistent");
544        if (i == 2)
545                ARGV_ERR("(-spersistent) need filename (not directory)\n");
546
547        sc->granularity = getpagesize();
548        sc->mediasize = STV_FileSize(sc->fd, av[1], &sc->granularity,
549            "-spersistent");
550
551        AZ(ftruncate(sc->fd, sc->mediasize));
552
553        sc->ptr = mmap(NULL, sc->mediasize, PROT_READ|PROT_WRITE,
554            MAP_NOCORE | MAP_NOSYNC | MAP_SHARED, sc->fd, 0);
555
556        if (sc->ptr == MAP_FAILED)
557                ARGV_ERR("(-spersistent) failed to mmap (%s)\n",
558                    strerror(errno));
559
560        smp_def_sign(sc, &sc->idn, 0, "SILO");
561        sc->ident = SIGN_DATA(&sc->idn);
562
563        i = smp_valid_silo(sc);
564        if (i)
565                smp_newsilo(sc);
566        AZ(smp_valid_silo(sc));
567
568        smp_metrics(sc);
569
570        parent->priv = sc;
571
572        /* XXX: only for sendfile I guess... */
573        mgt_child_inherit(sc->fd, "storage_persistent");
574}
575
576
577/*--------------------------------------------------------------------
578 * Write the segmentlist back to the silo.
579 *
580 * We write the first copy, sync it synchronously, then write the
581 * second copy and sync it synchronously.
582 *
583 * Provided the kernel doesn't lie, that means we will always have
584 * at least one valid copy on in the silo.
585 */
586
587static void
588smp_save_seg(const struct smp_sc *sc, struct smp_signctx *ctx)
589{
590        struct smp_segptr *ss;
591        struct smp_seg *sg;
592        uint64_t length;
593
594        Lck_AssertHeld(&sc->mtx);
595        smp_reset_sign(ctx);
596        ss = SIGN_DATA(ctx);
597        length = 0;
598        VTAILQ_FOREACH(sg, &sc->segments, list) {
599                assert(sg->offset < sc->mediasize);
600                assert(sg->offset + sg->length <= sc->mediasize);
601                ss->offset = sg->offset;
602                ss->length = sg->length;
603                ss++;
604                length += sizeof *ss;
605        }
606        smp_append_sign(ctx, SIGN_DATA(ctx), length);
607        smp_sync_sign(ctx);
608}
609
610static void
611smp_save_segs(struct smp_sc *sc)
612{
613        struct smp_seg *sg, *sg2;
614
615        Lck_AssertHeld(&sc->mtx);
616
617        /* Elide any empty segments from the list before we write it */
618        VTAILQ_FOREACH_SAFE(sg, &sc->segments, list, sg2) {
619                if (sg->nalloc > 0)
620                        continue;
621                if (sg == sc->cur_seg)
622                        continue;
623                VTAILQ_REMOVE(&sc->segments, sg, list);
624                // XXX: free segment
625        }
626
627        smp_save_seg(sc, &sc->seg1);
628        smp_save_seg(sc, &sc->seg2);
629}
630
631/*--------------------------------------------------------------------
632 * Fixup an object
633 */
634
635void
636SMP_Fixup(struct sess *sp, struct objhead *oh, struct objcore *oc)
637{
638        struct smp_seg *sg;
639        struct smp_object *so;
640
641        Lck_AssertHeld(&oh->mtx);
642        (void)sp;
643        sg = oc->smp_seg;
644        CHECK_OBJ_NOTNULL(sg, SMP_SEG_MAGIC);
645
646        so = (void*)oc->obj;
647        oc->obj = so->ptr;
648
649        /* XXX: This check should fail gracefully */
650        CHECK_OBJ_NOTNULL(oc->obj, OBJECT_MAGIC);
651
652        oc->obj->smp_object = so;
653
654        AN(oc->flags & OC_F_PERSISTENT);
655        oc->flags &= ~OC_F_PERSISTENT;
656
657        /* refcnt is one because the object is in the hash */
658        oc->obj->refcnt = 1;
659        oc->obj->objcore = oc;
660        oc->objhead = oh;
661        oc->obj->ban = oc->ban;
662
663        sg->nfixed++;
664        sp->wrk->stats.n_object++;
665        sp->wrk->stats.n_vampireobject--;
666}
667
668/*--------------------------------------------------------------------
669 * Add a new ban to all silos
670 */
671
672static void
673smp_appendban(struct smp_sc *sc, struct smp_signctx *ctx, double t0, uint32_t flags, uint32_t len, const char *ban)
674{
675        uint8_t *ptr, *ptr2;
676       
677        (void)sc;
678        ptr = ptr2 = SIGN_END(ctx);
679
680        memcpy(ptr, "BAN", 4);
681        ptr += 4;
682
683        memcpy(ptr, &t0, sizeof t0);
684        ptr += sizeof t0;
685
686        memcpy(ptr, &flags, sizeof flags);
687        ptr += sizeof flags;
688
689        memcpy(ptr, &len, sizeof len);
690        ptr += sizeof len;
691
692        memcpy(ptr, ban, len);
693        ptr += len;
694
695        smp_append_sign(ctx, ptr2, ptr - ptr2);
696}
697
698void
699SMP_NewBan(double t0, const char *ban)
700{
701        struct smp_sc *sc;
702        uint32_t l = strlen(ban) + 1;
703
704        VTAILQ_FOREACH(sc, &silos, list) {
705                smp_appendban(sc, &sc->ban1, t0, 0, l, ban);
706                smp_appendban(sc, &sc->ban2, t0, 0, l, ban);
707        }
708}
709
710/*--------------------------------------------------------------------
711 * Attempt to open and read in a ban list
712 */
713
714static int
715smp_open_bans(struct smp_sc *sc, struct smp_signctx *ctx)
716{
717        uint8_t *ptr, *pe;
718        double t0;
719        uint32_t flags, length;
720        int i, retval = 0;
721
722        ASSERT_CLI();
723        (void)sc;
724        i = smp_chk_sign(ctx); 
725        if (i)
726                return (i);
727        ptr = SIGN_DATA(ctx);
728        pe = ptr + ctx->ss->length;
729
730        while (ptr < pe) {
731                if (memcmp(ptr, "BAN", 4)) {
732                        retval = 1001;
733                        break;
734                }
735                ptr += 4;
736
737                memcpy(&t0, ptr, sizeof t0);
738                ptr += sizeof t0;
739
740                memcpy(&flags, ptr, sizeof flags);
741                ptr += sizeof flags;
742                if (flags != 0) {
743                        retval = 1002;
744                        break;
745                }
746
747                memcpy(&length, ptr, sizeof length);
748                ptr += sizeof length;
749                if (ptr + length > pe) {
750                        retval = 1003;
751                        break;
752                }
753
754                if (ptr[length - 1] != '\0') {
755                        retval = 1004;
756                        break;
757                }
758
759                BAN_Reload(t0, flags, (const char *)ptr);
760
761                ptr += length;
762        }
763        assert(ptr <= pe);
764        return (retval);
765}
766
767/*--------------------------------------------------------------------
768 * Update objects
769 */
770
771void
772SMP_FreeObj(struct object *o)
773{
774        struct smp_seg *sg;
775
776        AN(o->smp_object);
777        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
778        AZ(o->objcore->flags & OC_F_PERSISTENT);
779        sg = o->objcore->smp_seg;
780        CHECK_OBJ_NOTNULL(sg, SMP_SEG_MAGIC);
781
782        Lck_Lock(&sg->sc->mtx);
783        o->smp_object->ttl = 0;
784        assert(sg->nalloc > 0);
785        assert(sg->nfixed > 0);
786
787        sg->nalloc--;
788        o->smp_object = NULL;
789
790        sg->nfixed--;
791        Lck_Unlock(&sg->sc->mtx);
792
793        /* XXX: check if seg is empty, or leave to thread ? */
794}
795
796void
797SMP_BANchanged(const struct object *o, double t)
798{
799        struct smp_seg *sg;
800
801        AN(o->smp_object);
802        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
803        sg = o->objcore->smp_seg;
804        CHECK_OBJ_NOTNULL(sg, SMP_SEG_MAGIC);
805        CHECK_OBJ_NOTNULL(sg->sc, SMP_SC_MAGIC);
806
807        o->smp_object->ban = t;
808}
809
810void
811SMP_TTLchanged(const struct object *o)
812{
813        struct smp_seg *sg;
814
815        AN(o->smp_object);
816        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
817        sg = o->objcore->smp_seg;
818        CHECK_OBJ_NOTNULL(sg, SMP_SEG_MAGIC);
819        CHECK_OBJ_NOTNULL(sg->sc, SMP_SC_MAGIC);
820
821        o->smp_object->ttl = o->ttl;
822}
823
824/*--------------------------------------------------------------------
825 * Load segments
826 *
827 * The overall objective is to register the existence of an object, based
828 * only on the minimally sized struct smp_object, without causing the
829 * main object to be faulted in.
830 *
831 * XXX: We can test this by mprotecting the main body of the segment
832 * XXX: until the first fixup happens, or even just over this loop,
833 * XXX: However: the requires that the smp_objects starter further
834 * XXX: into the segment than a page so that they do not get hit
835 * XXX: by the protection.
836 */
837
838static void
839smp_load_seg(struct sess *sp, const struct smp_sc *sc, struct smp_seg *sg)
840{
841        void *ptr;
842        struct smp_segment *ss;
843        struct smp_object *so;
844        struct objcore *oc;
845        uint32_t no;
846        double t_now = TIM_real();
847        struct smp_signctx ctx[1];
848
849        ASSERT_SILO_THREAD(sc);
850        (void)sp;
851        AN(sg->offset);
852        smp_def_sign(sc, ctx, sg->offset, "SEGMENT");
853        if (smp_chk_sign(ctx))
854                return;
855        ptr = SIGN_DATA(ctx);
856        ss = ptr;
857        so = (void*)(sc->ptr + ss->objlist);
858        no = ss->nalloc;
859        /* Clear the bogus "hold" count */
860        sg->nalloc = 0;
861        for (;no > 0; so++,no--) {
862                if (so->ttl < t_now)
863                        continue;
864                HSH_Prealloc(sp);
865                oc = sp->wrk->nobjcore;
866                oc->flags |= OC_F_PERSISTENT | OC_F_LRUDONTMOVE;
867                oc->flags &= ~OC_F_BUSY;
868                oc->obj = (void*)so;
869                oc->smp_seg = sg;
870                oc->ban = BAN_RefBan(oc, so->ban, sc->tailban);
871                memcpy(sp->wrk->nobjhead->digest, so->hash, SHA256_LEN);
872                (void)HSH_Insert(sp);
873                AZ(sp->wrk->nobjcore);
874                EXP_Inject(oc, sg->lru, so->ttl);
875                sg->nalloc++;
876        }
877        WRK_SumStat(sp->wrk);
878}
879
880/*--------------------------------------------------------------------
881 * Attempt to open and read in a segment list
882 */
883
884static int
885smp_open_segs(struct smp_sc *sc, struct smp_signctx *ctx)
886{
887        uint64_t length, l;
888        struct smp_segptr *ss, *se;
889        struct smp_seg *sg, *sg1, *sg2;
890        int i, n = 0;
891
892        ASSERT_CLI();
893        i = smp_chk_sign(ctx); 
894        if (i)
895                return (i);
896
897        ss = SIGN_DATA(ctx);
898        length = ctx->ss->length;
899
900        if (length == 0) {
901                /* No segments */
902                sc->free_offset = sc->ident->stuff[SMP_SPC_STUFF];
903                return (0);
904        }
905        se = ss + length / sizeof *ss;
906        se--;
907        assert(ss <= se);
908
909        /*
910         * Locate the free reserve, there are only two basic cases,
911         * but once we start dropping segments, things gets more complicated.
912         */
913
914        sc->free_offset = se->offset + se->length;
915        l = sc->mediasize - sc->free_offset;
916        if (se->offset > ss->offset && l >= sc->free_reserve) {
917                /*
918                 * [__xxxxyyyyzzzz___]
919                 * Plenty of space at tail, do nothing.
920                 */
921//printf("TRS: %jx @ %jx\n", l, sc->free_offset);
922        } else if (ss->offset > se->offset) {
923                /*
924                 * [zzzz____xxxxyyyy_]
925                 * (make) space between ends
926                 * We might nuke the entire tail end without getting
927                 * enough space, in which case we fall through to the
928                 * last check.
929                 */
930                while (ss < se && ss->offset > se->offset) {
931//printf("TEST_SEG1 %jx...%jx\n", ss->offset, ss->offset + ss->length);
932                        l = ss->offset - (se->offset + se->length);
933                        if (l > sc->free_reserve)
934                                break;
935//printf("DROP_SEG1 %jx...%jx\n", ss->offset, ss->offset + ss->length);
936                        ss++;
937                        n++;
938                }
939        }
940
941        if (l < sc->free_reserve) {
942                /*
943                 * [__xxxxyyyyzzzz___]
944                 * (make) space at front
945                 */
946                sc->free_offset = sc->ident->stuff[SMP_SPC_STUFF];
947                while (ss < se) {
948//printf("TEST_SEG2 %jx...%jx\n", ss->offset, ss->offset + ss->length);
949                        l = ss->offset - sc->free_offset;
950                        if (l > sc->free_reserve)
951                                break;
952//printf("DROP_SEG2 %jx...%jx\n", ss->offset, ss->offset + ss->length);
953                        ss++;
954                        n++;
955                }
956        }
957
958        assert (l >= sc->free_reserve);
959
960//printf("FRS: %jx @ %jx\n", l, sc->free_offset);
961
962        sg1 = NULL;
963        sg2 = NULL;
964        for(; ss <= se; ss++) {
965// printf("LOAD_SEG %jx...%jx\n", ss->offset, ss->offset + ss->length);
966                ALLOC_OBJ(sg, SMP_SEG_MAGIC);
967                AN(sg);
968                sg->lru = LRU_Alloc();
969                sg->offset = ss->offset;
970                sg->length = ss->length;
971                /*
972                 * HACK: prevent save_segs from nuking segment until we have
973                 * HACK: loaded it.
974                 */
975                sg->nalloc = 1;
976                if (sg1 != NULL) {
977                        assert(sg1->offset != sg->offset);
978                        if (sg1->offset < sg->offset)
979                                assert(sg1->offset + sg1->length <= sg->offset);
980                        else
981                                assert(sg->offset + sg->length <= sg1->offset);
982                }
983                if (sg2 != NULL) {
984                        assert(sg2->offset != sg->offset);
985                        if (sg2->offset < sg->offset)
986                                assert(sg2->offset + sg2->length <= sg->offset);
987                        else
988                                assert(sg->offset + sg->length <= sg2->offset);
989                }
990
991                /* XXX: check that they are inside silo */
992                /* XXX: check that they don't overlap */
993                /* XXX: check that they are serial */
994                sg->sc = sc;
995                VTAILQ_INSERT_TAIL(&sc->segments, sg, list);
996                sg2 = sg;
997                if (sg1 == NULL)
998                        sg1 = sg;
999        }
1000        printf("Dropped %d segments to make free_reserve\n", n);
1001        return (0);
1002}
1003
1004/*--------------------------------------------------------------------
1005 * Create a new segment
1006 */
1007
1008static void
1009smp_new_seg(struct smp_sc *sc)
1010{
1011        struct smp_seg *sg, *sg2;
1012
1013        Lck_AssertHeld(&sc->mtx);
1014        ALLOC_OBJ(sg, SMP_SEG_MAGIC);
1015        AN(sg);
1016        sg->sc = sc;
1017
1018        sg->maxobj = sc->aim_nobj;
1019        sg->objs = malloc(sizeof *sg->objs * sg->maxobj);
1020        AN(sg->objs);
1021
1022        /* XXX: find where it goes in silo */
1023
1024        sg->offset = sc->free_offset;
1025        assert(sg->offset >= sc->ident->stuff[SMP_SPC_STUFF]);
1026        assert(sg->offset < sc->mediasize);
1027
1028        sg->length = sc->aim_segl;
1029        sg->length &= ~7;
1030
1031
1032        assert(sg->offset + sg->length <= sc->mediasize);
1033
1034        sg2 = VTAILQ_FIRST(&sc->segments);
1035        if (sg2 != NULL && sg2->offset > sc->free_offset) {
1036//printf("SG %jx...%jx\n", sg->offset, sg->offset + sg->length);
1037//printf("SG2 %jx...%jx\n", sg2->offset, sg2->offset + sg2->length);
1038
1039//printf("spc %jx %jx\n", sg2->offset + sg2->length - sg->offset, sc->free_reserve);
1040
1041                if (sg->offset + sg->length > sg2->offset) {
1042                        printf("Out of space in persistent silo\n");
1043                        printf("Committing suicide, restart will make space\n");
1044                        exit (0);
1045                }
1046                assert(sg->offset + sg->length <= sg2->offset);
1047        }
1048
1049        sc->free_offset += sg->length;
1050
1051//printf("NEW_SEG %jx...%jx\n", sg->offset, sg->offset + sg->length);
1052
1053        VTAILQ_INSERT_TAIL(&sc->segments, sg, list);
1054
1055        /* Neuter the new segment in case there is an old one there */
1056        AN(sg->offset);
1057        smp_def_sign(sc, sg->ctx, sg->offset, "SEGMENT");
1058        smp_reset_sign(sg->ctx);
1059        memcpy(SIGN_DATA(sg->ctx), &sg->segment, sizeof sg->segment);
1060        smp_append_sign(sg->ctx, &sg->segment, sizeof sg->segment);
1061        smp_sync_sign(sg->ctx);
1062
1063
1064        /* Set up our allocation point */
1065        sc->cur_seg = sg;
1066        sg->next_addr = sg->offset +
1067            sizeof (struct smp_sign) +
1068            sizeof (struct smp_segment) +
1069            SHA256_LEN;
1070        memcpy(sc->ptr + sg->next_addr, "HERE", 4);
1071        sc->objreserv = sizeof *sg->objs + SHA256_LEN;
1072
1073        /* Then add it to the segment list. */
1074        /* XXX: could be done cheaper with append ? */
1075        smp_save_segs(sc);
1076}
1077
1078/*--------------------------------------------------------------------
1079 * Close a segment
1080 */
1081
1082static void
1083smp_close_seg(struct smp_sc *sc, struct smp_seg *sg)
1084{
1085        size_t sz;
1086
1087        (void)sc;
1088
1089        Lck_AssertHeld(&sc->mtx);
1090
1091        /* XXX: if segment is empty, delete instead */
1092
1093
1094
1095        /* Copy the objects into the segment */
1096        sz = sizeof *sg->objs * sg->nalloc;
1097        assert(sg->next_addr + sz <= sg->offset + sg->length);
1098
1099        memcpy(sc->ptr + sg->next_addr, sg->objs, sz);
1100
1101        /* Update the segment header */
1102        sg->segment.objlist = sg->next_addr;
1103        sg->segment.nalloc = sg->nalloc;
1104
1105        /* Write it to silo */
1106        smp_reset_sign(sg->ctx);
1107        memcpy(SIGN_DATA(sg->ctx), &sg->segment, sizeof sg->segment);
1108        smp_append_sign(sg->ctx, &sg->segment, sizeof sg->segment);
1109        smp_sync_sign(sg->ctx);
1110
1111        sg->next_addr += sizeof *sg->objs * sg->nalloc;
1112        sg->length = sg->next_addr - sg->offset;
1113        sg->length |= 15;
1114        sg->length++;
1115
1116        /* Save segment list */
1117        smp_save_segs(sc);
1118        sc->free_offset = sg->offset + sg->length;
1119}
1120
1121/*--------------------------------------------------------------------
1122 * Silo worker thread
1123 */
1124
1125static void *
1126smp_thread(struct sess *sp, void *priv)
1127{
1128        struct smp_sc   *sc;
1129        struct smp_seg *sg;
1130
1131        (void)sp;
1132        CAST_OBJ_NOTNULL(sc, priv, SMP_SC_MAGIC);
1133
1134        /* First, load all the objects from all segments */
1135        VTAILQ_FOREACH(sg, &sc->segments, list)
1136                smp_load_seg(sp, sc, sg);
1137
1138        sc->flags |= SMP_F_LOADED;
1139        BAN_Deref(&sc->tailban);
1140        sc->tailban = NULL;
1141        printf("Silo completely loaded\n");
1142        while (1)       
1143                (void)sleep (1);
1144        NEEDLESS_RETURN(NULL);
1145}
1146
1147/*--------------------------------------------------------------------
1148 * Open a silo in the worker process
1149 */
1150
1151static void
1152smp_open(const struct stevedore *st)
1153{
1154        struct smp_sc   *sc;
1155
1156        ASSERT_CLI();
1157
1158        CAST_OBJ_NOTNULL(sc, st->priv, SMP_SC_MAGIC);
1159
1160        Lck_New(&sc->mtx);
1161        Lck_Lock(&sc->mtx);
1162
1163        /* We trust the parent to give us a valid silo, for good measure: */
1164        AZ(smp_valid_silo(sc));
1165
1166        sc->ident = SIGN_DATA(&sc->idn);
1167
1168        /* We attempt ban1 first, and if that fails, try ban2 */
1169        if (smp_open_bans(sc, &sc->ban1))
1170                AZ(smp_open_bans(sc, &sc->ban2));
1171
1172        /* We attempt seg1 first, and if that fails, try seg2 */
1173        if (smp_open_segs(sc, &sc->seg1))
1174                AZ(smp_open_segs(sc, &sc->seg2));
1175
1176        sc->tailban = BAN_TailRef();
1177        AN(sc->tailban);
1178
1179        /* XXX: save segments to ensure consistency between seg1 & seg2 ? */
1180
1181        /* XXX: abandon early segments to make sure we have free space ? */
1182
1183        /* Open a new segment, so we are ready to write */
1184        smp_new_seg(sc);
1185
1186        /* Start the worker silo worker thread, it will load the objects */
1187        WRK_BgThread(&sc->thread, "persistence", smp_thread, sc);
1188
1189        VTAILQ_INSERT_TAIL(&silos, sc, list);
1190        Lck_Unlock(&sc->mtx);
1191}
1192
1193/*--------------------------------------------------------------------
1194 * Close a silo
1195 */
1196
1197static void
1198smp_close(const struct stevedore *st)
1199{
1200        struct smp_sc   *sc;
1201
1202        ASSERT_CLI();
1203
1204        CAST_OBJ_NOTNULL(sc, st->priv, SMP_SC_MAGIC);
1205        Lck_Lock(&sc->mtx);
1206        smp_close_seg(sc, sc->cur_seg);
1207        Lck_Unlock(&sc->mtx);
1208
1209        /* XXX: reap thread */
1210}
1211
1212/*--------------------------------------------------------------------
1213 * Designate object
1214 */
1215
1216static void
1217smp_object(const struct sess *sp)
1218{
1219        struct smp_sc   *sc;
1220        struct smp_seg *sg;
1221        struct smp_object *so;
1222
1223        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
1224        CHECK_OBJ_NOTNULL(sp->obj->objstore, STORAGE_MAGIC);
1225        CHECK_OBJ_NOTNULL(sp->obj->objstore->stevedore, STEVEDORE_MAGIC);
1226        CHECK_OBJ_NOTNULL(sp->obj->objcore->smp_seg, SMP_SEG_MAGIC);
1227        CAST_OBJ_NOTNULL(sc, sp->obj->objstore->priv, SMP_SC_MAGIC);
1228
1229        sp->obj->objcore->flags |= OC_F_LRUDONTMOVE;
1230        Lck_Lock(&sc->mtx);
1231        sg = sp->obj->objcore->smp_seg;
1232        sc->objreserv += sizeof *so;
1233        assert(sg->nalloc < sg->nfilled);
1234        so = &sg->objs[sg->nalloc++];
1235        sg->nfixed++;
1236        memcpy(so->hash, sp->obj->objcore->objhead->digest, DIGEST_LEN);
1237        so->ttl = sp->obj->ttl;
1238        so->ptr = sp->obj;
1239        so->ban = sp->obj->ban_t;
1240        /* XXX: if segment is already closed, write sg->objs */
1241        sp->obj->smp_object = so;
1242        Lck_Unlock(&sc->mtx);
1243
1244}
1245
1246/*--------------------------------------------------------------------
1247 * Allocate a bite
1248 */
1249
1250static struct storage *
1251smp_alloc(struct stevedore *st, size_t size, struct objcore *oc)
1252{
1253        struct smp_sc *sc;
1254        struct storage *ss;
1255        struct smp_seg *sg;
1256        size_t sz2;
1257
1258        (void)oc;
1259        CAST_OBJ_NOTNULL(sc, st->priv, SMP_SC_MAGIC);
1260        Lck_Lock(&sc->mtx);
1261        sg = sc->cur_seg;
1262
1263        AN(sg->next_addr);
1264
1265        /*
1266         * XXX: We do not have a mechanism for deciding which allocations
1267         * XXX: have mandatory size and which can be chopped into smaller
1268         * XXX: allocations.
1269         * XXX: The primary unchoppable allocation is from HSH_NewObject()
1270         * XXX: which needs an object + workspace.
1271         */
1272        sz2 = sizeof (struct object) + 1024;
1273        if (size < sz2)
1274                sz2 = size;
1275
1276        /* If the segment is full, get a new one right away */
1277        if (sg->next_addr + sizeof *ss + sz2 + sc->objreserv >
1278             sg->offset + sg->length) {
1279                smp_close_seg(sc, sc->cur_seg);
1280                smp_new_seg(sc);
1281                sg = sc->cur_seg;
1282        }
1283
1284        assert (sg->next_addr + sizeof *ss + sz2 + sc->objreserv <=
1285            sg->offset + sg->length);
1286
1287        if (sg->next_addr + sizeof *ss + size + sc->objreserv >
1288            sg->offset + sg->length)
1289                size = (sg->offset + sg->length) -
1290                        (sg->next_addr + sizeof *ss + sc->objreserv);
1291
1292        ss = (void *)(sc->ptr + sg->next_addr);
1293
1294        sg->next_addr += size + sizeof *ss;
1295        assert(sg->next_addr <= sg->offset + sg->length);
1296        memcpy(sc->ptr + sg->next_addr, "HERE", 4);
1297        if (oc != NULL) {
1298                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1299                if (++sg->nfilled >= sg->maxobj) {
1300                        smp_close_seg(sc, sc->cur_seg);
1301                        smp_new_seg(sc);
1302                        fprintf(stderr, "New Segment\n");
1303                        sg = sc->cur_seg;
1304                }
1305                oc->smp_seg = sg;
1306        }
1307        Lck_Unlock(&sc->mtx);
1308
1309        /* Grab and fill a storage structure */
1310        memset(ss, 0, sizeof *ss);
1311        ss->magic = STORAGE_MAGIC;
1312        ss->space = size;
1313        ss->ptr = (void *)(ss + 1);
1314        ss->priv = sc;
1315        ss->stevedore = st;
1316        ss->fd = sc->fd;
1317        ss->where = sg->next_addr + sizeof *ss;
1318        assert((uintmax_t)ss->space == (uintmax_t)size);
1319        assert((char*)ss->ptr > (char*)ss);
1320        assert((char*)ss->ptr + ss->space <= (char*)sc->ptr + sc->mediasize);
1321        return (ss);
1322}
1323
1324static void
1325smp_trim(struct storage *ss, size_t size)
1326{
1327        struct smp_sc *sc;
1328        struct smp_seg *sg;
1329        const char z[4] = { 0, 0, 0, 0};
1330
1331        return;
1332
1333        CAST_OBJ_NOTNULL(sc, ss->priv, SMP_SC_MAGIC);
1334
1335        /* We want 16 bytes alignment */
1336        size |= 0xf;
1337        size += 1;
1338
1339        sg = sc->cur_seg;
1340        if (ss->ptr + ss->space != sg->next_addr + sc->ptr) 
1341                return;
1342
1343        Lck_Lock(&sc->mtx);
1344        sg = sc->cur_seg;
1345        if (ss->ptr + ss->space == sg->next_addr + sc->ptr) {
1346                memcpy(sc->ptr + sg->next_addr, z, 4);
1347                sg->next_addr -= ss->space - size;
1348                ss->space = size;
1349                memcpy(sc->ptr + sg->next_addr, "HERE", 4);
1350        }
1351        Lck_Unlock(&sc->mtx);
1352}
1353
1354/*--------------------------------------------------------------------
1355 * We don't track frees of storage, we track the objects which own them
1356 * instead, when there are no more objects in in the first segment, it
1357 * can be reclaimed.
1358 */
1359
1360static void
1361smp_free(struct storage *st)
1362{
1363
1364        /* XXX */
1365        (void)st;
1366}
1367
1368/*--------------------------------------------------------------------
1369 * Pause until all silos have loaded.
1370 */
1371
1372void
1373SMP_Ready(void)
1374{
1375        struct smp_sc *sc;
1376
1377        ASSERT_CLI();
1378        while (1) {
1379                VTAILQ_FOREACH(sc, &silos, list) {
1380                        if (sc->flags & SMP_F_LOADED)
1381                                continue;
1382                        (void)sleep(1);
1383                        break;
1384                }
1385                if (sc == NULL)
1386                        break;
1387        }
1388}
1389
1390/*--------------------------------------------------------------------*/
1391
1392struct stevedore smp_stevedore = {
1393        .magic  =       STEVEDORE_MAGIC,
1394        .name   =       "persistent",
1395        .init   =       smp_init,
1396        .open   =       smp_open,
1397        .close  =       smp_close,
1398        .alloc  =       smp_alloc,
1399        .object =       smp_object,
1400        .free   =       smp_free,
1401        .trim   =       smp_trim,
1402};
Note: See TracBrowser for help on using the repository browser.