// BFSDDMgr.bcpl -- procedures to manage DiskDescriptor pages // Copyright Xerox Corporation 1979 // Last modified December 22, 1979 1:18 AM by Boggs get "Altofilesys.d" get "Disks.d" get "BFS.d" external [ // Outgoing procedures BFSCreateDDMgr // These are private procedures declared external because they must // be declared Overlay Entry Points (OEPs) if this module lives in an overlay. BFSLockDD; BFSReadDDPage; BFSUnlockDD; BFSFlushDD; BFSCloseDD; BFSDestroyDDMgr // 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. It is created by calling: // ddMgr = CreateDDMgr(zone) // Thereafter, the following operations are defined on it: // BFSOpenDD(ddMgr, disk) // Adds disk to the set of DDs managed by ddMgr. // BFSLockDD(ddMgr, disk) // Locks out all other access to the DD on the specified disk. // buf = BFSReadDDPage(ddMgr, disk, page) // Returns a pointer to a copy (in memory) of the specified // DD page on the specified disk. The KDH starts in page 1 // followed by the bit map. // Guarantees that buf will not move until either the next // BFSReadDDPage or BFSUnlockDD. The DD must be locked. // BFSUnlockDD(ddMgr, disk, dirty [false]) // Unlocks a DD previously locked. If dirty is true, marks // as dirty the page most recently read by BFSReadDDPage. // BFSFlushDD(ddMgr, disk) // Flush any dirty DD pages out to the specified disk. // The DD must NOT be locked. // BFSCloseDD(ddMgr, disk) // Removes disk from the set of DDs managed by ddMgr. // It is the caller's responsibility to do a BFSFlushDD first. // BFSDestroyDDMgr(ddMgr) // Destroys ddMgr. //---------------------------------------------------------------------------- structure BFSDDMgr: //---------------------------------------------------------------------------- [ // Defined operations @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 lenBFSDDMgr = size BFSDDMgr/16 //---------------------------------------------------------------------------- let BFSCreateDDMgr(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 BFSFlushDD is done. [ let ddMgr = Allocate(zone, lenBFSDDMgr) Zero(ddMgr, lenBFSDDMgr) ddMgr>>DDMgr.OpenDD = Noop ddMgr>>DDMgr.LockDD = BFSLockDD ddMgr>>DDMgr.ReadDDPage = BFSReadDDPage ddMgr>>DDMgr.UnlockDD = BFSUnlockDD ddMgr>>DDMgr.FlushDD = BFSFlushDD ddMgr>>DDMgr.CloseDD = BFSCloseDD ddMgr>>DDMgr.DestroyDDMgr = BFSDestroyDDMgr ddMgr>>BFSDDMgr.buffer = Allocate(zone, BFSwordsPerPage) ddMgr>>BFSDDMgr.zone = zone resultis ddMgr ] //---------------------------------------------------------------------------- and BFSDestroyDDMgr(ddMgr) be //---------------------------------------------------------------------------- [ Free(ddMgr>>BFSDDMgr.zone, ddMgr>>BFSDDMgr.buffer) Free(ddMgr>>BFSDDMgr.zone, ddMgr) ] //---------------------------------------------------------------------------- and BFSCloseDD(ddMgr, disk) be //---------------------------------------------------------------------------- if ddMgr>>BFSDDMgr.disk eq disk then ddMgr>>BFSDDMgr.disk = 0 //---------------------------------------------------------------------------- and BFSLockDD(ddMgr, disk) be //---------------------------------------------------------------------------- [ while ddMgr>>BFSDDMgr.locked do Idle() ddMgr>>BFSDDMgr.locked = true ] //---------------------------------------------------------------------------- and BFSUnlockDD(ddMgr, disk, dirty; numargs na) be //---------------------------------------------------------------------------- [ if na ge 3 & dirty then ddMgr>>BFSDDMgr.dirty = true ddMgr>>BFSDDMgr.locked = false ] //---------------------------------------------------------------------------- and BFSReadDDPage(ddMgr, disk, page) = valof //---------------------------------------------------------------------------- [ if disk ne ddMgr>>BFSDDMgr.disk % page ne ddMgr>>BFSDDMgr.page then [ if ddMgr>>BFSDDMgr.dirty then BFSTransferDDPage(ddMgr, DCwriteD) ddMgr>>BFSDDMgr.disk = disk ddMgr>>BFSDDMgr.page = page BFSTransferDDPage(ddMgr, DCreadD) ] resultis ddMgr>>BFSDDMgr.buffer ] //---------------------------------------------------------------------------- and BFSFlushDD(ddMgr, disk) be //---------------------------------------------------------------------------- [ BFSLockDD(ddMgr, disk) if ddMgr>>BFSDDMgr.dirty then BFSTransferDDPage(ddMgr, DCwriteD) BFSUnlockDD(ddMgr, disk) ] //---------------------------------------------------------------------------- and BFSTransferDDPage(ddMgr, action) be //---------------------------------------------------------------------------- [ let page = ddMgr>>BFSDDMgr.page let disk = ddMgr>>BFSDDMgr.disk if page le 0 % page ge BFSmaxDDPage % disk>>BFSDSK.VDAdiskDD↑page eq 0 then SysErr(page, ecBadBtPage) ddMgr>>BFSDDMgr.dirty = false // Page becomes clean whether reading or writing ActOnDiskPages(disk, (lv ddMgr>>BFSDDMgr.buffer)-page, (lv disk>>BFSDSK.VDAdiskDD)-1, disk>>DSK.fpDiskDescriptor, page, page, action) ]