📄 ck_retag.cxx
字号:
/* * Copyright (C) 1998, 1999, 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>#include <eros/SysTraceKey.h>#include <arch-kerninc/PTE.hxx>#define dbg_retag 0x1 /* frame retag */#define dbg_frameinfo 0x2 /* frame info collection *//* 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 DEBUGEX(x,y) if (((dbg_##x) & dbg_flags) && (y))/* This is a simplified version of the retag logic. It is modestly * wasteful of CPU cycles, but considerably easier to understand than * the previous version. * * Retag Strategy: * * We must first bring in enough information to know the current frame * type of the frame we are retagging. If there is an object in * memory within the frame, or if there is a checkpoint directory * entry for some object in the frame in any generation, this is * sufficient to learn the frame type. Otherwise we must bring in the * tag pot associated with the frame. * * We must then compute the largest allocation count (or in the case * of a node frame, the largest call count) presently associated with * this frame. If the frame is a page or capability page, this can be * computed using the same information we used to get the frame type. * If it is a node frame, we must regrettably bring in all of the * member nodes, because the call count is not available from the tag * pot. * * We now know all of the information needed to create the new objects * associated with this frame. We therefore reserve directory space * for all of the new objects. * * We now blow away all of the in-core node pots and objects currently * associated with this frame. We also RELEASE all current core * directory entries associated with this frame. * * Finally, we create zero object directory entries for the new frame * type. */uint8_tCheckpoint::GetFrameInfo(FrameInfo& fi, PagePot *pagePot, ObCount& count, uint8_t newType){ CoreDirent *cde = CkNIL; DEBUG(frameinfo) MsgLog::dprintf(false, "Enter frameinfo. pgPot=0x%08x\n", pagePot); /* If object has been modified, frame type is type associated with * checkpoint directory entry of youngest matching generation. * Otherwise frame type is as reported in the page pot. */ for (uint8_t g = current; g < nGeneration; g++) { cde = coreGeneration[g].FindFrame(fi.oid); if (cde != CkNIL) break; } count = 0; uint8_t curType = pagePot->type[fi.tagEntry]; if (cde != CkNIL) curType = cde->type; DEBUG(frameinfo) MsgLog::dprintf(false, "Current type is %d\n", cde->type); /* Use the zero types here so that we can compare to the requested * new type. */ switch(curType) { case FRM_TYPE_DPAGE: curType = FRM_TYPE_ZDPAGE; break; case FRM_TYPE_NODE: curType = FRM_TYPE_ZNODE; break; } assert (curType != newType); /* If the frame type is NODE, we might as well bring the objects in * here. */ if (curType == FRM_TYPE_ZNODE) { for (uint32_t n = 0; n < DISK_NODES_PER_PAGE; n++) { OID oid = fi.obFrameOid + n; Node * pNode = Persist::GetNode(oid, 0, false); assert(pNode); pNode->TransLock(); if (pNode->callCount > count) count = pNode->callCount; } } else if (cde != CkNIL) /* page or cap page in ckpt area */ count = cde->count; else count = pagePot->count[fi.tagEntry]; DEBUG(frameinfo) MsgLog::dprintf(false, "Exit frameinfo. curType=%d\n", curType); return curType;}/* If the in-core frames are associated with the last checkpoint, we * MUST write them to the disk, because the currently active * checkpoint might not complete, and we might subsequently need them * back. */voidCheckpoint::CleanCkptFrames(uint8_t curType, FrameInfo& fi){ ObType::Type ty = ObType::PtDataPage; switch(curType) { case FRM_TYPE_ZDPAGE: { ObjectHeader *pObj = ObjectHeader::Lookup(ty, fi.oid); if (pObj) pObj->FlushIfCkpt(); break; } case FRM_TYPE_ZNODE: { for (uint32_t n = 0; n < DISK_NODES_PER_PAGE; n++) { OID oid = fi.obFrameOid + n; Node * pNode = ObjectHeader::LookupNode(oid); assert(pNode); /* we pinned them previously! */ pNode->FlushIfCkpt(); } break; } }}voidCheckpoint::RetagFrame(OID oid, uint8_t newType){ KernStats.nRetag++; assert(newType == FRM_TYPE_ZNODE || newType == FRM_TYPE_ZDPAGE); DEBUGEX(retag, newType != FRM_TYPE_ZNODE) MsgLog::dprintf(false, "Enter RetagFrame(0x%08x%08x, %d)\n", (uint32_t) (oid >> 32), (uint32_t) oid, newType); #ifdef DBG_WILD_PTR if (dbg_wild_ptr) { Check::Consistency("Top RetagFrame()"); Checkpoint::CheckConsistency(false); }#endif FrameInfo fi(oid); ObjectHeader *pPotHdr = Persist::GetTagPot(fi); assert(pPotHdr); pPotHdr->TransLock(); /* we will need this again... */ PagePot *pagePot = (PagePot *) ObjectCache::ObHdrToPage(pPotHdr); ObCount count; uint8_t curType = GetFrameInfo(fi, pagePot, count, newType); assert (curType != newType); assert(curType == FRM_TYPE_ZNODE || curType == FRM_TYPE_ZDPAGE); /* We now know everything we need to know about the current frame. * Reserve space for the new objects: */ uint32_t nObjects = (newType == FRM_TYPE_ZNODE) ? DISK_NODES_PER_PAGE : 1; CleanCkptFrames(curType, fi); /* Since we will be commited to making progress after we reserve the log directories, ensure that any cached state associated with the OLD object is killed before we reserve them. */ switch(curType) { case FRM_TYPE_ZDPAGE: case FRM_TYPE_DPAGE: { ObjectHeader *pObj = ObjectHeader::Lookup(ObType::PtDataPage, fi.oid); if (pObj) { if (pObj->GetFlags(OFLG_CKPT)) assert(pObj->IsDirty() == false); pObj->kr.UnprepareAll(); /* This zaps any PTE's as a side effect. */ pObj->InvalidateProducts(); assert ( PTE::ObIsNotWritable(pObj) ); } break; } case FRM_TYPE_ZNODE: case FRM_TYPE_NODE: { for (uint32_t n = 0; n < DISK_NODES_PER_PAGE; n++) { OID oid = fi.obFrameOid + n; Node * pNode = ObjectHeader::LookupNode(oid); assert(pNode); /* we pinned them previously! */ if (pNode->GetFlags(OFLG_CKPT)) assert(pNode->IsDirty() == false); pNode->Unprepare(false); pNode->kr.UnprepareAll(); for (uint32_t i = 0; i < EROS_NODE_SIZE; i++) { assert ( (*pNode)[i].IsHazard() == false ); (*pNode)[i].NH_Unprepare(); assert ( (*pNode)[i].IsUnprepared() ); } } break; } } /* Make sure we have sufficient core and disk directory entries: */ if (CoreDirent::Require(nObjects) == false) TakeCheckpoint(); /* Once we get the reserve on log directory entries we MUST go * forward, as any yield from that point on cause them to be left * dangling. However, it is possible that we have zapped a PTE * somewhere, and that the COMMIT_POINT() call will consequently * fail when we make it. * * To make matters more interesting, reserving the log directory * entries can fail, in which case we need to take a checkpoint and * will yield as a result (which means we cannot commit yet). * * Make sure the commit will succeed before we attempt it. The * alternative is to unreserve them, but that is simply more hassle * than it is worth. */ inv.MaybeDecommit(); if (coreGeneration[current].ReserveDirent(nObjects) == false) TakeCheckpoint(); assert (inv.CanCommit()); DEBUGEX(retag, newType != FRM_TYPE_ZNODE) MsgLog::dprintf(false, "RetagFrame(0x%08x%08x, %d): got reserves\n", (uint32_t) (oid >> 32), (uint32_t) oid, newType); /* Okay. We are now free and clear to proceed. Zap all in-core * objects associated with the old frame, and also all associated * directory entries in the current generation. * * As long as the objects are part of the current generation, it * does not matter if they are dirty -- we can just blow them away. * Unfortunately, it is possible that the object is: * * Dirty, Marked for checkpoint, Not yet Writen. * * In that event we must force the object out before we kill it. */ /* Since the objects are being destroyed, it does not matter if they * are dirty. Further, it does not matter if that log frame is * actively being written, since we are about to blow away all * references in the core directory to that frame (which will cause * it to become free). */ bool needBump = false; switch(curType) { case FRM_TYPE_ZDPAGE: { ObjectHeader *pObj = ObjectHeader::Lookup(ObType::PtDataPage, fi.oid); if (pObj) { if (pObj->GetFlags(OFLG_CKPT)) assert(pObj->IsDirty() == false); assert ( pObj->kr.IsEmpty() ); assert ( pObj->products == 0 ); assert ( PTE::ObIsNotWritable(pObj) );#ifdef OFLG_PIN pObj->ClearFlags(OFLG_PIN);#endif pObj->ClearFlags(OFLG_CKPT|OFLG_DIRTY|OFLG_REDIRTY|OFLG_IO); ObjectCache::ReleasePageFrame(pObj); } CoreDirent *cde = coreGeneration[current].FindObject(fi.oid); assert(cde); if (cde != CkNIL) { coreGeneration[current].Release(cde); coreGeneration[current].RemoveFromOidMap(cde); coreGeneration[current].alloc.nCoreDirent--; coreGeneration[current].UnreserveDirent(); delete cde; } break; } case FRM_TYPE_ZNODE: { for (uint32_t n = 0; n < DISK_NODES_PER_PAGE; n++) { OID oid = fi.obFrameOid + n; Node * pNode = ObjectHeader::LookupNode(oid); assert(pNode); /* we pinned them previously! */ if (pNode->GetFlags(OFLG_CKPT)) assert(pNode->IsDirty() == false); pNode->TransUnlock(); if (pNode->GetFlags(OFLG_DISKCAPS)) needBump = true; assert (pNode->obType == ObType::NtUnprepared); assert (pNode->kr.IsEmpty());#ifndef NDEBUG for (uint32_t i = 0; i < EROS_NODE_SIZE; i++) { assert ( (*pNode)[i].IsHazard() == false ); assert ( (*pNode)[i].IsUnprepared() ); }#endif#ifdef OFLG_PIN pNode->ClearFlags(OFLG_PIN);#endif pNode->ClearFlags(OFLG_CKPT|OFLG_DIRTY|OFLG_REDIRTY|OFLG_IO); ObjectCache::ReleaseNodeFrame(pNode); CoreDirent *cde = coreGeneration[current].FindObject(oid); assert(cde); if (cde != CkNIL) { coreGeneration[current].Release(cde); coreGeneration[current].RemoveFromOidMap(cde); coreGeneration[current].alloc.nCoreDirent--; coreGeneration[current].UnreserveDirent(); delete cde; } } break; } } if (needBump) count++; DEBUGEX(retag, newType != FRM_TYPE_ZNODE) MsgLog::dprintf(false, "RetagFrame(0x%08x%08x, %d): zapped old residents\n", (uint32_t) (oid >> 32), (uint32_t) oid, newType); /* So much for the old frame. Now create a bunch of new, zero * objects. */ for (uint32_t n = 0; n < nObjects; n++) { OID oid = fi.obFrameOid + n; CoreDirent *cde = new CoreDirent; assert(cde && cde != CkNIL); cde->oid = oid; cde->color = CoreDirent::red; cde->count = count; cde->lid = ZERO_LID; cde->type = newType; assert(cde->left == CkNIL); assert(cde->right == CkNIL); assert(cde->parent == CkNIL); coreGeneration[current].alloc.nCoreDirent++; coreGeneration[current].AddToOidMap(cde); } DEBUGEX(retag, newType != FRM_TYPE_ZNODE) MsgLog::dprintf(newType != FRM_TYPE_ZNODE, "Exit RetagFrame(0x%08x%08x, %d)\n", (uint32_t) (oid >> 32), (uint32_t) oid, newType);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -