i looked at kenfs's dumpblock() from /n/sources/extra/fs/fs/dev/cw.c
but i do not see what you mean. the code just goes thru the cache
looking for a block to dump while trying to get one as close to
the previous dumped block address as possible in both directions.
(trying to avoid seeks?)

can you point to the specific code that makes sure that blocks
get only written to the worm after the previous superblock?

what makes me think (i could be wrong here) that the assumption
does *not* hold is this (using kenfs here from /n/sources/extra/fs):

blocks have the following states:

        /* states -- beware these are recorded on the cache */
                                /*    cache    worm     */
        Cnone = 0,              /*      0       ?       */
        Cdirty,                 /*      1       0       */
        Cdump,                  /*      1       0->1    */
        Cread,                  /*      1       1       */
        Cwrite,                 /*      2       1       */
        Cdump1,                 /* inactive form of dump */
        Cerror,

the blocks maintained in the freelist should be blocks not already written
to the worm. like, when we delete a file that was already written to the
worm (states Cread, Cwrite), it is not put into the freelist and we'll
just forget about it. however, if the block was just in the cache (Cdirty)
it *is* put on the freelist:

int
cwfree(Device *dev, Off addr)
{
        int state;

        if(dev->type == Devcw) {
                state = cwio(dev, addr, 0, Ofree);
                if(state != Cdirty)
                        return 1;       /* do not put in freelist */
        }
        return 0;                       /* put in freelist */
}

now, such a Cdirty block could just sit in the freelist for a while no?
while the filesystem does many dump generations. if that Cdirty block
becomes part of the filesystem again because it is allocated, then
the next cwrecur() should pick it up and call split() on it.

Off
split(Cw *cw, Iobuf *p, Off addr)
{
        Off na;
        int state;

        na = 0;
        if(p && (p->flags & Bmod)) {
                p->flags |= Bimm;
                putbuf(p);
                p = 0;
        }
        state = cwio(cw->dev, addr, 0, Onone);  /* read the state (twice?) */
        switch(state)
        {
        default:
                panic("split: unknown state %s", cwnames[state]);

        case Cerror:
        case Cnone:
        case Cdump:
        case Cread:
                break;

        case Cdump1:
        case Cwrite:
                /*
                 * botch.. could be done by relabeling
                 */
                if(!p) {
                        p = getbuf(cw->dev, addr, Bread);
                        if(!p) {
                                print("split: null getbuf\n");
                                break;
                        }
                }
                na = cw->fsize;
                cw->fsize = na+1;
                cwio(cw->dev, na, 0, Ogrow);
                cwio(cw->dev, na, p->iobuf, Owrite);
                cwio(cw->dev, na, 0, Odump);
                cwio(cw->dev, addr, 0, Orele);
                break;

        case Cdirty:
                cwio(cw->dev, addr, 0, Odump); // <- *here*
                break;
        }
        if(p)
                putbuf(p);
        return na;
}

we see in this case, that we wont make a new address for the block, but
we'll just mark it for dumping at its original address which i think
is not limited to after the last dumps superblock address.

in the other case, when that block already had a version in the worm
(Cdump1, Cwrite) it is indeed copied to the end of the filesystem like
i think you ment by saying it will fill the worm only after the previous
dumped superblock.

does this make any sense?

--
cinap

Reply via email to