📄 volume.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 <assert.h>#include <limits.h>#include <stdlib.h>#include <memory.h>#include <unistd.h>#include <stdio.h>#include <errno.h>#include <time.h>#include <a.out.h>#include <sys/fcntl.h>#include <sys/stat.h>#include <disk/DiskNode.hxx>#include <disk/PagePot.hxx>#include <disk/DiskCkpt.hxx>#include <erosimg/App.hxx>#include <erosimg/Volume.hxx>#include <erosimg/DiskDescrip.hxx>#include <erosimg/ExecImage.hxx>#include <eros/Reserve.h>#include <new.h>#define BOOT "/eros/lib/boot/boot"#define min(x,y) ((x) > (y) ? (y) : (x))#define RESERVE_BYTES (MAX_CPU_RESERVE * sizeof(CpuReserveInfo))#define RESERVES_PER_PAGE (EROS_PAGE_SIZE / sizeof(CpuReserveInfo))#define RESERVE_PAGES ((RESERVE_BYTES + EROS_PAGE_SIZE - 1) / EROS_PAGE_SIZE)voidVolume::InitVolume(){ working_fd = -1; target_fd = -1; topDiv = 0; topLogLid = 0; lastAvailLogLid = 0; firstAvailLogLid = (2 * EROS_OBJECTS_PER_FRAME); dskCkptHdr0 = (DiskCheckpoint*) new uint8_t[EROS_PAGE_SIZE]; dskCkptHdr1 = (DiskCheckpoint*) new uint8_t[EROS_PAGE_SIZE]; curDskCkpt = dskCkptHdr0; oldDskCkpt = dskCkptHdr1; rewriting = true; ckptDir = 0; maxCkptDirent = 0; nCkptDirent = 0; threadDir = 0; maxThreadDirent = 0; nThreadDirent = 0; reserveTable = new CpuReserveInfo[MAX_CPU_RESERVE]; bzero(reserveTable, sizeof(CpuReserveInfo) * MAX_CPU_RESERVE); /* Following just for now... */ for (int i = 0; i < STD_CPU_RESERVE; i++) { reserveTable[i].index = i; reserveTable[i].normPrio = i; reserveTable[i].rsrvPrio = -2; } for (int i = STD_CPU_RESERVE; i < MAX_CPU_RESERVE; i++) { reserveTable[i].index = i; reserveTable[i].normPrio = -2; reserveTable[i].rsrvPrio = -2; } needSyncDivisions = false; needSyncHdr = false; needSyncCkptLog = false; needDivInit = false; curLogPotLid = UNDEF_LID;}Volume::Volume(){ InitVolume();#ifdef DEAD_BAD_MAP /* spare ranges are a thing of the past */ divTable = (Division *) divPage; badmap = (BadEnt*) &divTable[NDIVENT];#endif}Volume::~Volume(){ Close();}CpuReserveInfoVolume::GetReserve(uint32_t ndx){ if (ndx >= MAX_CPU_RESERVE) Diag::fatal(1, "Reserve %d is out of range\n"); return reserveTable[ndx];}voidVolume::SetReserve(const CpuReserveInfo& cri){ if (cri.index >= MAX_CPU_RESERVE) Diag::fatal(1, "Reserve %d is out of range\n"); reserveTable[cri.index] = cri;}boolVolume::Read(uint32_t offset, void *buf, uint32_t sz){ assert(working_fd >= 0); if (::lseek(working_fd, (int) offset, SEEK_SET) < 0) return false; if (::read(working_fd, buf, (int) sz) != (int) sz) return false; return true;}boolVolume::Write(uint32_t offset, const void *buf, uint32_t sz){ assert(working_fd >= 0); if (::lseek(working_fd, (int) offset, SEEK_SET) < 0) return false; if (::write(working_fd, buf, (int) sz) != (int) sz) return false; return true;}/* This version finds an empty spot big enough for the division and puts it * there. */intVolume::AddDivision(DivType type, uint32_t sz, const OID& oid){ uint32_t nObFrames = sz / EROS_PAGE_SECTORS; OID endOid; switch (type) { case dt_Kernel: case dt_Object: nObFrames -= (nObFrames / PAGES_PER_PAGE_CLUSTER); if (nObFrames < 1) Diag::fatal(1, "Range too small\n"); if (nObFrames % PAGES_PER_PAGE_CLUSTER) nObFrames -= 1; /* at least one page pot */ if (nObFrames < 1) Diag::fatal(1, "Range too small\n"); /* Take out one more for the first page, which is used to capture * seqno of most recent checkpoint. */ nObFrames--; endOid = oid + (nObFrames * EROS_OBJECTS_PER_FRAME); break; case dt_Log: endOid = oid + (nObFrames * EROS_OBJECTS_PER_FRAME); break; default: Diag::fatal(1, "Attempt to set OID on inappropriate division type\n"); break; } if ((type != dt_Log) && (oid % EROS_OBJECTS_PER_FRAME)) Diag::fatal(1, "Starting OID for range must be multiple of %d\n", EROS_OBJECTS_PER_FRAME); int div = AddAdjustableDivision(type, sz); if (type == dt_Log && endOid > topLogLid) { topLogLid = endOid; lastAvailLogLid = endOid; } divTable[div].startOid = oid; divTable[div].endOid = endOid; Diag::printf("Division %d: %6d %6d [%6s] %s=[", div, divTable[div].start, divTable[div].end, div_TypeName(divTable[div].type), (type == dt_Log) ? "LID" : "OID"); Diag::print(divTable[div].startOid); Diag::printf(", "); Diag::print(divTable[div].endOid); Diag::printf(")\n"); return div;}/* This version finds an empty spot big enough for the division and puts it * there. */intVolume::AddDivision(DivType type, uint32_t sz){ switch (type) { case dt_Object: case dt_Log: Diag::fatal(1, "Attempt to create %s division without OID\n", div_TypeName(type)); break; default: break; } int div = AddAdjustableDivision(type, sz); Diag::printf("Division %d: %6d %6d [%6s]\n", div, divTable[div].start, divTable[div].end, div_TypeName(divTable[div].type)); return div;}intVolume::AddAdjustableDivision(DivType type, uint32_t sz){ int i; uint32_t start = 0; assert(working_fd >= 0); /* make sure we do not collide with another division: */ for (i = 0; i < topDiv; i++) { uint32_t end = start + sz; /* if some other division starts or ends in our proposed range, * go to the end of the colliding division: */ if ((divTable[i].start >= start && divTable[i].start < end) || (divTable[i].end > start && divTable[i].end <= end)) { start = divTable[i].end; i = -1; /* restart for loop */ } } int div = DoAddDivision(type, start, sz); return div;}intVolume::AddFixedDivision(DivType type, uint32_t start, uint32_t sz){ int div = DoAddDivision(type, start, sz); Diag::printf("Division %d: %6d %6d [%6s]\n", div, start, start+sz, div_TypeName(divTable[div].type)); return div;}/* The versions that follow add a division at a fixed location: */intVolume::DoAddDivision(DivType type, uint32_t start, uint32_t sz){ assert(working_fd >= 0); if (topDiv >= NDIVENT) Diag::fatal(4, "Too many divisions\n"); uint32_t end = start + sz; /* Need to verify that this division does not overlap some other * division if it has nonzero size */ int i; if (sz) { for (i = 0; i < topDiv; i++) { if ((divTable[i].start != divTable[i].end) && (start >= divTable[i].start && start < divTable[i].end) || (end > divTable[i].start && end <= divTable[i].end)) Diag::fatal(4, "Division range error\n"); } } int div = topDiv; topDiv++; divTable[div].type = type; divTable[div].start = start; divTable[div].end = end; divTable[div].startOid = 0; divTable[div].endOid = 0; if (type == dt_DivTbl) { /* Perfectly okay to have lots of division tables, but only two * end up in the volume header: */ /* assert(!volHdr.AltDivTable); */ if (!volHdr.DivTable) volHdr.DivTable = start; else volHdr.AltDivTable = start; } needSyncHdr = 1; /* if nothing else, volume size changed */ #ifdef DEAD_BAD_MAP /* spare ranges are a thing of the past */ if (type == dt_Spare) spareDivNdx = div;#endif divNeedsInit[div] = true; needDivInit = true; needSyncDivisions = true; return div;}voidVolume::FormatObjectDivision(int ndx){ assert(working_fd >= 0); if (ndx >= topDiv) Diag::fatal(1, "Attempt to format nonexistent division\n"); Division& d = divTable[ndx]; for (OID oid = d.startOid; oid < d.endOid; oid += EROS_OBJECTS_PER_FRAME) { VolPagePot pagePot; ReadPagePotEntry(oid, pagePot); pagePot.type = FRM_TYPE_ZDPAGE; pagePot.count = 0; WritePagePotEntry(oid, pagePot); oid++; } /* Set up a first page with suitable ckpt sequence number: */ uint8_t buf[EROS_PAGE_SIZE]; uint64_t *seqNo = (uint64_t *) buf; *seqNo = 1; Write(d.start * EROS_SECTOR_SIZE, buf, EROS_PAGE_SIZE);}/* Once the log division has been zeroed, we simply need to write * suitable checkpoint header pages: */voidVolume::FormatLogDivision(int ndx){ assert(working_fd >= 0); if (ndx >= topDiv) Diag::fatal(1, "Attempt to format nonexistent division\n"); Division& d = divTable[ndx]; if (d.startOid == 0) { oldDskCkpt->sequenceNumber = 0; oldDskCkpt->hasMigrated = true; oldDskCkpt->maxLogLid = topLogLid; oldDskCkpt->nRsrvPage = 0; oldDskCkpt->nThreadPage = 0; oldDskCkpt->nDirPage = 0; curDskCkpt->sequenceNumber = 1; curDskCkpt->hasMigrated = false; curDskCkpt->maxLogLid = topLogLid; curDskCkpt->nRsrvPage = 0; curDskCkpt->nThreadPage = 0; curDskCkpt->nDirPage = 0; WriteLogPage((lid_t)0, (uint8_t *) dskCkptHdr0); WriteLogPage((lid_t)(1*EROS_OBJECTS_PER_FRAME), (uint8_t *) dskCkptHdr1); } needSyncCkptLog = true;}voidVolume::ZeroDivision(int ndx){ assert(working_fd >= 0); if (ndx >= topDiv) Diag::fatal(1, "Attempt to zero nonexistent division\n"); uint8_t buf[EROS_SECTOR_SIZE]; bzero(buf, EROS_SECTOR_SIZE); Division& d = divTable[ndx]; for (uint32_t i = d.start; i < d.end; i++) if ( !Write(i * EROS_SECTOR_SIZE, buf, EROS_SECTOR_SIZE) ) Diag::fatal(1, "Couldn't zero division %d\n", ndx); divNeedsInit[ndx] = false;}voidVolume::SetVolFlag(VolHdr::Flags flag){ volHdr.BootFlags |= flag; needSyncHdr = 1;}voidVolume::ClearVolFlag(VolHdr::Flags flag){ volHdr.BootFlags &= ~flag; needSyncHdr = 1;}voidVolume::SetIplSysId(uint64_t dw){ volHdr.iplSysId = dw; needSyncHdr = 1;}voidVolume::SetIplKey(const DiskKey& k){ volHdr.iplKey = k; needSyncHdr = 1;}voidVolume::WriteKernelImage(int div, const ExecImage& image){ ZeroDivision(div); FormatObjectDivision(div); divNeedsInit[div] = false; assert(working_fd >= 0); if (div >= topDiv) Diag::fatal(1, "Attempt to write image %s on nonexistent division\n", image.GetName().str()); if (image.NumRegions() != 1) Diag::fatal(1, "Image %s has inappropriate number of regions\n", image.GetName().str()); const ExecRegion& er = image.GetRegion(0); /* If the image was built correctly, it should start at a page boundary: */ if (er.vaddr % EROS_PAGE_SIZE) Diag::fatal(1, "ELF Image %s has start vaddr at nonpage boundary\n", image.GetName().str()); uint32_t bytes = er.filesz; const uint8_t *fileImage = image.GetImage(); fileImage += er.offset; Division& d = divTable[div]; OID oid = d.startOid; uint32_t divPages = (d.endOid - d.startOid) / EROS_OBJECTS_PER_FRAME; if (divPages * EROS_PAGE_SIZE < er.filesz) Diag::fatal(1, "Image \"%s\" (%d bytes) will not fit in division %d (%d pages)\n", image.GetName().str(), bytes, div, divPages); while (bytes) { uint8_t buf[EROS_PAGE_SIZE]; memset(buf, 0, EROS_PAGE_SIZE); memcpy(buf, fileImage, min (bytes, EROS_PAGE_SIZE)); WriteDataPage(oid, buf); fileImage += EROS_PAGE_SIZE; bytes -= min(bytes, EROS_PAGE_SIZE); oid += EROS_OBJECTS_PER_FRAME; }}/* NOTE!!! This only works for dense images, such as the kernel and * bootstrap code. Domain images MUST be handled through the * DomainImage class. Offset is in bytes. */voidVolume::WriteImageAtDivisionOffset(int div, const ExecImage& image, uint32_t offset){ assert(working_fd >= 0); if (div >= topDiv) Diag::fatal(1, "Attempt to write image %s on nonexistent division\n", image.GetName().str()); if (image.NumRegions() != 1) Diag::fatal(1, "Image %s has inappropriate number of regions\n", image.GetName().str()); const ExecRegion& er = image.GetRegion(0); /* If the image was built correctly, it should start at a page boundary: */ if (er.vaddr % EROS_PAGE_SIZE) Diag::fatal(1, "ELF Image %s has start vaddr at nonpage boundary\n", image.GetName().str()); uint32_t secs = er.filesz / EROS_SECTOR_SIZE; if (er.filesz % EROS_SECTOR_SIZE) secs++; uint32_t imageSz = secs * EROS_SECTOR_SIZE; /* The following copy is necessary because the file itself may * contain garbage or other stuff at the tail of the alleged region, * so we must zero-extend to the end of the sector by hand. */ uint8_t *imageBuf = new uint8_t[imageSz]; bzero(imageBuf, imageSz); const uint8_t *fileImage = image.GetImage(); memcpy(imageBuf, &fileImage[er.offset], er.filesz); Division& d = divTable[div]; uint32_t divStart = d.start * EROS_SECTOR_SIZE; uint32_t divEnd = d.end * EROS_SECTOR_SIZE; if (divStart + offset + imageSz > divEnd) Diag::fatal(1, "Image \"%s\" will not fit in division %d\n", image.GetName().str(), div); Write(divStart + offset, imageBuf, imageSz); delete [] imageBuf; divNeedsInit[div] = false;}voidVolume::DelDivision(int ndx){ int i; assert(working_fd >= 0); if (ndx >= topDiv) Diag::fatal(1, "Attempt to delete nonexistent division\n"); switch (divTable[ndx].type) { case dt_Boot: case dt_DivTbl: Diag::fatal(1, "Division type %s cannot be deleted\n", div_TypeName(divTable[ndx].type)); break; break; case dt_Spare: /* Can only delete spare division if no spare sectors are * in use. */ break; } for (i = ndx+1; i < topDiv; i++) divTable[i-1] = divTable[i]; divTable[i].type = dt_Unused; topDiv--; needSyncHdr = 1; /* volume size may have changed */}uint32_tVolume::DivisionSetFlags(int ndx, uint32_t flags){ assert(working_fd >= 0); if (ndx >= topDiv) Diag::fatal(1, "Attempt to update flags for nonexistent division\n"); divTable[ndx].flags |= flags; Diag::printf("Division %d: flags set to [ ", ndx); if (divTable[ndx].flags & DF_PRELOAD) Diag::printf("preload "); Diag::printf("]\n"); needSyncDivisions = true; return divTable[ndx].flags;}uint32_t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -