📄 kern_persist.cxx
字号:
/* * Copyright (C) 1998, 1999, 2001, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <kerninc/kernel.hxx>#include <kerninc/MsgLog.hxx>#include <kerninc/Check.hxx>#include <kerninc/Persist.hxx>#include <arch-kerninc/KernTune.hxx>#include <eros/memory.h>#include <disk/DiskNode.hxx>#include <disk/PagePot.hxx>#include <kerninc/ObjectCache.hxx>#include <kerninc/Thread.hxx>#include <kerninc/Node.hxx>#include <kerninc/util.h>#include <kerninc/Partition.hxx>#include <kerninc/Checkpoint.hxx>#include <kerninc/Persist.hxx>#include <eros/Invoke.h>#include <arch-kerninc/PTE.hxx>#define dbg_io 0x1 /* io requests */#define dbg_div 0x2 /* div tbl */#define dbg_req 0x4 /* requests (high level) */#define dbg_obread 0x8 /* low-level object reads *//* Following should be an OR of some of the above */#define dbg_flags ( 0u )#define DEBUG(x) if (dbg_##x & dbg_flags)#ifndef NDEBUGextern bool InvocationCommitted;#endif/* static to ensure it ends up in BSS: */static CoreDivision coreDivTbl[KTUNE_NCOREDIV];void *CoreDivision::operator new(size_t /* sz */){ int i; for (i = 0; i < KTUNE_NCOREDIV; i++) { CoreDivision& cd = coreDivTbl[i]; if (cd.partition == 0) { cd.partition = (Partition*) 0x1; /* HACK!! corrected in */ /* constructor */ return &cd; } } return 0;}CoreDivision::CoreDivision(Partition* part, const Division& d){ *((Division*)this) = d; partition = part; #if 0 nPages = (end - start) / EROS_PAGE_SECTORS; if (type == dt_Page) nPages = endOid - startOid;#endif}voidPersist::RegisterDivision(Partition *part, const Division& d){ switch(d.type) { case dt_Unused: case dt_Boot: case dt_DivTbl: case dt_Spare: /* These are silently ignored */#if 1 printf("Divsn on %s%d-%d, secs [%d,%d) (%s) skipped\n", part->ctrlr->name, part->unit, part->ndx, d.start, d.end, div_TypeName(d.type) );#endif return; case dt_Kernel: break; } /* FIX: Verify that ranges do not overlap improperly */ bool isDuplex = false; for (uint32_t i = 0; i < KTUNE_NCOREDIV; i++) { if (coreDivTbl[i].type == d.type && coreDivTbl[i].startOid == d.startOid && coreDivTbl[i].endOid == d.endOid) { isDuplex = true; printf("It's a duplex\n"); } } CoreDivision *cd = new CoreDivision(part, d); /* Kernel division is mounted as a page division: */ if (cd->type == dt_Kernel) cd->type = dt_Object; if (cd->type == dt_Log && isDuplex == false) Checkpoint::AttachRange(d.startOid, d.endOid); if (!cd) fatal("Out of core divisions\n"); #if 1 printf("Divsn on %s%d-%d, secs [%d,%d)" " %s [", part->ctrlr->name, part->unit, part->ndx, cd->start, cd->end, (cd->type == dt_Log) ? "lid" : "oid"); print(cd->startOid); printf(","); print(cd->endOid); printf(") (%s)\n", div_TypeName(d.type));#endif return;}#ifdef OPTION_DDBvoidPersist::ddb_DumpDivisions(){ extern void db_printf(const char *, ...); for (int i = 0; i < KTUNE_NCOREDIV; i++) { if (coreDivTbl[i].type != dt_Unused) { CoreDivision* cd = &coreDivTbl[i]; db_printf("Divsn on %s%d-%d, secs [%d,%d)" " oid [", cd->partition->ctrlr->name, cd->partition->unit, cd->partition->ndx, cd->start, cd->end); db_printf("0x%08x%08x", (uint32_t) (cd->startOid >> 32), (uint32_t) cd->startOid); db_printf(","); db_printf("0x%08x%08x", (uint32_t) (cd->endOid >> 32), (uint32_t) cd->endOid); db_printf(") (%s)\n", div_TypeName(cd->type)); } }}#endifvoidPersist::UnregisterDivisions(Partition* part){ int i; for (i = 0; i < KTUNE_NCOREDIV; i++) { if (coreDivTbl[i].type != dt_Unused && coreDivTbl[i].partition == part) delete &coreDivTbl[i]; }}boolPersist::HaveCkptLog(){ int i; for (i = 0; i < KTUNE_NCOREDIV; i++) { if (coreDivTbl[i].type == dt_Log) return true; } return false;}/* In order to proceed, we must reserve an object page frame for the * inbound I/O (which will be grabbed later), we must verify that * there are a sufficiency of Request structures, and we must lay our * hands on the appropriate DuplexedIO structure for the OID we are * trying to load. Having the DuplexedIO structures be keyed by OID * prevents redundant I/O on the same object. Ensuring space to begin * with guarantees that a read will never preclude a write on a * hash-colliding OID, but we may later want to make read and write * DuplexedIO structures independent since the two operations * fundamentally cannot collide. * * If a user thread fails to satisfy any of the conditions, it will * Yield() while having reserved an IO page frame. The Yield code * checks for and takes care of this case, but note that kernel * threads and user threads call CommitIoPageFrame in different places * because kernel threads do not unwind completely. We will * definitely need to reconsider what to do when tasks start * initiating I/O. That issue in and of itself may be a sufficient * reason to retain kernel threads. * * Finally, note that when invoked on log pages, this routine is * handed a LogLoc, not an OID. */voidPersist::ReadPageFrame( CoreDivision *pcd, uint32_t relativePage, ObType::Type obty, OID oid, ObCount count){ DEBUG(io) dprintf(true, "Reserving I/O frame...\n"); /* First make sure the I/O won't block: */ ObjectCache::ReserveIoPageFrame(); DEBUG(io) dprintf(true, "Reserving Requests...\n"); Request::Require(KTUNE_MAXDUPLEX); DEBUG(io) dprintf(true, "Grabbing DIO...\n"); DuplexedIO *dio = DuplexedIO::Grab(oid, IoCmd::Read); ObjectCache::CommitIoPageFrame(); DEBUG(io) dprintf(true, "Setting up request (dt=%s)...\n", div_TypeName(pcd->type)); dio->allocCount = count; dio->obType = obty; dio->isObjectRead = true; /* I/O is free to complete while this loop is still running (happens * mostly with ramdisk), so we need to go to sleep before queueing * any of the requests. Nothing below this point in this function * will sleep, but we MUST avoid preemption until we yield * voluntarily! */ Thread::Current()->SleepOn(dio->stallQ); uint32_t sectorOffset = relativePage * EROS_PAGE_SECTORS; for (uint32_t i = 0; i < KTUNE_NCOREDIV; i++) { CoreDivision *cd = &coreDivTbl[i]; DEBUG(div) if (cd->type != dt_Unused) dprintf(true, "Check cd %d (type %s) start=0x%x, end=0x%x\n", i, div_TypeName(cd->type), (uint32_t) cd->startOid, (uint32_t) cd->endOid); if (cd->type != pcd->type) continue; if ( cd->startOid != pcd->startOid ) 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::Read, sectorOffset + cd->start, EROS_PAGE_SECTORS); 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); } DEBUG(io) dprintf(true, "Post-setup DIO release\n"); dio->Release(); Thread::Current()->Yield(/* true */);}voidPersist::ReadLogFrame(lid_t lid){ assert ((lid % EROS_OBJECTS_PER_FRAME) == 0); CoreDivision * pcd = FindDivision(dt_Log, lid); uint64_t relativeOid = lid - pcd->startOid; uint32_t relativePage = relativeOid / EROS_OBJECTS_PER_FRAME; ReadPageFrame( pcd, relativePage, ObType::PtLogPage, lid, 0 );}FrameInfo::FrameInfo(OID argOid){ oid = argOid; cd = Persist::FindDivision(dt_Object, oid); if (cd == 0) return; assert ((cd->startOid % EROS_OBJECTS_PER_FRAME) == 0); uint64_t relativeOid = (oid - cd->startOid); /* No, some of this calculation is NOT the most straightforward way, * but I am trying to avoid divisions involving 64-bit quantities * where the divisor is not a power of two. Also, GCC seems to be * barfing on some 64 bit x 32 bit multiplies in certain cases. */ obFrameNdx = oid % EROS_OBJECTS_PER_FRAME; obFrameOid = oid - obFrameNdx; relObFrame = relativeOid / EROS_OBJECTS_PER_FRAME; clusterNo = relObFrame / DATA_PAGES_PER_PAGE_CLUSTER; tagEntry = relObFrame % DATA_PAGES_PER_PAGE_CLUSTER; tagFrameOid = relObFrame - tagEntry; tagFrameOid *= EROS_OBJECTS_PER_FRAME; tagFrameOid += cd->startOid; relObFrame += clusterNo; relObFrame++; /* add one for cluster pot */ relObFrame++; /* add one for seq no */ relTagFrame = clusterNo * PAGES_PER_PAGE_CLUSTER; relTagFrame++; /* add one for seq no */#if 0 dprintf(false, " OID=0x%08x%08x frmOid=0x%08x%08x tagOid=0x%08x%08x\n" " relFrm 0x%08x clusNo 0x%08x tagEnt 0x%08x tagFrame 0x%08x\n", (uint32_t) (oid >> 32), (uint32_t) (oid), (uint32_t) (obFrameOid >> 32), (uint32_t) (obFrameOid), (uint32_t) (tagFrameOid >> 32), (uint32_t) (tagFrameOid), relObFrame, clusterNo, tagEntry, relTagFrame);#endif assert( tagEntry < DATA_PAGES_PER_PAGE_CLUSTER ); assert( obFrameNdx < EROS_OBJECTS_PER_FRAME );}CoreDivision*Persist::FindDivision(DivType dt, OID oid){ for (uint32_t i = 0; i < KTUNE_NCOREDIV; i++) { CoreDivision *cd = &coreDivTbl[i]; if (cd->type != dt) continue; OID divOID = cd->startOid; if (divOID > oid || cd->endOid <= oid) continue; return cd; } return 0;}ObjectHeader *Persist::GetObjectPot(FrameInfo& fi){#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top GetObjectPot()");#endif if (fi.cd == 0) fatal("Bad oid 0x%08x%08x to GetObjectPot()\n", (fi.oid >> 32), fi.oid); ObjectHeader *obPotHdr = ObjectHeader::Lookup(ObType::PtObjectPot, fi.obFrameOid); if (obPotHdr) {#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("End GetObjectPot()");#endif return obPotHdr; } /* Must load node pot: */ ReadPageFrame(fi.cd, fi.relObFrame, ObType::PtObjectPot, fi.obFrameOid, 0); assert (false); return 0;}ObjectHeader *Persist::GetTagPot(FrameInfo& fi){#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top GetTagPot()");#endif if (fi.cd == 0) fatal("Bad oid 0x%08x%08x to GetTagPot()\n", (fi.oid >> 32), fi.oid); ObjectHeader *tagPotHdr = ObjectHeader::Lookup(ObType::PtAllocPot, fi.tagFrameOid); if (tagPotHdr) {#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("End GetTagPot()");#endif return tagPotHdr; } /* Must load node pot: */ ReadPageFrame(fi.cd, fi.relTagFrame, ObType::PtAllocPot, fi.tagFrameOid, 0); assert (false); return 0;}Node *Persist::CopyDiskNode(FrameInfo &fi, DiskNode *nodePot){ if (nodePot[fi.obFrameNdx].oid != fi.oid) dprintf(false, "oid=0x%08x%08x, potOid=0x%08x%08x ndOid=0x%08x%08x\n", (uint32_t) (fi.oid >> 32), (uint32_t) fi.oid, (uint32_t) (fi.obFrameOid >> 32), (uint32_t) fi.obFrameOid, (uint32_t) (nodePot[fi.obFrameNdx].oid >> 32), (uint32_t) (nodePot[fi.obFrameNdx].oid) ); assert (nodePot[fi.obFrameNdx].oid == fi.oid); Node *pNode = ObjectCache::GrabNodeFrame(); assert(Thread::Current()->state == Thread::Running); assert(ObjectCache::ValidNodePtr(pNode)); assert (pNode->kr.IsEmpty()); assert (pNode->obType == ObType::NtUnprepared); (*pNode) = nodePot[fi.obFrameNdx];#ifdef OPTION_OB_MOD_CHECK pNode->ob.check = pNode->CalcCheck();#endif pNode->SetFlags(OFLG_CURRENT|OFLG_DISKCAPS);#ifdef OFLG_PIN assert (pNode->GetFlags(OFLG_PIN) == 0);#endif pNode->ClearFlags(OFLG_CKPT|OFLG_DIRTY|OFLG_REDIRTY|OFLG_IO);#ifdef DBG_CLEAN printf("Object ty %d oid=0x%08x%08x loaded clean\n", pNode->obType, (uint32_t) (pNode->oid >> 32), (uint32_t) pNode->oid);#endif pNode->ResetKeyRing(); pNode->Intern(); assert (pNode->Validate()); return pNode;}Node *Persist::GetNode(OID oid, ObCount count, bool useCount){ Node *pNode; pNode = ObjectHeader::LookupNode(oid); if (pNode) {#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("End GetNode()");#endif assertex(pNode, pNode->Validate()); if (useCount && pNode->ob.allocCount != count) return 0; return pNode; } FrameInfo fi(oid); if (fi.cd == 0) { fatal("nd oid= 0x%08x%08x. Should sleep on mountwait queue here\n", (uint32_t)(oid>>32), (uint32_t) oid); return 0; }#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top GetNode()");#endif DEBUG(req) printf("Doing lookup on node 0x%08x%08x\n", (uint32_t) (oid >> 32), (uint32_t) oid); assert (InvocationCommitted == false); DEBUG(req) printf("Loading node from ckpt area\n"); CoreDirent* cde = Checkpoint::FindObject(oid, ObType::NtUnprepared, Checkpoint::current); if (cde == 0) return 0; if (cde != CkNIL) { if (cde->type != FRM_TYPE_NODE && cde->type != FRM_TYPE_ZNODE) return 0; if (useCount && cde->count != count) return 0; return Checkpoint::LoadCurrentNode(cde); } ObjectHeader *pPot = GetTagPot(fi); assert (pPot); PagePot *pp = (PagePot *) ObjectCache::ObHdrToPage(pPot); if (pp->type[fi.tagEntry] != FRM_TYPE_NODE) return 0; DEBUG(req) printf("Loading node from home loc area\n"); ObjectHeader *nodePotHdr = GetObjectPot(fi); assert(nodePotHdr); nodePotHdr->TransLock(); DiskNode* nodePot = (DiskNode*) ObjectCache::ObHdrToPage(nodePotHdr); pNode = CopyDiskNode(fi, nodePot); nodePotHdr->TransUnlock(); if (useCount && pNode->ob.allocCount != count) return 0; assert (pNode->Validate()); return pNode;}ObjectHeader *Persist::GetPage(OID oid, ObCount count, bool useCount){#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top GetPage()");#endif bool stop=false; DEBUG(req) dprintf(stop, "Doing lookup on page oid=0x%08x%08x\n", (uint32_t) (oid >> 32), (uint32_t) oid); ObjectHeader *pPage; pPage = ObjectHeader::Lookup(ObType::PtDataPage, oid); if (pPage) {#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("End GetPage()");#endif if (useCount && pPage->ob.allocCount != count) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -