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 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; --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; 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; 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; 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; --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; --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; 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. öCedar Nucleus (Files): access to physical and logical volumes PhysicalVolumeImpl.mesa Andrew Birrell December 7, 1983 4:49 pm Last Edited by: Levin, August 8, 1983 6:04 pm This implementation currently doesn't handle correctly volumes going offline. (ADB November 22, 1983 2:30 pm). ******** Raw access to global pages of the volume ******** I'd prefer using the pvID and a separate file type. For now, compatibility wins (ADB) Need to do a second transfer to get the label verify. Beware of Dolphin 8 word labels! ******** Global list of Physical Volumes ******** -- Broadcast on new physical volume; timeout causes poll for new channel. now register the existence of its sub-volumes ******** Operations on Physical root and bad page table ******** Count free pages by repeated allocations. AllocatePages doesn't update anything! ******** Accumulation of sub-volumes into logical volumes ******** As logical sub-volumes are encountered (by physical volumes coming on-line, or by being created), they are accumulated in the list of "LogicalObject"s. Calling "GetNextLogical" will find if any "LogicalObject" describes a complete logical volume, and if so will (optionally) remove it from the list of "LogicalObject"s and return it. Broadcast on new sub-volume; timeout causes poll for new channel. First, check for any more physical volumes; InnerNextPhysical may call RegisterSubVolume Search for complete logical volumes check entire volume is known -- ******** Global list of File.Volume objects ******** Construct a File.VolumeObject from the sub-volumes accumulated in a "LogicalObject" and add it to the global list. ******** Creation of physical volumes ******** Remove physical volume and its sub-volumes from various lists Remove from list of complete volumes, and build "LogicalObject" for remaining sv's ******** Creation of logical volumes ******** Called by high-level client to prevent allocation of various reserved areas of disk (initial microcode, Alto partitions) Returns the first free run of pages, not exceeding the wanted size. This procedure assumes that "physical.reserved" is sorted by non-decreasing start address. Loop 1: ensure start isn't inside a reserved area: Loop 2: restrict size to not reach into a reserved area ******** Marker Page Stuff ******** NOTE: this is called only from inside FileInternal.InitRootPage, which is called from CreateLogicalVolume, which is inside our monitor. Hence this is "INTERNAL". This mess is caused by the physical and logical marker info being on a single page. ʳ˜Jšœ>™>Jšœ™Jšœ(™(J™-J™šÏk ˜ Jšœ œ˜'JšœœŒ˜–Jšœ œ˜Jšœœ œ ˜"Jšœ œ˜Jšœ œ>˜PJšœ ˜ Jšœœd˜xJšœœ˜ JšœœY˜aJšœœœ˜/—J˜šœœ˜!Jšœ Ïc œ˜ž ˜I—šœ˜ Jšœœ˜)J˜ Jšœœ˜$Jšœ œœ˜J˜—Jšœ˜—J˜šŸ œœœ˜.J˜Jšœœœœ ˜"J˜J˜Jšœ œž4œ˜GJšœ˜(Jš˜Jšœœœœ0˜SJ˜˜J˜J˜ ˜Jš œœ œœœœœ˜PJšœœœœ˜.—J˜ —Jšœ œ0˜@J˜6Jšœœ0˜BJšœ˜—J˜šŸœœœ˜/Jšœœ œ2˜E—J˜šŸœœ˜%J˜Jšœœœœ ˜"Jšœ œ˜Jšœ*˜8Jš˜Jšœœœ˜œ ˜‘Jš˜Jšœ'˜'šœV˜VJšœœ˜!—Jšœ(˜.Jšœ˜—J˜š Ÿœœœ>œ ˜‰Jš˜Jšœ'˜'šœV˜VJšœžœ˜B—Jšœ(˜.Jšœ˜—J˜—J˜Jšœ4™4˜šžœœœœ˜8J˜Jšœ+˜+Jš œœœœœ˜6Jš œœœœœ˜4Jšœ œœ˜Jšœœ˜Jšœœœ˜!—J˜Jš œœœœœ/˜RJ˜Jšœ œœ˜$J˜Jšœœœž˜DJ˜š Ÿ œœœœœœ˜]Jš˜Jšœœœ˜Jš œ$œœœœœ˜SJšœ˜—J˜šœ œ(˜?JšœF™F—J˜Jšœœ˜ J˜šŸœœœ˜0Jšœ˜!Jš˜š œœœœœ ˜9Jšœœœœ˜š˜J˜2Jšœ˜ Jšœ:˜>Jšœœ˜ —Jšœ˜—Jšœ˜Jšœ˜—J˜šŸœœœ˜0Jš˜Jšœœ˜Jš œ$œœœ œ˜IJšœœœœ˜;Jš œ˜Jšœ˜—J˜š Ÿ œœœœ˜RJš˜J˜Jšœœ&˜/Jšœœ/œœ˜@J˜/Jšœ6˜6Jšœœœ˜#Jšœ$˜&Jšœ1˜3Jšœ"œ˜/Jšœ>˜EJšœ-™-Jšœœœ˜*Jšœ1œ˜;Jšœ˜—J˜—J˜Jšœ@™@˜šŸœœ˜Jšœœœœœœ%œœ˜PJšœœ˜ Jšœœ˜Jš˜Jš œœœœœ ˜#Jš œœœ œœ˜8J˜Jšœ˜Jšœ˜—J˜š Ÿ œœœœœ˜˜>Jšœ'˜'—Jšœ˜—J˜š žŸœœœœUœ$˜¾Jš˜Jšœœœ˜Jšœœœ˜=Jšœ-˜-J˜,Jšœ œ˜)Jšœ˜—J˜š Ÿœœœœ œ%œ ˜Jš˜Jšœœœ˜Jšœœœ˜=Jšœ.˜.Jšœ œ%˜6Jšœ˜Jšœ˜—J˜š žŸœœœœ/œ-˜ŸJš˜Jšœœœ˜Jšœœœ˜=Jšœœœ%˜?Jšœ ˜šœ˜ Jšœœ ˜8Jšœœœœ˜*šœœ˜Jš˜Jšœ3˜3Jšœ%˜%Jšœ ˜šœ˜ Jšœ:˜:Jšœ˜Jšœ œ;˜NJšœ˜—Jš˜—Jšœ˜Jšœ˜—Jšœ˜—J˜š žŸ œœœœ3œ˜Jš˜Jšœœœ˜Jšœ(˜(Jš œœœœœ!˜SJšœœœ!˜;Jšœ˜šœœœ ˜=šœ(˜*Jšœ˜Jšœ)˜,Jšœ/˜3—Jšœ˜—Jšœ˜—J˜—J˜JšœB™B˜JšœÎ™ÎJ˜šœœœ˜J˜J˜$Jšœ œœ#œž˜WJšœœœ˜ —J˜Jšœ œœ˜"J˜Jšœ œœ˜%J˜šœ œ(˜>JšœA™A—J˜š Ÿœœœœœœ˜oJš˜Jšœ œ˜Jšœœ˜Jšœœ˜)šœœœœ˜ Jšœ ˜ —šœœ˜Jš˜Jšœœ8œ˜EJšœœœœ˜6Jšœ˜—Jšœ˜Jšœ˜Jšœ˜—J˜š Ÿ œœœ&œœœ˜vJš˜šœ(œ*˜UJ˜ J˜J˜Jšœ˜Jšœ˜J˜—Jšœœœ#œ˜4Jš œ ˜Jš œœœ6œ˜Sšœœ˜!šœœž˜#Jšœ(˜*Jšœ'œ˜4Jšœ˜ Jšœ œ˜,Jšœ œ˜-Jš˜Jšœ˜—Jšœ,˜.Jšœ'œ˜4J˜ —šœœ˜Jšœ˜ Jšœ œœ˜-Jšœ œœ˜-—Jšœ˜Jšœ˜—J˜Jšœœœž5˜]J˜šŸ œœœœ˜3Jš˜JšœY™YJšœœ˜JšœN˜QJšœ˜ Jšœœ˜Jšœ#™#Jšœœ˜2šœ œ˜Jšœ™Jšœœœ8˜GJšœ˜šœœœœ˜(J˜ —Jšœ˜Jšœœœ˜ J˜ —Jšœ˜Jšœ˜ šœ˜ Jšœœœœ˜FJšœ œ˜Jšœ˜—Jšœ˜—J˜—J˜Jšž œž%™4˜Jšœœœ˜ J˜Jšž œœœ˜?J˜Jšœœž˜-J˜š ž Ÿ œœœœœœ˜JJšœ˜Jš˜Jšœœœ˜š œœ œœ œ ˜;Jšœœœœ˜š˜Jšœ˜Jšœ˜ Jšœ˜Jš œœœœ œœ˜1—Jš˜—Jšœ˜Jšœ˜—J˜šŸ œœœ˜.Jš˜Jšœ)˜)Jšœ"˜"Jšœœ˜Jšœ˜—J˜šŸœœœœ˜IJš˜Jšœr™ršœ˜JšœS˜V—Jšœ˜Jšœ˜šœœ˜'Jš œœ œœœœ˜:—Jšœ˜—J˜—J˜Jšœ.™.˜šžŸœœœœ!œœ˜”Jš˜Jšœœœ˜Jšœ#˜#Jšœ˜Jšœœ0˜9Jšœ œœœ˜Jšœ ˜ Jšœ ˜ Jšœ œ0˜@Jšœ˜Jšœ œœ˜—Jšœœœ˜,Jšœ#œ˜-Jšœ œœœ˜IJšœœœ˜HJš œœ$œœœ˜;Jšœœœ˜$Jšœ œœ˜1JšœH˜LJšœœœ˜'Jšœžœ˜;Jšœ œžœ˜CJš œ œœœœ˜1J˜Jšœ˜—J˜šŸœœœ˜/Jš˜Jšœ=™=Jšœœ˜Jšœœ˜Jšœ$œ˜4šœœ˜ Jš œœ œœœœ˜QJšœ ˜—Jšœ˜Jšœœœ˜#Jšœ œ˜0šœœœ˜Jšœœœ#œ˜6Jšœœœ8˜GJšœ˜šœœ˜šœ œ˜Jšœ œœœ˜H—Jšœ ˜—Jšœ˜Jšœ˜šœ˜ JšœR™RJšœ œœœ˜AJšœœž0˜DJšœ˜šœ˜JšœU˜X—Jš˜—Jšœ ˜—Jšœ˜Jšœ˜—J˜—J˜Jšœ-™-˜š žŸ œœœœD˜vJšœx™xJš˜Jšœœœ˜Jšœœ˜Jšœœ*œ˜GJš œœœœœ!˜SJšœ1œ˜Cšœœœœ˜)J˜ —Jšœ˜Jšœ˜ Jšœ:˜>Jšœ*˜.Jšœ˜—J˜š žŸœœœœ˜JJš œœœœœ˜3J˜—š Ÿ œœœœ˜SJš˜Jšœ!˜#Jšœœž+˜<šœ˜ šœ$˜$Jšœ9˜9—Jšœ#žœ˜:Jšœ˜—Jšœ˜—J˜š Ÿ œœœFœ1˜¡JšœŸ™ŸJš˜™2Jšœœ œœ˜?Jšœ1œ˜Cšœœœ)˜KJšœ,˜0—Jšœ˜—šœ7™7Jšœœ@˜JJšœ1œ˜Cšœœœ˜?Jšœ˜#—Jšœ˜—Jšœ˜—J˜š Ÿœœœužœœ"˜ÝJš˜šœœœœ˜1Jšœ8˜8—šœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—J˜*Jšœ œœ˜Jšœ>˜>Jšœ˜Jšœ˜ Jšœ%˜)Jšœ?˜CJšœ˜—J˜šžŸœœœœœœœ œœœ˜¡Jš˜Jšœœœ˜Jšœ œ˜Jšœœ(˜>šŸ œœœ˜8Jš˜Jšœœ˜Jš œœœœœœ ˜Dšœ˜ Jšœ˜Jšœœœ˜HJšœœœ8˜JJšœ ˜šœ˜Jšœ˜Jšœ4žœ ˜MJšœœœ˜JšœžD˜Tš ˜ Jšœ ˜JšœL˜PJšœ œœ˜Jšœžœ˜0Jšœ˜—J˜—Jšœ˜—Jšœ˜Jšœ œ˜#Jšœ˜Jšœ˜—Jšœž:˜LJšœ˜ šœ˜ Jšœ˜J˜!J˜-Jšœ˜—Jš œ œœœœ˜1Jšœ˜—J˜—J˜Jšœ#™#˜š œ œœ œœž!˜NJšœ1˜1šœœ'˜2Jš œœ-œœœ˜I—Jšœ,˜,šœ œ˜/Jš œœ%œœœ˜F—Jšœœ˜Jšœ˜—J˜šŸœœœ,œ&˜|Jš˜Jšœ˜—J˜š žŸœœœœœ œ˜cJš˜Jšœœœ˜Jšœ˜—J˜š žŸœœœœœ œ˜eJš˜Jšœø™øJšœ˜—J˜—J˜Jšœ˜J˜J˜—…—WªS