--last changed August 13, 1982 4:28 PM by Glen Williams --now return firstPage rather than lastPage when not proceeding to rewrite pages. DIRECTORY InlineDefs: FROM "inlinedefs" USING [BITAND, BITOR, BITSHIFT], SystemDefs: FROM "systemdefs" USING [AllocateHeapNode, FreeHeapNode], TridentDefs: FROM "tridentdefs"; TfsWrite: PROGRAM IMPORTS SystemDefs, TridentDefs, InlineDefs EXPORTS TridentDefs = BEGIN OPEN SystemDefs, TridentDefs, InlineDefs; TfsWritePages: PUBLIC PROCEDURE [disk: tfsdskPtr, caS: DESCRIPTOR FOR ARRAY OF POINTER, daS: DESCRIPTOR FOR ARRAY OF PAGE, fp: FP, firstPage, lastPage: INTEGER, lastAction: WORD, numcharsPtr: POINTER, lastnumChars: CARDINAL, fixedCA: POINTER, dummy1: UNSPECIFIED, errorRtn: ErrorRoutType, dummy2: UNSPECIFIED, hintLastPage: INTEGER] RETURNS [resPage: INTEGER] = -- This procedure acts similarly to TfsActOnPages (which reads or writes a specified range of pages). TfsWritePages only writes, however, and must be used if a filed will be extended. Note also that daS[firstPage-1] will be referenced (remembering that files have forward and backward links) except when the label of firstPage doesn't need to be rewritten. BEGIN i, firstNewPage: INTEGER; numChars: CARDINAL _ 0; cb: cbPtr; cbz: cbzPtr; temp: POINTER; prevPagePtr: POINTER TO PAGE; -- The first six arguments should have valid values. The others may be NIL, zero, or some No-Op routine, as appropriate. Three of the others are forced to non-zero defaults. Also, a real procedure has to be passed through errorRtn. --IF lastnumChars = 0 THEN lastnumChars _ TFSwordsPerPage*2; ---- set defaults IF lastAction = 0 THEN lastAction _ dcWriteD; IF numcharsPtr = NIL THEN numcharsPtr _ @numChars; -- Rewrite existing pages in the file before worrying about adding new ones. -- The following is code to help rename a file. To do so TfsActOnPages is used to read several pages into memory and to build a daS array. Then this procedure is called with lastAction = -1, and all those pages (and labels) are rewritten. IF lastAction # 177777B THEN BEGIN IF daS[firstPage] = fillInDA -- 1st page is to be appended THEN firstNewPage _ firstPage -- else rewrite some of the pages ELSE {firstPage _ TfsActOnPages[disk, caS, daS, fp, firstPage, lastPage, dcWriteD, numcharsPtr, lastAction, fixedCA, DefaultTfsCleanupRtn, errorRtn, FALSE, hintLastPage]; IF firstPage = lastPage AND (lastAction # dcWriteD OR numcharsPtr^ = lastnumChars) THEN RETURN [firstPage]; firstNewPage _ firstPage + 1; }; -- Here's the code to assign more pages to the file. Three things are done here: -- 1. TfsAssignDisk page is called to allocate the pages using the BitMap. -- 2. TfsActOnPages is used to read the labels, which are checked by CheckFreePage to see if they're free. -- 3. We go through a loop to see if all the assigned pages are free (CheckFreePage stuffs fillInDA if not). For any not free, we start -- again at 1. DO -- Assign any new pages FOR i IN [firstNewPage..lastPage] DO prevPagePtr _ @daS[i]-1; daS[i] _ TfsAssignDiskPage[disk, prevPagePtr^, FALSE]; IF daS[i] = eofDA THEN ERROR NoMorePages; ENDLOOP; -- Read the labels of the assigned pages and checkl2963(0,3648)(1,4256)(2,4896)(3,5536)(4,6176)(5,7456)(6,8064)(7,11818)\i139I312b13B353i359I128i235I2i79I100i318I69i29I33i33I330i81I2i74I2i106I2i137I2i15I6i23I185i51I [] _ TfsActOnPages[disk, caS, daS, freePageFP, firstNewPage, lastPage, dcReadLnD, NIL, dcReadLnD, NIL, CheckFreePage, errorRtn, FALSE, 0];l4868d4233 --Assign new pages if not free FOR i IN [firstNewPage..lastPage] DO daS[firstNewPage] _ daS[i]; IF daS[i] # fillInDA THEN firstNewPage _ firstNewPage + 1; ENDLOOP; IF firstNewPage - lastPage > 0 THEN EXIT; ENDLOOP; -- end of 3-phase assignment loop END; -- of lastAction # -1 block -- All pages have been checked. Write labels and data, including possibly revising lastnumChars. cbz _ AllocateHeapNode[cbZoneLength]; TfsInitializeCBStorage[disk,cbz,firstPage,cbZoneLength,Wretry,errorRtn]; BEGIN ENABLE Wretry => RETRY; --start this block over when TfsGetCb raises this SIGNAL FOR i IN [cbz.currentPage..lastPage] DO cb _ TfsGetCb[disk,cbz,FALSE,FALSE]; -- set up eofDA as the page after the End of File IF ((i = lastPage AND lastnumChars # TFSwordsPerPage*2) OR (daS[i+1] = fillInDA)) THEN daS[i+1] _ eofDA; -- Set up the label to be written on this page prevPagePtr _ @daS[i]-1; cb.label.next _ TfsRealDA[disk, daS[i+1]]; cb.label.previous _ TfsRealDA[disk, prevPagePtr^]; cb.label.numChars _ (IF i = lastPage THEN lastnumChars ELSE TFSwordsPerPage*2); -- Perform the I/O IF fixedCA # NIL THEN temp _ fixedCA ELSE temp _ caS[i]; TfsDoDiskCommand[disk,cb,temp,daS[i],fp,i,dcWriteLD,NIL]; ENDLOOP; --of FOR i IN [cbz.currentPage..lastPage] WHILE cbz.head # NIL DO [] _ TfsGetCb[disk,cbz,FALSE,FALSE]; -- wait ENDLOOP; -- End of wait loop END; --of BEGIN ENABLE Wretry => RETRY FreeHeapNode[cbz]; RETURN[lastPage]; END; -- of TfsWritePages l2963\3i31I207i33I12i27I2i98I144i56I86i50I114i47I211i21I138i15I3i23I68i7I15i19I5i42I49i19I TfsAssignDiskPage: PUBLIC PROCEDURE [disk: tfsdskPtr, diskAddr: PAGE, test: BOOLEAN] RETURNS [resPage: PAGE] = -- Assigns in a sequential manner, in order of increasing virtual disk addresses. Second argument is a VDA previously assigned; the code tries to assign pages sequentially in this case. However, for a new file, the VDA passed is eofDA; in this case, the code resumes looking in the bit table where it last left off trying to allocate a file. The idea is to reduce bit table scanning time and also page in/outs. -- -- Test is a special argument to determine if a page is available without -- assigning it. Result is vda if next page is available, else 0. -- BEGIN ddMgr: ddMgrPtr; -- pointer to DD mgr object diskBTaddr: POINTER; buffer: DESCRIPTOR FOR ARRAY [0..TFSwordsPerPage]OF WORD; free: BOOLEAN; -- is this page free? wa: WordNumInPage; --word address pa: PageNum; -- page address vda: VDA; -- virtual disk address bitMask: WORD; -- 1 bit on i, loopsize: CARDINAL; ddMgr _ disk.tfskd.ddMgr; -- get the pointer to the DD manager TfsLockDD[ddMgr, disk]; -- lock the disk descriptor IF diskAddr = eofDA THEN -- this means start where we left off diskAddr _ disk.tfskd.lastPageAlloc -- get last page allocated ELSE diskAddr _ diskAddr + 1; vda _ LOOPHOLE[diskAddr]; -- data convert -- We may have to do (bit-table pages) + 2 iterations loopsize _ BITSHIFT[disk.tfskd.kdh.diskBTsize, Right*TFSlnWordsPerPage]+3; FOR i IN [1..loopsize] DO -- At top of loop vda IF vda.pageAndWord >= disk.tfskd.kdh.diskBTsize -- = vda to be examined next THEN {vda.pageAndWord _0; vda.bitNum _0}; pa _ vda.pageNum; -- get the right bitmap page and read it diskBTaddr _ TfsReadDDPage[ddMgr,disk,pa+lTfsDDPreamble]; buffer _ DESCRIPTOR[diskBTaddr, TFSwordsPerPage]; -- Test the bit corresponding to vda. FAIL => test the remainder of the word 1 bit at a time. wa _ vda.wordNumInPage; -- get the right word in the page bitMask _ oneBits[vda.bitNum]; -- get the bit in the word DO -- search from here down for a free page free _ BITAND[buffer[wa],bitMask]=0; -- is this page free? IF test THEN BEGIN -- we just wanted to look TfsUnlockDD[ddMgr,disk,FALSE]; -- don't set dirty flag IF free THEN resPage _ LOOPHOLE[vda] ELSE resPage _ 0; RETURN [resPage]; -- return from test END; IF free THEN -- assign the page if it's free BEGIN buffer[wa] _ BITOR[buffer[wa], bitMask]; disk.tfskd.kdh.freePages _ disk.tfskd.kdh.freePages - 1; disk.tfskd.lastPageAlloc _ LOOPHOLE[vda]; TfsUnlockDD[ddMgr,disk,TRUE]; RETURN[LOOPHOLE[vda]]; -- return page number assigned END; -- if not free continue looking thru the bitmap word bitMask _ BITSHIFT[bitMask, Right*1]; IF bitMask = 0 THEN EXIT; -- No mre bits diskAddr _ diskAddr + 1; -- get next address vda _ LOOPHOLE[diskAddr]; ENDLOOP; -- of search in pageAndWord DO -- look through rest of page wa _ wa + 1; IF wa >= TFSwordsPerPage OR buffer[wa] # 177777B THEN EXIT; ENDLOOP; -- Now wa addresses a word # -1 or wa = TfsWordsPerPage IF wa >= TFSwordsPerPage THEN BEGIN -- Finished with this page of bitmap pa _ pa + 1; -- Set to look at next page -- vda _ VDA[pageNum: pa, wordNumInPage: 0, bitPos: 0]; ---- Construct a vda vda.pageNum _ pa; vda.wordNumInPage _ 0; vda.bitPos _ 0; LOOP; -- Go get next page END; --buffer[wa] has one or more 0 bits FOR j: INTEGER IN [0..16) DO -- A zero bit means free page IF 0=BITAND[oneBits[j],buffer[wa]] THEN BEGIN vda.pageNum _ pa; vda.wordNumInPage _ wa; vda.bitPos _ j;--Found, construct vda EXIT; -- Drop out since search is done END; ENDLOOP; -- Look for first free bit in buffer[wa] ENDLOOP; --of FOR i IN [1..loopsize]; Go assign page or read bitmap TfsUnlockDD[ddMgr,disk,FALSE]; -- no pages available RETURN[eofDA]; END; -- of TfsAssignDiskPagel2963(0,3634)(1,4269)(2,4904)(3,5539)(4,5539)(5,7444)(6,8079)\531i141I682i54I434i95I796i54I338i56I128i79I101i36I CheckFreePage: PROCEDURE [disk: tfsdskPtr, cb: cbPtr, cbz: cbzPtr] = -- This procedure is used as a cleanup routine in TfsWritePages in a call -- to TfsActOnPages. fillInDA is stored in the daS array for pages which -- are not free. BEGIN fid: DESCRIPTOR FOR ARRAY [0..lFID) OF WORD; pageindex,i: INTEGER; fid _ DESCRIPTOR[cb.kcb.blockL.addr, lFID]; -- Describe the fileid FOR i IN [0..lFID) DO IF fid[i] # 177777B THEN -- Used to be freePageFID[i] BEGIN pageindex _ cb.truePageNumber; cbz.daS[pageindex] _ fillInDA; disk.tfskd.nBTErrors _ disk.tfskd.nBTErrors + 1; EXIT; -- leave the DO-loop END; ENDLOOP; END; -- of CheckFreePagel2963(635)\1b13B56i165I NoMorePages: PUBLIC ERROR = CODE; -- disk full Wretry: SIGNAL = CODE;l2963\1b11B39b6B l2963 END. -- of TfsWrite.mesa --last changed September 25, 1981 2:01 PM by Glen Williams --dropped an arg to TfsInitializeCBStorage --last changed July 17, 1981 11:49 AM by Glen Williams --added 'j' to TfsAssignDiskPage --changed call on TfsRealDA in TfsWritePage --changed Wretry scoping to include a wait for the command block at the end of TfWritePages. Also made it a BEGIN..END rather -- than a DO..ENDLOOP. --last changed August 4, 1982 6:00 PM by Glen Williams --no longer default lastnumChars to 2048 if came in as a zero (as stated in BFS/TFS documentation). \232i190I