DIRECTORY BootFile USING [DiskFileID, Location], Disk USING [Channel, invalid, Label, labelCheck, ok, PageNumber, PageCount, Request, Status], DiskFace USING [DontCare, RelID], File USING [FP, FileID, Handle, nullFP, PageCount, PageNumber, PropertyStorage, RC, Volume, VolumeFile, VolumeID], FileBackdoor USING [VolumeFlusher], Rope USING [ROPE], VolumeFormat USING [LogicalPage, LogicalPageCount, LogicalRoot, LogicalRun, LogicalRunObject, LVBootFile, PVBootFile, RunPageCount, VAMObject], PhysicalVolume USING [Physical, PhysicalRC, SubVolumeDetails], VMBacking USING [Run, RunTableObject]; FileInternal: CEDAR DEFINITIONS = BEGIN FileImplMonitorLock: MONITORLOCK; -- monitor for FileImpl and FilePagesImpl FileID: TYPE = RECORD[INT]; VolumeObject: TYPE = MONITORED RECORD[ rest: REF VolumeObject _ NIL, id: File.VolumeID, subVolumes: LIST OF PhysicalVolume.SubVolumeDetails, initialised: BOOL _ FALSE, destroyed: BOOL _ FALSE, root: LONG POINTER TO VolumeFormat.LogicalRoot _ NIL, rootStatus: File.RC _ inconsistent, vamStatus: File.RC _ inconsistent, vamChanged: BOOL _ FALSE, checkpointing: BOOL _ TRUE, name: Rope.ROPE _ NIL, size: VolumeFormat.LogicalPageCount, free: VolumeFormat.LogicalPageCount _ 0, vam: VAM _ NIL, vamFile: File.Handle _ NIL, lastFileID: FileID _ NULL, freeboard: INT _ 0, flusher: FileBackdoor.VolumeFlusher _ NIL, flusherData: REF ANY _ NIL, flushing: BOOL _ FALSE ]; Handle: TYPE = REF Object; Object: PUBLIC TYPE = MONITORED RECORD[ fp: File.FP _ File.nullFP, -- fp.id is immutable; fp.da is under the per-file interlock volume: File.Volume _ NIL, -- immutable rest: Handle _ NIL, -- chain in file hash table used by FileTableImpl inside its monitor reissued: BOOL _ FALSE, -- marker used by FileTableImpl inside its monitor users: INT _ 0, -- per-file shared/exclusive interlock. Accessed under FileImpl monitor lock state: { none, opened, deleted } _ none, headerVMPages: INT _ 0, -- how many to free headerVM: LONG POINTER _ NIL, properties: File.PropertyStorage _ NIL, size: File.PageCount _ 0, diskRunPages: CARDINAL _ 1, runPages: CARDINAL _ 1, diskPropertyPages: CARDINAL _ 1, propertyPages: CARDINAL _ 1, logicalRunTable: LONG POINTER TO VolumeFormat.LogicalRunObject _ NIL, runTable: RunTable _ NIL ]; RunTable: TYPE = REF VMBacking.RunTableObject; PhysicalRun: TYPE = VMBacking.Run; scratchWriter: LONG POINTER; -- scratch buffer for writing (all 0) scratchReader: LONG POINTER; -- scratch buffer for reading notReallyFree: INT ; DoPinnedIO: PROC[channel: Disk.Channel, label: POINTER TO Disk.Label, req: POINTER TO Disk.Request] RETURNS[ status: Disk.Status, countDone: Disk.PageCount] ; TranslateStatus: PROC[status: Disk.Status] RETURNS [File.RC] = INLINE { RETURN[ SELECT status FROM Disk.ok => ok, Disk.labelCheck => software, Disk.invalid => wentOffline, ENDCASE => hardware ] }; ActionType: TYPE = {write, read}; WhereLocation: TYPE = {header, data}; MaxTransferRun: Disk.PageCount; Transfer: PROC[file: Handle, data: LONG POINTER, filePage: File.PageNumber, nPages: File.PageCount, action: ActionType, where: WhereLocation ]; CheckStatus: PROC[status: Disk.Status, diskPage: INT]; HeaderLabel: PROC[fp: File.FP] RETURNS[Disk.Label]; DataLabel: PROC[fp: File.FP] RETURNS[Disk.Label] ; FreeLabel: PROC[volume: File.Volume] RETURNS[Disk.Label] ; WriteLabels: PROC[channel: Disk.Channel, diskPage: Disk.PageNumber, count: Disk.PageCount, data: LONG POINTER, label: POINTER TO Disk.Label] RETURNS[ status: Disk.Status, countDone: Disk.PageCount] ; VerifyLabels: PROC[channel: Disk.Channel, diskPage: Disk.PageNumber, count: Disk.PageCount, label: POINTER TO Disk.Label] RETURNS[ status: Disk.Status, countDone: Disk.PageCount] ; GetScratchPage: PROC RETURNS[data: LONG POINTER]; FreeScratchPage: PUBLIC PROC[data: LONG POINTER]; LockAndCloseFiles: PROC; UnlockFiles: PROC; LockVolume: PROC[volume: File.Volume]; ReadRootPage: PROC[volume: File.Volume]; InitRootPage: PROC[volume: File.Volume, name: Rope.ROPE] RETURNS[File.RC]; LockMode: TYPE = { shared, exclusive }; Lock: PROC[file: Handle, mode: LockMode]; Unlock: PROC[file: Handle]; Acquire: PROC[file: Handle, mode: LockMode]; PhysicalPageBad: PROC[physical: PhysicalVolume.Physical, address: Disk.PageNumber] RETURNS[ badTableFull: BOOL, status: PhysicalVolume.PhysicalRC ]; GetBadPages: PROC[subVolume: PhysicalVolume.SubVolumeDetails, work: PROC[VolumeFormat.LogicalPage]]; TranslateLogicalRun: PROC[logicalRun: VolumeFormat.LogicalRun, volume: File.Volume] RETURNS[channel: Disk.Channel, diskPage: Disk.PageNumber]; RecordRootFile: PROC[volume: File.Volume, root: File.VolumeFile, fp: File.FP, page: File.PageNumber, id: DiskFace.RelID, link: DiskFace.DontCare, channel: Disk.Channel]; NewID: PROC[volume: File.Volume] RETURNS [File.FileID]; WriteLogicalMarkers: PROC[volume: File.Volume] RETURNS[File.RC]; InitLogicalMarkers: PROC[volume: File.Volume] RETURNS[File.RC]; VAM: TYPE = LONG POINTER TO VolumeFormat.VAMObject; FindLargestFreeBlockInBiggestSubVolume: PROC[volume: File.Volume] RETURNS [first: VolumeFormat.LogicalPage, count: VolumeFormat.LogicalPageCount, subVolume: PhysicalVolume.SubVolumeDetails]; IsUsed: PROC[volume: File.Volume, page: VolumeFormat.LogicalPage] RETURNS [inUse: BOOL]; SetPageUsed: PROC[volume: File.Volume, page: VolumeFormat.LogicalPage, inUse: BOOL] RETURNS [wasInUse: BOOL]; Alloc: PROC[volume: File.Volume, first: VolumeFormat.LogicalPage, size, min: VolumeFormat.LogicalPageCount] RETURNS[given: VolumeFormat.LogicalRun]; Free: PROC[volume: File.Volume, logicalRun: VolumeFormat.LogicalRun]; Commit: PROC[volume: File.Volume]; Flush: PROC[volume: File.Volume, lack: VolumeFormat.LogicalPageCount] RETURNS[BOOL]; RunsToHeaderPages: PROC[runs: CARDINAL] RETURNS [pages: VolumeFormat.LogicalPageCount]; HeaderPagesToRuns: PROC[pages: VolumeFormat.LogicalPageCount] RETURNS [runs: CARDINAL]; WriteRunTable: PROC[file: Handle]; GetHeaderVM: PROC[file: Handle, runs: CARDINAL, propertyPages: CARDINAL _ 1]; FreeHeaderVM: PROC[file: Handle]; TranslateLogicalRunTable: PROC[file: Handle, prefixOnly: BOOL _ FALSE] RETURNS[ File.PageCount ]; AddRun: PROC[file: Handle, run: POINTER TO PhysicalRun, logicalPage: VolumeFormat.LogicalPage, okPages: VolumeFormat.RunPageCount]; LastLogicalPage: PROC[file: Handle] RETURNS [VolumeFormat.LogicalPage]; RemoveFromRunTable: PROC[file: Handle, remove: INT]; FindRun: PROC[start: File.PageNumber, nPages: File.PageCount, runTable: RunTable] RETURNS[diskPage: Disk.PageNumber, size: Disk.PageCount, channel: Disk.Channel]; SplitPhysicalRunTable: PROC[file: File.Handle, page: VolumeFormat.LogicalPage] RETURNS [runNumber: CARDINAL]; ExtendFileHeader: PROC[file: File.Handle, newRunPages: CARDINAL, newPropertyPages: CARDINAL]; RegisterVMFile: PROC[file: File.Handle]; FreeRun: PROC[logicalRun: VolumeFormat.LogicalRun, volume: File.Volume, verifyLabel: POINTER TO Disk.Label _ NIL]; EnumeratePagesProc: TYPE = PROC[status: Disk.Status, da: VolumeFormat.LogicalPage, label: POINTER TO Disk.Label, diskPage: INT] RETURNS[exit: BOOL _ FALSE]; EnumeratePages: PROC[volume: File.Volume, start: VolumeFormat.LogicalPage, skipBadPages: BOOL _ TRUE, work: EnumeratePagesProc]; AllocForCreate: PROC RETURNS[Handle]; Insert: PROC [Handle]; DontInsert: PROC; Lookup: PROC [volume: File.Volume, fp: File.FP] RETURNS[Handle]; GetFileLocation: PROC [file: File.Handle, firstPage: File.PageNumber] RETURNS[location: BootFile.Location]; GetLogicalLocation: PROC [volume: File.Volume, root: VolumeFormat.LVBootFile] RETURNS[location: BootFile.Location]; GetPhysicalLocation: PROC [physical: PhysicalVolume.Physical, root: VolumeFormat.PVBootFile] RETURNS[location: BootFile.Location]; SetPhysicalLocation: PROC [physical: PhysicalVolume.Physical, root: VolumeFormat.PVBootFile, diskFileID: BootFile.DiskFileID] RETURNS[PhysicalVolume.PhysicalRC]; END. VFileInternal.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Andrew Birrell December 7, 1983 6:10 pm Levin, August 8, 1983 5:54 pm Bob Hagmann March 19, 1985 11:33:34 am PST Doug Wyatt, February 27, 1985 12:07:36 pm PST Russ Atkinson (RRA) February 27, 1985 9:36:23 pm PST Cedar Nucleus (Files): internal interface. Data Types and minor subroutines File File Exported to File The remaining fields (and fp.da) are accessed only under the per-file interlock, or during initialization or finalization of the object SwapIn and do the I/O Read/Write from/to the disk. filePage is either in the header, or the data area of the file (selected by where). filePage is counted from 0. Convert status to an File.Error ERROR if not ok. -- ******** Labels ******** -- -- ******** Checkpoint and Rollback (and ReadRootPage) ******** -- Checkpoint and Rollback (and ReadRootPage) Lock all existing file objects, and ensure next access will re-open them; suspend future file object creations. Unlock existing file objects and allow creation of new ones. Lock volume to suspend subsequent access to its monitored data or VAM file; unlock by calling ReadRootPage. Reads the volume's VAM from disk and records free page count; unlocks if volume was locked for a checkpoint. Writes a root page for the volume. Size and ID are taken from "volume", name is as given. Other fields of "volume" and the root page are initialised, but no VAM is created. On normal exit (reulst is "ok"), the volume is well enough initialized that calling EraseVolume will succeed; equally, it is well enough initialized that the rootStatus will be ok in some subsequent run. Result comes from the write of the root page (and is kept as volume.rootStatus). Unlocks if volume was locked for a checkpoint. Acquire lock on file (for use by LockAndCloseFiles in FileTableImpl) Release previously acquired lock on file (for use by UnlockFiles in FileTableImpl) Bad page table Record page as bad in the physical volume root Enumerate the bad pages in the subvolume Access to volume root page and volume's list of sub-volumes Gives physical-volume-relative data for a logical-volume-relative run Records the root file in the logical volume root page. Issues a new unique ID, ensuring all issued ID's are recorded in the volume root Replicates critical logical root information in the volume marker pages. See PhysicalVolumeImpl. Replicates critical logical root information in the volume marker pages. See PhysicalVolumeImpl. Must be called only from InitRootPage: see comment beside implementation of this procedure. This mess is caused by the physical and logical marker info being on a single page. Volume Allocation Map Find the largest free piece of disk. The only use of this is for allocating the VM Backing File Test to see if a page is in-use. This test is done under the monitor, but no guarantee is made about how long the result will be true. Test to see if a page is in-use, and set it to "inUse". This test is done under the monitor, but no guarantee is made about how long the result will be true. Find a logical run marked free in the in-core VAM. May be smaller than "size", but is never smaller than "min" Mark the logical run free in the in-core VAM. Ensure the volume's VAM is up to date on disk Try to ensure there are at least "lack" free pages on the volume by running any volume flusher. Returns TRUE iff it might have succeeded. Header and Run-table management Write the memory resident run table to disk. Will grow the run table if needed during growing of header for extended run table or property pages. The caller guarantees header will not need to be expanded. Allocate VM for a file's header, initializing file.logicalRunTable. Free VM that was used for file's header. Copy file's logical run table into newly allocated physical run table. prefixOnly is used during file open when only a prefix of the run table is available (for multi-page run tables) Add pages to the file's physical and logical run tables Returns the logical page number of the last page of the file. Removes pages from the file's physical and logical run tables Find the physical location of contiguous initial subset of the given pages of the file. Split the run table so that a new run begins at "page". This assumes that the run table will not overflow. Operations involving access to pages within a volume Write labels of specified pages marking them as "free". diskPage is only valid when status # ok High speed enumeration of page labels. Calls "work" sequentially with successive page labels. Tries its best to avoid missing disk revolutions. Global table of file objects Allocate an object, but don't place it in the table. Insert the object into the table (after successful creation). Note that a handle returned from AllocForCreate has been abandoned Look-up the [volume,fp] in the table, inserting if needed. Boot Locations Get location for passing to germ. Also writes bootchain links into the file. Get location of the appropriate logical root file Get location of the appropriate physical root file Set location of the appropriate physical root file Bob Hagmann March 19, 1985 8:09:06 am PST changes to: DIRECTORY, FileID, File, VolumeObject, Object, PhysicalRun, DoPinnedIO, TranslateStatus, ActionType, WhereLocation, Transfer, CheckStatus, Unlock, Alloc, GetHeaderVM, TranslateLogicalRunTable, RegisterVMFile, EnumeratePages Κ !˜codešœ™Kšœ Οmœ1™Kšœ žœ˜&—K˜KšΠbl œžœž ˜Kšœž˜K˜Kšœž œΟc)˜Lheadšœ ™ Jšœ™Kšœžœžœžœ˜K˜Jš ™šœžœž œžœ˜&Kšœžœžœ˜Kšœ˜Kšœ žœžœ!˜4Kšœ žœžœ˜Kšœ žœžœ˜Kš œžœžœžœžœ˜5Kšœžœ˜#Kšœžœ˜"Kšœ žœžœ˜Kšœžœžœ˜Kšœ žœžœ˜K˜$K˜(Kšœžœžœ˜Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœ&žœ˜*Kšœ žœžœžœ˜Kšœ žœž˜Kšœ˜—K˜Kšœžœžœ˜K˜Jš œ™š œžœžœž œžœ˜'Kšœ žœ <˜WKšœžœ  ˜'Kšœžœ D˜XKšœ žœžœ 2˜JKšœžœ M˜]Kšœ9 œ8™‡Kšœ(˜(Kšœžœ ˜+Kšœ žœžœžœ˜Kšœ#žœ˜'Kšœ˜Kšœžœ˜Kšœ žœ˜Kšœžœ˜ Kšœžœ˜Kšœžœ!žœ˜EKšœž˜Kšœ˜—K˜Kšœ žœžœ˜.K˜Kšœ žœ˜"K˜Jšœžœžœ %˜CJšœžœžœ ˜;J˜Jšœžœ˜J˜šΟn œžœžœžœžœžœžœ3˜žJ™—K˜K˜š‘œžœžœ ž˜Gšžœ˜šžœž˜K˜K˜K˜Kšžœ˜——Kšžœ˜K˜—Jšœ žœ˜!Jšœžœ˜%J˜J˜š‘œžœžœžœ`˜JšœΟeœD’œ’œ™Ž—J˜š‘ œžœ žœ˜6Jšœ’œΟsœ ™0J˜—J˜J˜—š  œ  ™™J™—Jš‘ œžœ žœžœ ˜3J˜Jš‘ œžœ žœžœ˜2J˜Jš‘ œžœžœ˜:J˜š ‘ œžœPžœžœ žœžœ ˜ŒJšžœ3˜:—J˜š‘ œžœQžœžœ ˜yJšžœ3˜:—J˜J˜Jš ‘œžœžœžœžœ˜1J˜Jš‘œž œžœžœ˜1J˜—J™š  œ*  ™BK˜—šœ*™*š‘œžœ˜Kšœo™o—K˜š‘ œžœ˜Kšœ<™<—K˜š‘ œžœ˜&Kšœl™l—K˜š‘ œžœ˜(Kšœl™l—K˜š ‘ œžœ!žœžœžœ˜JKšœώ™ώ—K˜Kšœ žœ˜'K˜š‘œžœ˜)KšœD™D—K˜š‘œžœ˜KšœR™RK™—Jš‘œžœ˜,K™—šœ™š‘œžœ>žœžœ&˜”K™.—K˜š‘ œžœ3žœ˜dK™(K˜——šœ;™;š‘œžœ:˜Sšžœ3˜:KšœE™E——K˜š‘œžœ6žœ]˜©Kšœ6™6—K˜š‘œžœžœ˜7KšœP™P—K˜š‘œžœžœžœ˜@K™aK˜—š‘œžœžœžœ˜?K™”K˜——šœ™Kš žœžœžœžœžœ˜3K˜š‘&œžœžœu˜ΎK™`—K˜š‘œžœ6žœ žœ˜XJ™‡J™—š ‘ œžœ=žœžœ žœ˜mJšœž™ž—J™š‘œžœ6˜AK˜)šžœ!˜(Kšœo™o——K˜š‘œžœ;˜EKšœ-™-—K˜š‘œžœ˜"Kšœ-™-—K˜š‘œžœ;žœžœ˜TKšœŠ™ŠK˜——šœ™Jš‘œžœžœžœ(˜WJ˜Jš‘œžœ'žœžœ˜XJ˜š‘ œžœ˜"J™Ξ—K˜š‘ œžœžœžœ˜MKšœC™C—K˜š‘ œžœ˜!Kšœ(™(—K˜š ‘œžœžœžœžœ˜aKšœΈ™Έ—K˜š‘œžœ˜Kšœžœžœ ˜K˜&šœ$˜$Kšœ7™7——K˜š‘œžœžœ˜GKšœ=™=—K˜š‘œžœžœ˜4Kšœ=™=—K˜š‘œžœD˜QšžœI˜PKšœW™W——K˜šΟbœžœ4žœ žœ˜mJ™k—J˜Jš‘œžœ!žœžœ˜]K˜š‘œžœ˜(K˜——šœ4™4š ‘œžœHžœžœžœ˜rKšœ7™7—K˜š‘œžœžœ;žœžœžœžœžœžœ˜œKšœ'™'—K˜š‘œžœEžœžœ˜€Kšœ‘™‘K˜——šœ™š‘œžœžœ ˜%K™4—K˜š‘œžœ ˜K™=—K˜š‘ œžœ˜KšœB™B—K˜š‘œžœ žœžœ ˜@K™;K˜——šœ™š‘œžœ1žœ˜kK™M—K˜š‘œžœ6žœ˜sK™1—K˜š‘œžœDžœ˜‚K™2—K˜š‘œžœežœ˜‘K™2K™——K˜Kšžœ˜KšΟr™™)Kšœ ₯ί™λ—K™—…—Π?G