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; 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] ] }; --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; }; 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 { 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; }; 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; }; }; 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; }; --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; }; --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]; }; 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] = { }; }. PhysicalVolumeImpl.mesa - access to physical and logical volumes Copyright c 1985 by Xerox Corporation. All rights reserved. Andrew Birrell December 7, 1983 4:49 pm Levin, August 8, 1983 6:04 pm Willie-sue, August 20, 1984 4:42:56 pm PDT Bob Hagmann January 31, 1985 10:56:13 am PST Russ Atkinson (RRA) May 14, 1985 12:49:48 pm PDT 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! --FileBackdoor.-- need to read the bad page table and count from disk because they might have changed since the volume was full-booted IF physical.bad = NIL THEN [] _ ReadBadPageTable[physical]; ******** 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. insert before "sv" 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 ignore single-page runs, because they only allow the marker page! ******** 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. Bob Hagmann January 29, 1985 1:55:55 pm PST Cedar 6.0 conversion- change to FileBackdoor interface Κn˜codešœ@™@Kšœ Οmœ1™Ÿ ˜I—šžœ˜ Kšœžœ˜)K˜ Kšœžœ˜$Kšœ žœžœ˜K˜—Kšœ˜—K˜š  œžœžœ8žœžœžœFžœŸ4œžœžœ˜ŠKšžœžœžœžœ0˜SK˜˜K˜K˜ ˜Kš œžœ žœžœžœžœžœ˜PKšœžœžœžœ˜.—K˜ —Kšžœ žœ0˜@K˜6Kšžœžœ0˜BKšœ˜—K˜š œžœžœžœ˜2Kšžœ žœ2˜C—K˜š œžœ7žœžœžœžœžœ+žœ˜―Kšœžœžœ˜Kšžœžœ˜ —Kšœ˜—Kšžœ˜—Kšœ˜—K˜š œžœžœ˜3Kšœžœ˜Kš žœ$žœžœžœ žœ˜IKšžœžœžœžœ˜;Kšž œ˜Kšœ˜—K˜š   œžœžœžœžœ˜VK˜Kšœžœ&˜/Kšžœžœ/žœžœ˜@K˜/Kšœ6˜6Kšžœžœžœ˜#šžœ$˜&Kšžœ1˜3Kšžœ"žœ˜/—Kšžœ>˜EKšœ-™-šžœžœžœž˜-Kšœ0˜0Kšžœ˜—Kšœ˜—K˜—K˜Kšœ@™@˜š œžœ žœžœžœžœžœ%žœžœ žœžœžœžœ˜‡Kš œžœžœžœžœ ˜#Kš žœžœžœ žœžœ˜8K˜Kšžœ˜Kšœ˜—K˜š  œžœžœžœžœSŸ'œžœ9žœ'žœ˜―Kšžœžœžœ˜K˜5K˜K˜!šžœžœ˜KšœQ™QKšœ˜Kšœ ˜ šžœ˜Kšœ˜Kšœ:˜:Kšžœžœžœ˜KšœŸ?œ˜ZKšœ˜Kšžœ˜—K˜Kšœ˜Kšœ.˜.Kšœ$˜$Kšœ˜—Kšœ˜—K˜š Ÿ  œžœžœžœžœ#žœ˜|Kšžœžœžœ˜Kš žœžœžœžœžœ!˜SKšœžœ@˜Hšžœžœžœž˜#Kšœ>˜>šœ˜Kšœ˜Kšœ˜K˜K˜Kšœ˜—Kšžœ˜—Kšœ˜—K˜š Ÿ œžœžœžœ5žœ!žœ˜Kšžœžœžœ˜Kš žœžœžœžœžœ!˜SKšœ6˜6šœ>˜>Kšœ'˜'—Kšœ˜—K˜š Ÿ œžœžœžœVžœ%žœ˜ΒKšžœžœžœ˜Kšžœžœžœ˜=Kšœ-˜-K˜,Kšžœ žœ˜)Kšœ˜—K˜š œžœžœžœ!žœ%žœ!žœ˜‘Kšžœžœžœ˜Kšžœžœžœ˜=Kšœ.˜.Kšžœ žœ%˜6Kšžœ˜Kšœ˜—K˜š œžœžœžœ0žœž œ-žœ˜¬KšŸ™Kšžœžœžœ˜Kšžœžœžœžœ˜DKšžœžœžœ%˜?šžœ ž˜šžœžœ ž˜;Kšžœžœžœ˜'šžœžœ˜Kšžœ>žœžœžœ˜VKšœ3˜3Kšœ%˜%šžœ žœ˜Kšœ:˜:Kšœ˜Kšžœ žœ;˜NKšœ˜—Kšœ˜—Kšžœ˜——Kšœ˜—K˜š Ÿ  œžœžœžœ3žœžœ˜‘Kšœt™tKšžœžœžœ˜Kšœ(˜(Kšœžœžœžœ˜0K˜Kšœ˜Kšœ!˜!Kš žœžœžœžœžœ!˜SKšžœžœžœ!™;Kšœ3˜3Kš žœžœžœžœžœ!˜KKšœ ˜ Kšœžœ˜K˜Kšœžœ˜Kšœ ˜ šžœž˜šžœžœž˜-šœ'˜'šžœžœ)ž˜MKšœ.˜.——Kšžœ˜——Kšœ˜—K˜—K˜KšœB™B˜KšœΞ™ΞK˜šœžœžœ˜K˜K˜$Kšœ žœžœ#žœŸ˜WKšœžœžœ˜ —K˜Kšœ žœžœ˜"K˜Kšœ žœžœ˜%K˜šœ ž œ(˜>KšœA™A—K˜š œžœžœžœžœžœžœ˜rKšœ žœ˜Kšœžœ˜šžœžœž˜,Kšžœžœžœ˜Kšœ ˜ šžœžœ˜Kšœžœ8žœ˜EKšžœžœžœžœ˜6Kšœ˜—Kšžœ˜—Kšœ˜Kšœ˜—K˜š  œžœžœ'žœžœžœžœ˜yšœ(žœ*˜UK˜ K˜K˜Kšœ˜Kšœ˜K˜—Kšœžœžœ#žœ˜4Kšž œ ˜š žœžœžœ6žœž˜Všžœžœ˜%Kšœ™šžœ(žœ˜1Kšœ#˜#Kšžœ˜ —šžœž˜ Kšžœ žœ˜,Kšžœ žœ˜-—Kšž˜Kšœ˜—šžœ,žœ˜5Kšœ#˜#Kšžœ˜ —K˜ šžœžœ˜šžœž˜ Kšžœ žœžœ˜-Kšžœ žœžœ˜-——Kšžœ˜—Kšœ˜—K˜KšœžœžœŸ5˜]K˜š  œžœžœžœ˜6KšœY™YKšœžœ˜šžœNžœž˜bKšœ˜Kšžœ˜—Kšœ#™#šžœžœž˜5Kšœžœ˜Kšœ™š žœžœžœ8žœžœž˜YKšžœžœžœ˜%K˜ Kšžœ˜—Kšžœžœžœ˜ K˜ Kšžœ˜—šžœžœ˜Kšžœžœžœžœ˜FKšœ žœ˜Kšœ˜—Kšœ˜—K˜—K˜KšŸ œŸ%™4˜Kšœžœžœ˜ K˜KšŸ œžœžœ˜?K˜KšœžœŸ˜-K˜šŸ   œžœžœžœžœžœžœ˜fKšžœžœžœ˜šž˜Kš œžœ žœžœ žœ ˜8Kšžœžœžœžœ˜šœ˜Kšœ˜šžœž˜ Kšžœ˜Kš žœžœžœžœ žœžœ˜1—Kšœ˜—Kšžœ˜—Kšœ˜—K˜š  œžœžœ˜1Kšœ)˜)Kšœ"˜"Kšœžœ˜Kšœ˜—K˜š œžœžœžœ˜MKšœr™rKšœžœS˜_šžœž˜Kšžœ˜šžœžœž˜*Kšžœ žœžœžœ˜/Kšžœ˜——Kšœ˜—K˜—K˜Kšœ.™.˜šŸ œžœžœžœžœžœžœ˜‘Kšžœžœžœ˜Kšœ#˜#Kšœ˜Kšœžœ0˜9Kšœ žœžœžœ˜Jšœ ˜ Kšœ ˜ Kšœ žœ0˜@Kšœ˜Kšœ žœžœ˜—Kšžœžœžœ˜,Kšžœ#žœ˜-Kšœ žœžœžœ˜Išžœžœžœž˜KKšžœ$žœžœ˜0Kšžœ˜—šžœžœžœžœ žœžœžœ˜]Kšœ˜Kšœ.˜.Kšœ˜—Kšžœžœžœ˜'KšœžŸœ˜;Kšžœ žœžŸœ˜CKš žœ žœžœžœžœ˜1K˜Kšœ˜—K˜š œžœžœ˜2Kšœ=™=Kšœžœ˜Kšœžœ˜šžœ$žœž˜7šžœ˜ Kš žœžœ žœžœžœžœ˜QKšžœ ˜—Kšžœ˜—Kšžœžœžœ˜#šžœ žœž˜3Kšœžœžœ˜Kšœžœžœ#žœ˜6š žœžœžœ8žœž˜Yšžœ˜šžœ žœ˜Kšžœ žœžœžœ˜H—Kšžœ ˜—Kšžœ˜—šžœ˜šžœ˜KšœR™RKšžœ žœžœžœ˜AKšœžœŸ0˜Dšžœž˜Kšœ žœU˜f—Kšœ˜—Kšžœ ˜—Kšžœ˜—Kšœ˜—K˜—K˜Kšœ-™-˜š Ÿ  œžœžœžœG˜wKšœx™xKšžœžœžœ˜Kšœžœ˜Kšœžœ*žœ˜GKš žœžœžœžœžœ!˜Sšžœ1žœž˜FKšžœžœžœ˜&K˜ Kšžœ˜—šžœž˜ Kšžœ:˜>Kšžœ*˜.—Kšœ˜—K˜š Ÿ œžœžœžœ˜KKšžœžœžœ˜Kšœžœ˜Kšœ˜K˜—š   œžœžœžœžœ˜Wšžœ!˜#KšžœžœŸ+˜<šžœ˜šœ$˜$Kšœ9˜9—Kšžœ#Ÿœ˜:Kšœ˜——Kšœ˜—K˜š   œžœžœGžœ2žœ˜₯KšœŸ™ŸK™K™2Kšœžœ žœžœ˜?šžœ1žœž˜Fšžœžœ)ž˜MKšœ+˜+—Kšžœ˜—K™Kšœ7™7Kšœžœ@˜Jšžœ1žœž˜Fšžœžœž˜AKšœ˜—Kšžœ˜—Kšœ˜—K˜š  œžœžœvŸœžœ#žœ˜αšœžœžœžœ˜1Kšœ8˜8—šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜*Kšžœ žœžœ˜Kšœ>˜>Kšœ˜šžœ˜ Kšžœ%˜)Kšžœ?˜C—Kšœ˜—K˜šŸ œžœžœžœ žœžœžœžœžœžœ˜žKšžœžœžœ˜Kšœ žœ˜Kšœžœ(˜>š  œžœžœžœ˜;Kšœžœ˜š žœžœžœžœžœžœ ž˜GKšœ˜Kšœ˜Kšžœžœžœ˜Hš žœžœžœ8žœ ž˜_Kšœ˜Kšœ˜Kšœ4Ÿœ ˜MKšžœžœžœ˜šžœ žœ˜KšœA™Ašžœ ž˜KšœK˜K—Kšžœ žœžœ˜KšœŸœ˜0Kšœ˜—K˜Kšžœ˜—Kšžœ˜—Kšžœ žœ˜#Kšžœž˜Kšœ˜—KšœŸ:˜Lšžœ žœ˜Kšœ˜K˜!K˜-Kšœ˜—Kš žœ žœžœžœžœ˜1Kšœ˜——K˜Kšœ#™#˜š œ žœžœž œžœŸ!˜NKšœ1˜1šœžœ'˜2Kš žœžœ-žœžœžœ˜I—Kšœ,˜,šœ žœ˜/Kš žœžœ%žœžœžœ˜F—Kšœžœ˜Kšœ˜—K˜š œžœžœ-žœ)˜€Kšœ˜—K˜š Ÿ œžœžœžœžœ žœ ˜gKšžœžœžœ˜Kšœ˜—K˜š Ÿ œžœžœžœžœ žœ ˜iKšœψ™ψKšœ˜——K˜Kšœ˜K˜™+K™6—K™—…—Wζ€h