// TfsDDMgr.bcpl -- procedures to manage DiskDescriptor pages // Copyright Xerox Corporation 1979, 1980 // Last modified June 14, 1980 2:23 PM by Taft get "Altofilesys.d" get "Disks.d" get "Tfs.d" external [ // Outgoing procedures TFSCreateDDMgr // These are private procedures declared external because they must // be declared Overlay Entry Points (OEPs) if this module lives in an overlay. TFSLockDD; TFSReadDDPage; TFSUnlockDD; TFSFlushDD; TFSCloseDD; TFSDestroyDDMgr // Incoming procedures ActOnDiskPages; Idle; SysErr; Allocate; Free; Zero; Noop ] // A DDMgr is an object for managing pages of the DiskDescriptor (DD) files // on one or more disks. The default one is created by calling: // ddMgr = TFSCreateDDMgr(zone) // Thereafter, the following operations are defined on it: // OpenDD(ddMgr, disk) // Adds disk to the set of DDs managed by ddMgr. // LockDD(ddMgr, disk) // Locks out all other access to the DD on the specified disk. // buf = ReadDDPage(ddMgr, disk, page) // Returns a pointer to a copy (in memory) of the specified // DD page on the specified disk. The TFSKD is in page 1 // and the bit map is in pages 2 through n (n is at most 5). // Guarantees that buf will not move until either the next // ReadDDPage or UnlockDD. The DD must be locked. // UnlockDD(ddMgr, disk, dirty [false]) // Unlocks a DD previously locked. If dirty is true, marks // as dirty the page most recently read by ReadDDPage. // FlushDD(ddMgr, disk) // Flush any dirty DD pages out to the specified disk. // The DD must NOT be locked. // CloseDD(ddMgr, disk) // Removes disk from the set of DDs managed by ddMgr. // It is the caller's responsibility to do a FlushDD first. // DestroyDDMgr(ddMgr) // Destroys ddMgr. //---------------------------------------------------------------------------- structure TFSDDMgr: //---------------------------------------------------------------------------- [ // Defined standard operations, from Disks.d @DDMgr // Instance data (for this implementation) zone word // Zone from which allocated buffer word // Bit table buffer disk word // Disk that owns current contents of buffer page word // DD page number of current contents of buffer dirty word // Nonzero if buffer is dirty locked word // Nonzero if DD is locked ] manifest lenTFSDDMgr = size TFSDDMgr/16 //---------------------------------------------------------------------------- let TFSCreateDDMgr(zone) = valof //---------------------------------------------------------------------------- // This implementation of the DDMgr has the following properties: // (1) One page is permanently allocated to serve as a buffer for all DDs. // (2) There is only a single lock for the entire DDMgr, not one per DD. // (3) A dirty page is written out only if (a) the buffer is needed for // another DD page, or (b) an explicit FlushDD is done. [ let ddMgr = Allocate(zone, lenTFSDDMgr) Zero(ddMgr, lenTFSDDMgr) ddMgr>>TFSDDMgr.OpenDD = Noop ddMgr>>TFSDDMgr.LockDD = TFSLockDD ddMgr>>TFSDDMgr.ReadDDPage = TFSReadDDPage ddMgr>>TFSDDMgr.UnlockDD = TFSUnlockDD ddMgr>>TFSDDMgr.FlushDD = TFSFlushDD ddMgr>>TFSDDMgr.CloseDD = TFSCloseDD ddMgr>>TFSDDMgr.DestroyDDMgr = TFSDestroyDDMgr ddMgr>>TFSDDMgr.buffer = Allocate(zone, TFSwordsPerPage) ddMgr>>TFSDDMgr.zone = zone resultis ddMgr ] //---------------------------------------------------------------------------- and TFSDestroyDDMgr(ddMgr) be //---------------------------------------------------------------------------- [ Free(ddMgr>>TFSDDMgr.zone, ddMgr>>TFSDDMgr.buffer) Free(ddMgr>>TFSDDMgr.zone, ddMgr) ] //---------------------------------------------------------------------------- and TFSCloseDD(ddMgr, disk) be //---------------------------------------------------------------------------- if ddMgr>>TFSDDMgr.disk eq disk then ddMgr>>TFSDDMgr.disk = 0 //---------------------------------------------------------------------------- and TFSLockDD(ddMgr, disk) be //---------------------------------------------------------------------------- [ while ddMgr>>TFSDDMgr.locked do Idle() ddMgr>>TFSDDMgr.locked = true ] //---------------------------------------------------------------------------- and TFSUnlockDD(ddMgr, disk, dirty; numargs na) be //---------------------------------------------------------------------------- [ if na ge 3 & dirty then ddMgr>>TFSDDMgr.dirty = true ddMgr>>TFSDDMgr.locked = false ] //---------------------------------------------------------------------------- and TFSReadDDPage(ddMgr, disk, page) = valof //---------------------------------------------------------------------------- [ if disk ne ddMgr>>TFSDDMgr.disk % page ne ddMgr>>TFSDDMgr.page then [ if ddMgr>>TFSDDMgr.dirty then TransferDDPage(ddMgr, DCwriteD) ddMgr>>TFSDDMgr.disk = disk ddMgr>>TFSDDMgr.page = page TransferDDPage(ddMgr, DCreadD) ] resultis ddMgr>>TFSDDMgr.buffer ] //---------------------------------------------------------------------------- and TFSFlushDD(ddMgr, disk) be //---------------------------------------------------------------------------- [ TFSLockDD(ddMgr, disk) if ddMgr>>TFSDDMgr.dirty then TransferDDPage(ddMgr, DCwriteD) TFSUnlockDD(ddMgr, disk) ] //---------------------------------------------------------------------------- and TransferDDPage(ddMgr, action) be //---------------------------------------------------------------------------- [ let page = ddMgr>>TFSDDMgr.page let disk = ddMgr>>TFSDDMgr.disk if page le 0 % page ge lengthTFSDDpreamble+lengthTFSBT then SysErr(page, ecBadBtPage) // page becomes clean whether reading or writing ddMgr>>TFSDDMgr.dirty = false ActOnDiskPages(disk, (lv ddMgr>>TFSDDMgr.buffer)-page, (lv disk>>TFSDSK.VDAdiskDD)-1, disk>>TFSDSK.fpDiskDescriptor, page, page, action) ]