<> <> <> <> <<>> DIRECTORY BootFile USING[ DiskFileID, Location ], Disk USING[ DoIO, Channel, DriveAttributes, InspectDiskShape, Label, labelCheck, NextChannel, ok, PageCount, PageNumber, Request, SameDrive, Status ], DiskFace USING[ wordsPerPage ], File USING[ Error, RC, VolumeID ], FileExtra 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, FileExtra, FileInternal--GetPhysicalLocation--, PhysicalVolume = BEGIN <> <<******** 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 BEGIN RETURN[ [ fileID: [abs[AbsID[id]]], filePage: 0, attributes: Attributes[physicalRoot], dontCare: LOOPHOLE[LONG[0]] ] ] END; BadPageTableLabel: PROC[id: File.VolumeID] RETURNS[label: Disk.Label] = TRUSTED BEGIN label _ PhysRootLabel[id]; label.filePage _ 1; END; CredentialsLabel: PROC RETURNS[Disk.Label] = TRUSTED BEGIN <> 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]] ] ] END; 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 BEGIN 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]]; END; 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 BEGIN data _ VM.AddressForPageNumber[VM.Allocate[pagePages].page]; status _ AccessPage[channel, page, label, data, read, verifyLabel]; IF status # Disk.ok THEN { FreePage[data]; data _ NIL }; END; ReadPhysicalRoot: PROC[channel: Disk.Channel] RETURNS[ status: Disk.Status, root: LONG POINTER TO VolumeFormat.PhysicalRoot ] = TRUSTED BEGIN label: Disk.Label; data: PageData; [status, data] _ ReadPage[channel, VolumeFormat.rootPageNumber, @label, FALSE]; root _ LOOPHOLE[data]; IF status = Disk.ok THEN BEGIN <> label _ PhysRootLabel[root.pvID]; status _ AccessPage[channel, VolumeFormat.rootPageNumber, @label, data, read, TRUE]; IF status # Disk.ok THEN { FreePage[data]; root _ NIL }; END; END; WriteRoot: INTERNAL PROC[physical: Physical, verifyLabel: BOOL _ TRUE] RETURNS[ PhysicalVolume.PhysicalRC ] = TRUSTED BEGIN 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] ] END; badPageNumber: Disk.PageNumber = [VolumeFormat.rootPageNumber+1]; ReadBadPageTable: INTERNAL PROC[physical: Physical] RETURNS[PhysicalVolume.PhysicalRC] = TRUSTED BEGIN status: Disk.Status; label: Disk.Label _ BadPageTableLabel[physical.root.pvID]; [status, physical.bad] _ ReadPage[physical.channel, badPageNumber, @label, TRUE]; RETURN[FileInternal.TranslateStatus[status]] END; WriteBadPageTable: INTERNAL PROC[physical: Physical, verifyLabel: BOOL _ TRUE] RETURNS[PhysicalVolume.PhysicalRC] = TRUSTED BEGIN status: Disk.Status; label: Disk.Label _ BadPageTableLabel[physical.root.pvID]; status _ AccessPage[physical.channel, badPageNumber, @label, physical.bad, write, verifyLabel]; RETURN[FileInternal.TranslateStatus[status]] END; ReadCredentials: PUBLIC UNSAFE PROC[physical: Physical, credentials: PhysicalVolume.Credentials] RETURNS[ PhysicalVolume.PhysicalRC ] = UNCHECKED BEGIN label: Disk.Label _ CredentialsLabel[]; status: Disk.Status = AccessPage[physical.channel, VolumeFormat.credentialsPageNumber, @label, credentials, read, TRUE]; RETURN[ FileInternal.TranslateStatus[status] ] END; WriteCredentials: PUBLIC PROC[physical: Physical, credentials: PhysicalVolume.Credentials] RETURNS[ PhysicalVolume.PhysicalRC ] = TRUSTED BEGIN label: Disk.Label _ CredentialsLabel[]; status: Disk.Status = AccessPage[physical.channel, VolumeFormat.credentialsPageNumber, @label, credentials, write, FALSE--write label unconditionally--]; RETURN[ FileInternal.TranslateStatus[status] ] END; <<******** 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.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 BEGIN ENABLE UNWIND => NULL; WHILE (next _ InnerNextPhysical[prev]) = NIL AND wait DO WAIT physicalWait ENDLOOP; END; physicalWait: CONDITION _ [timeout: Process.SecondsToTicks[1]]; <> lastChannel: Disk.Channel _ NIL; InnerNextPhysical: INTERNAL PROC[prev: Physical] RETURNS[next: Physical] = TRUSTED BEGIN DO next _ IF prev = NIL THEN physicalList ELSE prev.rest; IF next # NIL THEN EXIT; BEGIN new: Disk.Channel = Disk.NextChannel[lastChannel]; IF new # NIL THEN { RegisterPhysical[NewPhysical[new]]; lastChannel _ new } ELSE EXIT; END; ENDLOOP; END; RegisterPhysical: INTERNAL PROC[new: Physical] = BEGIN 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; END; NewPhysical: INTERNAL PROC[channel: Disk.Channel] RETURNS[new: Physical] = TRUSTED BEGIN 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; END; <<******** 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.ROPE] = TRUSTED BEGIN 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]] END; PhysicalInfo: PUBLIC ENTRY PROC[physical: Physical] RETURNS[ channel: Disk.Channel, rootStatus: PhysicalVolume.PhysicalRC, id: File.VolumeID, -- unique id of this physical volume -- name: Rope.ROPE, size: Disk.PageCount, free: Disk.PageCount, timeValid: BOOL, time: VolumeFormat.TimeParameters] = TRUSTED BEGIN ENABLE UNWIND => NULL; size _ Disk.DriveAttributes[physical.channel].nPages; channel _ physical.channel; rootStatus _ physical.rootStatus; IF rootStatus = ok THEN BEGIN <> 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; END; END; --PhysicalVolume.--GetSubVolumes: PUBLIC ENTRY PROC[physical: Physical] RETURNS[sv: PhysicalVolume.SubVolumes] = TRUSTED BEGIN 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; END; --FileInternal.--GetPhysicalLocation: PUBLIC ENTRY PROC[physical: Physical, root: VolumeFormat.PVBootFile] RETURNS[location: BootFile.Location] = TRUSTED BEGIN 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]; END; --FileInternal.--SetPhysicalLocation: PUBLIC ENTRY PROC[physical: Physical, root: VolumeFormat.PVBootFile, diskFileID: BootFile.DiskFileID] RETURNS[ rc: PhysicalVolume.PhysicalRC ] = TRUSTED BEGIN 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]; END; WriteTimeParameters: PUBLIC ENTRY PROC[physical: Physical, timeValid: BOOL, time: VolumeFormat.TimeParameters] RETURNS[ PhysicalVolume.PhysicalRC ] = TRUSTED BEGIN 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] ] END; --PhysicalVolume.--PhysicalPageBad: PUBLIC ENTRY PROC[physical: Physical, address: Disk.PageNumber] RETURNS[ status: PhysicalVolume.PhysicalRC _ ok ] = TRUSTED BEGIN ENABLE UNWIND => NULL; IF physical.rootStatus # ok THEN RETURN[physical.rootStatus]; IF physical.bad = NIL THEN status _ ReadBadPageTable[physical]; IF status = ok THEN BEGIN FOR i: Disk.PageCount IN [0..physical.root.badPageCount) DO IF physical.bad[i] = address THEN EXIT; REPEAT FINISHED => BEGIN physical.bad[physical.root.badPageCount] _ address; status _ WriteBadPageTable[physical]; IF status = ok THEN BEGIN physical.root.badPageCount _ physical.root.badPageCount+1; status _ WriteRoot[physical]; IF status # ok THEN physical.root.badPageCount _ physical.root.badPageCount-1; END; END ENDLOOP; END; END; --PhysicalVolume.--GetBadPages: PUBLIC ENTRY PROC[subVolume: PhysicalVolume.SubVolumeDetails, work: PROC[VolumeFormat.LogicalPage]] = TRUSTED BEGIN ENABLE UNWIND => NULL; physical: Physical = subVolume.physical; IF physical.rootStatus # ok THEN RETURN WITH ERROR File.Error[physical.rootStatus]; IF physical.bad = NIL THEN [] _ ReadBadPageTable[physical]; IF physical.bad # NIL THEN FOR i: Disk.PageCount IN [0..physical.root.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; END; <<******** 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 BEGIN 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 => BEGIN l _ NEW[LogicalObject _ [id: svd.lvID, size: svd.lvSize, rest: NIL]]; IF prev = NIL THEN logicalList _ l ELSE prev.rest _ l; END; ENDLOOP; AddSubVolume[l, physical, svd]; END; AddSubVolume: INTERNAL PROC[l: Logical, physical: Physical, svd: LONG POINTER TO VolumeFormat.SubVolumeDesc] = TRUSTED BEGIN 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 BEGIN -- insert before "sv" -- 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 END; 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; END; lastPhysical: REF PhysicalObject _ NIL; -- last physical volume inspected by InnerNextLogical NextLogical: INTERNAL PROC RETURNS[next: Logical] = BEGIN <> 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 BEGIN IF prev = NIL THEN logicalList _ next.rest ELSE prev.rest _ next.rest; next.rest _ NIL; END; END; <<******** 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] = BEGIN ENABLE UNWIND => NULL; DO next _ IF volume = NIL THEN volumeList ELSE volume.rest; IF next # NIL THEN EXIT; BEGIN new: Logical = NextLogical[]; IF new # NIL THEN FoundVolume[new] ELSE { IF wait THEN WAIT logicalWait ELSE EXIT }; END ENDLOOP; END; FoundVolume: INTERNAL PROC[logical: Logical] = BEGIN volume: Volume = RegisterVolume[logical]; FileInternal.ReadRootPage[volume]; volume.initialised _ TRUE; END; RegisterVolume: INTERNAL PROC[logical: Logical] RETURNS[volume: Volume] = BEGIN <> 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; END; <<******** Creation of physical volumes ********>> --PhysicalVolume.--CreatePhysicalVolume: PUBLIC ENTRY PROC[where: Disk.Channel, name: Rope.ROPE, id: File.VolumeID] RETURNS[new: Physical] = TRUSTED BEGIN 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]; END; AbolishPhysical: INTERNAL PROC[old: Physical] = BEGIN <> 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 BEGIN <> 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]]; END ELSE prevV _ v; ENDLOOP; END; <<******** Creation of logical volumes ********>> --PhysicalVolume.--ReservePages: PUBLIC ENTRY PROC[physical: Physical, start: Disk.PageNumber, size: Disk.PageCount] = <> BEGIN 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 } END; --PhysicalVolume.--ReserveNoPages: PUBLIC ENTRY PROC[physical: Physical] = { ENABLE UNWIND => NULL; physical.reserved _ NIL }; FirstFreePage: INTERNAL PROC[physical: Physical] RETURNS[Disk.PageNumber] = TRUSTED BEGIN IF physical.root.subVolumeCount = 0 THEN RETURN[[3]] -- 0=>root, 1=>badPageTable, 2=>credentials ELSE BEGIN lastSV: VolumeFormat.SubVolumeDesc = physical.root.subVolumes[physical.root.subVolumeCount-1]; RETURN[[lastSV.pvPage + lastSV.nPages + 1--marker page--]] END; END; AllocatePages: INTERNAL PROC[physical: Physical, wanted: Disk.PageCount, origin: Disk.PageNumber] RETURNS[start: Disk.PageNumber, size: Disk.PageCount] = TRUSTED <> BEGIN <> 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; END; WriteSubVolume: INTERNAL PROC[logical: Logical, physical: Physical, lvPage: VolumeFormat.LogicalPage, start: Disk.PageNumber, size: Disk.PageCount--excludes marker page--] RETURNS[rc: PhysicalVolume.PhysicalRC] = TRUSTED BEGIN 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; END; --PhysicalVolume.--CreateLogicalVolume: PUBLIC ENTRY PROC[where: LIST OF Physical, size: INT, name: Rope.ROPE, id: File.VolumeID] RETURNS[volume: Volume _ NIL] = BEGIN ENABLE UNWIND => NULL; rc: File.RC _ ok; logical: Logical _ NEW[LogicalObject _ [id: id, size: size] ]; SubCreate: INTERNAL PROC[which: {check, doIt}] = TRUSTED BEGIN 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 -- ignore single-page runs, because they only allow the marker page! THEN BEGIN 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--); END; origin _ [start + thisTime]; ENDLOOP; ENDLOOP; IF wanted > 0 THEN rc _ volumeFull; EXITS bad => NULL END; SubCreate[check]; -- don't do anything to the permanent data structures yet! IF rc = ok THEN BEGIN SubCreate[doIt]; volume _ RegisterVolume[logical]; rc _ FileInternal.InitRootPage[volume, name]; END; IF rc # ok THEN RETURN WITH ERROR File.Error[rc]; END; <<******** 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] = BEGIN END; --FileInternal.--WriteLogicalMarkers: PUBLIC ENTRY PROC[volume: Volume] RETURNS[rc: File.RC _ ok] = BEGIN ENABLE UNWIND => NULL; END; --FileInternal.--InitLogicalMarkers: PUBLIC INTERNAL PROC[volume: Volume] RETURNS[rc: File.RC _ ok] = BEGIN <> END; END.