// IfsLeafVMemClose.bcpl - Leaf VMem Close - SWAPPABLE // Copyright Xerox Corporation 1979, 1980, 1982 // Last modified September 17, 1982 8:55 AM by Taft get ecBadFileMap, ecBrokenLeafQueue, ecBrokenLeafVMemQueue, ecCantPurgeVFile from "IfsLeafErrors.decl"; get FD, oldPageNumber from "IfsDirs.decl"; get fillInDA, eofDA from "Disks.d"; get "IfsLeaf.decl"; get "IfsLeafVMem.decl"; get "IfsIsf.d"; external [ //outgoing procedures FreeLeafVMem; LeafPurgeVFile; //incoming procedures Allocate; CloseIFSFile; Dismiss; FMapChecksum; Free; FreeFmap; IFSError; IndexedPageIO; InsertAfter; LookupFmap; Min; MoveBlock; ReadCalendar; SnarfBuffers; UnsnarfBuffers; TransferLeaderPage; Unqueue; //incoming statics leafVMI; sysZone; ] static fmapTruncations = 0; //---------------------------------------------------------------------------- let FreeLeafVMem(fd, lvmd) = valof //---------------------------------------------------------------------------- [ let refs = lvmd>>LVMD.refCount - 1; if refs ne 0 then [ lvmd>>LVMD.refCount = refs; CloseIFSFile(fd); resultis false; ] // There is a potential problem here if multiple Leaf contexts // are used and somebody tries to grab the lvmd being flushed. LeafPurgeVFile(lvmd); unless Unqueue(lv leafVMI>>LeafVMI.lvmdQueue, lvmd) then IFSError(ecBrokenLeafVMemQueue); let buffer = Allocate(sysZone, wordsPerPage); let lastPage = lvmd>>LVMD.lastAddress.high lshift logPagesPerWord + lvmd>>LVMD.lastAddress.low rshift logBytesPerPage + 1; let fmap = lv lvmd>>LVMD.fmap; let lastPageDA = nil; [ lastPageDA = LookupFmap(fmap, lastPage); switchon lastPageDA into [ case fillInDA: IndexedPageIO(fmap, lastPage, buffer, 1, 0); endcase; case eofDA: IFSError(ecBadFileMap); endcase; default: break; ] ] repeat TransferLeaderPage(fd, buffer); buffer>>ILD.hintLastPageFa.da = lastPageDA; buffer>>ILD.hintLastPageFa.pageNumber = lastPage; buffer>>ILD.hintLastPageFa.charPos = lvmd>>LVMD.lastAddress.low & bytesPerPage-1; // Write the filemap... let ildMap = lv buffer>>LeafILD.fmap; let last = Min(fmap>>FM.last-mapoffset, maxLenOldFMap-lenMapEntry); MoveBlock(ildMap, lv (fmap>>FM.fmap)>>FM.map, last+lenMapEntry); if last ne fmap>>FM.last-mapoffset then [ fmapTruncations = fmapTruncations + 1; // make sure map ends with fillInDA ildMap!(last+1) = fillInDA; ] // Write the filemap info... buffer>>LeafILD.fmapLast = last; buffer>>LeafILD.fmapChecksum = FMapChecksum(ildMap, last); ReadCalendar(lv buffer>>LeafILD.fmapWritten); MoveBlock(lv buffer>>LeafILD.fmapFP, lv fmap>>FM.fp, lFP); buffer>>LeafILD.fmapSeal = version; TransferLeaderPage(fd, buffer, true); Free(sysZone, buffer); FreeFmap(fmap); Free(sysZone, lvmd); // This is a bit kludgy, but since this is called from places other than the // Leaf Ctx, CtxRunning>>RSCtx.userInfo is not always valid. However, // upon examination it seems that CloseIFSFile only refers to CtxRunning // inside CreateFD. But this only happens when it is creating an FD to a // directory in which case CtxRunning is not used after all. CloseIFSFile(fd, lastPage - fd>>FD.oldPageNumber); resultis true; ] //---------------------------------------------------------------------------- and LeafPurgeVFile(lvmd) be //---------------------------------------------------------------------------- [ for leafPage = lv leafVMI>>LeafVMI.pages↑1 by lenLeafPage to lv leafVMI>>LeafVMI.pages↑lastLeafPage do [ let tries = 0; while leafPage>>LeafPage.probe & lvmd eq leafPage>>LeafPage.lvmd & leafPage>>LeafPage.address ne 0 do [ let cPage = leafPage>>LeafPage.address rshift logVMPageLength; // Snarf the entire page group so as to keep all VMem pages of the group // together on the available list. test SnarfBuffers(cPage, 1 lshift logVPagesPerLeafPage, 0) eq 0 ifso [ // Page is locked, perhaps because it is being swapped out already. // Allow up to 10 seconds for this complete. // Note: after waiting, be sure to re-evaluate whether or not // we are still interested in flushing this LeafPage, since it may // have gotten flushed by some other VMem activity in the meantime. tries = tries + 1; if tries gr 100 then IFSError(ecCantPurgeVFile); Dismiss(10); ] ifnot [ UnsnarfBuffers(cPage, 1 lshift logVPagesPerLeafPage); break ] ] ] if lvmd>>LVMD.written then [ // All this can be optimized so that "written" only applies to last page. let lastPage = lvmd>>LVMD.lastAddress.high lshift logPagesPerWord + lvmd>>LVMD.lastAddress.low rshift logBytesPerPage + 1; let lastByte = lvmd>>LVMD.lastAddress.low & bytesPerPage-1; let fmap = lv lvmd>>LVMD.fmap; let buffer = Allocate(sysZone, wordsPerPage); if lastByte ne IndexedPageIO(fmap, lastPage, buffer, 1, 0) then IndexedPageIO(fmap, lastPage, buffer, 1, -1, lastByte); lvmd>>LVMD.written = false; Free(sysZone, buffer); ] ]