ref: 6caee0300e6e8e51551a6a277ef4c6c9113982ff
dir: /ream.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <avl.h> #include "dat.h" #include "fns.h" enum { Qmainroot, Qadmroot, Qadmuser, Nreamqid, }; char *defaultusers ="-1:adm::%s\n0:none::\n"; static void fillxdir(Xdir *d, vlong qid, char *name, int type, int mode) { memset(d, 0, sizeof(Xdir)); d->qid = (Qid){qid, 0, type}; d->mode = mode; d->atime = 0; d->mtime = 0; d->length = 0; d->name = name; d->uid = -1; d->gid = -1; d->muid = 0; } static void initadm(Blk *r, Blk *u, int nu) { char *p, kbuf[Keymax], vbuf[Inlmax]; Kvp kv; Xdir d; /* nb: values must be inserted in key order */ kv.k = kbuf; kv.nk = Offksz; kv.v = vbuf; kv.nv = Ptrsz; kbuf[0] = Kdat; PACK64(kbuf+1, (uvlong)Qadmuser); PACK64(kbuf+9, 0ULL); packbp(kv.v, kv.nv, &u->bp); setval(r, &kv); fillxdir(&d, Qadmuser, "users", QTFILE, 0664); d.length = nu; if(dir2kv(Qadmroot, &d, &kv, vbuf, sizeof(vbuf)) == -1) sysfatal("ream: pack users: %r"); setval(r, &kv); fillxdir(&d, Qadmroot, "", QTDIR, DMDIR|0775); if(dir2kv(-1, &d, &kv, vbuf, sizeof(vbuf)) == -1) sysfatal("ream: pack root: %r"); setval(r, &kv); if((p = packsuper(kbuf, sizeof(kbuf), 0)) == nil) sysfatal("ream: pack super"); kv.k = kbuf; kv.nk = p - kbuf; if((p = packdkey(vbuf, sizeof(vbuf), -1, "")) == nil) sysfatal("ream: pack super"); kv.v = vbuf; kv.nv = p - vbuf; setval(r, &kv); } static void initroot(Blk *r) { char *p, kbuf[Keymax], vbuf[Inlmax]; Kvp kv; Xdir d; /* nb: values must be inserted in key order */ fillxdir(&d, Qmainroot, "", QTDIR, DMDIR|0775); if(dir2kv(-1, &d, &kv, vbuf, sizeof(vbuf)) == -1) sysfatal("ream: pack root: %r"); setval(r, &kv); if((p = packsuper(kbuf, sizeof(kbuf), 0)) == nil) sysfatal("ream: pack super"); kv.k = kbuf; kv.nk = p - kbuf; if((p = packdkey(vbuf, sizeof(vbuf), -1, "")) == nil) sysfatal("ream: pack super"); kv.v = vbuf; kv.nv = p - vbuf; setval(r, &kv); } static void initsnap(Blk *s, Blk *r, Blk *a) { char *p, *e, buf[Kvmax]; Tree t; Kvp kv; lbl2kv("adm", 1, Lmut, &kv, buf, sizeof(buf)); setval(s, &kv); lbl2kv("empty", 0, 0, &kv, buf, sizeof(buf)); setval(s, &kv); lbl2kv("main", 0, Lmut, &kv, buf, sizeof(buf)); setval(s, &kv); p = buf; e = p + sizeof(buf); kv.k = p; p = packsnap(buf, e - p, 0); kv.nk = p - kv.k; kv.v = p; memset(&t, 0, sizeof(Tree)); t.nsucc = 1; t.nlbl = 2; t.ht = 1; t.gen = fs->nextgen++; t.prev = -1ULL; t.bp = r->bp; p = packtree(p, e - p, &t); kv.nv = p - kv.v; setval(s, &kv); p = buf; e = p + sizeof(buf); kv.k = p; p = packsnap(p, e - p, 1); kv.nk = p - kv.k; kv.v = p; memset(&t, 0, sizeof(Tree)); t.nsucc = 0; t.nlbl = 1; t.ht = 1; t.gen = fs->nextgen++; t.prev = -1ULL; t.bp = a->bp; p = packtree(p, e - p, &t); kv.nv = p - kv.v; setval(s, &kv); } static void initarena(Arena *a, vlong start, vlong asz) { vlong addr, bo, bh; char *p; Blk *b, *hd, *tl; b = cachepluck(); if(start == 512*MiB){ start += Blksz; asz -= Blksz; } addr = start+Blksz; /* leave room for arena hdr */ a->loghd.addr = -1; a->loghd.hash = -1; a->loghd.gen = -1; memset(b->buf, 0, sizeof(b->buf)); b->type = Tlog; b->bp.addr = addr+Blksz; if(b->bp.addr == 512*MiB){ b->bp.addr += Blksz; asz -= Blksz; } b->logsz = 0; b->logp = (Bptr){-1, -1, -1}; b->data = b->buf + Loghdsz; setflag(b, Bdirty); p = b->buf + Loghdsz; b->logp = (Bptr){-1, -1, -1}; PACK64(p, addr|LogFree); p += 8; /* addr */ PACK64(p, asz-Blksz); p += 8; /* len */ PACK64(p, b->bp.addr|LogAlloc); p += 8; /* addr */ PACK64(p, Blksz); p += 8; /* len */ /* backup sb */ if(start <= 512*MiB && start+asz > 512*MiB){ PACK64(p, (512*MiB)|LogAlloc1); p += 8; } PACK64(p, (uvlong)LogSync); p += 8; /* barrier */ b->logsz = p - b->data; finalize(b); if(syncblk(b) == -1) sysfatal("ream: init log"); dropblk(b); bh = b->bp.hash; bo = b->bp.addr; a->loghd.addr = bo; a->loghd.hash = bh; a->loghd.gen = -1; a->size = asz; a->used = Blksz; hd = cachepluck(); tl = cachepluck(); memset(hd->buf, 0, sizeof(hd->buf)); hd->type = Tarena; hd->bp.addr = start; hd->data = hd->buf+2; finalize(hd); memset(tl->buf, 0, sizeof(tl->buf)); tl->type = Tarena; tl->bp.addr = start+asz; tl->data = tl->buf+2; finalize(tl); packarena(hd->data, Arenasz, a); packarena(tl->data, Arenasz, a); finalize(hd); finalize(tl); if(syncblk(hd) == -1) sysfatal("ream: write arena: %r"); if(syncblk(tl) == -1) sysfatal("ream: write arena: %r"); a->hd = hd; a->tl = tl; } void reamfs(char *dev) { Blk *sb0, *sb1, *tb, *mb, *ab, *ub; vlong sz, asz, off; Mount *mnt, *adm; Arena *a; Dir *d; int i; if((fs->fd = open(dev, ORDWR)) == -1) sysfatal("open %s: %r", dev); if((d = dirfstat(fs->fd)) == nil) sysfatal("ream: %r"); sz = d->length; free(d); if(sz < 512*MiB+Blksz) sysfatal("ream: disk too small"); if((mnt = mallocz(sizeof(Mount), 1)) == nil) sysfatal("ream: alloc mount: %r"); if((mnt->root = mallocz(sizeof(Tree), 1)) == nil) sysfatal("ream: alloc tree: %r"); if((adm = mallocz(sizeof(Mount), 1)) == nil) sysfatal("ream: alloc mount: %r"); if((adm->root = mallocz(sizeof(Tree), 1)) == nil) sysfatal("ream: alloc tree: %r"); sz = sz - sz%Blksz - 2*Blksz; fs->narena = (sz + 64ULL*GiB - 1) / (64ULL*GiB); if(fs->narena < 8) fs->narena = 8; if(fs->narena >= 128) fs->narena = 128; if((fs->arenas = calloc(fs->narena, sizeof(Arena))) == nil) sysfatal("malloc: %r"); off = Blksz; asz = sz/fs->narena; asz = asz - (asz % Blksz) - Blksz; fs->arenasz = asz; sb0 = cachepluck(); sb1 = cachepluck(); sb0->bp = (Bptr){0, -1, -1}; sb1->bp = (Bptr){512*MiB, -1, -1}; fs->arenabp = malloc(fs->narena * sizeof(Bptr)); for(i = 0; i < fs->narena; i++){ a = &fs->arenas[i]; print("\tarena %d: %lld blocks at %llx\n", i, asz/Blksz, off); initarena(a, off, asz); fs->arenabp[i] = a->hd->bp; off += asz+Blksz; } for(i = 0; i < fs->narena; i++){ a = &fs->arenas[i]; if((loadarena(a, a->hd->bp, asz)) == -1) sysfatal("ream: loadarena: %r"); if(loadlog(a, a->loghd) == -1) sysfatal("load log: %r"); } if((mb = newblk(mnt->root, Tleaf)) == nil) sysfatal("ream: allocate root: %r"); holdblk(mb); initroot(mb); finalize(mb); syncblk(mb); mnt->root->ht = 1; mnt->root->bp = mb->bp; if((ab = newblk(adm->root, Tleaf)) == nil) sysfatal("ream: allocate root: %r"); if((ub = newblk(adm->root, Tdat)) == nil) sysfatal("ream: allocate root: %r"); holdblk(ab); holdblk(ub); if(reamuser != nil){ defaultusers = smprint( "-1:adm::%s\n" "0:none::\n" "1:%s:%s:\n", reamuser, reamuser, reamuser); } memcpy(ub->data, defaultusers, strlen(defaultusers)); finalize(ub); syncblk(ub); initadm(ab, ub, strlen(defaultusers)); finalize(ab); syncblk(ab); adm->root->ht = 1; adm->root->bp = ab->bp; /* * Now that we have a completely empty fs, give it * a single snap block that the tree will insert * into, and take a snapshot as the initial state. */ if((tb = newblk(mnt->root, Tleaf)) == nil) sysfatal("ream: allocate snaps: %r"); holdblk(tb); initsnap(tb, mb, ab); finalize(tb); syncblk(tb); fs->snap.bp = tb->bp; fs->snap.ht = 1; fs->snapdl.hd.addr = -1; fs->snapdl.hd.hash = -1; fs->snapdl.tl.addr = -1; fs->snapdl.tl.hash = -1; fs->nextqid = Nreamqid; dropblk(mb); dropblk(ab); dropblk(ub); dropblk(tb); fs->nextqid = Nreamqid; /* * We need to write back all of the arenas * with the updated free lists */ for(i = 0; i < fs->narena; i++){ a = &fs->arenas[i]; finalize(a->logtl); if(syncblk(a->logtl) == -1) sysfatal("sync arena: %r"); packarena(a->hd->data, Blksz, a); finalize(a->hd); if(syncblk(a->hd) == -1) sysfatal("sync arena: %r"); packarena(a->tl->data, Blksz, a); finalize(a->tl); if(syncblk(a->tl) == -1) sysfatal("sync arena: %r"); fs->arenabp[i] = a->hd->bp; dropblk(a->hd); dropblk(a->tl); } dropblk(mb); dropblk(ab); dropblk(ub); dropblk(tb); /* * Finally, write back the superblock and backup * superblock. */ packsb(sb0->buf, Blksz, fs); packsb(sb1->buf, Blksz, fs); finalize(sb0); finalize(sb1); if(syncblk(sb0) == -1) sysfatal("sync superblock: %r"); if(syncblk(sb1) == -1) sysfatal("sync superblock: %r"); dropblk(sb0); dropblk(sb1); free(mnt); } void growfs(char *dev) { vlong sz, off; int i, narena; Bptr bp; Arena *a; Dir *d; if((fs->fd = open(dev, ORDWR)) == -1) sysfatal("open %s: %r", dev); if((d = dirfstat(fs->fd)) == nil) sysfatal("ream: %r"); sz = d->length; free(d); bp = (Bptr){0, -1, -1}; if((fs->sb0 = getblk(bp, GBnochk)) == nil) sysfatal("superblock: %r\n"); if(unpacksb(fs, fs->sb0->buf, Blksz) == nil) sysfatal("superblock: %r"); if((fs->arenas = calloc(fs->narena, sizeof(Arena))) == nil) sysfatal("malloc: %r"); for(i = 0; i < fs->narena; i++){ a = &fs->arenas[i]; if((loadarena(a, fs->arenabp[i], fs->arenasz)) == -1) sysfatal("growfs: %r"); } narena = sz/fs->arenasz; off = fs->arenasz * fs->narena; if(narena <= fs->narena) sysfatal("disk too small for more arenas"); if((fs->arenas = realloc(fs->arenas, narena*sizeof(Arena))) == nil) sysfatal("malloc: %r"); if((fs->arenabp = realloc(fs->arenas, narena*sizeof(Bptr))) == nil) sysfatal("malloc: %r"); for(i = fs->narena; i < narena; i++){ a = &fs->arenas[i]; print("\tadding %d: %lld blocks at %llx\n", i, fs->arenasz/Blksz, off); initarena(&fs->arenas[i], off, fs->arenasz); if((loadarena(a, fs->arenabp[i], fs->arenasz)) == -1) sysfatal("growfs: %r"); fs->arenabp[i] = a->hd->bp; off += fs->arenasz; } fs->narena = narena; for(i = 0; i < narena; i++){ a = &fs->arenas[i]; packarena(a->hd->data, Blksz, a); packarena(a->tl->data, Blksz, a); finalize(a->hd); finalize(a->tl); if(syncblk(a->hd) == -1) sysfatal("sync arena: %r"); if(syncblk(a->tl) == -1) sysfatal("sync arena: %r"); } packsb(fs->sb0->buf, Blksz, fs); packsb(fs->sb1->buf, Blksz, fs); finalize(fs->sb0); finalize(fs->sb1); if(syncblk(fs->sb0) == -1) sysfatal("sync superblock: %r"); if(syncblk(fs->sb1) == -1) sysfatal("sync superblock: %r"); }