-- VolAllocMapImpl.mesa (last edited by: Jose on: March 23, 1981 5:28 PM)
DIRECTORY
Environment USING [bitsPerWord, wordsPerPage],
File USING [Capability, ID, PageNumber, Type],
FileInternal USING [Descriptor, FilePtr, maxPermissions, PageGroup],
FMPrograms,
Inline USING [BITAND, BITSHIFT, BITXOR],
LabelTransfer USING [VerifyLabels, WriteLabels],
LogicalVolume USING [Free, Handle, PageNumber, Vam, Vfm],
PhysicalVolume USING [ErrorType],
PilotFileTypes USING [PilotVFileType, tFreePage],
SimpleSpace USING [Create, ForceOut, Map, Page, Unmap],
Space USING [Handle, WindowOrigin],
Utilities USING [LongPointerFromPage, ShortCARDINAL],
VolAllocMap,
Volume USING [ID, nullID];
VolAllocMapImpl: MONITOR -- to protect VAM buffer; volume page is protected by callers
IMPORTS Inline, LabelTransfer, LogicalVolume, SimpleSpace, Utilities
EXPORTS FMPrograms, PhysicalVolume, VolAllocMap
SHARES File =
BEGIN OPEN Inline;
-- The following is exported to PhysicalVolume as compiler "features" prevent it from
-- being exported by PhysicalVolumeImpl.
Error: PUBLIC ERROR [PhysicalVolume.ErrorType] = CODE;
FilePtr: TYPE = FileInternal.FilePtr;
GroupPtr: TYPE = POINTER TO FileInternal.PageGroup;
LvHandle: TYPE = LogicalVolume.Handle;
-- common buffer used by procedures to Access VAM; protected by monitor
bufferHandle: Space.Handle = SimpleSpace.Create[1, hyperspace];
bufferPointer: LONG POINTER = Utilities.LongPointerFromPage[
SimpleSpace.Page[bufferHandle]];
-- Whenever lvID#Volume.nullID, the buffer is (being) mapped. Therefore, if the ID is
-- wrong and non-null, one can automatically unmap. See Close, MapInternal.
currentBufferContents: RECORD [
lvID: Volume.ID, page: LogicalVolume.PageNumber] ← [Volume.nullID, ];
bitsPerPage: CARDINAL = (Environment.bitsPerWord*Environment.wordsPerPage);
VolAllocMapImplError: ERROR [{setSizeToZeroPageGroup}] = CODE;
-- This code assumes various powers of 2 (because of the truncation).
AccessVAM: PUBLIC PROCEDURE [
vol: LvHandle, volumePage: LogicalVolume.PageNumber, set: BOOLEAN,
clear: BOOLEAN] RETURNS [busy: BOOLEAN] =
-- set, clear or read one bit of vam, always returns the (previous) value;
BEGIN
bit: WORD;
vamPage: LogicalVolume.PageNumber;
word: LONG POINTER TO WORD;
DoIt: ENTRY PROCEDURE = INLINE
BEGIN
MapVamPageInternal[vol.vID, vamPage, Vam[vol]];
busy ← (0 # Inline.BITAND[word↑, bit]);
IF (busy AND clear) OR (~busy AND set) THEN
BEGIN
word↑ ← Inline.BITXOR[word↑, bit];
vol.freePageCount ← vol.freePageCount + (IF busy THEN 1 ELSE -1);
END;
IF clear THEN vol.lowerBound ← MIN[volumePage, vol.lowerBound];
-- keep lowerBound to help allocator
IF set AND volumePage = vol.lowerBound THEN vol.lowerBound ← vol.lowerBound+1;
END;
-- The bit and word calculations can correctly be done by truncating first
bit ← Inline.BITSHIFT[
1, Utilities.ShortCARDINAL[volumePage] MOD Environment.bitsPerWord];
word ←
bufferPointer +
(Utilities.ShortCARDINAL[volumePage]/Environment.bitsPerWord) MOD
Environment.wordsPerPage;
vamPage ← vol.vamStart + volumePage/bitsPerPage;
DoIt[];
END;
-- Allocate a group of pages and write labels (group is a modifiable hint)
AllocPageGroup: PUBLIC PROCEDURE [
vol: LvHandle, filePtr: FilePtr, groupPtr: GroupPtr, createFile: BOOLEAN] =
BEGIN OPEN groupPtr;
skip: [0..1] = IF ~createFile AND filePage = 0 THEN 1 ELSE 0;
offset: LONG CARDINAL;
startPage: LogicalVolume.PageNumber = MAX[volumePage, vol.lowerBound];
IF createFile OR filePage # 0 THEN
BEGIN
volumePage ← startPage;
WHILE AccessVAM[vol, volumePage, TRUE, FALSE] DO
--search for unbusy page
IF (volumePage ← volumePage + 1) >= vol.volumeSize - 1 THEN
volumePage ← vol.lowerBound;
-- avoid the following error rather thatn backing out
IF volumePage = startPage THEN ERROR; --Volume.InsufficientSpace--
ENDLOOP;
END;
FOR offset ← 0, offset + 1 WHILE offset < nextFilePage - filePage DO
IF volumePage + offset >= vol.volumeSize THEN EXIT;
IF offset # 0 THEN
IF AccessVAM[vol, volumePage + offset, TRUE, FALSE] THEN EXIT; --first is set
ENDLOOP;
WITH filePtr SELECT FROM
local =>
IF type IN PilotFileTypes.PilotVFileType THEN filePage ← volumePage;
ENDCASE;
nextFilePage ← filePage + offset; -- side effect
IF createFile AND nextFilePage = 0 -- creating only the attribute label page
THEN offset ← 1;
[] ← LabelTransfer.VerifyLabels[
filePtr↑, FileInternal.PageGroup[0, volumePage, skip], FALSE, TRUE];
[] ← LabelTransfer.VerifyLabels[
FreeDescriptor[vol],
[volumePage + skip, volumePage + skip, volumePage + offset],
FALSE, TRUE];
-- set new file size
WITH filePtr SELECT FROM local => size ← nextFilePage; ENDCASE => ERROR;
[] ← LabelTransfer.WriteLabels[
filePtr↑, [filePage, volumePage, filePage + offset]];
END;
FreeDescriptor: PROCEDURE [v: LvHandle] RETURNS [FileInternal.Descriptor] =
INLINE
BEGIN
RETURN[
[LogicalVolume.Free[v], v.vID,
local[FALSE, FALSE, v.volumeSize, PilotFileTypes.tFreePage]]];
END;
-- free a page group (assumes calls to label operations with zero sizes are noops)
-- This is closely related to SetSize and Delete in FileImpl, as well as VolFileMap.DeletePageGroup
FreePageGroup: PUBLIC PROCEDURE [
vol: LvHandle, filePtr: FilePtr, groupPtr: GroupPtr, deleteFile: BOOLEAN] =
BEGIN
Blast: PROCEDURE [g: FileInternal.PageGroup] =
BEGIN
p, nextVolumePage: LogicalVolume.PageNumber;
nextVolumePage ← g.volumePage + g.nextFilePage - g.filePage;
FOR p ← g.volumePage, p + 1 WHILE p < nextVolumePage DO
[] ← AccessVAM[vol, p, FALSE, TRUE];
ENDLOOP;
[] ← LabelTransfer.WriteLabels[
FreeDescriptor[vol], [g.volumePage, g.volumePage, nextVolumePage]];
END; -- Always verify labels; max is for zero size file [0, ?, 0]
[] ← LabelTransfer.VerifyLabels[
filePtr↑,
[groupPtr.filePage, groupPtr.volumePage,
MAX[groupPtr.nextFilePage, 1]], FALSE, TRUE];
WITH filePtr SELECT FROM local => size ← groupPtr.filePage; ENDCASE => ERROR;
SELECT TRUE FROM
groupPtr.filePage # 0 => -- if group start#0, always blast
Blast[groupPtr↑];
groupPtr.nextFilePage # 0 -- AND g.filePage=0-- => -- Set to zero size
BEGIN
Blast[
[groupPtr.filePage + 1, groupPtr.volumePage + 1,
groupPtr.nextFilePage]];
-- we could skip the write, but then we'd have to mess around with correcting
-- zero size files
[] ← LabelTransfer.WriteLabels[filePtr↑, [0, groupPtr.volumePage, 1]];
END;
ENDCASE -- g.filePage=g.nextPage=0-- =>
IF deleteFile THEN Blast[[0, groupPtr.volumePage, 1]] --delete it--
ELSE ERROR VolAllocMapImplError[setSizeToZeroPageGroup];
END;
Vam: PROCEDURE [v: LvHandle] RETURNS [File.ID] = INLINE
{ RETURN[LogicalVolume.Vam[v]]; };
Vfm: PROCEDURE [v: LvHandle] RETURNS [File.ID] = INLINE
{ RETURN[LogicalVolume.Vfm[v]]; };
-- ENTRY PROCEDURES (Also see local proc in AccessVAM)
-- Force out/ deallocate allocation map
Close: PUBLIC ENTRY PROCEDURE [final: BOOLEAN] =
BEGIN
IF currentBufferContents.lvID # Volume.nullID THEN
IF final THEN
BEGIN
SimpleSpace.Unmap[bufferHandle];
currentBufferContents.lvID ← Volume.nullID;
END
ELSE SimpleSpace.ForceOut[bufferHandle];
END;
-- INTERNAL PROCEDURE
MapVamPageInternal: INTERNAL PROCEDURE [
vID: Volume.ID, vamPage: LogicalVolume.PageNumber, vamID: File.ID] = INLINE
BEGIN
IF currentBufferContents.lvID # vID THEN
BEGIN
IF currentBufferContents.lvID # Volume.nullID THEN
SimpleSpace.Unmap[bufferHandle];
currentBufferContents.lvID ← vID; -- and fall through for map...
END
ELSE
IF currentBufferContents.page # vamPage THEN SimpleSpace.Unmap[bufferHandle]
-- and fall through for map...
ELSE -- vids equal and pages equal, so just.... -- RETURN;
currentBufferContents.page ← vamPage;
SimpleSpace.Map[
bufferHandle, Space.WindowOrigin[
File.Capability[vamID, FileInternal.maxPermissions], vamPage], FALSE];
END;
END.
LOG
Time: April 13, 1978 3:32 PM By: Purcell Action: Created file
Time: June 23, 1978 12:27 PM By: Purcell Action: page 0 special case in alloc/free group
Time: September 27, 1978 5:15 PM By: Purcell Action: don't raise signals and limit bound
Time: October 19, 1978 2:45 PM By: Purcell Action: CR 20.103: Use FileTypes directly
Time: March 20, 1979 9:30 PM By: Redell Action: Convert to Mesa 5.0
Time: August 1, 1979 3:10 PM By: Redell Action: Convert to use FilePageLabel
Time: August 8, 1979 12:05 PM By: Redell Action: Bug fix: wraparound condition in AllocPageGroup was off by one: ran off end of volume.
Time: August 29, 1979 10:05 AM By: Forrest Action: Changed to match new interface and new FileMgr organization.
Time: September 3, 1979 12:08 PM By: Forrest Action: Used LogicalVolume.free, vam, vfm vs Opens.
Time: September 4, 1979 11:04 AM By: Forrest Action: Fixed up buffer allocation/deallocation.
Time: October 1, 1979 5:56 PM By: Forrest Action: Moved out Open to scavanger.
Time: January 9, 1980 5:43 PM By: Gobbel Action: Change for new LabelTransfer interface: VerifyLabels now returns two values.
Time: March 7, 1980 8:49 PM By: Forrest Action: Lexically change types for New Logical Volume; deleted handle from Close.
Time: June 17, 1980 10:12 AM By: Luniewski Action: Exprt PhysicalVolume.Error.
Time: January 12, 1981 1:37 PM By: Luniewski Action: New LabelTransfer interface.
Time: March 23, 1981 5:28 PM By: Jose Action: Remove signal LabelError, remove handling of error from VerifyLabels.