<> <> <> <> <> <> <> <<>> DIRECTORY BootFile USING [ DiskFileID, Location ], Disk USING [ DoIO, Channel, DriveAttributes, InspectDiskShape, Label, labelCheck, NextChannel, ok, PageCount, PageNumber, Request, SameDrive, Status ], DiskFace USING [ PageCount, wordsPerPage ], File USING [ Error, RC, VolumeID ], FileBackdoor USING [], FileInternal USING [ InitRootPage, ReadRootPage, TranslateStatus, VolumeObject ], VolumeFormat, PhysicalVolume USING [ Credentials, PhysicalRC, SubVolumeDetails, SubVolumeDetailsObject, SubVolumes, SubVolumesObject ], Process USING [ SecondsToTicks ], VM USING [ AddressForPageNumber, Allocate, Free, PageNumberForAddress, Pin, Unpin, wordsPerPage ], Rope USING [ Fetch, FromRefText, Length, ROPE ]; PhysicalVolumeImpl: CEDAR MONITOR IMPORTS Disk, File--Error--, FileInternal, Process, Rope, VM EXPORTS DiskFace--AbsID--, File, FileBackdoor, FileInternal--GetPhysicalLocation--, PhysicalVolume = { ROPE: TYPE = Rope.ROPE; <> <<******** Raw access to global pages of the volume ********>> PageData: TYPE = LONG POINTER; pagePages: INT = (DiskFace.wordsPerPage+VM.wordsPerPage-1)/VM.wordsPerPage; --DiskFace.--AbsID: PUBLIC TYPE = VolumeFormat.AbsID; --DiskFace.--Attributes: PUBLIC TYPE = VolumeFormat.Attributes; PhysRootLabel: PROC [id: File.VolumeID] RETURNS [Disk.Label] = TRUSTED { RETURN[ [ fileID: [abs[AbsID[id]]], filePage: 0, attributes: Attributes[physicalRoot], dontCare: LOOPHOLE[LONG[0]] ] ] }; BadPageTableLabel: PROC [id: File.VolumeID] RETURNS [label: Disk.Label] = TRUSTED { label _ PhysRootLabel[id]; label.filePage _ 1; }; CredentialsLabel: PROC RETURNS [Disk.Label] = TRUSTED { <> cannedID: MACHINE DEPENDENT RECORD[a,b,c,d,e: CARDINAL] = [a: 076543B, b: 021076B, c: 054321B, d: 076543B, e: 021076B]; -- ask Roy! RETURN[ [ fileID: [abs[AbsID[LOOPHOLE[cannedID]]]], filePage: 0, attributes: Attributes[LOOPHOLE[0]], dontCare: LOOPHOLE[LONG[0]] ] ] }; AccessPage: UNSAFE PROC [ channel: Disk.Channel, page: Disk.PageNumber, label: LONG POINTER TO Disk.Label, data: PageData, direction: { read, write }, verifyLabel: BOOL -- else read/write label depending on "direction" --] RETURNS [ status: Disk.Status ] = TRUSTED { ENABLE UNWIND => VM.Unpin[[page: VM.PageNumberForAddress[data], count: pagePages]]; countDone: Disk.PageCount; req: Disk.Request _ [ diskPage: page, data: data, command: [header: verify, label: IF verifyLabel THEN verify ELSE (IF direction=read THEN read ELSE write), data: IF direction=read THEN read ELSE write], count: 1 ]; VM.Pin[[page: VM.PageNumberForAddress[data], count: pagePages]]; [status, countDone] _ Disk.DoIO[channel, label, @req]; VM.Unpin[[page: VM.PageNumberForAddress[data], count: pagePages]]; }; FreePage: UNSAFE PROC [data: PageData] = TRUSTED { VM.Free[[page: VM.PageNumberForAddress[data], count: pagePages]] }; ReadPage: PROC [channel: Disk.Channel, page: Disk.PageNumber, label: LONG POINTER TO Disk.Label, verifyLabel: BOOL] RETURNS [ status: Disk.Status, data: PageData ] = TRUSTED { data _ VM.AddressForPageNumber[VM.Allocate[pagePages].page]; status _ AccessPage[channel, page, label, data, read, verifyLabel]; IF status # Disk.ok THEN { FreePage[data]; data _ NIL }; }; ReadPhysicalRoot: PROC [channel: Disk.Channel] RETURNS [ status: Disk.Status, root: LONG POINTER TO VolumeFormat.PhysicalRoot ] = TRUSTED { label: Disk.Label; data: PageData; [status, data] _ ReadPage[channel, VolumeFormat.rootPageNumber, @label, FALSE]; root _ LOOPHOLE[data]; IF status = Disk.ok THEN { <> label _ PhysRootLabel[root.pvID]; status _ AccessPage[channel, VolumeFormat.rootPageNumber, @label, data, read, TRUE]; IF status # Disk.ok THEN { FreePage[data]; root _ NIL }; }; }; WriteRoot: INTERNAL PROC [physical: Physical, verifyLabel: BOOL _ TRUE] RETURNS [ PhysicalVolume.PhysicalRC ] = TRUSTED { label: Disk.Label _ PhysRootLabel[physical.root.pvID]; status: Disk.Status; status _ AccessPage[physical.channel, VolumeFormat.rootPageNumber, @label, physical.root, write, verifyLabel]; RETURN[ FileInternal.TranslateStatus[status] ] }; badPageNumber: Disk.PageNumber = [VolumeFormat.rootPageNumber+1]; ReadBadPageTable: INTERNAL PROC [physical: Physical] RETURNS [PhysicalVolume.PhysicalRC] = TRUSTED { status: Disk.Status; label: Disk.Label _ BadPageTableLabel[physical.root.pvID]; [status, physical.bad] _ ReadPage[physical.channel, badPageNumber, @label, TRUE]; RETURN[FileInternal.TranslateStatus[status]] }; WriteBadPageTable: INTERNAL PROC [physical: Physical, verifyLabel: BOOL _ TRUE] RETURNS [PhysicalVolume.PhysicalRC] = TRUSTED { status: Disk.Status; label: Disk.Label _ BadPageTableLabel[physical.root.pvID]; status _ AccessPage[physical.channel, badPageNumber, @label, physical.bad, write, verifyLabel]; RETURN[FileInternal.TranslateStatus[status]] }; ReadCredentials: PUBLIC UNSAFE PROC [physical: Physical, credentials: PhysicalVolume.Credentials] RETURNS [ PhysicalVolume.PhysicalRC ] = UNCHECKED { label: Disk.Label _ CredentialsLabel[]; status: Disk.Status = AccessPage[physical.channel, VolumeFormat.credentialsPageNumber, @label, credentials, read, TRUE]; RETURN[ FileInternal.TranslateStatus[status] ] }; WriteCredentials: PUBLIC PROC [physical: Physical, credentials: PhysicalVolume.Credentials] RETURNS [ PhysicalVolume.PhysicalRC ] = TRUSTED { label: Disk.Label _ CredentialsLabel[]; status: Disk.Status = AccessPage[physical.channel, VolumeFormat.credentialsPageNumber, @label, credentials, write, FALSE--write label unconditionally--]; RETURN[ FileInternal.TranslateStatus[status] ] }; <<******** Global list of Physical Volumes ******** -->> --PhysicalVolume.--PhysicalObject: PUBLIC TYPE = RECORD[ channel: Disk.Channel, rootStatus: PhysicalVolume.PhysicalRC _ ok, root: LONG POINTER TO VolumeFormat.PhysicalRoot _ NIL, bad: LONG POINTER TO VolumeFormat.BadPageList _ NIL, name: ROPE _ NIL, reserved: ReservedList _ NIL, rest: REF PhysicalObject _ NIL ]; ReservedList: TYPE = LIST OF RECORD[start: Disk.PageNumber, size: Disk.PageCount]; Physical: TYPE = REF PhysicalObject; physicalList: REF PhysicalObject _ NIL; -- known physical volumes -- NextPhysical: PUBLIC ENTRY PROC [prev: Physical, wait: BOOL] RETURNS [next: Physical] = TRUSTED { ENABLE UNWIND => NULL; WHILE (next _ InnerNextPhysical[prev]) = NIL AND wait DO WAIT physicalWait ENDLOOP; }; physicalWait: CONDITION _ [timeout: Process.SecondsToTicks[1]]; <> lastChannel: Disk.Channel _ NIL; InnerNextPhysical: INTERNAL PROC [prev: Physical] RETURNS [next: Physical] = TRUSTED { DO next _ IF prev = NIL THEN physicalList ELSE prev.rest; IF next # NIL THEN EXIT; { new: Disk.Channel = Disk.NextChannel[lastChannel]; IF new # NIL THEN { RegisterPhysical[NewPhysical[new]]; lastChannel _ new } ELSE EXIT; }; ENDLOOP; }; RegisterPhysical: INTERNAL PROC [new: Physical] = { tail: Physical _ NIL; FOR p: Physical _ physicalList, p.rest UNTIL p = NIL DO tail _ p ENDLOOP; IF tail = NIL THEN physicalList _ new ELSE tail.rest _ new; BROADCAST physicalWait; }; NewPhysical: INTERNAL PROC [channel: Disk.Channel] RETURNS [new: Physical] = TRUSTED { status: Disk.Status; new _ NEW[PhysicalObject _ [channel: channel]]; IF NOT Disk.InspectDiskShape[channel, quickReadOnly] THEN ERROR; [status, new.root] _ ReadPhysicalRoot[channel]; new.rootStatus _ FileInternal.TranslateStatus[status]; IF new.rootStatus # ok THEN RETURN; IF new.root.seal # VolumeFormat.PRSeal OR new.root.version # VolumeFormat.PRCurrentVersion THEN { new.rootStatus _ inconsistent; RETURN }; TRUSTED{ new.name _ GetName[@new.root.label, new.root.labelLength] }; <> FOR s: INT IN [0..new.root.subVolumeCount) DO RegisterSubVolume[new, @new.root.subVolumes[s]]; ENDLOOP; }; <<******** Operations on Physical root and bad page table ********>> GetName: PROC [chars: LONG POINTER TO PACKED ARRAY [0..VolumeFormat.volumeLabelLength) OF CHAR, length: INT] RETURNS [ROPE] = TRUSTED { text: REF TEXT = NEW[TEXT[length]]; FOR i: INT IN [0..length) DO text[i] _ chars[i] ENDLOOP; text.length _ length; RETURN[Rope.FromRefText[text]] }; PhysicalInfo: PUBLIC ENTRY PROC [physical: Physical] RETURNS [ channel: Disk.Channel, rootStatus: PhysicalVolume.PhysicalRC, id: File.VolumeID, -- unique id of this physical volume -- name: ROPE, size: Disk.PageCount, free: Disk.PageCount, timeValid: BOOL, time: VolumeFormat.TimeParameters] = TRUSTED { ENABLE UNWIND => NULL; size _ Disk.DriveAttributes[physical.channel].nPages; channel _ physical.channel; rootStatus _ physical.rootStatus; IF rootStatus = ok THEN { <> origin: Disk.PageNumber _ [0]; free _ 0; DO start: Disk.PageNumber; thisTime: Disk.PageCount; [start, thisTime] _ AllocatePages[physical, size, origin]; IF thisTime <= 0 THEN EXIT; free _ free + thisTime - 1--don't report last page: it will be needed for a marker page--; origin _ [start + thisTime]; ENDLOOP; id _ physical.root.pvID; name _ physical.name; timeValid _ physical.root.timeParametersValid; time _ physical.root.timeParameters; }; }; --PhysicalVolume.--GetSubVolumes: PUBLIC ENTRY PROC [physical: Physical] RETURNS [sv: PhysicalVolume.SubVolumes] = TRUSTED { ENABLE UNWIND => NULL; IF physical.rootStatus # ok THEN RETURN WITH ERROR File.Error[physical.rootStatus]; sv _ NEW[PhysicalVolume.SubVolumesObject[physical.root.subVolumeCount]]; FOR i: CARDINAL IN [0..sv.count) DO svd: VolumeFormat.SubVolumeDesc = physical.root.subVolumes[i]; sv[i] _ [id: svd.lvID, start: svd.lvPage, size: svd.nPages, physical: physical, channel: physical.channel, address: svd.pvPage]; ENDLOOP; }; --FileInternal.--GetPhysicalLocation: PUBLIC ENTRY PROC [physical: Physical, root: VolumeFormat.PVBootFile] RETURNS [location: BootFile.Location] = TRUSTED { ENABLE UNWIND => NULL; IF physical.rootStatus # ok THEN RETURN WITH ERROR File.Error[physical.rootStatus]; location.diskFileID _ physical.root.bootingInfo[root]; [type: location.deviceType, ordinal: location.deviceOrdinal] _ Disk.DriveAttributes[physical.channel]; }; --FileInternal.--SetPhysicalLocation: PUBLIC ENTRY PROC [physical: Physical, root: VolumeFormat.PVBootFile, diskFileID: BootFile.DiskFileID] RETURNS [ rc: PhysicalVolume.PhysicalRC ] = TRUSTED { ENABLE UNWIND => NULL; IF physical.rootStatus # ok THEN RETURN[physical.rootStatus]; physical.root.bootingInfo[root] _ diskFileID; rc _ WritePhysicalMarkers[physical, update]; IF rc = ok THEN rc _ WriteRoot[physical]; }; WriteTimeParameters: PUBLIC ENTRY PROC [physical: Physical, timeValid: BOOL, time: VolumeFormat.TimeParameters] RETURNS [ PhysicalVolume.PhysicalRC ] = TRUSTED { ENABLE UNWIND => NULL; IF physical.rootStatus # ok THEN RETURN[physical.rootStatus]; physical.root.timeParametersValid _ timeValid; IF timeValid THEN physical.root.timeParameters _ time; RETURN[ WriteRoot[physical] ] }; PhysicalPageBad: PUBLIC ENTRY PROC [physical: Physical, address: Disk.PageNumber] RETURNS [ badTableFull: BOOL _ FALSE, status: PhysicalVolume.PhysicalRC _ ok ] = TRUSTED { <<--FileBackdoor.-->> ENABLE UNWIND => NULL; IF physical.rootStatus # ok THEN RETURN[FALSE, physical.rootStatus]; IF physical.bad = NIL THEN status _ ReadBadPageTable[physical]; IF status = ok THEN FOR i: Disk.PageCount IN [0..physical.root.badPageCount) DO IF physical.bad[i] = address THEN EXIT; REPEAT FINISHED => { IF physical.root.badPageCount >= VolumeFormat.allocatedBadPages THEN RETURN[TRUE, ok]; physical.bad[physical.root.badPageCount] _ address; status _ WriteBadPageTable[physical]; IF status = ok THEN { physical.root.badPageCount _ physical.root.badPageCount+1; status _ WriteRoot[physical]; IF status # ok THEN physical.root.badPageCount _ physical.root.badPageCount-1; }; } ENDLOOP; }; --PhysicalVolume.--GetBadPages: PUBLIC ENTRY PROC [subVolume: PhysicalVolume.SubVolumeDetails, work: PROC [VolumeFormat.LogicalPage]] = TRUSTED { <> ENABLE UNWIND => NULL; physical: Physical = subVolume.physical; root: LONG POINTER TO VolumeFormat.PhysicalRoot; data: PageData; status: Disk.Status; badPageCount: DiskFace.PageCount; IF physical.rootStatus # ok THEN RETURN WITH ERROR File.Error[physical.rootStatus]; <> [status, root]_ ReadPhysicalRoot[physical.channel]; IF status # Disk.ok THEN RETURN WITH ERROR File.Error[physical.rootStatus]; badPageCount_ root.badPageCount; FreePage[data_ LOOPHOLE[root]]; physical.bad_ NIL; [] _ ReadBadPageTable[physical]; IF physical.bad # NIL THEN FOR i: Disk.PageCount IN [0..badPageCount) DO bad: Disk.PageNumber = physical.bad[i]; IF bad >= subVolume.address AND bad < subVolume.address + subVolume.size THEN work[[bad-subVolume.address+subVolume.start]]; ENDLOOP; }; <<******** Accumulation of sub-volumes into logical volumes ********>> <> LogicalObject: TYPE = RECORD[ id: File.VolumeID, size: VolumeFormat.LogicalPageCount, subVols: LIST OF PhysicalVolume.SubVolumeDetails _ NIL, -- ordered list of fragments -- rest: REF LogicalObject _ NIL ]; Logical: TYPE = REF LogicalObject; logicalList: REF LogicalObject _ NIL; logicalWait: CONDITION _ [timeout: Process.SecondsToTicks[1]]; <> RegisterSubVolume: INTERNAL PROC [physical: Physical, svd: LONG POINTER TO VolumeFormat.SubVolumeDesc] = TRUSTED { l: Logical _ NIL; prev: Logical _ NIL; FOR l _ logicalList, l.rest UNTIL l = NIL DO IF l.id = svd.lvID THEN EXIT; prev _ l; REPEAT FINISHED => { l _ NEW[LogicalObject _ [id: svd.lvID, size: svd.lvSize, rest: NIL]]; IF prev = NIL THEN logicalList _ l ELSE prev.rest _ l; }; ENDLOOP; AddSubVolume[l, physical, svd]; }; AddSubVolume: INTERNAL PROC [l: Logical, physical: Physical, svd: LONG POINTER TO VolumeFormat.SubVolumeDesc] = TRUSTED { this: PhysicalVolume.SubVolumeDetails = NEW[PhysicalVolume.SubVolumeDetailsObject _ [ id: svd.lvID, start: svd.lvPage, size: svd.nPages, physical: physical, channel: physical.channel, address: svd.pvPage] ]; prev: LIST OF PhysicalVolume.SubVolumeDetails _ NIL; BROADCAST logicalWait; FOR sv: LIST OF PhysicalVolume.SubVolumeDetails _ l.subVols, sv.rest UNTIL sv = NIL DO IF sv.first.start > this.start THEN { <> IF this.start + this.size > sv.first.start THEN { physical.rootStatus _ inconsistent; RETURN }; IF prev = NIL THEN l.subVols _ CONS[first: this, rest: sv] ELSE prev.rest _ CONS[first: this, rest: sv]; EXIT }; IF sv.first.start + sv.first.size > this.start THEN { physical.rootStatus _ inconsistent; RETURN }; prev _ sv; REPEAT FINISHED => IF prev = NIL THEN l.subVols _ CONS[first: this, rest: NIL] ELSE prev.rest _ CONS[first: this, rest: NIL] ENDLOOP; }; lastPhysical: REF PhysicalObject _ NIL; -- last physical volume inspected by InnerNextLogical NextLogical: INTERNAL PROC RETURNS [next: Logical] = { <> prev: Logical _ NIL; FOR p: Physical _ InnerNextPhysical[lastPhysical].next, InnerNextPhysical[p].next UNTIL p = NIL DO lastPhysical _ p; ENDLOOP; <> FOR next _ logicalList, next.rest UNTIL next = NIL DO wanted: INT _ 0; <> FOR sv: LIST OF PhysicalVolume.SubVolumeDetails _ next.subVols, sv.rest UNTIL sv = NIL DO IF wanted # sv.first.start THEN EXIT; wanted _ wanted + sv.first.size; ENDLOOP; IF wanted = next.size THEN EXIT; prev _ next; ENDLOOP; IF next # NIL THEN { IF prev = NIL THEN logicalList _ next.rest ELSE prev.rest _ next.rest; next.rest _ NIL; }; }; <<******** Global list of File.Volume objects ********>> Volume: TYPE = REF VolumeObject; --File.--VolumeObject: PUBLIC TYPE = FileInternal.VolumeObject; volumeList: Volume _ NIL; -- known volumes -- --File.--NextVolume: PUBLIC ENTRY PROC [volume: Volume, wait: BOOL _ FALSE] RETURNS [next: Volume] = { ENABLE UNWIND => NULL; DO next _ IF volume = NIL THEN volumeList ELSE volume.rest; IF next # NIL THEN EXIT; { new: Logical = NextLogical[]; IF new # NIL THEN FoundVolume[new] ELSE { IF wait THEN WAIT logicalWait ELSE EXIT }; } ENDLOOP; }; FoundVolume: INTERNAL PROC [logical: Logical] = { volume: Volume = RegisterVolume[logical]; FileInternal.ReadRootPage[volume]; volume.initialised _ TRUE; }; RegisterVolume: INTERNAL PROC [logical: Logical] RETURNS [volume: Volume] = { <> volume _ NEW[VolumeObject _ [id: logical.id, subVolumes: logical.subVols, size: logical.size]]; IF volumeList = NIL THEN volumeList _ volume ELSE FOR v: Volume _ volumeList, v.rest DO IF v.rest = NIL THEN { v.rest _ volume; EXIT }; ENDLOOP; }; <<******** Creation of physical volumes ********>> --FileBackdoor.--CreatePhysicalVolume: PUBLIC ENTRY PROC [where: Disk.Channel, name: ROPE, id: File.VolumeID] RETURNS [new: Physical] = TRUSTED { ENABLE UNWIND => NULL; rc: PhysicalVolume.PhysicalRC _ ok; old: Physical; new _ NEW[PhysicalObject _ [channel: where, name: name]]; new.root _ LOOPHOLE[VM.AddressForPageNumber[VM.Allocate[pagePages].page]]; new.root^ _ [ pvID: id, labelLength: MIN[name.Length[], VolumeFormat.volumeLabelLength], subVolumeCount: 0, subVolumes: ALL[NULL] ]; FOR i: CARDINAL IN [0..new.root.labelLength) DO new.root.label[i] _ name.Fetch[i] ENDLOOP; new.bad _ LOOPHOLE[VM.AddressForPageNumber[VM.Allocate[pagePages].page]]; FOR old _ InnerNextPhysical[NIL], InnerNextPhysical[old] UNTIL old = NIL DO IF Disk.SameDrive[old.channel, where] THEN EXIT; ENDLOOP; IF old # NIL AND old.rootStatus = ok AND (old.bad # NIL OR ReadBadPageTable[old] = ok) THEN { new.bad^ _ old.bad^; new.root.badPageCount _ old.root.badPageCount; }; IF old # NIL THEN AbolishPhysical[old]; rc _ WriteBadPageTable[new, FALSE--write label directly--]; IF rc = ok THEN rc _ WriteRoot[new, FALSE--write label directly--]; IF rc # ok THEN RETURN WITH ERROR File.Error[rc]; RegisterPhysical[new]; }; AbolishPhysical: INTERNAL PROC [old: Physical] = { <> prevP: Physical _ NIL; prevV: Volume _ NIL; FOR p: Physical _ physicalList, p.rest UNTIL p = NIL DO IF p = old THEN { IF prevP = NIL THEN physicalList _ p.rest ELSE prevP.rest _ p.rest; EXIT } ELSE prevP _ p; ENDLOOP; IF old.rootStatus # ok THEN RETURN; FOR v: Volume _ volumeList, v.rest UNTIL v = NIL DO match: BOOL _ FALSE; prevSV: LIST OF PhysicalVolume.SubVolumeDetails _ NIL; FOR sv: LIST OF PhysicalVolume.SubVolumeDetails _ v.subVolumes, sv.rest UNTIL sv = NIL DO IF sv.first.physical = old THEN { match _ TRUE; IF prevSV = NIL THEN v.subVolumes _ sv.rest ELSE prevSV.rest _ sv.rest } ELSE prevSV _ sv; ENDLOOP; IF match THEN { <> IF prevV = NIL THEN volumeList _ v.rest ELSE prevV.rest _ v.rest; v.destroyed _ TRUE; -- tell clients volume object is no longer valid IF v.subVolumes # NIL THEN logicalList _ NEW[LogicalObject _ [id: v.id, size: v.size, subVols: v.subVolumes, rest: logicalList]]; } ELSE prevV _ v; ENDLOOP; }; <<******** Creation of logical volumes ********>> --FileBackdoor.--ReservePages: PUBLIC ENTRY PROC [physical: Physical, start: Disk.PageNumber, size: Disk.PageCount] = { <> ENABLE UNWIND => NULL; prev: ReservedList _ NIL; new: ReservedList = CONS[first: [start: start, size: size], rest: NIL]; IF physical.rootStatus # ok THEN RETURN WITH ERROR File.Error[physical.rootStatus]; FOR res: ReservedList _ physical.reserved, res.rest UNTIL res = NIL DO IF res.first.start >= start THEN EXIT; prev _ res; ENDLOOP; IF prev = NIL THEN { new.rest _ physical.reserved; physical.reserved _ new } ELSE { new.rest _ prev.rest; prev.rest _ new } }; --FileBackdoor.--ReserveNoPages: PUBLIC ENTRY PROC [physical: Physical] = { ENABLE UNWIND => NULL; physical.reserved _ NIL; }; FirstFreePage: INTERNAL PROC [physical: Physical] RETURNS [Disk.PageNumber] = TRUSTED { IF physical.root.subVolumeCount = 0 THEN RETURN[[3]] -- 0=>root, 1=>badPageTable, 2=>credentials ELSE { lastSV: VolumeFormat.SubVolumeDesc = physical.root.subVolumes[physical.root.subVolumeCount-1]; RETURN[[lastSV.pvPage + lastSV.nPages + 1--marker page--]] }; }; AllocatePages: INTERNAL PROC [physical: Physical, wanted: Disk.PageCount, origin: Disk.PageNumber] RETURNS [start: Disk.PageNumber, size: Disk.PageCount] = TRUSTED { <> <<>> <> start _ IF origin = 0 THEN FirstFreePage[physical] ELSE origin; FOR res: ReservedList _ physical.reserved, res.rest UNTIL res = NIL DO IF start >= res.first.start AND start < res.first.start + res.first.size THEN start _ [res.first.start + res.first.size]; ENDLOOP; <<>> <> size _ MIN[Disk.DriveAttributes[physical.channel].nPages - start, wanted]; FOR res: ReservedList _ physical.reserved, res.rest UNTIL res = NIL DO IF start < res.first.start AND start+size >= res.first.start THEN size _ res.first.start - start ENDLOOP; }; WriteSubVolume: INTERNAL PROC [logical: Logical, physical: Physical, lvPage: VolumeFormat.LogicalPage, start: Disk.PageNumber, size: Disk.PageCount--excludes marker page--] RETURNS [rc: PhysicalVolume.PhysicalRC] = TRUSTED { svd: LONG POINTER TO VolumeFormat.SubVolumeDesc = @physical.root.subVolumes[physical.root.subVolumeCount]; svd^ _ [ lvID: logical.id, lvSize: logical.size, lvPage: lvPage, pvPage: start, nPages: size]; rc _ WritePhysicalMarkers[physical, init]; IF rc # ok THEN RETURN; physical.root.subVolumeCount _ physical.root.subVolumeCount+1; rc _ WriteRoot[physical]; IF rc = ok THEN AddSubVolume[logical, physical, svd] ELSE physical.root.subVolumeCount _ physical.root.subVolumeCount-1; }; --FileBackdoor.--CreateLogicalVolume: PUBLIC ENTRY PROC [where: LIST OF Physical, size: INT, name: ROPE, id: File.VolumeID] RETURNS [volume: Volume _ NIL] = { ENABLE UNWIND => NULL; rc: File.RC _ ok; logical: Logical _ NEW[LogicalObject _ [id: id, size: size] ]; SubCreate: INTERNAL PROC [which: {check, doIt}] = TRUSTED { wanted: INT _ size; FOR p: LIST OF Physical _ where, p.rest UNTIL p = NIL OR wanted <= 0 DO physical: Physical = p.first; origin: Disk.PageNumber _ [0]; IF physical.rootStatus # ok THEN { rc _ physical.rootStatus; GOTO bad }; FOR i: CARDINAL IN [physical.root.subVolumeCount..VolumeFormat.maxSubVols) UNTIL wanted <= 0 DO start: Disk.PageNumber; thisTime: Disk.PageCount; [start, thisTime] _ AllocatePages[physical, wanted+1--marker page--, origin]; IF thisTime <= 0 THEN EXIT; IF thisTime > 1 THEN { <> IF which = doIt THEN rc _ WriteSubVolume[logical, physical, [size - wanted], start, thisTime-1]; IF rc # ok THEN GOTO bad; wanted _ wanted - (thisTime - 1--marker page--); }; origin _ [start + thisTime]; ENDLOOP; ENDLOOP; IF wanted > 0 THEN rc _ volumeFull; EXITS bad => NULL }; SubCreate[check]; -- don't do anything to the permanent data structures yet! IF rc = ok THEN { SubCreate[doIt]; volume _ RegisterVolume[logical]; rc _ FileInternal.InitRootPage[volume, name]; }; IF rc # ok THEN RETURN WITH ERROR File.Error[rc]; }; <<******** Marker Page Stuff ********>> MarkerPage: TYPE = MACHINE DEPENDENT RECORD[ -- This should be in VolumeFormat logical (0): VolumeFormat.LogicalSubvolumeMarker, fill1 (SIZE[VolumeFormat.LogicalSubvolumeMarker]): ARRAY [SIZE[VolumeFormat.LogicalSubvolumeMarker]..200B) OF WORD _ ALL[0], physical(200B): VolumeFormat.PhysicalMarker, fill2 (200B+SIZE[VolumeFormat.PhysicalMarker]): ARRAY [200B+SIZE[VolumeFormat.PhysicalMarker]..377B) OF WORD _ ALL[0], checksum(377B): CARDINAL _ 0 ]; WritePhysicalMarkers: INTERNAL PROC [physical: Physical, which: {init, update}] RETURNS [rc: PhysicalVolume.PhysicalRC _ ok] = { }; --FileInternal.--WriteLogicalMarkers: PUBLIC ENTRY PROC [volume: Volume] RETURNS [rc: File.RC _ ok] = { ENABLE UNWIND => NULL; }; --FileInternal.--InitLogicalMarkers: PUBLIC INTERNAL PROC [volume: Volume] RETURNS [rc: File.RC _ ok] = { <> }; }. <> <> <<>>