-- 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.