bool reallocateWithCopy(OldAllocator &oldAllocator, NewAllocator &newAllocator, block &b, size_t n) { auto newBlock = newAllocator.allocate(n); if (!newBlock) { return false; } blockCopy(b, newBlock); oldAllocator.deallocate(b); b = newBlock; return true; }
void Blocks::build(bool block[], int round) { int i = 0, j = 0; bool * copy; ////////////////////// if (round < size) { for (i = 0; i < size; i++) { for (j = 0; j + i < size && j + i <= round; j++) { if (cellCheck(block, i, j)) { copy = blockCopy(block); copy[convert(i, j)] = one; build(copy, round + 1); } } } } else { add(block); } }
static int bumpEpoch(Fs *fs, int doarchive) { uint8_t oscore[VtScoreSize]; uint32_t oldaddr; Block *b, *bs; Entry e; Source *r; Super super; /* * Duplicate the root block. * * As a hint to flchk, the garbage collector, * and any (human) debuggers, store a pointer * to the old root block in entry 1 of the new root block. */ r = fs->source; b = cacheGlobal(fs->cache, r->score, BtDir, RootTag, OReadOnly); if(b == nil) return 0; memset(&e, 0, sizeof e); e.flags = VtEntryActive | VtEntryLocal | VtEntryDir; memmove(e.score, b->score, VtScoreSize); e.tag = RootTag; e.snap = b->l.epoch; b = blockCopy(b, RootTag, fs->ehi+1, fs->elo); if(b == nil){ fprint(2, "%s: bumpEpoch: blockCopy: %R\n", argv0); return 0; } if(0) fprint(2, "%s: snapshot root from %d to %d\n", argv0, oldaddr, b->addr); entryPack(&e, b->data, 1); blockDirty(b); /* * Update the superblock with the new root and epoch. */ if((bs = superGet(fs->cache, &super)) == nil) return 0; fs->ehi++; memmove(r->score, b->score, VtScoreSize); r->epoch = fs->ehi; super.epochHigh = fs->ehi; oldaddr = super.active; super.active = b->addr; if(doarchive) super.next = oldaddr; /* * Record that the new super.active can't get written out until * the new b gets written out. Until then, use the old value. */ localToGlobal(oldaddr, oscore); blockDependency(bs, b, 0, oscore, nil); blockPut(b); /* * We force the super block to disk so that super.epochHigh gets updated. * Otherwise, if we crash and come back, we might incorrectly treat as active * some of the blocks that making up the snapshot we just created. * Basically every block in the active file system and all the blocks in * the recently-created snapshot depend on the super block now. * Rather than record all those dependencies, we just force the block to disk. * * Note that blockWrite might actually (will probably) send a slightly outdated * super.active to disk. It will be the address of the most recent root that has * gone to disk. */ superWrite(bs, &super, 1); blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0); blockPut(bs); return 1; }
Fs * fsOpen(char *file, VtSession *z, int32_t ncache, int mode) { int fd, m; uint8_t oscore[VtScoreSize]; Block *b, *bs; Disk *disk; Fs *fs; Super super; switch(mode){ default: vtSetError(EBadMode); return nil; case OReadOnly: m = OREAD; break; case OReadWrite: m = ORDWR; break; } fd = open(file, m); if(fd < 0){ vtSetError("open %s: %r", file); return nil; } bwatchInit(); disk = diskAlloc(fd); if(disk == nil){ vtSetError("diskAlloc: %R"); close(fd); return nil; } fs = vtMemAllocZ(sizeof(Fs)); fs->mode = mode; fs->name = vtStrDup(file); fs->blockSize = diskBlockSize(disk); fs->elk = vtLockAlloc(); fs->cache = cacheAlloc(disk, z, ncache, mode); if(mode == OReadWrite && z) fs->arch = archInit(fs->cache, disk, fs, z); fs->z = z; b = cacheLocal(fs->cache, PartSuper, 0, mode); if(b == nil) goto Err; if(!superUnpack(&super, b->data)){ blockPut(b); vtSetError("bad super block"); goto Err; } blockPut(b); fs->ehi = super.epochHigh; fs->elo = super.epochLow; //fprint(2, "%s: fs->ehi %d fs->elo %d active=%d\n", argv0, fs->ehi, fs->elo, super.active); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ /* * Perhaps it failed because the block is copy-on-write. * Do the copy and try again. */ if(mode == OReadOnly || strcmp(vtGetError(), EBadRoot) != 0) goto Err; b = cacheLocalData(fs->cache, super.active, BtDir, RootTag, OReadWrite, 0); if(b == nil){ vtSetError("cacheLocalData: %R"); goto Err; } if(b->l.epoch == fs->ehi){ blockPut(b); vtSetError("bad root source block"); goto Err; } b = blockCopy(b, RootTag, fs->ehi, fs->elo); if(b == nil) goto Err; localToGlobal(super.active, oscore); super.active = b->addr; bs = cacheLocal(fs->cache, PartSuper, 0, OReadWrite); if(bs == nil){ blockPut(b); vtSetError("cacheLocal: %R"); goto Err; } superPack(&super, bs->data); blockDependency(bs, b, 0, oscore, nil); blockPut(b); blockDirty(bs); blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0); blockPut(bs); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ vtSetError("sourceRoot: %R"); goto Err; } } //fprint(2, "%s: got fs source\n", argv0); vtRLock(fs->elk); fs->file = fileRoot(fs->source); fs->source->file = fs->file; /* point back */ vtRUnlock(fs->elk); if(fs->file == nil){ vtSetError("fileRoot: %R"); goto Err; } //fprint(2, "%s: got file root\n", argv0); if(mode == OReadWrite){ fs->metaFlush = periodicAlloc(fsMetaFlush, fs, 1000); fs->snap = snapInit(fs); } return fs; Err: fprint(2, "%s: fsOpen error\n", argv0); fsClose(fs); return nil; }
static Block * blockWalk(Block *p, int index, int mode, Fs *fs, Entry *e) { Block *b; Cache *c; uint32_t addr; int type; uint8_t oscore[VtScoreSize], score[VtScoreSize]; Entry oe; c = fs->cache; if((p->l.type & BtLevelMask) == 0) { assert(p->l.type == BtDir); type = entryType(e); b = cacheGlobal(c, e->score, type, e->tag, mode); } else { type = p->l.type - 1; b = cacheGlobal(c, p->data + index*VtScoreSize, type, e->tag, mode); } if(b) b->pc = getcallerpc(&p); if(b == nil || mode == OReadOnly) return b; if(p->l.epoch != fs->ehi) { fprint(2, "blockWalk: parent not writable\n"); abort(); } if(b->l.epoch == fs->ehi) return b; oe = *e; /* * Copy on write. */ if(e->tag == 0) { assert(p->l.type == BtDir); e->tag = tagGen(); e->flags |= VtEntryLocal; } addr = b->addr; b = blockCopy(b, e->tag, fs->ehi, fs->elo); if(b == nil) return nil; b->pc = getcallerpc(&p); assert(b->l.epoch == fs->ehi); blockDirty(b); memmove(score, b->score, VtScoreSize); if(p->l.type == BtDir) { memmove(e->score, b->score, VtScoreSize); entryPack(e, p->data, index); blockDependency(p, b, index, nil, &oe); } else { memmove(oscore, p->data+index*VtScoreSize, VtScoreSize); memmove(p->data+index*VtScoreSize, b->score, VtScoreSize); blockDependency(p, b, index, oscore, nil); } blockDirty(p); if(addr != NilBlock) blockRemoveLink(p, addr, type, e->tag, 0); return b; }