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