static uvlong gbit64(void *a) { uchar *i; i = a; return (uvlong)gbit32(i+4)<<32 | gbit32(i); }
static void freedata(XDBlock *d) { int i; u32int paddr; uchar *ba, *pa; XDBlock *f; //print("free %ud size %ud\n", d->db.addr, d->m); //print("slots before:\n"); for(i=LogMindat; i<=d->s->lgpagesz; i++) print("%d %ud\n", 1<<i, d->s->free[i] ? d->s->free[i]->addr : 0); i = dblog2(d->m); assert(LogMindat <= i && i <= d->s->lgpagesz); d->db.n = ~(u32int)0; branddata(d); //print("free %p\n", d->pa); //print("%.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", // d->pa[0], d->pa[1], d->pa[2], d->pa[3], // d->pa[4], d->pa[5], d->pa[6], d->pa[7]); for(; i < d->s->lgpagesz; i++){ /* try to merge with buddy */ paddr = d->db.addr&~(2*d->m-1); if(paddr == d->db.addr){ pa = d->pa; ba = pa+d->m; }else{ pa = d->pa - d->m; ba = pa; } if(gbit32(ba+4) != ~(u32int)0 || gbit32(ba) != d->m) break; if(unfreedata(d->s, paddr+(ba-pa), i) < 0) break; DBG print("merged %ud and %lud in slot %d\n", d->db.addr, paddr+(ba-pa), i); d->db.addr = paddr; assert(pa == d->p->a+paddr-d->p->addr); d->pa = pa; d->db.a = d->pa+HdrSize; d->m *= 2; } branddata(d); f = d->s->free[i]; pbit32((uchar*)d->db.a+4, 0); if(f){ pbit32(d->db.a, f->db.addr); pbit32((uchar*)f->db.a+4, d->db.addr); ((Dpage*)f->p)->flags |= DDirty; }else pbit32(d->db.a, 0); DBG print("added %ud to slot %d next %ud (%ud)\n", d->db.addr, i, f ? f->db.addr: 0, gbit32(d->db.a)); d->next = f; d->s->free[i] = d; //print("slots after:\n"); for(i=LogMindat; i<=d->s->lgpagesz; i++) print("%d %ud\n", 1<<i, d->s->free[i] ? d->s->free[i]->addr : 0); }
/* * * * * * utility * * * * * */ static int Bgbit32(Biobuf *b, u32int *p) { uchar tmp[4]; if(Bread(b, tmp, 4) != 4) return -1; *p = gbit32(tmp); return 0; }
/* * * * * * logging * * * * * */ static int applylog(XDStore *ds) { int np; uchar *a, *buf; u32int addr; Biobuf *b; Dpage *p; buf = malloc(ds->ds.pagesize); if(buf == nil) return -1; b = malloc(sizeof(Biobuf)); if(b == nil) goto Error; if(seek(ds->logfd, 0, 0) != 0){ Error: free(buf); free(b); return -1; } Binit(b, ds->logfd, OREAD); if(Bgbit32(b, &addr) < 0) goto Error; if(addr != gbit32((uchar*)"log\n")){ werrstr("malformed log"); goto Error; } np = 0; for(;;){ if(Bgbit32(b, &addr) < 0) goto Error; if(addr == ~(u32int)0) break; DBG print("apply log page %ud\n", addr); p = findpage(ds, addr); if(p) a = p->a; else a = buf; if(Bread(b, a, ds->ds.pagesize) != ds->ds.pagesize) goto Error; if(pwrite(ds->fd, a, ds->ds.pagesize, addr) != ds->ds.pagesize) { abort(); goto Error; } np++; } fprint(2, "applied changes to %d pages\n", np); free(b); free(buf); return 0 && fsync(ds->fd); }
static XDBlock* loaddata(XDStore *s, u32int addr) { XDBlock *d; Dpage *p; p = loadpage(s, addr&~(s->ds.pagesize-1)); if(p == nil) return nil; d = mkdata(s, p, p->a+(addr&(s->ds.pagesize-1)), 0); if(d == nil){ p->nref--; return nil; } //print("load %ud p->addr %ud off %ud pa %p ", // addr, p->addr, (addr&(s->ds.pagesize-1)), p->a); //print("%.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", // d->pa[0], d->pa[1], d->pa[2], d->pa[3], // d->pa[4], d->pa[5], d->pa[6], d->pa[7]); d->m = gbit32(d->pa); d->db.n = gbit32(d->pa+4); return d; }
static XDBlock* popfree(XDStore *s, int slot) { u32int na; XDBlock *d, *nd; d = s->free[slot]; if(d == nil){ werrstr("empty slot %d", slot); return nil; } if(d->db.n != ~(u32int)0){ fprint(2, "slot %d allocated page on the free list (oops)\n", slot); abort(); } if(d->p == nil){ d->p = loadpage(s, d->db.addr&~(s->ds.pagesize-1)); if(d->p == nil){ werrstr("loadpage %ud: %r", d->db.addr&~(s->ds.pagesize-1)); return nil; } d->pa = d->p->a + (d->db.addr&(s->ds.pagesize-1)); d->db.a = d->pa+HdrSize; } if(d->next){ DBG print("used slot %d got %ud next %ud\n", slot, d->db.addr, d->next->db.addr); s->free[slot] = d->next; return d; } na = gbit32(d->db.a); if(na == 0){ DBG print("used slot %d got %ud next 0\n", slot, d->db.addr); s->free[slot] = nil; return d; } nd = loaddata(s, na); if(nd == nil){ /* if we return d we'll leak the rest of the free chain */ DBG print("used slot %d got %ud next %ud bad: %r\n", slot, d->db.addr, na); werrstr("loaddata %ud: %r", na); return nil; } pbit32((uchar*)nd->db.a+4, 0); ((Dpage*)nd->p)->flags |= DDirty; s->free[slot] = nd; DBG print("used slot %d got %ud next %ud (loaded)\n", slot, d->db.addr, nd->db.addr); return d; }
static int identify(Ctlr *c, ushort *id) { int i; uchar oserial[21]; uvlong osectors, s; osectors = c->sectors; memmove(oserial, c->serial, sizeof c->serial); c->feat &= ~(Dllba|Dpower|Dsmart|Dnop); i = gbit16(id+83) | gbit16(id+86); if(i & (1<<10)){ c->feat |= Dllba; s = gbit64(id+100); }else s = gbit32(id+60); i = gbit16(id+83); if((i>>14) == 1) { if(i & (1<<3)) c->feat |= Dpower; i = gbit16(id+82); if(i & 1) c->feat |= Dsmart; if(i & (1<<14)) c->feat |= Dnop; } aoeidmove(c->serial, id+10, 20); aoeidmove(c->firmware, id+23, 8); aoeidmove(c->model, id+27, 40); if((osectors == 0 || osectors != s) && memcmp(oserial, c->serial, sizeof oserial) != 0){ c->sectors = s; c->mediachange = 1; c->vers++; } return 0; }
if(nd == nil){ /* if we return d we'll leak the rest of the free chain */ DBG print("used slot %d got %ud next %ud bad: %r\n", slot, d->db.addr, na); werrstr("loaddata %ud: %r", na); return nil; } pbit32((uchar*)nd->db.a+4, 0); ((Dpage*)nd->p)->flags |= DDirty; s->free[slot] = nd; DBG print("used slot %d got %ud next %ud (loaded)\n", slot, d->db.addr, nd->db.addr); return d; } static void unloaddata(XDBlock *d) { DBG if(d->db.addr == 28288) print("\t%ud -> %ud, %ud\n", d->db.addr, gbit32(d->db.a), gbit32((uchar*)d->db.a+4)); if(d->db.flags&DDirty) d->p->flags |= DDirty; d->p->nref--; d->p = (Dpage*)0xBBBBBBBB; //print("unloaddata %p\n", d->pa); //print("%.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", // d->pa[0], d->pa[1], d->pa[2], d->pa[3], // d->pa[4], d->pa[5], d->pa[6], d->pa[7]); free(d); } static int unfreedata(XDStore *s, u32int addr, int slot) { u32int naddr, paddr;