📄 kern_persist.cxx
字号:
return pPage; } FrameInfo fi(oid); if (fi.cd == 0) { fatal("pg oid= 0x%08x%08x. Should sleep on mountwait queue here\n", (uint32_t)(oid>>32), (uint32_t) oid); return 0; } assert (InvocationCommitted == false); DEBUG(req) dprintf(stop, "Page lookup failed\n"); CoreDirent* cde = Checkpoint::FindObject(oid, ObType::PtDataPage, Checkpoint::current); if (cde == 0) { DEBUG(req) dprintf(true, "Wrong tag type\n"); return 0; } if (cde != CkNIL) { if (useCount && cde->count != count) return 0; return Checkpoint::LoadCurrentPage(cde); } DEBUG(req) dprintf(stop, "Loading home location of page\n"); ObjectHeader *pPot = GetTagPot(fi); assert (pPot); PagePot *pp = (PagePot *) ObjectCache::ObHdrToPage(pPot); DEBUG(req) dprintf(stop, "rel tag frame %d gives tag %d\n", fi.relTagFrame, pp->type[fi.tagEntry]); switch (pp->type[fi.tagEntry]) { case FRM_TYPE_ZDPAGE: { ObjectHeader* pPage = ObjectCache::GrabPageFrame(); uint8_t * pbuf = (uint8_t *) ObjectCache::ObHdrToPage(pPage); bzero( (void*) pbuf, EROS_PAGE_SIZE); pPage->ob.oid = oid; pPage->ob.allocCount = pp->count[fi.tagEntry]; pPage->SetFlags(OFLG_CURRENT|OFLG_DISKCAPS);#ifdef OFLG_PIN assert (pPage->GetFlags(OFLG_PIN) == 0);#endif pPage->ClearFlags(OFLG_CKPT|OFLG_DIRTY|OFLG_REDIRTY|OFLG_IO);#ifdef DBG_CLEAN printf("Object ty %d oid=0x%08x%08x loaded clean\n", pPage->obType, (uint32_t) (pPage->oid >> 32), (uint32_t) pPage->oid);#endif pPage->ob.ioCount = 0; pPage->obType = ObType::PtDataPage; pPage->products = 0;#ifdef OPTION_OB_MOD_CHECK pPage->ob.check = pPage->CalcCheck();#endif pPage->ResetKeyRing(); pPage->Intern();#ifndef NDEBUG ObjectHeader *npPage = ObjectHeader::Lookup(ObType::PtDataPage,oid); assert(npPage == pPage);#endif return pPage; } case FRM_TYPE_DPAGE: ReadPageFrame(fi.cd, fi.relObFrame, ObType::PtDataPage, fi.obFrameOid, pp->count[fi.tagEntry]); assert(false); break; default: return 0; } /* If all of the above fail, page is for an out of range OID. */ printf("Out of range page OID "); print(oid); fatal("\n"); return 0;}/* Wrapper for GetCkFrame used in checkpoint load logic. Catches the * yield thrown by the checkpoint logic, issues a DirectedYield(), and * retries on wakeup. */ObjectHeader *Persist::KernGetCkFrame(lid_t lid){#ifndef NDEBUG extern uint32_t TrapDepth; assert ( Thread::Current()->IsKernel() && TrapDepth == 0);#endif Process *p = Thread::CurContext(); /* hand-construct a misc logpage key in slot 1: */ Key& k = p->keyReg[1]; k.NH_VoidKey(); /* restore slot to well-known state */ k.SetType(KT_LogFrame); k.nk.value[0] = lid; k.nk.value[1] = 0; k.nk.value[2] = 0; Message msg; bzero(&msg, sizeof(msg)); msg.invType = IT_Call; msg.snd_invKey = 1; msg.snd_code = OC_KeyType; msg.snd_w1 = 0; msg.snd_w2 = 0; msg.snd_w3 = 0; msg.rcv_key0 = KR_VOID; msg.rcv_key1 = KR_VOID; msg.rcv_key2 = KR_VOID; msg.rcv_key3 = KR_VOID; msg.snd_key0 = KR_VOID; msg.snd_key1 = KR_VOID; msg.snd_key2 = KR_VOID; msg.snd_key3 = KR_VOID; CALL(&msg); ObjectHeader * pLogPageHdr = ObjectHeader::Lookup(ObType::PtLogPage, lid); assert(pLogPageHdr); DEBUG(req) printf("GetCkPage: pLogPageHdr = 0x%08x\n", pLogPageHdr); assert (pLogPageHdr); return pLogPageHdr;}ObjectHeader *Persist::ZeroCkFrame(lid_t lid){ ObjectHeader *pObj = ObjectCache::GrabPageFrame(); bzero( (void*) ObjectCache::ObHdrToPage(pObj), EROS_PAGE_SIZE ); pObj->ob.oid = lid; pObj->ob.allocCount = 0; pObj->SetFlags(OFLG_CURRENT|OFLG_DISKCAPS);#ifdef OFLG_PIN assert (pObj->GetFlags(OFLG_PIN) == 0);#endif pObj->ClearFlags(OFLG_CKPT|OFLG_IO); pObj->SetFlags(OFLG_DIRTY|OFLG_REDIRTY);#ifdef DBG_CLEAN printf("Object ty %d oid=0x%08x%08x loaded clean\n", pObj->obType, (uint32_t) (pObj->oid >> 32), (uint32_t) pObj->oid);#endif pObj->ob.ioCount = 0; pObj->obType = ObType::PtLogPage; pObj->products = 0;#ifdef OPTION_OB_MOD_CHECK pObj->ob.check = pObj->CalcCheck();#endif pObj->ResetKeyRing(); pObj->Intern(); return pObj;}ObjectHeader *Persist::GetCkFrame(lid_t lid){ lid = EROS_FRAME_FROM_OID(lid); DEBUG(req) printf("GetCkPage: lid = 0x%x\n", lid); CoreDivision *pcd = FindDivision(dt_Log, lid); if (!pcd) return 0; ObjectHeader * pLogPageHdr = ObjectHeader::Lookup(ObType::PtLogPage, lid); DEBUG(req) printf("GetCkPage: pLogPageHdr = 0x%08x\n", pLogPageHdr); if (pLogPageHdr) return pLogPageHdr; assert (InvocationCommitted == false); DEBUG(req) printf("GetCkPage: Reading page...\n"); /* If an I/O is already pending, wait for it. If there are live * objects in the frame, fetch it. Otherwise, allocate a new zero * frame. */ DuplexedIO *pDio = DuplexedIO::FindPendingIO(lid, ObType::PtLogPage); if (pDio) { DEBUG(req) printf("Thread 0x%08x Sleeps because I/O is " "already in progress\n"); DEBUG(req) dprintf(true, "DIO [0x%08x]: status %d nReq %d pObHdr=0x%08x\n", pDio, pDio->status, pDio->nRequest, pDio->pObHdr); Thread::Current()->SleepOn(pDio->stallQ); Thread::Current()->Yield(); } if (Checkpoint::FrameIsEmpty(lid)) { ObjectHeader *pObj = ZeroCkFrame(lid); assert ( PTE::ObIsNotWritable(pObj) ); pObj->ClearFlags(OFLG_DIRTY|OFLG_REDIRTY); return pObj; } else { ReadLogFrame(lid); return 0; /* suppress GCC warning */ }}/* Return true if the passed division is a duplex of 'this', including * if it *is* this. */boolCoreDivision::IsDuplexOf(const CoreDivision *cd){ DEBUG(div) if (cd->type != dt_Unused) dprintf(true, "Check cd %d (type %s) start=0x%x, end=0x%x\n", cd - coreDivTbl, div_TypeName(cd->type), (uint32_t) cd->startOid, (uint32_t) cd->endOid); if (cd->type != type) return false; if ( cd->startOid != startOid ) return false; return true;}/* Write a page to the first sector of all object ranges... */voidPersist::WriteRangeHeaders(struct ObjectHeader *pObj){ Request::Require(KTUNE_NCOREDIV); /* This must not be done lazily: */ DuplexedIO *dio = DuplexedIO::Grab(0, IoCmd::Write); DEBUG(io) dprintf(true, "Setting up request (dt=ALL)...\n"); dio->pObHdr = pObj; dio->completionCallBack = 0; pObj->SetFlags(OFLG_IO); pObj->ClearFlags(OFLG_REDIRTY); pObj->ob.ioCount = 1; dio->ioaddr = ObjectCache::ObHdrToPage(pObj); for (uint32_t i = 0; i < KTUNE_NCOREDIV; i++) { CoreDivision *cd = &coreDivTbl[i]; if (cd->type != dt_Object) continue; /* Found an object range. Queue the I/O on the device: */ Partition *part = cd->partition; assert(part); Request *req = new Request(part->unit, IoCmd::Write, cd->start, EROS_PAGE_SECTORS); assert(req); dio->AddRequest(req); assert(req); DEBUG(io) dprintf(true, "Insert request on %s%d-%d\n", part->ctrlr->name, part->unit, part->ndx); part->InsertRequest(req); }#if 0 /* There is never any need to wait for this I/O. */ if (synchronous) Thread::Current()->SleepOn(dio.stallQ);#endif#if 0 dprintf(true, "Write dt=%s DIO 0x%08x pOb 0x%08x data 0x%08x ready to run\n", pcd->TypeName(), &dio, dio.pObHdr, dio.ioaddr);#endif dio->Release(); assert(Thread::Current()); Thread::Current()->pageWriteCount++;#if 0 if (synchronous) Thread::Current()->Yield();#endif}/* Write a page to a core division and all of it's duplexes, without * regard to the type of the page -- this is the bottom level write * implementation. */voidPersist::WritePageTo(struct ObjectHeader *pObj, CoreDivision *pcd, uint32_t atSector, bool synchronous, void (*callBack)(DuplexedIO*)){ assert (pObj); assert (pcd); assert (pObj->obType > ObType::NtLAST_NODE_TYPE);#if defined(OPTION_OB_MOD_CHECK) && 0 if (pObj->IsDirty()) pObj->check = pObj->CalcCheck();#endif if (pObj->GetFlags(OFLG_IO)) { Thread::Current()->SleepOn(pObj->ObjectSleepQueue()); Thread::Current()->Yield(); } assert ( PTE::ObIsNotWritable(pObj) ); Request::Require(KTUNE_MAXDUPLEX); DuplexedIO *dio = DuplexedIO::Grab(pObj->ob.oid, IoCmd::Write); DEBUG(io) dprintf(true, "Setting up request (dt=%s)...\n", div_TypeName(pcd->type)); dio->pObHdr = pObj; dio->completionCallBack = callBack; pObj->SetFlags(OFLG_IO); pObj->ClearFlags(OFLG_REDIRTY); pObj->ob.ioCount = 1; dio->ioaddr = ObjectCache::ObHdrToPage(pObj); for (uint32_t i = 0; i < KTUNE_NCOREDIV; i++) { CoreDivision *cd = &coreDivTbl[i]; if (! cd->IsDuplexOf(pcd)) continue; /* Found a replicate of the right range. Queue the I/O on the * device: */ Partition *part = cd->partition; assert(part); Request *req = new Request(part->unit, IoCmd::Write, atSector + cd->start, EROS_PAGE_SECTORS); assert(req); dio->AddRequest(req); assert(req); DEBUG(io) dprintf(true, "Insert request on %s%d-%d\n", part->ctrlr->name, part->unit, part->ndx); part->InsertRequest(req); } if (synchronous) Thread::Current()->SleepOn(dio->stallQ);#if 0 dprintf(true, "Write dt=%s DIO 0x%08x pOb 0x%08x data 0x%08x ready to run\n", pcd->TypeName(), dio, dio->pObHdr, dio->ioaddr);#endif dio->Release(); assert(Thread::Current()); Thread::Current()->pageWriteCount++; if (synchronous) Thread::Current()->Yield();}voidPersist::WritePageToHome(struct ObjectHeader *pObj, OID oid){ assert (pObj->obType == ObType::PtLogPage || pObj->obType == ObType::PtDataPage); /* assert(pObj->IsDirty()); */ FrameInfo fi(oid); if (fi.cd == 0) fatal("Writing object to nonexistent range\n"); WritePageTo(pObj, fi.cd, fi.relObFrame * EROS_PAGE_SECTORS);}voidPersist::WritePageToLog(struct ObjectHeader *pObj, lid_t lid, bool synchronous, void (*callBack)(DuplexedIO*)){ assert (pObj->obType == ObType::PtLogPage || pObj->obType == ObType::PtDriverPage); #ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top WritePageToLog()");#endif#ifndef NDEBUG if ( pObj->obType == ObType::PtLogPage && pObj->IsDirty() == false ) dprintf(true, "Object (hdr=0x%08x) is not dirty in WritePageToLog()\n", pObj); assert(pObj->obType == ObType::PtDriverPage || pObj->IsDirty());#endif ObjectHeader * pLogPageHdr = ObjectHeader::Lookup(ObType::PtLogPage, lid); if (pLogPageHdr) { assert (pLogPageHdr != pObj); ObjectCache::ReleasePageFrame(pLogPageHdr); } CoreDivision * pcd = FindDivision(dt_Log, lid); /* Do not deal with dismounted home ranges yet. */ assert (pcd); uint64_t relativeOid = lid - pcd->startOid; uint32_t relativePage = relativeOid / EROS_OBJECTS_PER_FRAME; WritePageTo(pObj, pcd, relativePage * EROS_PAGE_SECTORS, synchronous, callBack);}/* WritePage() is called by the ageing logic to force pages to disk. * To my initial surprise, deciding where to put them is not * difficult: * * LogPage written to the log * UserPage written to the log * NodePot written to home location -- node pots are ONLY * dirtied by the migrator, so their content is safe. * AllocPot written to home location, as with NodePot. * * Rewriting dirty pages back to home locations might seem a bit * tricky, but turns out to be very simple. The page isn't migrated * unless it is current. If it *is* current, the migrator brings it * in to core and then uses Persist::WritePageToHome() to force it to * go out to it's home location. * * In general, the I/O subsystem allows a dirty page to be remodified * if it is in an outbound I/O queue. Note that since it was current, * the user page going to home location CANNOT be dirty. Attempts to * mutate it will therefore generate a fault, at which point we will * notice that this page is the checkpoint version and perform COW. *//* FIX: if page being written is ckpt and dirty, should retag as log frame. */voidPersist::WritePage(struct ObjectHeader *pObj, bool synchronous){ uint32_t relativePage = 0; CoreDivision *cd = 0; assert(pObj->IsDirty()); switch(pObj->obType) { case ObType::PtAllocPot: { /* Going to home location. OID == oid of first covered entry, * so we don't need to round that. We do need to adjust the * offset by the overhead of intervening clusters, if any: */ FrameInfo fi(pObj->ob.oid); if (fi.cd == 0) fatal("Writing object to nonexistent range\n"); relativePage = fi.relTagFrame; cd = fi.cd; break; } case ObType::PtObjectPot: { /* Going to home location. OID == oid of first covered entry, * so we don't need to round that, but the computation of * relative page needs to be scaled by the cluster size: */ FrameInfo fi(pObj->ob.oid); if (fi.cd == 0) fatal("Writing object to nonexistent range\n"); relativePage = fi.relObFrame; cd = fi.cd; break; } case ObType::PtDataPage: { lid_t where = Checkpoint::GetLidForPage(pObj);#if 1 if (where == ZERO_LID) {#ifdef OPTION_OB_MOD_CHECK pObj->ob.check = pObj->CalcCheck(); assert(pObj->ob.check == 0);#endif pObj->ClearFlags(OFLG_IO|OFLG_DIRTY|OFLG_REDIRTY);#ifdef DBG_CLEAN printf("Object ty %d oid=0x%08x%08x written zero\n", pObj->obType, (uint32_t) (pObj->oid >> 32), (uint32_t) pObj->oid);#endif pObj->ObjectSleepQueue().WakeAll(); return; }#endif#if 0 /* FIX: this seems to be causing trouble, and it isn't * necessary. * * * If this is no longer the current version of the page, retag * this object as a copy of the log frame so that the migrator * will be able to find it later if it has not been aged out. * Note that if we fail to get the proper I/O request structure, * this write will recur properly, because StabilizePages() * stabilizes dirty log frames as well. */ if (pObj->flags.current == 0) { assert (pObj->flags.ckpt); pObj->flags.ckpt = 0; pObj->obType = ObType::PtLogPage; pObj->oid = where; pObj->Intern(); }#endif cd = FindDivision(dt_Log, where); relativePage = where - (uint32_t) cd->startOid; relativePage /= EROS_OBJECTS_PER_FRAME; break; } case ObType::PtLogPage: { lid_t where = pObj->ob.oid; cd = FindDivision(dt_Log, where); relativePage = where - (uint32_t) cd->startOid; relativePage /= EROS_OBJECTS_PER_FRAME; break; } default: fatal("Don't know how to write obtype=%d\n", pObj->obType); break; } WritePageTo(pObj, cd, relativePage * EROS_PAGE_SECTORS, synchronous);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -