// IfsScav1-3.bcpl - Pass 1 Phase 3 // Copyright Xerox Corporation 1979, 1980, 1982 // Last modified July 27, 1982 7:30 PM by Boggs get "IfsScavenger.decl" get "Streams.d" get "Disks.d" get "TFS.d" external [ // outgoing procedures Pass1Phase3 // incoming procedures OpenFile; Closes; Puts; Gets RealDiskDA; ActOnDiskPages InitializeDiskCBZ; GetDiskCb; DoDiskCommand Allocate; Free; Zero; MoveBlock; IFSError; Usc EnumerateLPT; GetLpteIfp; GetLpteType; GetLpteFlags GetLpteIfsName; GetLpteTfsName; GetLpteFa ReadCalendar; PrintDiskError; SysErr CopyString; PutTemplate; Ws; PrintTime; PrintPLME PVRR; LockCell; UnlockCell // incoming statics sysZone; dsp; keys; freePageFid; debugFlag scavDisk; scratchDisk; maxVDA; wordsPerPage plme; bpl; phase; lpt ] manifest ecImpossibleType = 502 //----------------------------------------------------------------------------------------- let Pass1Phase3() = valof //----------------------------------------------------------------------------------------- // This phase makes the changes to the disk that were announced // during phase 2. Any page that is not free and was not marked // 'accessible' during phase 2 is made free here, and a truth // bit map is built up in 'scavenger.dd'. [ phase = 3 Ws("*N[1-3]"); if debugFlag then Gets(keys) let dds = OpenFile("IfsScavenger.bitTable", ksTypeWriteOnly, 0, 0, 0, 0, 0, 0, scratchDisk) if dds eq 0 then IFSError(ecScratchFile, "IfsScavenger.bitTable") // rewrite any labels that need changing Ws("*N[1-3] PLM & BT"); if debugFlag then Gets(keys) let startTime = vec 1; ReadCalendar(startTime) let cbz = Allocate(sysZone, CBzoneLength) plme = 0; LockCell(lv plme) let bmWord, bmCount = 0, 0 //bit map let free, rewrite = nil, nil let vda = 0 [pageLoop plme = PVRR(vda) switchon plme>>PLME.type into [ case ptFree: [ free = true; rewrite = plme>>PLME.rewrite; endcase ] case ptIncorr: [ free = false; rewrite = true; endcase ] case ptBad: [ MoveBlock(lv plme>>PLME.fileId, freePageFid, lFID) free = true; rewrite = true endcase ] case ptGood: [ if plme>>PLME.accessible eq 0 & vda ne 0 then [ //vda 0 is special. No sense alarming people. if debugFlag then [ Ws("*N[1-3] Inaccessible page:"); PrintPLME(vda) ] docase ptBad ] free = false; rewrite = plme>>PLME.rewrite endcase ] default: IFSError(ecImpossibleType) ] // special page zero check if vda eq 0 then [ // vda 0 plays a crucial role in end-of-file detection // and must have a special label, so unconditionally set it here. // Note that this may not be physical page 0 if this is a T-300. Zero(plme, lenPLME) free = false rewrite = true ] // Pass1Phase3 (cont'd) // record page in bit table bmWord = (bmWord lshift 1) + (free? 0, 1) bmCount = bmCount +1; if bmCount eq 16 then [ Puts(dds, bmWord) bmCount, bmWord = 0, 0 ] if rewrite then [ // some change to the page is necessary. // only the label is rewritten from the information in the plme. InitializeDiskCBZ(scavDisk, cbz, 0, CBzoneLength, plmRetry, lv Phase3Error) plmRetry: //<-------------=== ***** let cb = GetDiskCb(scavDisk, cbz) let label = lv cb>>CB.label label>>DL.numChars = plme>>PLME.numChars RealDiskDA(scavDisk, plme>>PLME.nextP, lv label>>DL.next) RealDiskDA(scavDisk, plme>>PLME.backP, lv label>>DL.previous) DoDiskCommand(scavDisk, cb, 0, vda, lv plme>>PLME.fileId, plme>>PLME.pn, (plme>>PLME.type eq ptIncorr? DCwriteHLD, DCwriteLnD)) while @cbz>>CBZ.queueHead ne 0 do GetDiskCb(scavDisk, cbz) ] vda = vda +1 ]pageLoop repeatuntil Usc(vda, maxVDA) gr 0 PrintTime(startTime) UnlockCell(lv plme) // fill out last bit table word and close bit table file if bmCount ne 0 then Puts(dds, bmWord lshift (16-bmCount) + -1 rshift bmCount) Closes(dds) // write out the bad page list // ActOnPages is not used, because we want REAL page 0, not just VDA 0 Ws("*N[1-3] BPL"); if debugFlag then Gets(keys) InitializeDiskCBZ(scavDisk, cbz, 0, CBzoneLength, bplRetry, lv Phase3Error) bplRetry: //<-------------=== ***** let fpBPL = vec lFP; Zero(fpBPL, lFP) let cb = GetDiskCb(scavDisk, cbz) DoDiskCommand(scavDisk, cb, bpl, fillInDA, fpBPL, 0, DCwriteD) while @cbz>>CBZ.queueHead ne 0 do GetDiskCb(scavDisk, cbz) Free(sysZone, cbz) // The disk now contains only well formed files and free pages. // We have a correct bit table, but don't yet know the state // of SysDir or DiskDescriptor. // rewrite leader pages that need changing Ws("*N[1-3] LPT"); if debugFlag then Gets(keys) let ld = Allocate(sysZone, wordsPerPage) EnumerateLPT(lpt, CheckLD, ld) Free(sysZone, ld) resultis true ] //----------------------------------------------------------------------------------------- and CheckLD(l, lpte, ld) be //----------------------------------------------------------------------------------------- // Called for each lpte, it updates the leader page if necessary, // and remembers the highest serial number (used when rebuilding the // disk descriptor in phase 4). [ if GetLpteType(lpte) eq dvTypeFile then [ let ifp = GetLpteIfp(lpte) let flags = GetLpteFlags(lpte) if (flags & (lfRewrite % lfDamaged)) ne 0 then [ ActOnDiskPages(scavDisk, lv ld, lv ifp>>IFP.page, ifp, 0, 0, DCreadD) if (flags & lfRewrite) ne 0 then [ MoveBlock(lv ld>>LD.hintLastPageFa, GetLpteFa(lpte), lFA) if GetLpteTfsName(lpte)>>String.length ne 0 then CopyString(lv ld>>ILD.name, GetLpteTfsName(lpte)) if GetLpteIfsName(lpte)>>String.length ne 0 then CopyString(lv ld>>ILD.pathName, GetLpteIfsName(lpte)) ] if (flags & lfDamaged) ne 0 then ld>>ILD.damaged = true ActOnDiskPages(scavDisk, lv ld, lv ifp>>IFP.page, ifp, 0, 0, DCwriteD) ] // remember the largest file Sn. let fileSn = lv ifp>>IFP.serialNumber let lastSn = lv scavDisk>>TFSDSK.lastSn switchon Usc(lastSn>>ISN.part1, fileSn>>ISN.part1) into [ case 1: endcase case 0: if Usc(lastSn>>ISN.part2, fileSn>>ISN.part2) ge 0 endcase case -1: [ lastSn>>ISN.part2 = fileSn>>ISN.part2 lastSn>>ISN.part1 = fileSn>>ISN.part1 endcase ] ] ] ] //----------------------------------------------------------------------------------------- and Phase3Error(nil, cb, errorCode) be //----------------------------------------------------------------------------------------- test errorCode eq ecUnRecovDiskError ifso PrintDiskError(cb) ifnot SysErr(0, errorCode, cb)