FileInternal.mesa
Copyright © 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.
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
Data Types and minor subroutines
 File
FileID: TYPE = RECORD[INT];
 File
VolumeObject: TYPE = MONITORED RECORD[
rest: REF VolumeObject ← NIL,
id: File.VolumeID,
subVolumes: LIST OF PhysicalVolume.SubVolumeDetails,
initialised: BOOLFALSE,
destroyed: BOOLFALSE,
root: LONG POINTER TO VolumeFormat.LogicalRoot ← NIL,
rootStatus: File.RC ← inconsistent,
vamStatus: File.RC ← inconsistent,
vamChanged: BOOLFALSE,
checkpointing: BOOLTRUE,
name: Rope.ROPENIL,
size: VolumeFormat.LogicalPageCount,
free: VolumeFormat.LogicalPageCount ← 0,
vam: VAMNIL,
vamFile: File.Handle ← NIL,
lastFileID: FileID ← NULL,
freeboard: INT ← 0,
flusher: FileBackdoor.VolumeFlusher ← NIL,
flusherData: REF ANYNIL,
flushing: BOOLFALSE
];
Handle: TYPE = REF Object;
Exported to File
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: BOOLFALSE, -- marker used by FileTableImpl inside its monitor
users: INT ← 0, -- per-file shared/exclusive interlock. Accessed under FileImpl monitor lock
The remaining fields (and fp.da) are accessed only under the per-file interlock, or during initialization or finalization of the object
state: { none, opened, deleted } ← none,
headerVMPages: INT ← 0, -- how many to free
headerVM: LONG POINTERNIL,
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] ;
SwapIn and do the I/O
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 ];
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.
CheckStatus: PROC[status: Disk.Status, diskPage: INT];
Convert status to an File.Error ERROR if not ok.
-- ******** Labels ******** --
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];
-- ******** Checkpoint and Rollback (and ReadRootPage) ******** --
Checkpoint and Rollback (and ReadRootPage)
LockAndCloseFiles: PROC;
Lock all existing file objects, and ensure next access will re-open them; suspend future file object creations.
UnlockFiles: PROC;
Unlock existing file objects and allow creation of new ones.
LockVolume: PROC[volume: File.Volume];
Lock volume to suspend subsequent access to its monitored data or VAM file; unlock by calling ReadRootPage.
ReadRootPage: PROC[volume: File.Volume];
Reads the volume's VAM from disk and records free page count; unlocks if volume was locked for a checkpoint.
InitRootPage: PROC[volume: File.Volume, name: Rope.ROPE] RETURNS[File.RC];
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.
LockMode: TYPE = { shared, exclusive };
Lock: PROC[file: Handle, mode: LockMode];
Acquire lock on file (for use by LockAndCloseFiles in FileTableImpl)
Unlock: PROC[file: Handle];
Release previously acquired lock on file (for use by UnlockFiles in FileTableImpl)
Acquire: PROC[file: Handle, mode: LockMode];
Bad page table
PhysicalPageBad: PROC[physical: PhysicalVolume.Physical, address: Disk.PageNumber] RETURNS[ badTableFull: BOOL, status: PhysicalVolume.PhysicalRC ];
Record page as bad in the physical volume root
GetBadPages: PROC[subVolume: PhysicalVolume.SubVolumeDetails, work: PROC[VolumeFormat.LogicalPage]];
Enumerate the bad pages in the subvolume
Access to volume root page and volume's list of sub-volumes
TranslateLogicalRun: PROC[logicalRun: VolumeFormat.LogicalRun, volume: File.Volume]
RETURNS[channel: Disk.Channel, diskPage: Disk.PageNumber];
Gives physical-volume-relative data for a logical-volume-relative run
RecordRootFile: PROC[volume: File.Volume, root: File.VolumeFile, fp: File.FP, page: File.PageNumber, id: DiskFace.RelID, link: DiskFace.DontCare, channel: Disk.Channel];
Records the root file in the logical volume root page.
NewID: PROC[volume: File.Volume] RETURNS [File.FileID];
Issues a new unique ID, ensuring all issued ID's are recorded in the volume root
WriteLogicalMarkers: PROC[volume: File.Volume] RETURNS[File.RC];
Replicates critical logical root information in the volume marker pages. See PhysicalVolumeImpl.
InitLogicalMarkers: PROC[volume: File.Volume] RETURNS[File.RC];
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
VAM: TYPE = LONG POINTER TO VolumeFormat.VAMObject;
FindLargestFreeBlockInBiggestSubVolume: PROC[volume: File.Volume] RETURNS [first: VolumeFormat.LogicalPage, count: VolumeFormat.LogicalPageCount, subVolume: PhysicalVolume.SubVolumeDetails];
Find the largest free piece of disk. The only use of this is for allocating the VM Backing File
IsUsed: PROC[volume: File.Volume, page: VolumeFormat.LogicalPage] RETURNS [inUse: BOOL];
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.
SetPageUsed: PROC[volume: File.Volume, page: VolumeFormat.LogicalPage, inUse: BOOL] RETURNS [wasInUse: BOOL];
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.
Alloc: PROC[volume: File.Volume, first: VolumeFormat.LogicalPage,
size, min: VolumeFormat.LogicalPageCount]
RETURNS[given: VolumeFormat.LogicalRun];
Find a logical run marked free in the in-core VAM. May be smaller than "size", but is never smaller than "min"
Free: PROC[volume: File.Volume, logicalRun: VolumeFormat.LogicalRun];
Mark the logical run free in the in-core VAM.
Commit: PROC[volume: File.Volume];
Ensure the volume's VAM is up to date on disk
Flush: PROC[volume: File.Volume, lack: VolumeFormat.LogicalPageCount] RETURNS[BOOL];
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
RunsToHeaderPages: PROC[runs: CARDINAL] RETURNS [pages: VolumeFormat.LogicalPageCount];
HeaderPagesToRuns: PROC[pages: VolumeFormat.LogicalPageCount] RETURNS [runs: CARDINAL];
WriteRunTable: PROC[file: Handle];
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.
GetHeaderVM: PROC[file: Handle, runs: CARDINAL, propertyPages: CARDINAL ← 1];
Allocate VM for a file's header, initializing file.logicalRunTable.
FreeHeaderVM: PROC[file: Handle];
Free VM that was used for file's header.
TranslateLogicalRunTable: PROC[file: Handle, prefixOnly: BOOLFALSE] RETURNS[ File.PageCount ];
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)
AddRun: PROC[file: Handle,
run: POINTER TO PhysicalRun,
logicalPage: VolumeFormat.LogicalPage,
okPages: VolumeFormat.RunPageCount];
Add pages to the file's physical and logical run tables
LastLogicalPage: PROC[file: Handle] RETURNS [VolumeFormat.LogicalPage];
Returns the logical page number of the last page of the file.
RemoveFromRunTable: PROC[file: Handle, remove: INT];
Removes pages from the file's physical and logical run tables
FindRun: PROC[start: File.PageNumber, nPages: File.PageCount, runTable: RunTable]
RETURNS[diskPage: Disk.PageNumber, size: Disk.PageCount, channel: Disk.Channel];
Find the physical location of contiguous initial subset of the given pages of the file.
SplitPhysicalRunTable: PROC[file: File.Handle, page: VolumeFormat.LogicalPage] RETURNS [runNumber: CARDINAL];
Split the run table so that a new run begins at "page". This assumes that the run table will not overflow.
ExtendFileHeader: PROC[file: File.Handle, newRunPages: CARDINAL, newPropertyPages: CARDINAL];
RegisterVMFile: PROC[file: File.Handle];
Operations involving access to pages within a volume
FreeRun: PROC[logicalRun: VolumeFormat.LogicalRun, volume: File.Volume, verifyLabel: POINTER TO Disk.Label ← NIL];
Write labels of specified pages marking them as "free".
EnumeratePagesProc: TYPE = PROC[status: Disk.Status, da: VolumeFormat.LogicalPage, label: POINTER TO Disk.Label, diskPage: INT] RETURNS[exit: BOOLFALSE];
diskPage is only valid when status # ok
EnumeratePages: PROC[volume: File.Volume, start: VolumeFormat.LogicalPage, skipBadPages: BOOLTRUE, work: EnumeratePagesProc];
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
AllocForCreate: PROC RETURNS[Handle];
Allocate an object, but don't place it in the table.
Insert: PROC [Handle];
Insert the object into the table (after successful creation).
DontInsert: PROC;
Note that a handle returned from AllocForCreate has been abandoned
Lookup: PROC [volume: File.Volume, fp: File.FP] RETURNS[Handle];
Look-up the [volume,fp] in the table, inserting if needed.
Boot Locations
GetFileLocation: PROC [file: File.Handle, firstPage: File.PageNumber] RETURNS[location: BootFile.Location];
Get location for passing to germ. Also writes bootchain links into the file.
GetLogicalLocation: PROC [volume: File.Volume, root: VolumeFormat.LVBootFile] RETURNS[location: BootFile.Location];
Get location of the appropriate logical root file
GetPhysicalLocation: PROC [physical: PhysicalVolume.Physical, root: VolumeFormat.PVBootFile] RETURNS[location: BootFile.Location];
Get location of the appropriate physical root file
SetPhysicalLocation: PROC [physical: PhysicalVolume.Physical, root: VolumeFormat.PVBootFile, diskFileID: BootFile.DiskFileID] RETURNS[PhysicalVolume.PhysicalRC];
Set location of the appropriate physical root file
END.

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