// IfsScav1-2.bcpl - Pass 1 Phase 2 // Copyright Xerox Corporation 1979, 1982 // Last modified February 13, 1982 3:37 PM by Boggs get "IfsScavenger.decl" get "Disks.d" get "TFS.d" external [ // outgoing procedures Pass1Phase2 // incoming procedures PVWR; PVRR; LockCell; UnlockCell; FlushBuffers Allocate; Free; MultEq; MoveBlock; RealDiskDA Gets; PutTemplate; Ws; Wss; PrintPLME EnumerateLPT; GetLpteIfsName; GetLpteTfsName GetLpteFa; SetLpteFa; GetLpteFlags; SetLpteFlags SetLpteType; GetLpteIfp; GetLptLpte // incoming statics dsp; keys; sysZone; debugFlag; scavDisk; phase plme; maxVDA; bytesPerPage; numPages; lpt ] static [ printLPTE; printPLME; curVDA ] //----------------------------------------------------------------------------------------- let Pass1Phase2() = valof //----------------------------------------------------------------------------------------- // This is basically the marking pass of a page garbage collector. // Starting from the set of leader pages, it marks all accessible // file pages and checks that chains of pages are 'well formed'. // The output of this phase is some changes to the plm and the lpt. // This phase never references the pack being scavenged! [ phase = 2 Ws("*N[1-2]"); if debugFlag then Gets(keys) plme = 0; LockCell(lv plme) numPages = 0 EnumerateLPT(lpt, CheckFile, nil) PutTemplate(dsp, "*N[1-2] $UD pages used out of $UD", numPages, maxVDA) UnlockCell(lv plme) FlushBuffers() resultis true ] //----------------------------------------------------------------------------------------- and CheckFile(l, lpte, nil) be //----------------------------------------------------------------------------------------- // This is called once for each leader page table entry. // It follows the chain of pages starting at the leader page. [ printLPTE = true // follow the pointers and build a maximal length chain let lastPN, lastVDA = -1, eofDA let ifp = GetLpteIfp(lpte) curVDA = ifp>>IFP.page let lfFlags = 0 [pageLoop plme = PVWR(curVDA) printPLME = true // We check 3 things in deciding whether a page belongs to a chain: // nextP backP FID Action // ok ok ok no action // ok ok bad fix FID // ok bad ok fix backP // ok bad bad backup and truncate // bad d/c d/c backup and truncate // bad d/c d/c backup and truncate // bad d/c d/c backup and truncate // bad d/c d/c backup and truncate manifest [ nextpBad = 1; backpBad = 2; fidBad = 4 ] let state = 0 // this page must not be free, bad, or incorrigable if plme>>PLME.type ne ptGood then [ PrintPage("this is a $S page!", selecton plme>>PLME.type into [ case ptGood: "good" case ptBad: "bad" case ptIncorr: "incorrigable" case ptFree: "free" default: "?" ]) state = state % nextpBad ] // this page must point back to where we just came from if plme>>PLME.backP ne lastVDA then [ PrintPage("back pointer is wrong") state = state % backpBad ] // this page's FID must match the file's FID unless MultEq(lv plme>>PLME.fileId, lv ifp>>IFP.serialNumber, lFID) do [ PrintPage("file ID is wrong") state = state % fidBad ] //Pass1Phase2 (cont'd) switchon state into [ case 0: endcase //everything ok case fidBad: [ plme>>PLME.rewrite = true PrintPage("setting FID to $EUO;$UO", lv ifp>>IFP.serialNumber, ifp>>IFP.version) MoveBlock(lv plme>>PLME.fileId, lv ifp>>IFP.serialNumber, lFID) endcase ] case backpBad: [ plme>>PLME.rewrite = true PrintPage("setting back pointer to $UO", lastVDA) plme>>PLME.backP = lastVDA endcase ] case fidBad+backpBad: default: [ if lastPN eq -1 then [ // This isn't a very good prospect for a leader page. // Act like we never saw the plme and get rid of that lpte! SetLpteType(lpte, dvTypeFree) return ] PrintPage("backing up to vda $UO and truncating", lastVDA) curVDA = lastVDA //back up plme = PVWR(curVDA) printPLME = true plme>>PLME.rewrite = true plme>>PLME.nextP = eofDA //truncate break //pageLoop ] ] //Pass1Phase2 (cont'd) // page is accessible, though it may have non-fatal problems numPages = numPages +1 plme>>PLME.accessible = true // check page number if plme>>PLME.pn ne lastPN+1 then [ plme>>PLME.rewrite = true PrintPage("setting page number to $UO", lastPN+1) plme>>PLME.pn = lastPN+1 ] // if this is the last page then exit pageLoop if plme>>PLME.nextP eq eofDA break //end of chain // this is not the last page, so it must be full if plme>>PLME.numChars ne bytesPerPage then [ plme>>PLME.rewrite = true PrintPage("setting num Chars to $UO", bytesPerPage) plme>>PLME.numChars = bytesPerPage ] // advance to next page lastPN = plme>>PLME.pn lastVDA = curVDA curVDA = plme>>PLME.nextP if plme>>PLME.rewrite then lfFlags = lfFlags % lfDamaged ]pageLoop repeat // We are now at the end of a well-formed chain of pages // that started with a page that looked like a leader page. // last page must not be full if plme>>PLME.numChars eq bytesPerPage then [ plme>>PLME.rewrite = true PrintPage("setting numChars to $UO", bytesPerPage-1) plme>>PLME.numChars = bytesPerPage-1 ] // in case we truncated the file or the last page was full: if plme>>PLME.rewrite then lfFlags = lfFlags % lfDamaged // verify the last fa hint kept in the leader page let hintFA = GetLpteFa(lpte) let realFA = vec lFA realFA>>FA.da = curVDA realFA>>FA.pageNumber = plme>>PLME.pn realFA>>FA.charPos = plme>>PLME.numChars unless MultEq(hintFA, realFA, lFA) do [ PrintPage("setting last fa hint: vda $UO, page number $UO, num chars $UO", realFA>>FA.da, realFA>>FA.pageNumber, realFA>>FA.charPos) SetLpteFa(lpte, realFA) lfFlags = lfFlags % lfRewrite ] // files must contain at least two pages test plme>>PLME.pn eq 0 ifso [ PrintPage("deleted this file - just a leader page") plme>>PLME.accessible = false //free this page (done by [1-3]) SetLpteType(lpte, dvTypeFree) //not a file so forget this leader page ] ifnot if lfFlags ne 0 then SetLpteFlags(lpte, GetLpteFlags(lpte) % lfFlags) ] //----------------------------------------------------------------------------------------- and PrintPage(string, arg0, arg1, arg2, arg3; numargs na) be //----------------------------------------------------------------------------------------- [ if printLPTE then [ let lpte = GetLptLpte(lpt, false) let ifp = GetLpteIfp(lpte) PutTemplate(dsp, "*N[1-2] FID $EUO;$UO, IFS name *"$S*", TFS name *"$S*"", lv ifp>>IFP.serialNumber, ifp>>IFP.version, GetLpteIfsName(lpte), GetLpteTfsName(lpte)) printLPTE = false ] if printPLME then [ PrintPLME(curVDA) printPLME = false ] if string ne 0 & na gr 0 then [ Ws("*N[1-2]*T*T") PutTemplate(dsp, string, arg0, arg1, arg2, arg3) ] ]