📄 ck_readwrite.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 <disk/DiskNode.hxx>#include <disk/PagePot.hxx>#include <kerninc/kernel.hxx>#include <kerninc/MsgLog.hxx>#include <kerninc/Check.hxx>#include <kerninc/Checkpoint.hxx>#include <kerninc/Persist.hxx>#include <kerninc/ObjectCache.hxx>#include <kerninc/Thread.hxx>#include <kerninc/CpuReserve.hxx>#include <kerninc/BlockDev.hxx>#include <kerninc/Check.hxx>#include <kerninc/Invocation.hxx>#include <kerninc/Machine.hxx>#define dbg_ckage 0x1 /* migration state machine */#define dbg_reservation 0x2 /* reservation logic */#define dbg_dirent 0x4 /* dirent manipulation */#define dbg_ndload 0x8/* Following should be an OR of some of the above */#define dbg_flags ( 0u )#define DBCOND(x) (dbg_##x & dbg_flags)#define DEBUG(x) if DBCOND(x)#define DEBUG2(x,y) if ((dbg_##x|dbg_##y) & dbg_flags)voidCheckpoint::AllocateMasterLid(lid_t ll){ logframe_t lf = (ll / EROS_OBJECTS_PER_FRAME); allocMap.Allocate(lf); nAvailLogFrame --; nMasterPage ++;}voidCheckpoint::WriteNodeToLog(Node *pNode){#ifdef DBG_WILD_PTR Check::Consistency("Top WriteNodeToLog()");#endif assert(pNode->obType <= ObType::NtLAST_NODE_TYPE); assert (pNode->IsDirty()); uint32_t gen = pNode->GetFlags(OFLG_CKPT) ? last_ckpt : current; CoreGeneration *pGen = &coreGeneration[gen]; DEBUG(ckage) MsgLog::dprintf(false, "Writing node 0x%08x%08x to log, generation %d\n", (uint32_t) (pNode->ob.oid > 32), (uint32_t) pNode->ob.oid, gen);#ifdef DBG_WILD_PTR if (pNode->Validate() == false) { MsgLog::printf("Node no good prior to hazard clearance\n"); Debugger(); }#endif bool isZero = true; for (uint32_t k = 0; k < EROS_NODE_SIZE; k++) { if ( (*pNode)[k].IsRdHazard() ) pNode->ClearHazard(k); isZero = isZero && pNode->slot[k].IsVoidKey(); } #ifndef NDEBUG if (pNode->Validate() == false) { MsgLog::printf("Node no good post hazard clearance\n"); Debugger(); }#endif CoreDirent *cde = FindObject(pNode->ob.oid, ObType::NtUnprepared, gen); if (cde == 0 || cde == CkNIL) MsgLog::dprintf(true, "Cleaning nd 0x%08x%08x -- cde=0x%08x not in cur dir\n", (uint32_t) (pNode->ob.oid >> 32), (uint32_t) pNode->ob.oid, cde); assert(cde && cde != CkNIL); /* No ZNODE's here, as they should have been converted in * RegisterDirtyObject() */ assert (cde->type == FRM_TYPE_NODE); ObjectHeader * pLogPageHdr = 0; cde->count = pNode->ob.allocCount;#ifdef DBG_WILD_PTR CheckConsistency(false);#endif /* It would be nice if we could assume that /cde->lid == UNDEF_LID/. * Regrettably, we can allocate a lid here in the call to * pGen->Allocate() and then yield trying to fetch in that frame. * When we subsequently try to rewrite the node, we will discover * the previously allocated lid. Note that we do not try to * decommit the previously assigned location -- in all likelihood it * was assigned very recently, and we do not want the effort to * bring in the frame to be wasted. * * Just to make life interesting, however, it is possible that some * other operation has zeroed the node in the interim. In that * case, we really do need to release the allocated storage. */ if (isZero) { pGen->Release(cde); cde->type = FRM_TYPE_ZNODE; cde->lid = ZERO_LID; DEBUG(ckage) MsgLog::dprintf(false, " at lid=0x%08x\n", cde->lid);#ifdef DBG_WILD_PTR CheckConsistency(false);#endif } else { pGen->Allocate(cde); DEBUG(ckage) MsgLog::dprintf(false, " at lid=0x%08x\n", cde->lid); #ifdef DBG_WILD_PTR CheckConsistency(false);#endif pLogPageHdr = Persist::GetCkFrame(cde->lid); assert(pLogPageHdr); pLogPageHdr->TransLock(); assert( pLogPageHdr->GetFlags(OFLG_CKPT) == 0 );#ifdef DBG_CLEAN MsgLog::printf("Object ty %d oid=0x%08x%08x marked dirty\n", pLogPageHdr->obType, (uint32_t) (pLogPageHdr->oid >> 32), (uint32_t) pLogPageHdr->oid);#endif pLogPageHdr->SetDirtyFlag(); pLogPageHdr->age = Age::NewBorn;#ifdef DBG_WILD_PTR CheckConsistency(false);#endif DiskNode *potBase = (DiskNode *) ObjectCache::ObHdrToPage(pLogPageHdr); DiskNode *pDiskNode = potBase + (cde->lid % EROS_OBJECTS_PER_FRAME); DEBUG(ckage) MsgLog::printf("WrNdToLg: lid=0x%x potBase=0x%x " "potHdr=0x%x pDiskNode=0x%x\n", cde->lid, potBase, pLogPageHdr, pDiskNode); /* Copy the node to the log pot: */ *pDiskNode = *pNode;#ifdef DBG_WILD_PTR CheckConsistency(false);#endif } #ifdef OPTION_OB_MOD_CHECK pNode->ob.check = pNode->CalcCheck();#endif pNode->ClearFlags(OFLG_DIRTY|OFLG_REDIRTY);#ifdef DBG_CLEAN MsgLog::printf("Object 0x%08x ty %d oid=0x%08x%08x cleaned to node pot\n", pNode, pNode->obType, (uint32_t) (pNode->oid >> 32), (uint32_t) pNode->oid);#endif#ifdef DBG_WILD_PTR CheckConsistency(false); if (dbg_wild_ptr) Check::Nodes();#endif #if defined(DBG_WILD_PTR) if (dbg_wild_ptr) Check::Consistency("Bottom WriteNodeToLog()");#endif}lid_tCheckpoint::FindFreeFrame(){ logframe_t stop = LastAllocatedFrame; logframe_t loc = LastAllocatedFrame + 1; for (;loc != stop; loc++) { if (loc == totLogFrame) loc = 0; if ( allocMap.IsFree(loc) ) { LastAllocatedFrame = loc; break; } } if (loc == stop) { MsgLog::fatal("loc: %d, lastAlloc: %d, totFrame: %d\n", loc, LastAllocatedFrame, totLogFrame); }#if 0 MsgLog::dprintf(true, "Allocated log loc=%d\n", loc);#endif /* If the log page exists in core, blow it away: */ lid_t ll = loc * EROS_OBJECTS_PER_FRAME; #ifndef NDEBUG ObjectHeader * pLogPageHdr = ObjectHeader::Lookup(ObType::PtLogPage, ll);#endif assert (pLogPageHdr == 0);#if 0 if (pLogPageHdr) { /* It should not be involved in I/O -- if so, then it was not really * free because migration was not done with it. */ assert (pLogPageHdr->GetFlags(OFLG_IO) == 0); ObjectCache::ReleasePageFrame(pLogPageHdr); }#endif return ll;}lid_tCheckpoint::AllocateLid(lid_t ll){ logframe_t frm = ll / EROS_OBJECTS_PER_FRAME; assert (nReservedLogFrame >= nAllocatedLogFrame); assert (CONTENT_LID(ll)); if (allocMap.IsFree(frm)) { nAllocatedLogFrame++; assert (nReservedLogFrame >= nAllocatedLogFrame); } allocMap.Allocate(frm); return ll;}/* return true if log frame is now empty. */boolCheckpoint::DeallocateLid(lid_t ll){ logframe_t frm = ll / EROS_OBJECTS_PER_FRAME; assert (nReservedLogFrame >= nAllocatedLogFrame); assert (CONTENT_LID(ll)); allocMap.Deallocate(frm); if (allocMap.IsFree(frm)) { ll &= ~0xffu; ObjectHeader * pLogPageHdr = ObjectHeader::Lookup(ObType::PtLogPage, ll); if (pLogPageHdr) { assert(pLogPageHdr->IsDirty() == false); pLogPageHdr->Unintern(); ObjectCache::ReleasePageFrame(pLogPageHdr); } nAllocatedLogFrame--; nReservedLogFrame--; return true; } return false;}boolCheckpoint::ReserveLogFrame(){ if (nReservedLogFrame == nAvailLogFrame) { for (uint32_t g = nGeneration - 1; g >= first_migrated; g--) { DEBUG(reservation) MsgLog::printf("Reclaiming log frame from generation %d\n", g); if (coreGeneration[g].ReclaimLogPage()) break; } } if (nReservedLogFrame == nAvailLogFrame) return false; assert (nReservedLogFrame <= nAvailLogFrame); nReservedLogFrame++; return true;}/* We are making an object dirty. If it is already dirty and non-zero * in the current checkpoint, do nothing and return. * * If space is not already reserved for this object, See if we can * reserve space for the object in the log . If so, reserve the * space. * * If no directory entry exists, attempt to reserve a disk directory * entry for the object. If that fails, declare a checkpoint. * * If no directory entry exists, attempt to allocate and populate a * core directory entry for the object. If that fails, declare a * checkpoint. */voidCheckpoint::RegisterDirtyObject(ObjectHeader *pObj){#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top RegisterDirtyObject()");#endif if (enabled == false) return;#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Nodes();#endif bool haveSpace = true; if (migrationStatus != mg_Idle) ProcessMigration(); /* RegisterDirtyObject() is called to tell the checkpoint logic that * the object should be added to the checkpoint directory. * * It is possible that the object we are trying to make dirty was in * core, and was just started on it's way to home location by the * migrator. If so, we must wait for the I/O to complete: */ if (pObj->GetFlags(OFLG_IO)) {#if 0 if (pObj->GetFlags(OFLG_CKPT) == 0) MsgLog::dprintf(true, "Object hdr 0x%x OFLG_IO but not OFLG_CKPT!\n", pObj);#endif Thread::Current()->SleepOn(pObj->ObjectSleepQueue()); Thread::Current()->Yield(); } assert (!pObj->IsDirty()); bool isNode = (pObj->obType <= ObType::NtLAST_NODE_TYPE); CoreDirent* cde = coreGeneration[current].FindObject(pObj->ob.oid); DEBUG(reservation) MsgLog::dprintf(false, "Reserving space for %s 0x%08x%08x\n", isNode ? "Node" : "Page", (uint32_t) (pObj->ob.oid >> 32), (uint32_t) pObj->ob.oid);#ifdef DBG_WILD_PTR Checkpoint::CheckConsistency(false);#endif bool neededDirent = false; /* Allocate the directory entry first, as this is easier to * deallocate if we aren't able to get space for the actual object. */ if (cde == CkNIL) { neededDirent = true; /* MUST grab the core dirent first, as allocating it might kick in * the ageing mechanism, during which the reservation counts for * core and disk dirents would disagree if we reserve the disk * dirent first. This in turn violates the consistency checker. */ cde = new CoreDirent; if (cde == 0 || cde == CkNIL) /* FIX: not sure */ goto take_checkpoint; haveSpace = coreGeneration[current].ReserveDirent(); if (haveSpace == false) { MsgLog::dprintf(true, "Could not reserve disk dirent\n"); goto release_core_dirent; } cde->oid = pObj->ob.oid; cde->color = CoreDirent::red; cde->count = pObj->ob.allocCount; /* Note that we TEMPORARILY use VIRGIN_LID so that the Release() * logic will know not to release any existing storage. */ cde->lid = VIRGIN_LID; cde->type = isNode ? FRM_TYPE_NODE : FRM_TYPE_DPAGE; assert(cde->left == CkNIL); assert(cde->right == CkNIL); assert(cde->parent == CkNIL); coreGeneration[current].alloc.nCoreDirent++; } /* Now reserve space for the actual object: */ if (isNode) { if (! coreGeneration[current].ReserveNode() ) { MsgLog::dprintf(true, "Could not reserve log space for node\n"); goto release_dirent; } coreGeneration[current].Release(cde); cde->lid = UNDEF_LID; cde->type = FRM_TYPE_NODE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -