// 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)
]
]