Cedar Nucleus (Files): internal interface
FileInternal.mesa
Andrew Birrell December 7, 1983 6:10 pm
Last Edited by: Levin, August 8, 1983 5:54 pm
DIRECTORY
BootFile USING[ DiskFileID, Location ],
Disk USING[ Channel, invalid, Label, labelCheck, ok, PageNumber, PageCount, Status],
DiskFace USING[ DontCare, RelID],
File USING[ FP, FileID, Handle, nullFP, PageCount, PageNumber, PropertyStorage, RC, Volume, VolumeFile, VolumeFlusher, VolumeID ],
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
-- ******** 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: File.VolumeFlusher ← NIL,
flusherData: REF ANYNIL,
flushing: BOOLFALSE];
Handle: TYPE = REF Object;
--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,
logicalRunTable: LONG POINTER TO VolumeFormat.LogicalRunObject ← NIL,
runTable: RunTable ← NIL ];
RunTable: TYPE = REF VMBacking.RunTableObject;
PhysicalRun: TYPE = VMBacking.Run;
TranslateStatus: PROC[status: Disk.Status] RETURNS [File.RC] = INLINE
BEGIN
RETURN[
SELECT status FROM
Disk.ok => ok,
Disk.labelCheck => software,
Disk.invalid => wentOffline,
ENDCASE => hardware ]
END;
-- ******** 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)
-- ******** Bad page table ******** --
PhysicalPageBad: PROC[physical: PhysicalVolume.Physical, address: Disk.PageNumber] RETURNS[ 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;
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 ******** --
GetHeaderVM: PROC[file: Handle, runs: CARDINAL];
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] RETURNS[ File.PageCount ];
Copy file's logical run table into newly allocated physical run table.
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.
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] RETURNS[exit: BOOLFALSE];
EnumeratePages: PROC[volume: File.Volume, start: VolumeFormat.LogicalPage, 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.