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
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];
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: 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;
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: BOOL ← FALSE, -- 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 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] ;
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)
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];
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:
BOOL ←
FALSE]
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];
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
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