ref: 99c900d718ea1343036656b7384af56bcad2f28f
dir: /snap.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <avl.h> #include "dat.h" #include "fns.h" vlong inc64(uvlong *v, uvlong dv) { vlong ov, nv; while(1){ ov = *v; nv = ov + dv; if(cas64(v, ov, nv)) return nv; } } int syncblk(Blk *b) { assert(b->flag & Bfinal); lock(b); b->flag &= ~(Bqueued|Bdirty); unlock(b); return pwrite(fs->fd, b->buf, Blksz, b->bp.addr); } void enqueue(Blk *b) { assert(b->flag&Bdirty); finalize(b); if(syncblk(b) == -1){ ainc(&fs->broken); fprint(2, "write: %r"); abort(); } } char* opensnap(Tree *t, char *name) { char dbuf[Keymax], buf[Kvmax]; char *p, *e; int n; Key k; Kvp kv; n = strlen(name); p = dbuf; p[0] = Klabel; p += 1; memcpy(p, name, n); p += n; k.k = dbuf; k.nk = p - dbuf; if((e = btlookup(&fs->snap, &k, &kv, buf, sizeof(buf))) != nil) return e; memmove(dbuf, kv.v, kv.nv); k.k = dbuf; k.nk = kv.nv; if((e = btlookup(&fs->snap, &k, &kv, buf, sizeof(buf))) != nil) return e; if(unpacktree(t, kv.v, kv.nv) == nil) return Efs; return nil; } static char* modifysnap(vlong gen, char *name, int del) { char dbuf[Keymax], sbuf[Snapsz]; char *p, *e; int n, nm; Msg m[2]; p = sbuf; nm = 0; p[0] = Ksnap; p += 1; PBIT64(p, gen); p += 8; m[nm].op = del ? Ounrefsnap : Orefsnap; m[nm].k = sbuf; m[nm].nk = p - sbuf; m[nm].v = nil; m[nm].nv = 0; nm++; if(name != nil){ p = dbuf; n = strlen(name); m[nm].op = del ? Odelete : Oinsert; p[0] = Klabel; p += 1; memcpy(p, name, n); p += n; m[nm].k = dbuf; m[nm].nk = p - dbuf; m[nm].v = m[nm-1].k; m[nm].nv = m[nm-1].nk; nm++; } if((e = btupsert(&fs->snap, m, nm)) != nil) return e; return nil; } char* labelsnap(vlong gen, char *name) { return modifysnap(gen, name, 0); } char* unlabelsnap(vlong gen, char *name) { return modifysnap(gen, name, 1); } char* refsnap(vlong gen) { return modifysnap(gen, nil, 0); } char* unrefsnap(vlong gen) { return modifysnap(gen, nil, 1); } char* snapshot(Tree *t, vlong *genp, vlong *oldp) { char kbuf[Snapsz], vbuf[Treesz]; char *p, *e; uvlong gen; Msg m; int i; gen = inc64(&fs->nextgen, 1); p = kbuf; p[0] = Ksnap; p += 1; PBIT64(p, gen); p += 8; m.op = Oinsert; m.k = kbuf; m.nk = p - kbuf; for(i = 0; i < Ndead; i++){ if(t->dead[i].tail != nil){ finalize(t->dead[i].tail); syncblk(t->dead[i].tail); putblk(t->dead[i].tail); } } p = packtree(vbuf, sizeof(vbuf), t); m.v = vbuf; m.nv = p - vbuf; if((e = btupsert(&fs->snap, &m, 1)) != nil) return e; if(sync() == -1) return Eio; /* shift deadlist down */ if(t->dead[Ndead-1].tail != nil) putblk(t->dead[Ndead-1].tail); for(i = Ndead-1; i >= 0; i--){ t->prev[i] = i == 0 ? gen : t->prev[i-1]; t->dead[i].head = -1; t->dead[i].hash = -1; t->dead[i].tail = nil; } *genp = gen; *oldp = t->prev[0]; return nil; } int sync(void) { int i, r; Blk *b, *s; Arena *a; qlock(&fs->snaplk); r = 0; s = fs->super; fillsuper(s); enqueue(s); for(i = 0; i < fs->narena; i++){ a = &fs->arenas[i]; finalize(a->log.tail); if(syncblk(a->log.tail) == -1) r = -1; } for(b = fs->chead; b != nil; b = b->cnext){ if(!(b->flag & Bdirty)) continue; if(syncblk(b) == -1) r = -1; } if(r != -1) r = syncblk(s); qunlock(&fs->snaplk); return r; } void quiesce(int tid) { int i, allquiesced; Bfree *p, *n; lock(&fs->activelk); allquiesced = 1; fs->active[tid]++; for(i = 0; i < fs->nproc; i++){ /* * Odd parity on quiescence implies * that we're between the exit from * and waiting for the next message * that enters us into the critical * section. */ if((fs->active[i] & 1) == 0) continue; if(fs->active[i] == fs->lastactive[i]) allquiesced = 0; } if(allquiesced) for(i = 0; i < fs->nproc; i++) fs->lastactive[i] = fs->active[i]; unlock(&fs->activelk); if(!allquiesced) return; lock(&fs->freelk); p = nil; if(fs->freep != nil){ p = fs->freep->next; fs->freep->next = nil; } unlock(&fs->freelk); while(p != nil){ n = p->next; reclaimblk(p->bp); p = n; } fs->freep = fs->freehd; }