ref: 6a371792659d530b9ff9e9ff6eb684b2b5d28c92
dir: /cons.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <avl.h> #include <bio.h> #include "dat.h" #include "fns.h" typedef struct Cmd Cmd; struct Cmd { char *name; char *sub; int minarg; int maxarg; int epoch; void (*fn)(int, char**, int); }; static void setdbg(int fd, char **ap, int na) { debug = (na == 1) ? atoi(ap[0]) : !debug; fprint(fd, "debug → %d\n", debug); } static void sendsync(int fd, int halt) { Amsg *a; a = mallocz(sizeof(Amsg), 1); if(a == nil){ fprint(fd, "alloc sync msg: %r\n"); free(a); return; } a->op = AOsync; a->halt = halt; a->fd = fd; chsend(fs->admchan, a); } static void syncfs(int fd, char **, int) { sendsync(fd, 0); fprint(fd, "synced\n"); } static void haltfs(int fd, char **, int) { sendsync(fd, 1); fprint(fd, "gefs: ending...\n"); } static void listsnap(int fd) { char pfx[Snapsz]; Scan s; uint flg; int sz; pfx[0] = Klabel; sz = 1; btnewscan(&s, pfx, sz); btenter(&fs->snap, &s); while(1){ if(!btnext(&s, &s.kv)) break; flg = UNPACK32(s.kv.v+1+8); fprint(fd, "snap %.*s", s.kv.nk-1, s.kv.k+1); if(flg != 0) fprint(fd, " ["); if(flg & Lmut) fprint(fd, " mutable"); if(flg & Lauto) fprint(fd, " auto"); if(flg & Ltsnap) fprint(fd, " tsnap"); if(flg != 0) fprint(fd, " ]"); fprint(fd, "\n"); } btexit(&s); } static void snapfs(int fd, char **ap, int na) { Amsg *a; int i; if((a = mallocz(sizeof(Amsg), 1)) == nil){ fprint(fd, "alloc sync msg: %r\n"); return; } a->op = AOsnap; a->fd = fd; a->flag = Ltsnap; while(ap[0][0] == '-'){ for(i = 1; ap[0][i]; i++){ switch(ap[0][i]){ case 'S': a->flag &= ~Ltsnap; break; case 'm': a->flag |= Lmut; break; case 'd': a->delete++; break; case 'l': listsnap(fd); free(a); return; default: fprint(fd, "usage: snap -[Smdl] [old [new]]\n"); free(a); return; } } na--; ap++; } if(a->delete && na != 1 || !a->delete && na != 2){ fprint(fd, "usage: snap -[md] old [new]\n"); free(a); return; } if(na >= 1) strecpy(a->old, a->old+sizeof(a->old), ap[0]); if(na >= 2) strecpy(a->new, a->new+sizeof(a->new), ap[1]); sendsync(fd, 0); chsend(fs->admchan, a); } static void fsckfs(int fd, char**, int) { if(checkfs(fd)) fprint(fd, "ok\n"); else fprint(fd, "broken\n"); } static void refreshusers(int fd, char **, int) { Mount *mnt; if((mnt = getmount("adm")) == nil){ fprint(fd, "load users: missing 'adm'\n"); return; } if(waserror()){ fprint(fd, "load users: %s\n", errmsg()); clunkmount(mnt); return; } loadusers(fd, mnt->root); fprint(fd, "refreshed users\n"); clunkmount(mnt); } static void showbstate(int fd, char**, int) { char *p, fbuf[8]; Blk *b; for(b = blkbuf; b != blkbuf+fs->cmax; b++){ p = fbuf; if(b->flag & Bdirty) *p++ = 'd'; if(b->flag & Bfinal) *p++ = 'f'; if(b->flag & Bfreed) *p++ = 'F'; if(b->flag & Bcached) *p++ = 'c'; if(b->flag & Bqueued) *p++ = 'q'; if(b->flag & Blimbo) *p++ = 'L'; *p = 0; fprint(fd, "blk %#p type %d flag %s bp %B ref %ld alloc %#p queued %#p, hold %#p drop %#p cached %#p\n", b, b->type, fbuf, b->bp, b->ref, b->alloced, b->queued, b->lasthold, b->lastdrop, b->cached); } } static void showusers(int fd, char**, int) { User *u, *v; int i, j; char *sep; rlock(&fs->userlk); for(i = 0; i < fs->nusers; i++){ u = &fs->users[i]; fprint(fd, "%d:%s:", u->id, u->name); if((v = uid2user(u->lead)) == nil) fprint(fd, "???:"); else fprint(fd, "%s:", v->name); sep = ""; for(j = 0; j < u->nmemb; j++){ if((v = uid2user(u->memb[j])) == nil) fprint(fd, "%s???", sep); else fprint(fd, "%s%s", sep, v->name); sep = ","; } fprint(fd, "\n"); } runlock(&fs->userlk); } static void showdf(int fd, char**, int) { char *units[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", nil}; vlong size, used, free; double hsize, hused, hfree; double pct; Arena *a; int i, us, uu, uf; size = 0; used = 0; for(i = 0; i < fs->narena; i++){ a = &fs->arenas[i]; qlock(a); size += a->size; used += a->used; qunlock(a); fprint(fd, "arena %d: %llx/%llx (%.2f%%)\n", i, a->used, a->size, 100*(double)a->used/(double)a->size); } free = size - used; hsize = size; hused = used; hfree = free; for(us = 0; us < nelem(units)-1 && hsize >= 500 ; us++) hsize /= 1024; for(uu = 0; uu < nelem(units)-1 && hused >= 500 ; uu++) hused /= 1024; for(uf = 0; uf < nelem(units)-1 && hfree >= 500 ; uf++) hfree /= 1024; pct = 100.0*(double)used/(double)size; fprint(fd, "fill:\t%.2f%%\n", pct); fprint(fd, "used:\t%lld (%.2f %s)\n", used, hused, units[uu]); fprint(fd, "size:\t%lld (%.2f %s)\n", size, hsize, units[us]); fprint(fd, "free:\t%lld (%.2f %s)\n", free, hfree, units[uf]); } void showfid(int fd, char**, int) { int i; Fid *f; Conn *c; for(c = fs->conns; c != nil; c = c->next){ fprint(fd, "-- conn %p: fids --\n", c); for(i = 0; i < Nfidtab; i++){ lock(&c->fidtablk[i]); for(f = c->fidtab[i]; f != nil; f = f->next){ rlock(f->dent); fprint(fd, "\tfid[%d] from %#zx: %d [refs=%ld, k=%K, qid=%Q m=%d, dmode:%d duid: %d, dgid: %d]\n", i, getmalloctag(f), f->fid, f->dent->ref, &f->dent->Key, f->dent->qid, f->mode, f->dmode, f->duid, f->dgid); runlock(f->dent); } unlock(&c->fidtablk[i]); } } } void showtree(int fd, char **ap, int na) { char *name; Tree *t; Blk *b; int h; name = "main"; memset(&t, 0, sizeof(t)); if(na == 1) name = ap[0]; if(strcmp(name, "snap") == 0) t = &fs->snap; else if((t = opensnap(name, nil)) == nil){ fprint(fd, "open %s: %r\n", name); return; } b = getroot(t, &h); fprint(fd, "=== [%s] %B @%d\n", name, t->bp, t->ht); showblk(fd, b, "contents", 1); dropblk(b); if(t != &fs->snap) closesnap(t); } static void permflip(int fd, char **ap, int) { if(strcmp(ap[0], "on") == 0) permissive = 1; else if(strcmp(ap[0], "off") == 0) permissive = 0; else fprint(2, "unknown permissive %s\n", ap[0]); fprint(fd, "permissive: %d → %d\n", !permissive, permissive); } static void savetrace(int fd, char **ap, int na) { Biobuf *bfd; Trace *t; int i; if(na == 0) bfd = Bfdopen(dup(fd, -1), OWRITE); else bfd = Bopen(ap[0], OWRITE); if(bfd == nil){ fprint(fd, "error opening output"); return; } for(i = 0; i < fs->ntrace; i++){ t = &fs->trace[(fs->traceidx + i) % fs->ntrace]; if(t->msg[0] == 0) continue; Bprint(bfd, "[%d@%d] %s", t->tid, t->qgen, t->msg); if(t->bp.addr != -1) Bprint(bfd, " %B", t->bp); if(t->v0 != -1) Bprint(bfd, " %llx", t->v0); if(t->v1 != -1) Bprint(bfd, " %llx", t->v1); Bprint(bfd, "\n"); } Bterm(bfd); fprint(fd, "saved\n"); } static void showfree(int fd, char **, int) { Arange *r; Arena *a; int i; for(i = 0; i < fs->narena; i++){ a = &fs->arenas[i]; qlock(a); fprint(fd, "arena %d %llx+%llx{\n", i, a->h0->bp.addr, a->size); for(r = (Arange*)avlmin(a->free); r != nil; r = (Arange*)avlnext(r)) fprint(fd, "\t%llx..%llx (%llx)\n", r->off, r->off+r->len, r->len); fprint(fd, "}\n"); qunlock(a); } } static void unreserve(int fd, char **ap, int) { if(strcmp(ap[0], "on") == 0) usereserve = 0; else if(strcmp(ap[0], "off") == 0) usereserve = 1; else fprint(2, "unknown reserve %s\n", ap[0]); fprint(fd, "reserve: %d → %d\n", !permissive, permissive); } static void help(int fd, char**, int) { char *msg = "help -- show this help\n" "check -- check for consistency\n" "df -- show disk usage\n" "halt -- stop all writers, sync, and go read-only\n" "permit [on|off] -- switch to/from permissive mode\n" "reserve [on|off] -- enable block reserves\n" "snap -[Smdl] [old [new]] -- manage snapshots\n" "sync -- flush all pending writes to disk\n" "users -- reload user table from adm snapshot\n" "save trace [name] -- save a trace of recent activity\n" "show -- debug dumps\n" " tree [name]\n" " fid\n" " users\n"; fprint(fd, "%s", msg); } Cmd cmdtab[] = { /* admin */ {.name="check", .sub=nil, .minarg=0, .maxarg=0, .fn=fsckfs, .epoch=1}, {.name="df", .sub=nil, .minarg=0, .maxarg=0, .fn=showdf}, {.name="halt", .sub=nil, .minarg=0, .maxarg=0, .fn=haltfs}, {.name="help", .sub=nil, .minarg=0, .maxarg=0, .fn=help}, {.name="permit", .sub=nil, .minarg=1, .maxarg=1, .fn=permflip}, {.name="snap", .sub=nil, .minarg=1, .maxarg=3, .fn=snapfs}, {.name="sync", .sub=nil, .minarg=0, .maxarg=0, .fn=syncfs}, {.name="reserve", .sub=nil, .minarg=0, .maxarg=1, .fn=unreserve}, {.name="users", .sub=nil, .minarg=0, .maxarg=1, .fn=refreshusers}, /* debugging */ {.name="show", .sub="fid", .minarg=0, .maxarg=0, .fn=showfid}, {.name="show", .sub="tree", .minarg=0, .maxarg=1, .fn=showtree, .epoch=1}, {.name="show", .sub="users", .minarg=0, .maxarg=0, .fn=showusers}, {.name="show", .sub="bstate", .minarg=0, .maxarg=0, .fn=showbstate, .epoch=1}, {.name="show", .sub="free", .minarg=0, .maxarg=0, .fn=showfree}, {.name="debug", .sub=nil, .minarg=0, .maxarg=1, .fn=setdbg}, {.name="save", .sub="trace", .minarg=0, .maxarg=1, .fn=savetrace}, {.name=nil, .sub=nil}, }; void runcons(int tid, void *pfd) { char buf[256], *f[4], **ap; int i, n, nf, na, fd; Cmd *c; fd = (uintptr)pfd; while(1){ fprint(fd, "gefs# "); if((n = read(fd, buf, sizeof(buf)-1)) == -1) break; buf[n] = 0; nf = tokenize(buf, f, nelem(f)); if(nf == 0 || strlen(f[0]) == 0) continue; for(c = cmdtab; c->name != nil; c++){ ap = f; na = nf; if(strcmp(c->name, *ap) != 0) continue; ap++; na--; if(c->sub != nil){ if(na == 0 || strcmp(c->sub, *ap) != 0) continue; ap++; na--; } if(na < c->minarg || na > c->maxarg) continue; if(c->epoch) epochstart(tid); if(!waserror()){ c->fn(fd, ap, na); poperror(); }else fprint(fd, "%s: %s\n", f[0], errmsg()); if(c->epoch) epochend(tid); break; } if(c->name == nil){ fprint(fd, "unknown command '%s", f[0]); for(i = 1; i < nf; i++) fprint(fd, " %s", f[i]); fprint(fd, "'\n"); } } }