-- FileMgr>FileImpl.mesa (December 9, 1982 11:37 am by Levin)
-- Note on monitors in this module: All procedures in this module that must read or change entries in the FileMgr's caches do their actual work through LogicalVolume.VolumeAccess, and are thus protected by VolumeImpl's monitor lock from inconsistencies that might otherwise result if cache accesses were interleaved. Simply (I hope) stated: VolumeImpl's monitor is used to insure the consistency of individual cache entries, FileCacheImpl's monitor insures consistency of the global state of the caches, and FileImpl's monitor is used to serialize access to files at a higher level (i.e., above the level of the caches). There is at least one procedure, GetFileDescriptor, which must be outside of FileImpl's monitor (because it is used by the FileHelper), but which must access the FileMgr caches.
DIRECTORY
Boot USING [Location, LVBootFiles],
Device USING [Type],
DiskChannel USING [Address, Handle, Drive, GetAttributes, GetDriveAttributes,
GetDriveTag],
Environment USING [PageCount, PageNumber, wordsPerPage],
File USING [Capability, delete, ErrorType, grow, ID, lastPageNumber, nullCapability,
nullID, PageCount, PageNumber, Permissions, read, shrink, Type, write],
FileCache USING [FlushFile, GetFilePtrs, GetPageGroup, SetFile, SetPageGroup,
ReturnFilePtrs],
FileInternal USING [Descriptor, FilePtr, LocalFilePtr, maxPermissions, PageGroup],
FilePageTransfer USING [Initiate, Request],
FilerException USING [Await],
FMPrograms USING [MarkerPageImpl, PhysicalVolumeImpl, VolAllocMapImpl,
VolFileMapImpl],
Inline USING [BITAND, LowHalf],
KernelFile USING [defaultPageCount, GetNextFile, GetRootFile],
LabelTransfer USING [ReadLabel, VerifyLabels, WriteLabelAndData],
LogicalVolume USING [CloseLogicalVolume, FileVolumeStatus, FreeVolumePages,
Handle, nullVolumePage, OpenLogicalVolume, PageNumber, PutRootFile,
VolumeAccess, VolumeAccessProc, VolumeAccessStatus],
PilotDisk USING [Address, GetLabelFilePage, Label, LabelCheckSum, SetLabelFilePage],
PilotFileTypes USING [PilotRootFileType, PilotVFileType, tTempFileList],
PilotSwitches USING [switches --.f--],
Process USING [GetPriority, Priority, SetPriority],
ProcessPriorities USING [priorityPageFaultHigh],
Runtime USING [CallDebugger],
SimpleSpace USING [Create, ForceOut, Handle, Map, Page, Unmap],
Space USING [defaultWindow],
SpecialFile USING [Link],
SpecialVolume USING [GetLogicalVolumeBootFiles, SetLogicalVolumeBootFiles],
StoragePrograms,
SubVolume USING [Find, GetPageAddress, Handle],
System USING [GetUniversalID, VolumeID],
SystemInternal USING [ --altoFPSeries,--Unimplemented],
Transaction USING [Handle, InvalidHandle, nullHandle],
TransactionState USING [FileOps, Log, LogEntry],
Utilities USING [LongPointerFromPage],
VMMapLog USING [Entry],
VolAllocMap USING [AllocPageGroup, FreePageGroup],
VolFileMap USING [DeletePageGroup, GetPageGroup, InsertPageGroup],
Volume USING [GetNext, ID, InsufficientSpace, NeedsScavenging, NotOpen, nullID,
systemID, TypeSet, Unknown];
FileImpl: MONITOR
IMPORTS
DiskChannel, FileCache, FilePageTransfer, FilerException, FMPrograms, Inline,
KernelFile, LabelTransfer, LogicalVolume, PilotDisk, PilotSwitches,
Process, Runtime, SimpleSpace, SpecialVolume, SubVolume, System,
SystemInternal, Transaction, TransactionState, Utilities, VolAllocMap,
VolFileMap, Volume
EXPORTS File, LogicalVolume, KernelFile, SpecialFile, StoragePrograms
SHARES DiskChannel, File, System, SystemInternal =
BEGIN OPEN File, FileInternal;
VolProc: TYPE = LogicalVolume.VolumeAccessProc;
-- One-page buffer used by MakePermanent, MakeImmutable, MakeBootable:
pageBuffer: SimpleSpace.Handle = SimpleSpace.Create[1, hyperspace];
bufferPage: Environment.PageNumber = SimpleSpace.Page[pageBuffer];
bufferPointer: LONG POINTER = Utilities.LongPointerFromPage[bufferPage];
-- Temporary File list used by DeleteTemps and EnterInTempFileList
-- (these values assume list entries do not overlap pages)
tmpsBuffer: SimpleSpace.Handle ← SimpleSpace.Create[1, hyperspace];
tmpsVolume: Volume.ID ← Volume.nullID;
tmpsFile: File.Capability;
tmpsFileSize: File.PageCount;
tmpStart: LONG POINTER TO File.ID =
Utilities.LongPointerFromPage[SimpleSpace.Page[tmpsBuffer]];
tmpsLast: LONG POINTER TO File.ID =
tmpStart+(Environment.wordsPerPage/SIZE[File.ID])*SIZE[File.ID];
tmps: LONG POINTER TO File.ID;
nullTransaction: Transaction.Handle = Transaction.nullHandle;
AttributeAction: TYPE = {immutable, permanent, mutable, temporary};
Error: PUBLIC ERROR [type: ErrorType] = CODE;
InvalidParameters: PUBLIC ERROR = CODE;
LabelError: SIGNAL = CODE;
Unknown: PUBLIC ERROR [file: Capability] = CODE;
ExistingFile: PUBLIC ERROR = CODE;
FileImplError: ERROR [{disappearedOrRemoteTempFile, fileWithHole, illegalAttributeAction,
impossibleFileType, makeBootablePageGroupNotFound, makeBootableImpossibleError,
missingPage0, missingPageGroupSetSize, missingPinnedPageGroup, remoteTmpsFile,
remoteTxLog, SubvolumeNotFoundInGetFilePoint, tmpsFileProblem, tmpsFileWentAway,
tmpsVolumeWentAway, volumeWentAwayDuringDeleteTemps, setSizeImpossibleError}] =
CODE;
-- MONITOR EXTERNAL PROCEDURES
Create: PUBLIC SAFE PROCEDURE [volume: System.VolumeID, initialSize: PageCount, type: Type,
transaction: Transaction.Handle] RETURNS [file: Capability] = TRUSTED
BEGIN
IF type IN PilotFileTypes.PilotVFileType THEN ERROR Error[reservedType];
file ← [[System.GetUniversalID[]], FileInternal.maxPermissions];
CreateWithIDExternal[volume, initialSize, type, file.fID, transaction];
END;
CreateWithID: PUBLIC PROCEDURE [volume: System.VolumeID, initialSize: PageCount,
type: Type, id: ID] = -- Create file given the file identifier
{CreateWithIDExternal[volume, initialSize, type, id]};
Delete: PUBLIC PROCEDURE [file: Capability, transaction: Transaction.Handle] =
{DeleteCommon[@file, NIL, transaction]};
DeleteImmutable: PUBLIC PROCEDURE [file: Capability, volume: System.VolumeID,
transaction: Transaction.Handle] =
{DeleteCommon[@file, @volume, transaction]};
FileHelperProcess: PROCEDURE =
BEGIN
helpCount: CARDINAL ← 0; -- for perfomance monitoring.
fileD: FileInternal.Descriptor;
req: FilePageTransfer.Request;
DO --FOREVER--
req ← FilerException.Await[];
GetFileDescriptorSignals[@req.file, @fileD]; -- file cache updated as side effect
WITH fileD SELECT FROM
local =>
BEGIN
Helper1: VolProc =
BEGIN
fPtr: FileInternal.FilePtr;
success: BOOLEAN;
group: FileInternal.PageGroup;
updateMarkers ← FALSE;
[success, fPtr] ← FileCache.GetFilePtrs[1, fileD.fileID];
IF ~success THEN RETURN; -- fell out of cache, let exception happen again
[success, group] ←
VolFileMap.GetPageGroup[volume, @fileD, req.filePage];
IF (success ← (success AND req.filePage<group.nextFilePage)) THEN
FileCache.SetPageGroup[req.file.fID, group, FALSE]; -- page is within file?
FileCache.ReturnFilePtrs[1, fPtr];
IF ~success THEN Runtime.CallDebugger["Mapped off File (Helper)"L];
END;
SELECT LogicalVolume.VolumeAccess[@fileD.volumeID, Helper1] FROM
ok => NULL;
ENDCASE => Runtime.CallDebugger[
"Volume vanished between Descriptor and PageGroup (Helper)"];
END; --Helper1--
remote => NULL;
ENDCASE;
FilePageTransfer.Initiate[req];
helpCount ← helpCount+1;
ENDLOOP
END;
GetAttributes: PUBLIC SAFE PROCEDURE [file: Capability, transaction: Transaction.Handle]
RETURNS [type: Type, immutable, temporary: BOOLEAN, volume: System.VolumeID] = TRUSTED
BEGIN
f: FileInternal.Descriptor;
GetFileDescriptorSignals[@file, @f];
WITH f SELECT FROM
local => RETURN[type, immutable, temporary, f.volumeID];
ENDCASE => --RETURN[File.Type[0], FALSE, FALSE, VolumeInternal.altoVolume]
ERROR SystemInternal.Unimplemented
END;
GetBootLocation: PUBLIC PROCEDURE [
file: File.Capability, filePage: File.PageNumber]
RETURNS [deviceType: Device.Type, deviceOrdinal: CARDINAL, link: SpecialFile.Link] =
BEGIN
v: Volume.ID;
grp: FileInternal.PageGroup;
channel: DiskChannel.Handle;
GetVIDAndGroup[@v, @grp, @file, filePage]; -- set vID, group
[channel, LOOPHOLE[link, DiskChannel.Address]] ←
SubVolume.GetPageAddress[v, grp.volumePage+(filePage-grp.filePage)];
[deviceType: deviceType, deviceOrdinal: deviceOrdinal] ←
DiskChannel.GetDriveAttributes[DiskChannel.GetAttributes[channel].drive];
END;
GetFileDescriptor: PROCEDURE [
file: POINTER TO READONLY File.Capability, fileD: FileInternal.FilePtr,
vP: POINTER TO READONLY Volume.ID ← NIL] RETURNS [found: BOOLEAN] =
-- Look up file in cache and then in given volume or all volumes (vP=NIL),
-- and set the descriptor. Return success
BEGIN
fPtr: FileInternal.FilePtr;
success: BOOLEAN;
v: Volume.ID;
getAll: Volume.TypeSet = [normal: TRUE, debugger: TRUE, debuggerDebugger: TRUE];
GetFileDescriptor1: VolProc =
BEGIN
group: FileInternal.PageGroup;
label: PilotDisk.Label;
lf: local FileInternal.Descriptor ← [file.fID, v, local[, , , ]];
updateMarkers ← FALSE;
[success, group] ← VolFileMap.GetPageGroup[volume, @lf, 0];
IF ~success THEN RETURN;
label ← LabelTransfer.ReadLabel[lf, 0, group.volumePage].label;
IF label.fileID#lf.fileID OR PilotDisk.GetLabelFilePage[@label]#0 THEN
SIGNAL LabelError;
lf.body ← local[
immutable: label.immutable, temporary: label.temporary,
size: VolFileMap.GetPageGroup[
volume, LONG[@lf], File.lastPageNumber].group.filePage,
type: label.type];
-- success??
fileD↑ ← lf;
DO
FileCache.SetFile[lf, FALSE];
[success, fPtr] ← FileCache.GetFilePtrs[1, lf.fileID];
IF success THEN
BEGIN
FileCache.SetPageGroup[lf.fileID, group, FALSE];
FileCache.ReturnFilePtrs[1, fPtr];
RETURN;
END;
ENDLOOP;
END;
IF file.fID = File.nullID THEN RETURN[FALSE];
--IF LOOPHOLE[file.fID, SystemInternal.UniversalID].series=SystemInternal.altoFPSeries THEN
--IF GetAltoSize[file]=0 THEN ERROR Unknown[file↑] ELSE RETURN[[file.fID, VolumeInternal.altoVolume, remote[]]];
[success, fPtr] ← FileCache.GetFilePtrs[1, file.fID];
IF success THEN
BEGIN
fileD↑ ← fPtr↑;
FileCache.ReturnFilePtrs[1, fPtr];
IF vP=NIL OR fileD.volumeID=vP↑ THEN RETURN[TRUE];
END;
v ← IF vP=NIL THEN Volume.GetNext[Volume.nullID, getAll] ELSE vP↑;
WHILE v#Volume.nullID DO
IF LogicalVolume.VolumeAccess[@v, GetFileDescriptor1]=ok AND success THEN
RETURN[TRUE];
IF vP#NIL THEN EXIT ELSE v ← Volume.GetNext[v, getAll];
ENDLOOP;
RETURN[FALSE];
END;
GetFileDescriptorSignals: PROCEDURE [
file: POINTER TO READONLY File.Capability, fileD: FileInternal.FilePtr,
vP: POINTER TO READONLY Volume.ID ← NIL] =
BEGIN
IF ~GetFileDescriptor[file, fileD, vP].found THEN ERROR Unknown[file↑];
END;
GetFilePoint: PUBLIC PROCEDURE [
pEntry: LONG POINTER TO VMMapLog.Entry, pFile: POINTER TO File.Capability,
filePage: File.PageNumber] =
BEGIN
countMax: CARDINAL = 4096;
vID: Volume.ID;
group: FileInternal.PageGroup;
lvPage: LogicalVolume.PageNumber;
success: BOOLEAN;
svH: SubVolume.Handle;
label: PilotDisk.Label;
GetVIDAndGroup[@vID, @group, pFile, filePage];
lvPage ← filePage-group.filePage+group.volumePage;
-- file => logical vol page
[success, svH] ← SubVolume.Find[vID, lvPage];
IF ~success THEN ERROR FileImplError[SubvolumeNotFoundInGetFilePoint];
label.fileID ← pFile.fID;
PilotDisk.SetLabelFilePage[@label, filePage];
pEntry↑ ←
[page:, writeProtected:, fill:,
count: MIN[countMax, Inline.LowHalf[group.nextFilePage-filePage]],
filePoint: disk[
driveTag: DiskChannel.GetDriveTag[DiskChannel.GetAttributes[svH.channel].drive],
diskPage: lvPage-svH.lvPage+svH.pvPage,
-- logical vol => physical vol page,
labelCheck: PilotDisk.LabelCheckSum[@label, 0]]];
END;
GetSize: PUBLIC SAFE PROCEDURE [file: Capability, transaction: Transaction.Handle]
RETURNS [size: PageCount] = TRUSTED
BEGIN
fileD: FileInternal.Descriptor;
GetFileDescriptorSignals[@file, @fileD];
RETURN[
WITH fileD SELECT FROM
local => size,
ENDCASE => --GetAltoSize[@file]--ERROR SystemInternal.Unimplemented]
END;
IsOnVolume: PUBLIC SAFE PROCEDURE [file: Capability, volume: System.VolumeID] = TRUSTED
BEGIN
fileD: FileInternal.Descriptor;
IF ~GetFileDescriptor[@file, @fileD] THEN
FileCache.SetFile[[file.fID, volume, remote[]], FALSE];
END;
MakeBootable: PUBLIC PROCEDURE [
file: File.Capability, firstPage: File.PageNumber, count: File.PageCount,
lastLink: SpecialFile.Link] RETURNS [firstLink: SpecialFile.Link] =
BEGIN
RETURN[LOOPHOLE[MakeBootableOrUnbootable[
bootable, @file, firstPage, count, LOOPHOLE[lastLink]]]];
END;
MakeImmutable: PUBLIC PROCEDURE [file: Capability, transaction: Transaction.Handle] =
{ChangeAttributes[@file, immutable, transaction]};
MakeMutable: PUBLIC PROCEDURE [file: Capability] =
{ChangeAttributes[@file, mutable]};
MakePermanent: PUBLIC SAFE PROCEDURE [file: Capability, transaction: Transaction.Handle] =
TRUSTED {ChangeAttributes[@file, permanent, transaction]};
MakeTemporary: PUBLIC PROCEDURE [file: Capability] =
BEGIN
fileD: FileInternal.Descriptor;
IF ~GetFileDescriptor[@file, @fileD] THEN ERROR Unknown[file];
TmpsEnter[@file, @fileD.volumeID];
ChangeAttributes[@file, temporary];
END;
MakeUnbootable: PUBLIC PROCEDURE [
file: File.Capability, firstPage: File.PageNumber, count: File.PageCount] =
{[] ← MakeBootableOrUnbootable[unbootable, @file, firstPage, count, ]};
Move: PUBLIC PROCEDURE [
file: Capability, volume: System.VolumeID, transaction: Transaction.Handle] =
{SIGNAL SystemInternal.Unimplemented};
ReplicateImmutable: PUBLIC SAFE PROCEDURE [
file: Capability, volume: System.VolumeID, transaction: Transaction.Handle] = TRUSTED
{SIGNAL SystemInternal.Unimplemented};
SetDebuggerFiles: PUBLIC PROCEDURE [debugger, debuggee: File.Capability] =
BEGIN
bootFiles: Boot.LVBootFiles;
fileD: FileInternal.Descriptor;
dTEr, dTEe: Device.Type;
dOEr, dOEe: CARDINAL;
linkEr, linkEe: SpecialFile.Link;
id: Volume.ID = Volume.systemID;
[deviceType: dTEr, deviceOrdinal: dOEr, link: linkEr] ← GetBootLocation[debugger, 0];
[deviceType: dTEe, deviceOrdinal: dOEe, link: linkEe] ← GetBootLocation[debuggee, 0];
GetFileDescriptorSignals[@debugger, @fileD];
IF dTEr#dTEe OR dOEr#dOEe OR fileD.volumeID#id THEN ERROR InvalidParameters;
SpecialVolume.GetLogicalVolumeBootFiles[id, @bootFiles];
bootFiles[debugger] ← [debugger.fID, 0, LOOPHOLE[linkEr]];
bootFiles[debuggee] ← [debuggee.fID, 0, LOOPHOLE[linkEe]];
SpecialVolume.SetLogicalVolumeBootFiles[id, @bootFiles];
END;
SufficientPermissions: PROCEDURE [given, needed: Permissions] RETURNS [BOOLEAN] =
INLINE {RETURN[Inline.BITAND[given, needed]=needed]};
-- ENTRY PROCEDURES
ChangeAttributes: ENTRY PROCEDURE [
file: POINTER TO READONLY File.Capability, action: AttributeAction,
transaction: Transaction.Handle ← nullTransaction] =
BEGIN
fileD: FileInternal.Descriptor;
IF ~GetFileDescriptor[file, @fileD] THEN RETURN WITH ERROR Unknown[file↑];
WITH f: fileD SELECT FROM
local =>
BEGIN
IF f.immutable AND action#mutable THEN RETURN WITH ERROR Error[immutable];
IF action=permanent AND ~f.temporary THEN RETURN;
IF transaction#nullTransaction THEN
BEGIN OPEN TransactionState;
entry: LogEntry ← SELECT action FROM
immutable => [makeMutable[id: file.fID]],
permanent => [makeTemporary[id: file.fID]],
ENDCASE => ERROR FileImplError[illegalAttributeAction];
Log[transaction, @entry, txFileProcs !
Volume.InsufficientSpace => GOTO InsufficientSpace;
Transaction.InvalidHandle => GOTO InvalidTxHandle];
EXITS
InsufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace;
InvalidTxHandle => RETURN WITH ERROR Transaction.InvalidHandle;
END;
SELECT ChangeAttributesInternal[@f, action] FROM
ok => NULL;
volumeUnknown => RETURN WITH ERROR Volume.Unknown[f.volumeID];
volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[f.volumeID];
ENDCASE;
END
ENDCASE => RETURN WITH ERROR SystemInternal.Unimplemented;
END;
CloseVolumeAndFlushFiles: PUBLIC ENTRY PROCEDURE [
v: POINTER TO READONLY Volume.ID] =
BEGIN -- Someday, flush file caches & make sure nobody is mapped to the bugger
IF tmpsVolume=v↑ THEN TmpsUnmap[];
LogicalVolume.CloseLogicalVolume[v ! Volume.Unknown => GOTO unknown];
EXITS unknown => RETURN WITH ERROR Volume.Unknown[v↑];
END;
CreateWithIDExternal: PROCEDURE [
volume: System.VolumeID, initialSize: PageCount, type: Type, id: ID,
transaction: Transaction.Handle ← nullTransaction] =
BEGIN
file: Capability ← [id, FileInternal.maxPermissions];
fileD: FileInternal.Descriptor;
CreateWithIDEntry: ENTRY PROCEDURE = INLINE
BEGIN
IF type IN PilotFileTypes.PilotVFileType THEN ERROR FileImplError[impossibleFileType];
IF GetFileDescriptor[@file, @fileD, @volume] THEN RETURN WITH ERROR ExistingFile;
IF transaction#nullTransaction THEN
BEGIN OPEN TransactionState;
entry: LogEntry ← [delete[id: file.fID]];
Log[transaction, @entry, txFileProcs !
Volume.InsufficientSpace => GOTO InsufficientSpace;
Transaction.InvalidHandle => GOTO InvalidTxHandle];
EXITS
InsufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace;
InvalidTxHandle => RETURN WITH ERROR Transaction.InvalidHandle;
END;
SELECT CreateWithIDInternal[@volume, @initialSize, type, @id] FROM
ok => NULL;
insufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace;
ENDCASE;
END;
TmpsEnter[@file, @volume];
CreateWithIDEntry[];
END;
DeleteCommon: ENTRY PROCEDURE [
file: POINTER TO READONLY File.Capability,
volume: POINTER TO READONLY Volume.ID,
-- NIL if Delete, volume if DeleteImmutable--
transaction: Transaction.Handle] =
BEGIN
fileD: FileInternal.Descriptor;
IF ~GetFileDescriptor[file, @fileD, volume] THEN RETURN WITH ERROR Unknown[file↑];
IF ~SufficientPermissions[file.permissions, File.delete] THEN
RETURN WITH ERROR Error[insufficientPermissions];
WITH f: fileD SELECT FROM
local =>
BEGIN
IF volume = NIL THEN {IF f.immutable THEN RETURN WITH ERROR Error[immutable]}
ELSE IF ~f.immutable THEN RETURN WITH ERROR Error[notImmutable];
IF transaction#nullTransaction THEN
BEGIN OPEN TransactionState;
ENABLE {
Volume.InsufficientSpace => GOTO InsufficientSpace;
Transaction.InvalidHandle => GOTO InvalidTxHandle};
entry: LogEntry ←
[setContents[
id: f.fileID, base: 0, size: f.size,
makePermanent: ~f.temporary, makeImmutable: f.immutable]];
Log[transaction, @entry, txFileProcs];
entry ← [create[id: f.fileID, volume: f.volumeID, size: f.size, type: f.type]];
Log[transaction, @entry, txFileProcs];
EXITS
InsufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace;
InvalidTxHandle => RETURN WITH ERROR Transaction.InvalidHandle;
END;
SELECT DeleteFileOnVolumeInternal[@f] FROM
ok => NULL;
volumeUnknown => RETURN WITH ERROR Volume.Unknown[f.volumeID];
volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[f.volumeID];
ENDCASE;
IF f.temporary THEN TmpsRemove[file, @f.volumeID];
END;
ENDCASE => RETURN WITH ERROR SystemInternal.Unimplemented;
END;
GetFileAttributes: PUBLIC ENTRY PROCEDURE [file: Capability]
RETURNS [size: PageCount, immutable: BOOLEAN, readOnly: BOOLEAN] =
BEGIN
f: FileInternal.Descriptor;
IF ~GetFileDescriptor[@file, @f] THEN RETURN WITH ERROR Unknown[file];
WITH f SELECT FROM
local => RETURN[size, immutable, ~SufficientPermissions[file.permissions, write]];
ENDCASE => RETURN WITH ERROR SystemInternal.Unimplemented
END;
--DeleteTemps: PUBLIC PROCEDURE [volume: Volume.ID] =
--BEGIN
--DeleteTempsEntry: ENTRY PROCEDURE =
--BEGIN
--SELECT DeleteTempsInternal[
--@volume] FROM
--ok => NULL;
--volumeUnknown => RETURN WITH ERROR Volume.Unknown[volume];
--volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[volume];
--ENDCASE;
--END;
--DeleteTempsEntry[];
--END;
-- Maintained by AltoSize
-- cacheA, cacheB: RECORD[file: File.ID, size: PageCount] ← [File.nullID, 0];
-- Access file attributes in label given fileID keeping 2 element MRU cache
--GetAltoSize: ENTRY PROCEDURE [file: POINTER TO READONLY File.Capability] RETURNS[size: PageCount] =
--BEGIN
--faP: LONG POINTER TO AltoFileDefs.FA = @LOOPHOLE[bufferPointer, LONG POINTER TO AltoFileDefs.LD].eofFA;
--IF file.fID=cacheA.file THEN RETURN[cacheA.size];
--IF file.fID=cacheB.file THEN size ← cacheB.size ELSE
--BEGIN
--SimpleSpace.Map[pageBuffer, Space.WindowOrigin[file↑, 0], FALSE];
--size ← faP.page+MIN[faP.byte, 1];
--SimpleSpace.Unmap[pageBuffer]
--END;
--cacheB ← cacheA; cacheA ← [file.fID, size]
--END;
-- Look up file in cache and then in all vfm's, set vID and page group descriptor or signal error.
GetVIDAndGroup: ENTRY PROCEDURE [
pVID: POINTER TO Volume.ID, pGroup: POINTER TO FileInternal.PageGroup,
pFile: POINTER TO READONLY File.Capability, filePage: File.PageNumber] =
BEGIN
fileD: FileInternal.Descriptor;
IF ~GetFileDescriptor[pFile, @fileD] THEN RETURN WITH ERROR Unknown[pFile↑];
WITH fileD SELECT FROM
local =>
BEGIN
GetVIDAndGroup1: VolProc =
BEGIN
success: BOOLEAN;
updateMarkers ← FALSE;
[success, pGroup↑] ← FileCache.GetPageGroup[fileD.fileID, filePage];
IF ~success THEN
[success, pGroup↑] ← VolFileMap.GetPageGroup[volume, @fileD, filePage];
IF ~(success AND filePage<pGroup.nextFilePage) THEN
ERROR FileImplError[fileWithHole];
END;
pVID↑ ← fileD.volumeID;
SELECT LogicalVolume.VolumeAccess[pVID, GetVIDAndGroup1] FROM
ok => NULL;
volumeUnknown => RETURN WITH ERROR Volume.Unknown[pVID↑];
volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[pVID↑];
ENDCASE;
END;
remote => RETURN WITH ERROR SystemInternal.Unimplemented;
ENDCASE;
END;
LogContents: PUBLIC ENTRY PROCEDURE [
transaction: Transaction.Handle, file: Capability, base: PageNumber,
count: PageCount] =
BEGIN OPEN TransactionState; ENABLE UNWIND => NULL;
entry: LogEntry ← [setContents[id: file.fID, base: base, size: count]];
Log[transaction, @entry, txFileProcs];
END;
MakeBootableOrUnbootable: ENTRY PROCEDURE [
op: {bootable, unbootable}, file: POINTER TO READONLY File.Capability,
firstPage: File.PageNumber, count: File.PageCount,
lastLink: DiskChannel.Address] RETURNS [firstLink: DiskChannel.Address] =
BEGIN
fileD: FileInternal.Descriptor;
group: FileInternal.PageGroup;
limitPage: File.PageNumber = firstPage+count;
nextLink: DiskChannel.Address;
page: File.PageNumber ← firstPage;
success: BOOLEAN;
GetStuff: VolProc =
BEGIN
updateMarkers ← FALSE;
[success, group] ← VolFileMap.GetPageGroup[volume, @fileD, page];
IF ~success THEN ERROR FileImplError[makeBootablePageGroupNotFound];
IF firstPage=page THEN
firstLink ← SubVolume.GetPageAddress[fileD.volumeID,
group.volumePage+(firstPage-group.filePage)].address;
SELECT TRUE FROM
op=unbootable => nextLink ← [0, 0, 0];
group.nextFilePage>=limitPage =>
{group.nextFilePage ← limitPage; nextLink ← lastLink};
ENDCASE => -- should check success of GetPageGroup in next statement
nextLink ← SubVolume.GetPageAddress[fileD.volumeID,
VolFileMap.GetPageGroup[volume, @fileD,
group.nextFilePage].group.volumePage].address;
IF group.filePage>=group.nextFilePage THEN
ERROR FileImplError[makeBootableImpossibleError];
group.volumePage ← group.volumePage+(group.nextFilePage-group.filePage)-1;
group.filePage ← group.nextFilePage-1;
END;
TransferLabels: PROCEDURE = INLINE
BEGIN
SimpleSpace.Map[pageBuffer, [[fileD.fileID, File.read], group.filePage], TRUE, 1];
[] ← LabelTransfer.WriteLabelAndData[
fileD, group.filePage, group.volumePage, bufferPage, nextLink];
SimpleSpace.Unmap[pageBuffer];
END;
IF ~GetFileDescriptor[file, @fileD] THEN RETURN WITH ERROR Unknown[file↑];
IF (WITH fD: fileD SELECT FROM local => limitPage>fD.size, ENDCASE => TRUE)
THEN RETURN WITH ERROR InvalidParameters;
WHILE page<limitPage DO
SELECT LogicalVolume.VolumeAccess[@fileD.volumeID, GetStuff] FROM
ok => NULL;
volumeUnknown => RETURN WITH ERROR Volume.Unknown[fileD.volumeID];
volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[fileD.volumeID];
ENDCASE;
IF success THEN TransferLabels[];
page ← group.nextFilePage;
ENDLOOP;
END;
OpenVolumeAndDeleteTemps: PUBLIC ENTRY PROCEDURE [
volume: POINTER TO READONLY Volume.ID] =
BEGIN
SELECT LogicalVolume.OpenLogicalVolume[volume] FROM
wasOpen => RETURN;
ok => NULL;
Unknown => RETURN WITH ERROR Volume.Unknown[volume↑];
VolumeNeedsScavenging => RETURN WITH ERROR Volume.NeedsScavenging;
ENDCASE;
IF PilotSwitches.switches.u=up THEN IF DeleteTempsInternal[volume]#ok THEN
ERROR FileImplError[volumeWentAwayDuringDeleteTemps];
END;
Pin: PUBLIC ENTRY PROCEDURE [
file: File.Capability, page: File.PageNumber, count: File.PageCount] =
BEGIN
fileD: FileInternal.Descriptor;
after: File.PageNumber;
IF ~GetFileDescriptor[@file, @fileD] THEN RETURN WITH ERROR Unknown[file];
WITH f: fileD SELECT FROM
local =>
BEGIN
p: FileInternal.LocalFilePtr ← @f; -- FOR COMPILER BUG
Pin1: VolProc =
BEGIN
success: BOOLEAN;
group: FileInternal.PageGroup ← [, , page];
FileCache.SetFile[fileD, TRUE];
updateMarkers ← FALSE;
WHILE group.nextFilePage<after DO
[success, group] ← VolFileMap.GetPageGroup[volume, p, group.nextFilePage];
IF ~success THEN ERROR FileImplError[missingPinnedPageGroup];
FileCache.SetPageGroup[file.fID, group, TRUE]
ENDLOOP;
END;
after ← IF count=KernelFile.defaultPageCount THEN p.size ELSE page+count;
SELECT LogicalVolume.VolumeAccess[@f.volumeID, Pin1] FROM
ok => NULL;
volumeUnknown => RETURN WITH ERROR Volume.Unknown[f.volumeID];
volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[f.volumeID];
ENDCASE;
END;
remote => RETURN WITH ERROR SystemInternal.Unimplemented;
ENDCASE;
END;
SetSize: PUBLIC ENTRY PROCEDURE [
file: Capability, size: PageCount, transaction: Transaction.Handle] =
BEGIN ENABLE UNWIND => NULL;
fileD: FileInternal.Descriptor;
IF ~GetFileDescriptor[@file, @fileD] THEN RETURN WITH ERROR Unknown[file];
IF ~SufficientPermissions[file.permissions, File.write] THEN
RETURN WITH ERROR Error[insufficientPermissions];
WITH f: fileD SELECT FROM
local =>
BEGIN
IF f.immutable THEN RETURN WITH ERROR Error[immutable];
IF transaction#nullTransaction THEN IF size#f.size THEN
BEGIN OPEN TransactionState;
entry: LogEntry ← (SELECT size FROM
>f.size => [shrink[id: file.fID, size: f.size]],
ENDCASE => [setContents[
id: file.fID, base: size, size: f.size-size]]);
Log[transaction, @entry, txFileProcs !
Volume.InsufficientSpace => GOTO InsufficientSpace;
Transaction.InvalidHandle => GOTO InvalidTxHandle];
EXITS
InsufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace;
InvalidTxHandle => RETURN WITH ERROR Transaction.InvalidHandle;
END;
SELECT SetSizeInternal[@f, @size, file.permissions] FROM
ok => RETURN;
insufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace;
insufficientPermissions => RETURN WITH ERROR Error[insufficientPermissions];
ENDCASE;
END;
remote => RETURN WITH ERROR SystemInternal.Unimplemented;
ENDCASE;
END;
-- this is its own entry procedure since it can get many nasty errors
TmpsEnter: ENTRY PROCEDURE [
f: POINTER TO READONLY File.Capability, v: POINTER TO READONLY Volume.ID] =
BEGIN
FindIt: INTERNAL PROCEDURE RETURNS [BOOLEAN] = INLINE
BEGIN
tOriginal: LONG POINTER TO File.ID ← tmps;
DO
IF tmps↑=File.nullID THEN RETURN[TRUE];
IF (tmps ← tmps+SIZE[File.ID])=tmpsLast THEN tmps ← tmpStart;
IF tmps=tOriginal THEN EXIT;
ENDLOOP;
RETURN[FALSE];
END;
SELECT TmpsGet[v, last] FROM
ok => NULL;
volumeUnknown => RETURN WITH ERROR Volume.Unknown[v↑];
notOpen => RETURN WITH ERROR Volume.NotOpen[v↑];
noFile => RETURN; -- next delete tmps will be hard way
ENDCASE;
IF ~FindIt[] THEN IF ~TmpsGrow[] THEN RETURN WITH ERROR Volume.InsufficientSpace;
tmps↑ ← f.fID;
SimpleSpace.ForceOut[tmpsBuffer];
END;
-- INTERNAL PROCEDURES
ChangeAttributesInternal: INTERNAL PROCEDURE [
fileD: LocalFilePtr, action: AttributeAction]
RETURNS [s: LogicalVolume.VolumeAccessStatus] =
BEGIN
file: Capability ← [fileD.fileID, maxPermissions];
link: DiskChannel.Address ← LOOPHOLE[LONG[0]];
volumePage: LogicalVolume.PageNumber;
volID: Volume.ID ← fileD.volumeID; -- FOR COMPILER BUG
GetGroup0: VolProc =
BEGIN
group: FileInternal.PageGroup;
success: BOOLEAN;
updateMarkers ← FALSE;
[success, group] ← VolFileMap.GetPageGroup[volume, fileD, 0];
IF ~success THEN ERROR FileImplError[missingPage0];
volumePage ← group.volumePage;
END;
SELECT s ← LogicalVolume.VolumeAccess[@volID, GetGroup0] FROM
ok => NULL;
volumeUnknown, volumeNotOpen => RETURN;
ENDCASE;
IF LabelTransfer.VerifyLabels[
fileD↑, [0, volumePage, 1], FALSE, FALSE].status ~= goodCompletion
THEN SIGNAL LabelError;
-- smash time, folks. Watch out for zero size file
IF action=permanent OR action=temporary THEN
BEGIN
IF fileD.type IN PilotFileTypes.PilotRootFileType THEN
LogicalVolume.PutRootFile[@volID, fileD.type, @file !
Volume.Unknown => GOTO VUnknown;
Volume.NotOpen => GOTO VNotOpen];
fileD.temporary ← action=temporary;
EXITS
VUnknown => RETURN[volumeUnknown];
VNotOpen => RETURN[volumeNotOpen];
END
ELSE fileD.immutable ← action=immutable;
SimpleSpace.Map[
pageBuffer, IF fileD.size=0 THEN Space.defaultWindow ELSE [file, 0], TRUE];
-- There's a small race here, since the label on the disk is now inconsistent with
-- the information in the FileCache. If someone tries to access page 0 before we
-- get the file cache updated, they will get a label check. The only fix for this
-- is to do the label transfer inside the FileCache monitor (ugh) or arrange for the
-- a recomputation of the label info and a retry of the i/o. Neither is easy, so
-- we'll leave the race in until Klamath. Note that calling FileCache.FlushFile is
-- bad too (that's what used to be done), because it flushes pinned page groups, causing
-- disaster elsewhere. That problem is more severe than the remaining one.
LOOPHOLE[link, PilotDisk.Address] ←
LabelTransfer.ReadLabel[fileD↑, 0, volumePage].label.bootChainLink;
[] ← LabelTransfer.WriteLabelAndData[
fileD↑, 0, volumePage, SimpleSpace.Page[pageBuffer], link];
FileCache.SetFile[fileD↑, FALSE];
SimpleSpace.Unmap[pageBuffer];
IF action=permanent THEN TmpsRemove[@file, @volID];
END;
CreateWithIDInternal: INTERNAL PROCEDURE [
volume: POINTER TO READONLY System.VolumeID,
initialSize: POINTER TO READONLY PageCount, type: File.Type,
file: POINTER TO READONLY File.ID]
RETURNS [s: LogicalVolume .FileVolumeStatus[ok..insufficientSpace]] =
-- Create file given the file identifier (called by CreateWithIDExternal,
-- OpenVolumeAndDeleteTemps). Expect to see Volume.Unknown,
-- Volume.NotOpen, Volume.InsufficientSpace
BEGIN
fileD: local FileInternal.Descriptor ← [file↑, volume↑, local[FALSE, TRUE, 0, type]];
CreateInner: VolProc =
BEGIN
group: FileInternal.PageGroup ← [, 0, 0];
updateMarkers ← FALSE;
IF LogicalVolume.FreeVolumePages[volume] <= initialSize↑ THEN
s ← insufficientSpace
ELSE
BEGIN
DO
group ←
[group.nextFilePage,
group.volumePage+group.nextFilePage-group.filePage,
initialSize↑];
VolAllocMap.AllocPageGroup[volume, LONG[@fileD], @group, TRUE];
-- results in modified group and FilePtr.size
VolFileMap.InsertPageGroup[volume, LONG[@fileD], @group];
IF fileD.size=initialSize↑ THEN EXIT;
ENDLOOP;
FileCache.SetFile[fileD, FALSE];
END;
END;
s ← ok;
SELECT LogicalVolume.VolumeAccess[@fileD.volumeID, CreateInner, TRUE] FROM
ok => NULL;
volumeUnknown => s ← volumeUnknown;
volumeNotOpen => s ← volumeNotOpen;
ENDCASE;
END;
DeleteFileOnVolumeInternal: INTERNAL PROCEDURE [
fileD: FileInternal.LocalFilePtr]
RETURNS [s: LogicalVolume.VolumeAccessStatus] =
BEGIN
vID: Volume.ID ← fileD.volumeID;
DeleteIt: VolProc =
BEGIN
g: FileInternal.PageGroup;
success: BOOLEAN;
FileCache.FlushFile[fileD.fileID];
updateMarkers ← FALSE;
DO
[success, g] ← VolFileMap.GetPageGroup[volume, fileD, File.lastPageNumber];
-- group.nextFile page is last page in file
IF ~success THEN EXIT;
g ← [0, LogicalVolume.nullVolumePage, g.nextFilePage];
VolFileMap.DeletePageGroup[volume, fileD, @g]; -- results in modified group
VolAllocMap.FreePageGroup[volume, fileD, @g, TRUE]; -- results in modified fileD
ENDLOOP;
END;
RETURN[LogicalVolume.VolumeAccess[@vID, DeleteIt, TRUE]];
END;
DeleteTempsInternal: INTERNAL PROCEDURE [v: POINTER TO READONLY Volume.ID]
RETURNS [s: LogicalVolume.VolumeAccessStatus] =
BEGIN
one: File.PageCount ← 1;
SELECT TmpsGet[v, first] FROM
noFile => s ← DeleteTmpsInternalOld[v];
ok => s ← DeleteTmpsInternalNew[v]; -- also deletes tempFile
volumeUnknown => RETURN[volumeUnknown];
notOpen => RETURN[volumeNotOpen];
ENDCASE;
IF s#ok THEN RETURN; -- Create a tmps file.
tmpsFile ← [[System.GetUniversalID[]], FileInternal.maxPermissions];
SELECT CreateWithIDInternal[v, @one, PilotFileTypes.tTempFileList, @tmpsFile.fID] FROM
insufficientSpace => RETURN; -- there will be no temp file; that's Ok
volumeUnknown, volumeNotOpen => FileImplError[tmpsVolumeWentAway];
ENDCASE;
LogicalVolume.PutRootFile[v, PilotFileTypes.tTempFileList, @tmpsFile !
Volume.Unknown, Volume.NotOpen => FileImplError[tmpsVolumeWentAway]];
END;
DeleteTmpsInternalNew: INTERNAL PROCEDURE [v: POINTER TO READONLY Volume.ID]
RETURNS [s: LogicalVolume.VolumeAccessStatus] =
BEGIN
cap: File.Capability ← [File.nullID, File.delete];
fileD: FileInternal.Descriptor;
p: File.PageNumber;
t: LONG POINTER TO File.ID;
FOR p ← 0, p+1 WHILE p<tmpsFileSize DO
TmpsMap[p];
FOR t ← tmpStart, t+SIZE[File.ID] WHILE t#tmpsLast DO
IF t↑=File.nullID THEN LOOP;
cap.fID ← t↑;
IF GetFileDescriptor[@cap, @fileD, v] THEN
WITH f: fileD SELECT FROM
local =>
IF f.temporary THEN IF (s ← DeleteFileOnVolumeInternal[@f])#ok THEN RETURN
ELSE LOOP;
ENDCASE; -- ingore remote files (can't happen), and delete errors
ENDLOOP;
ENDLOOP;
TmpsUnmap[]; -- finally, delete the file itself.
IF GetFileDescriptor[@tmpsFile, @fileD, v] THEN
WITH f: fileD SELECT FROM
local => RETURN[DeleteFileOnVolumeInternal[@f]];
ENDCASE;
ERROR FileImplError[disappearedOrRemoteTempFile];
END;
DeleteTmpsInternalOld: INTERNAL PROCEDURE [v: POINTER TO READONLY Volume.ID]
RETURNS [s: LogicalVolume.VolumeAccessStatus] =
BEGIN
lastCap: File.Capability ← File.nullCapability;
thisCap: File.Capability;
fileD: FileInternal.Descriptor;
DO
thisCap ← KernelFile.GetNextFile[v↑, lastCap !
Volume.Unknown => GOTO unknown;
Volume.NotOpen => GOTO notOpen];
IF thisCap=File.nullCapability THEN EXIT;
IF GetFileDescriptor[@thisCap, @fileD, v] THEN
WITH f: fileD SELECT FROM
local =>
IF f.temporary THEN
IF (s ← DeleteFileOnVolumeInternal[@f])#ok THEN RETURN ELSE LOOP;
ENDCASE; -- ignore remote files (can't happen)
lastCap ← thisCap;
ENDLOOP;
RETURN[ok];
EXITS unknown => RETURN[volumeUnknown]; notOpen => RETURN[volumeNotOpen];
END;
SetSizeInternal: INTERNAL PROCEDURE [
fileD: FileInternal.LocalFilePtr, size: POINTER TO READONLY File.PageCount,
permissions: File.Permissions] RETURNS [s: LogicalVolume.FileVolumeStatus] =
BEGIN
vID: Volume.ID ← fileD.volumeID;
vs: LogicalVolume.VolumeAccessStatus;
SizeIt: VolProc =
BEGIN
success: BOOLEAN;
group: FileInternal.PageGroup;
-- if the file has pinned cache entries, the following is bad, but we don't have
-- any other good way to deal with it unless the FileCache interface is changed. Better
-- to wait for Klamath.
FileCache.FlushFile[fileD.fileID];
updateMarkers ← FALSE;
SELECT fileD.size FROM
<size↑ =>
BEGIN
IF ~SufficientPermissions[permissions, File.write+File.grow] THEN
s ← insufficientPermissions
ELSE
IF LogicalVolume.FreeVolumePages[volume]<size↑-fileD.size THEN
s ← insufficientSpace
ELSE
BEGIN
[success, group] ←
VolFileMap.GetPageGroup[volume, fileD, fileD.size-MIN[fileD.size, 1]];
IF ~success THEN ERROR FileImplError[missingPageGroupSetSize];
WHILE fileD.size<size↑ DO
group ←
[group.nextFilePage,
group.volumePage+(group.nextFilePage-group.filePage),
size↑];
VolAllocMap.AllocPageGroup[volume, fileD, @group, FALSE];
-- change group+fileD
VolFileMap.InsertPageGroup[volume, fileD, @group];
ENDLOOP
END
END;
>size↑ =>
BEGIN
IF ~SufficientPermissions[permissions, File.write+File.shrink] THEN
s ← insufficientPermissions
ELSE
BEGIN
WHILE fileD.size>size↑ DO
group ← [size↑, LogicalVolume.nullVolumePage, fileD.size];
VolFileMap.DeletePageGroup[volume, fileD, @group]; -- changes group
VolAllocMap.FreePageGroup[volume, fileD, @group, FALSE]; -- changes FilePtr
ENDLOOP;
END;
END;
ENDCASE;
IF s = ok THEN FileCache.SetFile[fileD↑, FALSE];
END;
s ← ok;
IF (vs ← LogicalVolume.VolumeAccess[@vID, SizeIt, TRUE]) ~= ok THEN RETURN [vs];
RETURN[s]
END;
TmpsGet: INTERNAL PROCEDURE [
v: POINTER TO READONLY Volume.ID, pg: {first, last}]
RETURNS [{ok, volumeUnknown, notOpen, noFile}] =
BEGIN
IF v↑=Volume.nullID THEN RETURN[volumeUnknown];
IF tmpsVolume#v↑ THEN
BEGIN
fileD: FileInternal.Descriptor;
TmpsUnmap[];
tmpsFile ← KernelFile.GetRootFile[PilotFileTypes.tTempFileList, v↑ !
Volume.Unknown => GOTO unknown;
Volume.NotOpen => GOTO notOpen];
IF ~GetFileDescriptor[@tmpsFile, @fileD, v] THEN RETURN[noFile];
WITH fileD SELECT FROM
local => tmpsFileSize ← size;
ENDCASE => ERROR FileImplError[remoteTmpsFile];
TmpsMap[IF pg=first THEN 0 ELSE tmpsFileSize-1];
tmpsVolume ← v↑;
EXITS unknown => RETURN[volumeUnknown]; notOpen => RETURN[notOpen];
END;
RETURN[ok];
END;
TmpsGrow: INTERNAL PROCEDURE RETURNS [BOOLEAN] =
BEGIN
fileD: FileInternal.Descriptor;
newSize: File.PageCount ← tmpsFileSize+1;
IF ~GetFileDescriptor[@tmpsFile, @fileD, @tmpsVolume] THEN
ERROR FileImplError[tmpsFileWentAway];
WITH f: fileD SELECT FROM
local =>
SELECT SetSizeInternal[@f, @newSize, File.grow+File.write] FROM
insufficientSpace => RETURN[FALSE];
ok => NULL;
ENDCASE => FileImplError[tmpsFileProblem];
ENDCASE => ERROR FileImplError[remoteTmpsFile];
TmpsMap[tmpsFileSize];
tmpsFileSize ← tmpsFileSize+1;
RETURN[TRUE];
END;
TmpsMap: INTERNAL PROCEDURE [page: File.PageNumber] = INLINE
BEGIN
IF tmpsVolume#nullID THEN SimpleSpace.Unmap[tmpsBuffer];
SimpleSpace.Map[tmpsBuffer, [tmpsFile, page], FALSE];
tmps ← tmpStart;
END;
TmpsRemove: INTERNAL PROCEDURE [
f: POINTER TO READONLY File.Capability, v: POINTER TO READONLY Volume.ID] =
BEGIN
t: LONG POINTER TO File.ID ← tmps;
IF v↑#Volume.nullID -- impossible, he says-- AND tmpsVolume=v↑ THEN
DO
-- only cheap wins
IF t↑=f.fID THEN BEGIN t↑ ← File.nullID; RETURN; END;
IF t=tmpStart THEN t ← tmpsLast;
IF (t ← t-SIZE[File.ID])=tmps THEN EXIT;
ENDLOOP;
END;
TmpsUnmap: INTERNAL PROCEDURE = INLINE
BEGIN
IF tmpsVolume#Volume.nullID THEN
BEGIN SimpleSpace.Unmap[tmpsBuffer]; tmpsVolume ← Volume.nullID; END;
END;
-- Here follows a gross kludge to allow the transaction machinery to sneak
-- past our monitor lock.
txFileProcs: TransactionState.FileOps = [TxCreate, TxMakePerm, TxSetSize];
TxCreate: INTERNAL PROCEDURE [size: PageCount, type: Type] RETURNS [file: ID] =
BEGIN
volID: Volume.ID ← Volume.systemID;
file ← [System.GetUniversalID[]];
SELECT CreateWithIDInternal[@volID, @size, type, @file] FROM
ok => NULL;
insufficientSpace => ERROR Volume.InsufficientSpace;
ENDCASE;
END;
TxMakePerm: INTERNAL PROCEDURE [file: ID] =
BEGIN
fileC: Capability ← [file, maxPermissions];
fileD: FileInternal.Descriptor;
IF ~GetFileDescriptor[@fileC, @fileD] THEN ERROR Unknown[fileC];
WITH f: fileD SELECT FROM
local =>
BEGIN
SELECT ChangeAttributesInternal[@f, permanent] FROM
volumeUnknown => ERROR Volume.Unknown[f.volumeID];
volumeNotOpen => ERROR Volume.NotOpen[f.volumeID];
ENDCASE;
END;
ENDCASE => ERROR FileImplError[remoteTxLog];
END;
TxSetSize: INTERNAL PROCEDURE [file: ID, size: PageCount] =
BEGIN
fileC: Capability ← [file, maxPermissions];
fileD: FileInternal.Descriptor;
IF ~GetFileDescriptor[@fileC, @fileD] THEN ERROR Unknown[fileC];
WITH f: fileD SELECT FROM
local =>
BEGIN
SELECT SetSizeInternal[@f, @size, maxPermissions] FROM
insufficientSpace => ERROR Volume.InsufficientSpace;
volumeUnknown => ERROR Volume.Unknown[f.volumeID];
volumeNotOpen => ERROR Volume.NotOpen[f.volumeID];
ENDCASE;
END;
ENDCASE => ERROR FileImplError[remoteTxLog];
END;
-- Initialization
InitializeFileMgr: PUBLIC PROCEDURE [
bootFile: LONG POINTER TO disk Boot.Location,
pLVBootFiles: POINTER TO Boot.LVBootFiles]
RETURNS [debuggerDeviceType: Device.Type, debuggerDeviceOrdinal: CARDINAL] =
BEGIN
priorityPrev: Process.Priority;
throwAway: PROCESS;
IF PilotSwitches.switches.f=down THEN Runtime.CallDebugger["Key Stop F"L];
priorityPrev ← Process.GetPriority[];
Process.SetPriority[ProcessPriorities.priorityPageFaultHigh];
throwAway ← FORK FileHelperProcess[]; -- (no profit in Detaching)
Process.SetPriority[priorityPrev];
START FMPrograms.VolAllocMapImpl;
START FMPrograms.VolFileMapImpl;
START FMPrograms.MarkerPageImpl;
[debuggerDeviceType, debuggerDeviceOrdinal] ←
START FMPrograms.PhysicalVolumeImpl[bootFile, pLVBootFiles];
-- ..also starts VolumeImpl and ScavengeImpl.
END;
END.
(For earlier log entries, see Pilot 4.0 archive version.)
April 1, 1980 2:47 PM Gobbel
Added transaction handles
April 15, 1980 4:37 PM Gobbel
Added nullTransactionHandle
April 17, 1980 10:08 PM Luniewski
Added TransactionHandle argument to GetSize and GetAttributes
April 18, 1980 2:59 PM Luniewski
Temporary exportation of transaction.nullHandle added
May 15, 1980 6:11 PM McJones
Add page and count parameters to Pin
May 30, 1980 3:07 PM Luniewski
PhysicalVolume removed from DIRECTORY. Made compatible with
FileInternal.FileDescriptors being LONG POINTERs. STARTed
PhysicalVolumeImpl. Removed START of VolumeImpl as it is now started
by PhysicalVolumeImpl. LogicalVolume.{Open Close}Volume =>
LogicalVolume.{Open Close}LogicalVolume.
June 10, 1980 1:20 AM Gobbel
Added MakeTemporary and MakeMutable
June 10, 1980 3:10 PM Gobbel
Added transaction logging code
July 19, 1980 11:15 AM McJones
Deleted nullTransactionHandle and (Transaction.)nullHandle; adapted
for new PilotDisk.Label; removed dependency in initialization of
tmpsLast on SIZE[File.ID]
July 25, 1980 3:32 PM Luniewski
SpecialVolume.(NotOpen VolumeNeedsScavenging) => Volume.(NotOpen
NeedsScavenging)
August 11, 1980 5:24 PM Gobbel/Knutsen
Restructure Create to allow export of CreateWithID to KernelFile for
transaction crash recovery
August 14, 1980 11:15 AM McJones
Delete dependencies on tBootFile; FilePageLabel=>PilotDisk; require
File.write in SetSizeInternal
August 21, 1980 2:10 PM Gobbel
Restructure transactional operations to use new interface for
managing log files
September 12, 1980 12:07 PM Gobbel
Make GetFileDescriptor look at all volume types
September 17, 1980 3:07 PM Luniewski
Mods for new priocedure type passed to LogicalVolume.VolumeAccess.
September 26, 1980 4:29 PM McJones
GetBootLocation forgot to add offset to volume page
December 31, 1980 12:18 PM Gobbel
Changed tx log entries to have ids instead of capabilities.
January 12, 1981 12:18 PM Luniewski
New LabelTransfer interface.
January 12, 1981 12:18 PM Knutsen
Changed process priorities.
January 26, 1981 Knutsen
Renamed nullTransactionHandle to nullTransaction (export name conflict).
February 11, 1981 5:28 PM Knutsen
FilePageTransfer.Initiate now MStore.Promises itself.
February 24, 1981 6:15 PM Gobbel
Changed all procs that take transaction handles to be sure that monitor lock will
not be held in client catch phrase.
August 26, 1982 9:11 am Levin
Make things SAFE.
November 11, 1982 3:01 pm Levin
Move all relevant FileCache operations inside volume access lock to ensure proper atomicity of file cache.
December 8, 1982 5:11 pm Levin
Correct access to FileCache in ChangeAttributesInternal.
December 9, 1982 11:37 am Levin
Replace lost "s ← ok" in SetSizeInternal.