-- Filer>SubVolumeImpl.mesa (last edited by Luniewski on February 5, 1981 6:41 PM)
--Things to consider:
--1) Taking subvolumes offline needs more synchronization. Can probably cover subvolumes with filecache reference counts since holder of a SubVolume.Handle usually holds a FilePtr for a file on the subvolume. Offline must then flush file cache before removing subvolume (allows pending I/O to complete).
DIRECTORY
DiskChannel USING [
Address, Command, CompletionHandle, CreateCompletionObject, GetPageAddress,
Handle, --Idle,--InitiateIO, IORequestHandle, nullHandle, --Restart,--
WaitAny],
Environment USING [PageNumber],
File USING [ID, PageCount, PageNumber],
FileInternal USING [Operation],
FilePageLabel USING [Label, nullLabel, SetFilePage, SetType],
FilerPrograms,
FileTask USING [DiskFinish, DiskStart],
PhysicalVolumeFormat USING [SubVolumeDesc],
Process USING [GetPriority, Priority, SetPriority],
ProcessPriorities USING [priorityPageFaultHigh],
RuntimeInternal USING [WorryCallDebugger],
SubVolume USING [Descriptor, Handle, IOptr],
Volume USING [ID],
VolumeInternal USING [PageNumber];
SubVolumeImpl: MONITOR
IMPORTS DiskChannel, FilePageLabel, FileTask, Process, RuntimeInternal
EXPORTS SubVolume, FilerPrograms =
BEGIN OPEN DiskChannel; -- Preliminary version of subvolume cache
-- Gasp! each opened physical Volume takes one cacheEntry
-- plus 1 for each real subvolume.
cacheSize: CARDINAL = 12;
CacheIndex: TYPE = [1..cacheSize];
CacheEntry: TYPE = RECORD [occupied: BOOLEAN, svDesc: SubVolume.Descriptor];
CePtr: TYPE = ORDERED POINTER TO CacheEntry;
ceFirst: CePtr = LOOPHOLE[@cache[FIRST[CacheIndex]]]; -- loophole for Ordered
ceLast: CePtr = LOOPHOLE[@cache[LAST[CacheIndex]]];
cache: ARRAY CacheIndex OF CacheEntry ← ALL[[FALSE, ]];
completion: PUBLIC CompletionHandle;
InitializeSubVolume: PROCEDURE [] =
BEGIN
throwAway: PROCESS;
priorityPrev: Process.Priority;
completion ← CreateCompletionObject[];
priorityPrev ← Process.GetPriority[];
Process.SetPriority[ProcessPriorities.priorityPageFaultHigh];
throwAway ← FORK FinishIO[]; -- (no profit in Detaching)
Process.SetPriority[priorityPrev];
END;
ErrorHalt: PROCEDURE [s: STRING] = --Signals down here are bad--
BEGIN RuntimeInternal.WorryCallDebugger[s] END;
Find: PUBLIC ENTRY PROCEDURE [vID: Volume.ID, page: VolumeInternal.PageNumber]
RETURNS [success: BOOLEAN, subVolume: SubVolume.Handle] =
BEGIN [success, subVolume] ← FindSV[vID, page]; END;
FindSV: INTERNAL PROCEDURE [vID: Volume.ID, page: VolumeInternal.PageNumber]
RETURNS [BOOLEAN, SubVolume.Handle] = INLINE
BEGIN
cePtr: CePtr;
FOR cePtr ← ceFirst, cePtr + SIZE[CacheEntry] WHILE cePtr <= ceLast DO
IF cePtr.occupied AND vID = cePtr.svDesc.lvID AND
page IN [cePtr.svDesc.lvPage..cePtr.svDesc.lvPage + cePtr.svDesc.nPages) THEN
RETURN[TRUE, @cePtr.svDesc];
ENDLOOP;
RETURN[FALSE, NIL]
END;
GetNext: PUBLIC ENTRY PROCEDURE [inSubVolume: SubVolume.Handle]
RETURNS [outSubVolume: SubVolume.Handle] =
BEGIN
cePtr: CePtr;
found: BOOLEAN ← inSubVolume = NIL;
FOR cePtr ← ceFirst, cePtr + SIZE[CacheEntry] WHILE cePtr <= ceLast DO
IF found THEN {IF cePtr.occupied THEN RETURN[@cePtr.svDesc]}
ELSE found ← (inSubVolume = @cePtr.svDesc);
ENDLOOP;
IF ~found THEN ErrorHalt["illegalSubvolumeHandle"L];
RETURN[NIL]
END;
GetPageAddress: PUBLIC ENTRY PROCEDURE [
vID: Volume.ID, page: VolumeInternal.PageNumber]
RETURNS [channel: DiskChannel.Handle, address: DiskChannel.Address] =
BEGIN
found: BOOLEAN;
svH: SubVolume.Handle;
[found, svH] ← FindSV[vID, page];
IF NOT found THEN ErrorHalt["getPageAddressFailure"L];
RETURN[
svH.channel,
DiskChannel.GetPageAddress[svH.channel, svH.pvPage + (page - svH.lvPage)]]
END;
OnLine: PUBLIC ENTRY PROCEDURE [
subVolume: PhysicalVolumeFormat.SubVolumeDesc, channel: DiskChannel.Handle] =
BEGIN OPEN subVolume;
cePtr: CePtr;
FOR cePtr ← ceFirst, cePtr + SIZE[CacheEntry] WHILE cePtr <= ceLast DO
IF ~cePtr.occupied THEN
BEGIN
cePtr↑ ←
[occupied: TRUE,
svDesc:
[lvID: lvID, lvPage: lvPage, pvPage: pvPage, nPages: nPages,
channel: channel]];
RETURN;
END;
ENDLOOP;
ErrorHalt["subvolume cache overflow"L];
END;
-- Flush Subvolume; (null Handle flushes all subvolumes of a given logical volume)
OffLine: PUBLIC ENTRY PROCEDURE [vID: Volume.ID, channel: DiskChannel.Handle] =
BEGIN
cePtr: CePtr;
FOR cePtr ← ceFirst, cePtr + SIZE[CacheEntry] WHILE cePtr <= ceLast DO
OPEN cePtr;
IF svDesc.lvID = vID AND
(channel = DiskChannel.nullHandle OR channel = svDesc.channel) THEN
occupied ← FALSE;
ENDLOOP;
END;
--Acquire: PUBLIC ENTRY PROCEDURE =
--BEGIN ++ Idles all Pilot subvolumes to allow Alto file I/O
--cePtr: CePtr;
--FOR cePtr ← ceFirst, cePtr+SIZE[CacheEntry] WHILE cePtr <= ceLast
--DO IF cePtr.occupied THEN Idle[cePtr.svDesc.channel]; ENDLOOP;
--END;
--Release: PUBLIC ENTRY PROCEDURE =
--BEGIN ++ Restarts all Pilot subvolumes when Alto file I/O is completed
--cePtr: CePtr;
--FOR cePtr ← ceFirst, cePtr+SIZE[CacheEntry] WHILE cePtr <= ceLast
--DO IF cePtr.occupied THEN Restart[cePtr.svDesc.channel]; ENDLOOP;
--END;
StartIO: PUBLIC --ENTRY--PROCEDURE [io: SubVolume.IOptr] =
BEGIN
labelSize: CARDINAL = SIZE[FilePageLabel.Label];
ErrorHalt1: PROCEDURE RETURNS [DiskChannel.Command] = LOOPHOLE[ErrorHalt];
requestHandle: IORequestHandle;
properLabel: FilePageLabel.Label ← FilePageLabel.nullLabel;
properLabel.fileID ← io.filePtr.fileID;
FilePageLabel.SetFilePage[@properLabel, io.filePage];
IF io.chained THEN properLabel.bootChainLink ← LOOPHOLE[io.link];
WITH io.filePtr SELECT FROM -- couldn't his be done at a higher level???
local =>
BEGIN
FilePageLabel.SetType[@properLabel, type];
IF io.filePage = 0 THEN
BEGIN
properLabel.immutable ← immutable;
properLabel.temporary ← temporary;
properLabel.zeroSize ← (size = 0);
END;
END;
ENDCASE => ErrorHalt["can't do label operations on remote files"L];
requestHandle ← FileTask.DiskStart[io.memPage, io.pageCount, io.filePtr, io.op];
BEGIN OPEN requestHandle;
channel ← io.subVolume.channel;
diskPage ← io.subVolume.pvPage + io.subVolumePage;
label↑ ← LOOPHOLE[properLabel];
memoryPage ← io.memPage;
count ← io.pageCount;
dontIncrement ← io.fixedMemPage;
command ←
SELECT io.op FROM
read => vvr,
write => vvw,
readLabel => vrr,
writeLabel => vww,
verifyLabel => vvr,
readLabelAndData => vrr,
writeLabelsAndData => vww,
ENDCASE => ErrorHalt1[];
END;
InitiateIO[requestHandle];
END;
FinishIO: PROCEDURE = -- root of Finisher process
BEGIN
requestHandle: IORequestHandle;
labelValid: BOOLEAN ← TRUE;
hardErrorString: STRING ← "Unrecoverable disk error page XXXXX";
DO
requestHandle ← WaitAny[completion];
FileTask.DiskFinish[requestHandle];
ENDLOOP;
END;
InitializeSubVolume[];
END.
LOG
February 22, 1979 4:33 PM Redell Created file from old DiskImpl and VolumeCacheImpl.
March 21, 1979 6:00 PM Redell Converted to Mesa 5.0.
March 26, 1979 4:50 PM Redell Fixed typo: write => put in StartIO.
July 30, 1979 10:44 AM Forrest Made compile with new subvolume. Upped cache to 8.
August 13, 1979 6:32 PM Redell Added bootchain machinery; will be modified when disk driver is changed to accept runs of pages.
September 10, 1979 6:29 PM Forrest Use Pilot file types vs fileTypes.
September 19, 1979 8:54 AM Forrest Add GetNext; Change Offline to also take channel Handle.
September 21, 1979 11:43 AM Forrest Add Set/GetMarker ID.
September 22, 1979 2:44 PM Forrest took out Set/GetMarker ID.
November 26, 1979 3:45 PM Gobbel Changes for new DiskChannel (runs of pages).
December 13, 1979 7:20 PM Gobbel Added fixedMemPage option, make parameter to StartIO be handle on a record.
January 22, 1980 1:38 PM Gobbel Tell disk page number when we go to the debugger for a hard error.
January 30, 1980 3:30 PM Gobbel Remove Alto file stuff.
May 20, 1980 3:04 PM Luniewski PhysicalVolume => PhysicalVolumeFormat.
January 9, 1981 4:15 PM Luniewski Move error handling on I/O completion to FileTask.
January 20, 1981 1:35 PM Knutsen Change process priority.
February 5, 1981 6:41 PM Luniewski FineInternal.FilePtr no longer needed.