source: bin/varnishd/storage/storage_persistent.c @ f1dfb8

Revision f1dfb8, 15.5 KB checked in by Geoff Simmons <geoff@…>, 2 years ago (diff)

Merge branch 'master' of  ssh://git.varnish-cache.org/git/varnish-cache into experimental-ims

Also calling http_CopyHome(beresp) to ensure that header contents are copied from stale_obj
into beresp (pointed out by phk).

  • Property mode set to 100644
RevLine 
[fddd14]1/*-
[c11726]2 * Copyright (c) 2008-2011 Varnish Software AS
[fddd14]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
[178f09]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.
[ae96ce]32 *
33 * XXX: Do we ever free the LRU-lists ?
[fddd14]34 */
35
36#include "config.h"
37
[8aa1d8]38#include <sys/param.h>
39#include <sys/mman.h>
40
[fddd14]41#include <stdint.h>
[8aa1d8]42#include <stdio.h>
[7d2ce9]43#include <stdlib.h>
44#include <string.h>
[fddd14]45
[f3a414]46#include "cache/cache.h"
[fe7802]47#include "storage/storage.h"
[8aa1d8]48
[18edda]49#include "hash/hash_slinger.h"
[d5015d]50#include "vcli.h"
[92f239c]51#include "vcli_priv.h"
[52ef56]52#include "vend.h"
[8aa1d8]53#include "vsha256.h"
[fddd14]54
55#include "persistent.h"
[fe7802]56#include "storage/storage_persistent.h"
[26ff83]57
[8f848f]58/*--------------------------------------------------------------------*/
[26ff83]59
[a01e8b]60/*
[f06f73]61 * silos is unlocked, it only changes during startup when we are
[a01e8b]62 * single-threaded
63 */
[062e10]64static VTAILQ_HEAD(,smp_sc)     silos = VTAILQ_HEAD_INITIALIZER(silos);
65
[f23fc8]66/*--------------------------------------------------------------------
[ef2fac]67 * Add bans to silos
[ed19d9]68 */
69
[a01e8b]70static void
[52ef56]71smp_appendban(struct smp_sc *sc, struct smp_signctx *ctx,
72    uint32_t len, const uint8_t *ban)
[a01e8b]73{
[89c360]74        uint8_t *ptr, *ptr2;
[f06f73]75
[11030e]76        (void)sc;
[89c360]77        ptr = ptr2 = SIGN_END(ctx);
78
79        memcpy(ptr, "BAN", 4);
80        ptr += 4;
81
[52ef56]82        vbe32enc(ptr, len);
83        ptr += 4;
[89c360]84
85        memcpy(ptr, ban, len);
86        ptr += len;
87
88        smp_append_sign(ctx, ptr2, ptr - ptr2);
[a01e8b]89}
90
[ef2fac]91/* Trust that cache_ban.c takes care of locking */
92
[ed19d9]93void
[52ef56]94SMP_NewBan(const uint8_t *ban, unsigned ln)
[ed19d9]95{
[a01e8b]96        struct smp_sc *sc;
97
[89c360]98        VTAILQ_FOREACH(sc, &silos, list) {
[52ef56]99                smp_appendban(sc, &sc->ban1, ln, ban);
100                smp_appendban(sc, &sc->ban2, ln, ban);
[89c360]101        }
102}
103
104/*--------------------------------------------------------------------
105 * Attempt to open and read in a ban list
106 */
107
108static int
109smp_open_bans(struct smp_sc *sc, struct smp_signctx *ctx)
110{
111        uint8_t *ptr, *pe;
[52ef56]112        uint32_t length;
[89c360]113        int i, retval = 0;
114
[4049f9]115        ASSERT_CLI();
[89c360]116        (void)sc;
[f06f73]117        i = smp_chk_sign(ctx);
[89c360]118        if (i)
119                return (i);
120        ptr = SIGN_DATA(ctx);
121        pe = ptr + ctx->ss->length;
122
123        while (ptr < pe) {
124                if (memcmp(ptr, "BAN", 4)) {
125                        retval = 1001;
126                        break;
127                }
128                ptr += 4;
129
[52ef56]130                length = vbe32dec(ptr);
131                ptr += 4;
[89c360]132
133                if (ptr + length > pe) {
134                        retval = 1003;
135                        break;
136                }
137
[52ef56]138                BAN_Reload(ptr, length);
[89c360]139
140                ptr += length;
141        }
142        assert(ptr <= pe);
143        return (retval);
[ed19d9]144}
145
[119aa3]146/*--------------------------------------------------------------------
[2c8b2c]147 * Attempt to open and read in a segment list
148 */
[7d2ce9]149
[c2c2da]150static int
[a01e8b]151smp_open_segs(struct smp_sc *sc, struct smp_signctx *ctx)
[c2c2da]152{
[650fd4]153        uint64_t length, l;
154        struct smp_segptr *ss, *se;
155        struct smp_seg *sg, *sg1, *sg2;
156        int i, n = 0;
[c2c2da]157
[4049f9]158        ASSERT_CLI();
[f06f73]159        i = smp_chk_sign(ctx);
[a01e8b]160        if (i)
161                return (i);
[650fd4]162
[a01e8b]163        ss = SIGN_DATA(ctx);
164        length = ctx->ss->length;
[c2c2da]165
[650fd4]166        if (length == 0) {
167                /* No segments */
168                sc->free_offset = sc->ident->stuff[SMP_SPC_STUFF];
169                return (0);
170        }
171        se = ss + length / sizeof *ss;
172        se--;
173        assert(ss <= se);
174
175        /*
176         * Locate the free reserve, there are only two basic cases,
177         * but once we start dropping segments, things gets more complicated.
178         */
179
180        sc->free_offset = se->offset + se->length;
181        l = sc->mediasize - sc->free_offset;
182        if (se->offset > ss->offset && l >= sc->free_reserve) {
183                /*
[f06f73]184                 * [__xxxxyyyyzzzz___]
[650fd4]185                 * Plenty of space at tail, do nothing.
186                 */
187        } else if (ss->offset > se->offset) {
188                /*
189                 * [zzzz____xxxxyyyy_]
190                 * (make) space between ends
191                 * We might nuke the entire tail end without getting
192                 * enough space, in which case we fall through to the
193                 * last check.
194                 */
195                while (ss < se && ss->offset > se->offset) {
196                        l = ss->offset - (se->offset + se->length);
197                        if (l > sc->free_reserve)
198                                break;
199                        ss++;
200                        n++;
201                }
202        }
203
204        if (l < sc->free_reserve) {
205                /*
[f06f73]206                 * [__xxxxyyyyzzzz___]
[650fd4]207                 * (make) space at front
208                 */
209                sc->free_offset = sc->ident->stuff[SMP_SPC_STUFF];
210                while (ss < se) {
211                        l = ss->offset - sc->free_offset;
212                        if (l > sc->free_reserve)
213                                break;
214                        ss++;
215                        n++;
216                }
217        }
218
219        assert (l >= sc->free_reserve);
220
221
222        sg1 = NULL;
223        sg2 = NULL;
224        for(; ss <= se; ss++) {
[c2a924]225                ALLOC_OBJ(sg, SMP_SEG_MAGIC);
226                AN(sg);
[ed02f4]227                sg->lru = LRU_Alloc();
[1e1d24b]228                CHECK_OBJ_NOTNULL(sg->lru, LRU_MAGIC);
[26ff83]229                sg->p = *ss;
[1e1d24b]230
[99c0a1]231                sg->flags |= SMP_SEG_MUSTLOAD;
[1e1d24b]232
[f88445]233                /*
234                 * HACK: prevent save_segs from nuking segment until we have
235                 * HACK: loaded it.
236                 */
[9f6858]237                sg->nobj = 1;
[650fd4]238                if (sg1 != NULL) {
[26ff83]239                        assert(sg1->p.offset != sg->p.offset);
240                        if (sg1->p.offset < sg->p.offset)
241                                assert(smp_segend(sg1) <= sg->p.offset);
[650fd4]242                        else
[26ff83]243                                assert(smp_segend(sg) <= sg1->p.offset);
[650fd4]244                }
245                if (sg2 != NULL) {
[26ff83]246                        assert(sg2->p.offset != sg->p.offset);
247                        if (sg2->p.offset < sg->p.offset)
248                                assert(smp_segend(sg2) <= sg->p.offset);
[650fd4]249                        else
[26ff83]250                                assert(smp_segend(sg) <= sg2->p.offset);
[650fd4]251                }
252
[a01e8b]253                /* XXX: check that they are inside silo */
254                /* XXX: check that they don't overlap */
255                /* XXX: check that they are serial */
[2f8950]256                sg->sc = sc;
[c2a924]257                VTAILQ_INSERT_TAIL(&sc->segments, sg, list);
[650fd4]258                sg2 = sg;
259                if (sg1 == NULL)
260                        sg1 = sg;
[c2a924]261        }
[650fd4]262        printf("Dropped %d segments to make free_reserve\n", n);
[c4d93f]263        return (0);
264}
265
266/*--------------------------------------------------------------------
[d7f66f]267 * Silo worker thread
268 */
269
270static void *
271smp_thread(struct sess *sp, void *priv)
272{
273        struct smp_sc   *sc;
274        struct smp_seg *sg;
275
276        (void)sp;
277        CAST_OBJ_NOTNULL(sc, priv, SMP_SC_MAGIC);
278
[d2855e]279        /* First, load all the objects from all segments */
[d7f66f]280        VTAILQ_FOREACH(sg, &sc->segments, list)
[99c0a1]281                if (sg->flags & SMP_SEG_MUSTLOAD)
[1e1d24b]282                        smp_load_seg(sp, sc, sg);
[d7f66f]283
[99c0a1]284        sc->flags |= SMP_SC_LOADED;
[42a844]285        BAN_TailDeref(&sc->tailban);
286        AZ(sc->tailban);
[e852a4]287        printf("Silo completely loaded\n");
[1a30dd]288        while (1) {
[e59c96]289                (void)sleep (1);
[1a30dd]290                sg = VTAILQ_FIRST(&sc->segments);
291                if (sg != NULL && sg -> sc->cur_seg &&
292                    sg->nobj == 0) {
293                        Lck_Lock(&sc->mtx);
294                        smp_save_segs(sc);
295                        Lck_Unlock(&sc->mtx);
296                }
297        }
[0f16bc]298        NEEDLESS_RETURN(NULL);
[d7f66f]299}
300
301/*--------------------------------------------------------------------
[2c8b2c]302 * Open a silo in the worker process
303 */
[c2c2da]304
305static void
306smp_open(const struct stevedore *st)
307{
308        struct smp_sc   *sc;
309
[4049f9]310        ASSERT_CLI();
311
[c2c2da]312        CAST_OBJ_NOTNULL(sc, st->priv, SMP_SC_MAGIC);
313
[7b3607]314        Lck_New(&sc->mtx, lck_smp);
[b2e383]315        Lck_Lock(&sc->mtx);
[4049f9]316
[1d95c7]317        sc->stevedore = st;
318
[c2c2da]319        /* We trust the parent to give us a valid silo, for good measure: */
320        AZ(smp_valid_silo(sc));
321
[c157e5]322        AZ(mprotect(sc->base, 4096, PROT_READ));
[9f6858]323
[a01e8b]324        sc->ident = SIGN_DATA(&sc->idn);
[c2c2da]325
[89c360]326        /* We attempt ban1 first, and if that fails, try ban2 */
327        if (smp_open_bans(sc, &sc->ban1))
328                AZ(smp_open_bans(sc, &sc->ban2));
[c2c2da]329
[89c360]330        /* We attempt seg1 first, and if that fails, try seg2 */
[a01e8b]331        if (smp_open_segs(sc, &sc->seg1))
332                AZ(smp_open_segs(sc, &sc->seg2));
[c4d93f]333
[42a844]334        /*
335         * Grap a reference to the tail of the ban list, until the thread
336         * has loaded all objects, so we can be sure that all of our
337         * proto-bans survive until then.
338         */
[6da059]339        sc->tailban = BAN_TailRef();
340        AN(sc->tailban);
341
[89c360]342        /* XXX: save segments to ensure consistency between seg1 & seg2 ? */
343
[d2855e]344        /* XXX: abandon early segments to make sure we have free space ? */
345
[d7f66f]346        /* Open a new segment, so we are ready to write */
[c4d93f]347        smp_new_seg(sc);
[d7f66f]348
[d2855e]349        /* Start the worker silo worker thread, it will load the objects */
[d7f66f]350        WRK_BgThread(&sc->thread, "persistence", smp_thread, sc);
[062e10]351
352        VTAILQ_INSERT_TAIL(&silos, sc, list);
[b2e383]353        Lck_Unlock(&sc->mtx);
[c2c2da]354}
355
[c4d93f]356/*--------------------------------------------------------------------
[139f870]357 * Close a silo
358 */
359
360static void
361smp_close(const struct stevedore *st)
362{
[9b82c1]363        struct smp_sc   *sc;
364
[4049f9]365        ASSERT_CLI();
366
[9b82c1]367        CAST_OBJ_NOTNULL(sc, st->priv, SMP_SC_MAGIC);
[b2e383]368        Lck_Lock(&sc->mtx);
[9b82c1]369        smp_close_seg(sc, sc->cur_seg);
[b2e383]370        Lck_Unlock(&sc->mtx);
[4049f9]371
372        /* XXX: reap thread */
[139f870]373}
374
375/*--------------------------------------------------------------------
[6af425]376 * Allocate a bite.
[8053cd7]377 *
[6af425]378 * Allocate [min_size...max_size] space from the bottom of the segment,
379 * as is convenient.
380 *
[8edfa7]381 * If 'so' + 'idx' is given, also allocate a smp_object from the top
[6af425]382 * of the segment.
383 *
384 * Return the segment in 'ssg' if given.
[c4d93f]385 */
386
387static struct storage *
[6af425]388smp_allocx(struct stevedore *st, size_t min_size, size_t max_size,
389    struct smp_object **so, unsigned *idx, struct smp_seg **ssg)
[c4d93f]390{
391        struct smp_sc *sc;
392        struct storage *ss;
[9b82c1]393        struct smp_seg *sg;
[04dc69]394        unsigned tries;
[6af425]395        uint64_t left, extra;
[c4d93f]396
397        CAST_OBJ_NOTNULL(sc, st->priv, SMP_SC_MAGIC);
[6af425]398        assert(min_size <= max_size);
[c4d93f]399
[6af425]400        max_size = IRNUP(sc, max_size);
401        min_size = IRNUP(sc, min_size);
[3eb07d]402
[6af425]403        extra = IRNUP(sc, sizeof(*ss));
404        if (so != NULL) {
405                extra += sizeof(**so);
406                AN(idx);
407        }
[04dc69]408
[6af425]409        Lck_Lock(&sc->mtx);
410        sg = NULL;
411        ss = NULL;
412        for (tries = 0; tries < 3; tries++) {
413                left = smp_spaceleft(sc, sc->cur_seg);
[8edfa7]414                if (left >= extra + min_size)
[04dc69]415                        break;
[9041a9]416                smp_close_seg(sc, sc->cur_seg);
417                smp_new_seg(sc);
418        }
[6af425]419        if (left >= extra + min_size)  {
420                if (left < extra + max_size)
421                        max_size = IRNDN(sc, left - extra);
[9041a9]422
[6af425]423                sg = sc->cur_seg;
[b70e63]424                ss = (void*)(sc->base + sc->next_bot);
425                sc->next_bot += max_size + IRNUP(sc, sizeof(*ss));
[6af425]426                sg->nalloc++;
427                if (so != NULL) {
[b70e63]428                        sc->next_top -= sizeof(**so);
429                        *so = (void*)(sc->base + sc->next_top);
[6af425]430                        /* Render this smp_object mostly harmless */
431                        (*so)->ttl = 0.;
432                        (*so)->ban = 0.;
[8edfa7]433                        (*so)->ptr = 0;;
[6af425]434                        sg->objs = *so;
[b4916e]435                        *idx = ++sg->p.lobjlist;
[6af425]436                }
437                (void)smp_spaceleft(sc, sg);    /* for the assert */
[f88445]438        }
[4049f9]439        Lck_Unlock(&sc->mtx);
[c4d93f]440
[6af425]441        if (ss == NULL)
442                return (ss);
443        AN(sg);
444        assert(max_size >= min_size);
445
[04dc69]446        /* Fill the storage structure */
[c4d93f]447        memset(ss, 0, sizeof *ss);
448        ss->magic = STORAGE_MAGIC;
[6af425]449        ss->ptr = PRNUP(sc, ss + 1);
450        ss->space = max_size;
[139f870]451        ss->priv = sc;
[c4d93f]452        ss->stevedore = st;
[6af425]453        if (ssg != NULL)
454                *ssg = sg;
[c4d93f]455        return (ss);
456}
457
[856edab]458/*--------------------------------------------------------------------
[d4e7ed]459 * Allocate an object
460 */
461
462static struct object *
[efd6a98]463smp_allocobj(struct stevedore *stv, struct worker *wrk, unsigned ltot,
[8053cd7]464    const struct stv_objsecrets *soc)
[d4e7ed]465{
466        struct object *o;
467        struct storage *st;
468        struct smp_sc   *sc;
469        struct smp_seg *sg;
470        struct smp_object *so;
[8053cd7]471        struct objcore *oc;
[6af425]472        unsigned objidx;
[8053cd7]473
[6c1486]474        if (wrk->sp->req->objcore == NULL)
[cfad47]475                return (NULL);          /* from cnt_error */
[8053cd7]476        CAST_OBJ_NOTNULL(sc, stv->priv, SMP_SC_MAGIC);
[6c1486]477        AN(wrk->sp->req->objcore);
[9d67fc]478        AN(wrk->busyobj->exp.ttl > 0.);
[d4e7ed]479
[6af425]480        ltot = IRNUP(sc, ltot);
481
482        st = smp_allocx(stv, ltot, ltot, &so, &objidx, &sg);
[8053cd7]483        if (st == NULL)
484                return (NULL);
[d4e7ed]485
[8053cd7]486        assert(st->space >= ltot);
487        ltot = st->len = st->space;
488
[efd6a98]489        o = STV_MkObject(wrk, st->ptr, ltot, soc);
[8053cd7]490        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
491        o->objstore = st;
[f5f5ab]492
[8053cd7]493        oc = o->objcore;
494        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
495        oc->flags |= OC_F_LRUDONTMOVE;
[d4e7ed]496
497        Lck_Lock(&sc->mtx);
498        sg->nfixed++;
499        sg->nobj++;
[6af425]500
501        /* We have to do this somewhere, might as well be here... */
[d4e7ed]502        assert(sizeof so->hash == DIGEST_LEN);
[8053cd7]503        memcpy(so->hash, oc->objhead->digest, DIGEST_LEN);
[c2b0f1]504        so->ttl = EXP_Grace(NULL, o);
[8edfa7]505        so->ptr = (uint8_t*)o - sc->base;
[52ef56]506        so->ban = BAN_Time(oc->ban);
[d4e7ed]507
[052473]508        smp_init_oc(oc, sg, objidx);
[e0defb]509
[d4e7ed]510        Lck_Unlock(&sc->mtx);
[8053cd7]511        return (o);
[d4e7ed]512}
513
514/*--------------------------------------------------------------------
515 * Allocate a bite
516 */
517
518static struct storage *
519smp_alloc(struct stevedore *st, size_t size)
520{
521
[8edfa7]522        return (smp_allocx(st,
[b70e63]523            size > 4096 ? 4096 : size, size, NULL, NULL, NULL));
[d4e7ed]524}
525
[c157e5]526/*--------------------------------------------------------------------
527 * Trim a bite
528 * XXX: We could trim the last allocation.
529 */
530
[c4d93f]531static void
[139f870]532smp_trim(struct storage *ss, size_t size)
533{
534
[c157e5]535        (void)ss;
536        (void)size;
[139f870]537}
538
[4049f9]539/*--------------------------------------------------------------------
[c157e5]540 * We don't track frees of storage, we track the objects which own the
541 * storage and when there are no more objects in in the first segment,
542 * it can be reclaimed.
543 * XXX: We could free the last allocation, but does that happen ?
[4049f9]544 */
545
[302dca7]546static void __match_proto__(storage_free_f)
[c4d93f]547smp_free(struct storage *st)
548{
549
550        /* XXX */
551        (void)st;
552}
553
[062e10]554
555/*--------------------------------------------------------------------*/
556
[46035d]557const struct stevedore smp_stevedore = {
[fddd14]558        .magic  =       STEVEDORE_MAGIC,
559        .name   =       "persistent",
[c4c9db]560        .init   =       smp_mgt_init,
[c2c2da]561        .open   =       smp_open,
[139f870]562        .close  =       smp_close,
[c4d93f]563        .alloc  =       smp_alloc,
[bc4c952]564        .allocobj =     smp_allocobj,
[c4d93f]565        .free   =       smp_free,
[139f870]566        .trim   =       smp_trim,
[5fb157a]567        .dup    =       default_dup,
[fddd14]568};
[1d95c7]569
[8edfa7]570/*--------------------------------------------------------------------
571 * Persistence is a bear to test unadultered, so we cheat by adding
572 * a cli command we can use to make it do tricks for us.
573 */
[1d95c7]574
575static void
[8edfa7]576debug_report_silo(struct cli *cli, const struct smp_sc *sc, int objs)
[b70e63]577{
578        struct smp_seg *sg;
579        struct objcore *oc;
580
[ab0b3e]581        VCLI_Out(cli, "Silo: %s (%s)\n",
[b70e63]582            sc->stevedore->ident, sc->filename);
583        VTAILQ_FOREACH(sg, &sc->segments, list) {
[ab0b3e]584                VCLI_Out(cli, "  Seg: [0x%jx ... +0x%jx]\n",
[b70e63]585                   (uintmax_t)sg->p.offset, (uintmax_t)sg->p.length);
[8edfa7]586                if (sg == sc->cur_seg)
[ab0b3e]587                        VCLI_Out(cli,
[8edfa7]588                           "    Alloc: [0x%jx ... 0x%jx] = 0x%jx free\n",
[b70e63]589                           (uintmax_t)(sc->next_bot),
590                           (uintmax_t)(sc->next_top),
591                           (uintmax_t)(sc->next_top - sc->next_bot));
[ab0b3e]592                VCLI_Out(cli, "    %u nobj, %u alloc, %u lobjlist, %u fixed\n",
[b4916e]593                    sg->nobj, sg->nalloc, sg->p.lobjlist, sg->nfixed);
[8edfa7]594                if (objs) {
[d0db0a]595                        VTAILQ_FOREACH(oc, &sg->lru->lru_head, lru_list)
[ab0b3e]596                                VCLI_Out(cli, "      OC %p\n", oc);
[b70e63]597                }
598        }
599}
600
601static void
[1d95c7]602debug_persistent(struct cli *cli, const char * const * av, void *priv)
603{
604        struct smp_sc *sc;
605
606        (void)priv;
607
[b70e63]608        if (av[2] == NULL) {
609                VTAILQ_FOREACH(sc, &silos, list)
[8edfa7]610                        debug_report_silo(cli, sc, 0);
[1d95c7]611                return;
612        }
[b70e63]613        VTAILQ_FOREACH(sc, &silos, list)
614                if (!strcmp(av[2], sc->stevedore->ident))
615                        break;
616        if (sc == NULL) {
[ab0b3e]617                VCLI_Out(cli, "Silo <%s> not found\n", av[2]);
618                VCLI_SetResult(cli, CLIS_PARAM);
[b70e63]619                return;
620        }
621        if (av[3] == NULL) {
[8edfa7]622                debug_report_silo(cli, sc, 0);
[b70e63]623                return;
624        }
625        Lck_Lock(&sc->mtx);
626        if (!strcmp(av[3], "sync")) {
627                smp_close_seg(sc, sc->cur_seg);
628                smp_new_seg(sc);
[8edfa7]629        } else if (!strcmp(av[3], "dump")) {
630                debug_report_silo(cli, sc, 1);
[b70e63]631        } else {
[ab0b3e]632                VCLI_Out(cli, "Unknown operation\n");
633                VCLI_SetResult(cli, CLIS_PARAM);
[b70e63]634        }
635        Lck_Unlock(&sc->mtx);
[1d95c7]636}
637
638static struct cli_proto debug_cmds[] = {
639        { "debug.persistent", "debug.persistent",
[8edfa7]640                "Persistent debugging magic:\n"
641                "\tdebug.persistent [stevedore [cmd]]\n"
642                "With no cmd arg, a summary of the silo is returned.\n"
643                "Possible commands:\n"
644                "\tsync\tClose current segment, open a new one\n"
645                "\tdump\tinclude objcores in silo summary\n"
646                "",
647                0, 2, "d", debug_persistent },
[1d95c7]648        { NULL }
649};
650
[ef2fac]651/*--------------------------------------------------------------------*/
652
[1d95c7]653void
654SMP_Init(void)
655{
656        CLI_AddFuncs(debug_cmds);
657}
[ef2fac]658
659/*--------------------------------------------------------------------
660 * Pause until all silos have loaded.
661 */
662
663void
664SMP_Ready(void)
665{
666        struct smp_sc *sc;
667
668        ASSERT_CLI();
669        do {
670                VTAILQ_FOREACH(sc, &silos, list)
671                        if (!(sc->flags & SMP_SC_LOADED))
672                                break;
673                if (sc != NULL)
674                        (void)sleep(1);
675        } while (sc != NULL);
676}
Note: See TracBrowser for help on using the repository browser.