(FILECREATED "12-Mar-85 03:50:16" {ERIS}<LISPCORE>SOURCES>LLBFS.;11 75337        changes to:  (FNS \DISKERROR)      previous date: "14-Feb-85 23:35:26" {ERIS}<LISPCORE>SOURCES>LLBFS.;10)(* Copyright (c) 1982, 1983, 1984, 1985 by Xerox Corporation. All rights reserved.)(PRETTYCOMPRINT LLBFSCOMS)(RPAQQ LLBFSCOMS [(COMS (* Low-level subr calls)			(FNS \INITBFS \TESTPARTITION \ACTONDISKPAGES \WRITEDISKPAGES \DISKERROR 			     M44.SIGNAL.DISK.ERROR)			(DECLARE: EVAL@COMPILE DONTCOPY (MACROS .SETUPDISKBUFFERS. DISKWRITEACTION? 								DISKREADACTION?)				  (PROP DOPVAL .DISKPARTINSTR.)				  (CONSTANTS * DISKCOMMANDS)				  (CONSTANTS * DISKERRORS)				  (* Some of these are also used by MOD44IO)				  (RECORDS DISKREQUEST ALTODSKOBJ DDHEADER CB DISKLABEL REALDA 					   SHORTCB FP DSKOBJ \M44LeaderPage M44STREAM FID)				  (CONSTANTS (\FILLINDA 65534)					     (\EOFDA 65535)					     (\LENFP 5)					     (\FP.DIRECTORYP 32768)					     (\INITPROPPTR 6866)					     (\DDBITTABSTART 32)					     (\NBYTES.DISKINFO 12)					     (\OFFSET.DISKLASTSERIAL# 8)					     (\NWORDS.DSKOBJ 36))				  (GLOBALVARS \EMUDISKBUFEND \EMUDISKBUFFERS \EMUSCRATCH 					      \EMUSWAPBUFFERS \EXTRAISFBUF \ISFMAP \ISFMAXCHUNK 					      \ISFSCRATCHCAS \ISFSCRATCHDAS \#DISKBUFFERS \MAXDISKDAs 					      \#SWAPBUFFERS \SYSDISK \ISFCHUNKSIZE \MAINDISK 					      \DISKREQUESTBLOCK \SWAPREQUESTBLOCK \DISKDEBUG 					      \MAXSWAPBUFFERS \SPAREDISKWRITEBUFFER \FREEPAGEFID 					      \#EMUBUFFERS \EMUBUFFERS \LASTVMEMFILEPAGE \M44.READY)))	[COMS (* Super low level)	      (FNS \ACTONVMEMPAGES \WRITEVMEMPAGES \DOACTONDISKPAGES \DOWRITEDISKPAGES \CHECKFREEPAGE 		   \DODISKCOMMAND \GETDISKCB \CLEARCB \CLEANUPDISKQUEUE \VIRTUALDISKDA \REALDISKDA)	      (DECLARE: EVAL@COMPILE DONTCOPY (CONSTANTS * CBSTATUSCONSTANTS)			(CONSTANTS * IDISKCOMMANDS)			(CONSTANTS (\EM.DISKCOMMAND 337)				   (\EM.DISKADDRESS 339)				   (\FIXEDLENDISKREQUEST 42)				   (\DEFAULTDASTORAGELENGTH 60)				   (\LENCB 6)				   (\LENDSKOBJ 34)				   (\LENSHORTCB 18))			(CONSTANTS (\CB.PENDING 1)				   (\CB.FREE 0]	[COMS (* At MAKEINIT time)	      (FNS MAKEINITBFS)	      (DECLARE: DONTCOPY (ADDVARS (INITPTRS (\MAINDISK)						    (\SWAPREQUESTBLOCK)						    (\DISKREQUESTBLOCK)						    (\FREEPAGEFID))					  (INEWCOMS (FNS MAKEINITBFS)))			EVAL@COMPILE			(ADDVARS (DONTCOMPILEFNS MAKEINITBFS]	(COMS (* Swap stuff)	      (FNS \M44ACTONVMEMFILE \LOOKUPFMAP \M44EXTENDVMEMFILE \M44DOEXTENDVMEMFILE 		   \EXTENDISFMAP \M44VMEMEXTENDED \M44VMEMFRAGMENTS)	      (DECLARE: EVAL@COMPILE DONTCOPY (RECORDS ISFMAP)			(CONSTANTS (\ISFMAPOFFSET 18))			(GLOBALVARS \FRAGMENTATIONWARNED))	      (INITVARS (\DISKDEBUG)			(\MAXSWAPBUFFERS 1)			(\FRAGMENTATIONWARNED)			(\M44.READY))	      (ADDVARS (\SYSTEMCACHEVARS \FRAGMENTATIONWARNED \M44.READY)))	(DECLARE: DONTCOPY		  (ADDVARS (INEWCOMS (ALLOCAL (ADDVARS (LOCKEDFNS ERROR RAID \M44ACTONVMEMFILE 								  \ACTONVMEMFILESUBR \ACTONVMEMPAGES 								  \CLEANUPDISKQUEUE \CLEARCB 								  \DISKERROR \DOACTONDISKPAGES 								  \DODISKCOMMAND \EXTENDISFMAP 								  \M44DOEXTENDVMEMFILE \GETDISKCB 								  \INITBFS \INSUREVMEMFILE \LISPERROR 								  \LOOKUPFMAP \REALDISKDA 								  \VIRTUALDISKDA \CLEARWORDS 								  \TESTPARTITION)						       (LOCKEDVARS \DISKREQUESTBLOCK 								   \SWAPREQUESTBLOCK \MAINDISK 								   \ISFCHUNKSIZE \EMUSCRATCH 								   \EMUDISKBUFFERS \EMUSWAPBUFFERS 								   \EMUDISKBUFEND \MAXSWAPBUFFERS 								   \#DISKBUFFERS \InterfacePage 								   \ISFMAP \ISFSCRATCHCAS 								   \ISFSCRATCHDAS \SYSDISK 								   \#SWAPBUFFERS \MAXDISKDAs 								   %%STREAMTYPE# \DISKDEBUG 								   \SPAREDISKWRITEBUFFER \#EMUBUFFERS 								   \EMUBUFFERS \LASTVMEMFILEPAGE])(* Low-level subr calls)(DEFINEQ(\INITBFS  [LAMBDA (BASE NWORDS AFTER)                                (* bvm: "13-Feb-85 18:04")    (PROG ((DSK \MAINDISK)	   CBSTART CB DD)          (* BASE is the start of a chunk of space running for NWORDS words for disk scratch use. Divvy it up as follows: 	  first page as scratch buffer for \WRITEDISKPAGES, then short CB's for disk ops, then miscellaneous scratch for 	  copying DA and CA arrays)          (PROGN                                             (* For \WRITEDISKPAGES)		 (SETQ \SPAREDISKWRITEBUFFER BASE)		 (SETQ BASE (\ADDBASE BASE WORDSPERPAGE))		 (SETQ NWORDS (IDIFFERENCE NWORDS WORDSPERPAGE)))          [PROGN                                             (* Fill in pieces of \MAINDISK)		 (OR (SETQ \SYSDISK (EMPOINTER (fetch (IFPAGE SYSDISK) of \InterfacePage)))		     (RAID "Can't find sysDisk"))		 (SETQ DD (fetch DDHEADER of \SYSDISK))		 (SETQ CB (SETQ CBSTART (fetch CBQUEUE of DSK)))		 (do                                         (* Allocate Short CB's for disk controller)		     (replace SHORTCB of CB with BASE)		     (SETQ BASE (\ADDBASE BASE \LENSHORTCB))		     (SETQ NWORDS (IDIFFERENCE NWORDS \LENSHORTCB))		     (SETQ CB (fetch CBNEXT of CB)) repeatuntil (EQ CB CBSTART))		 (replace ddPOINTER of DSK with (LOCF (fetch (ALTODSKOBJ DDLASTSERIAL#) of \SYSDISK)))                                                             (* Make some fields indirect thru alto record for now)		 (replace ALTODSKOBJ of DSK with \SYSDISK)		 (PROGN (replace NDISKS of DSK with (fetch DD#DISKS of DD))                                                             (* Copy some constant fields from alto)			(replace NTRACKS of DSK with (fetch DD#TRACKS of DD))			(replace NHEADS of DSK with (fetch DD#HEADS of DD))			(replace NSECTORS of DSK with (fetch DD#SECTORS of DD)))		 (replace RETRYCOUNT of DSK with 8)		 (AND AFTER (replace DDDIRTY of DSK with (replace DDVALID of DSK with NIL]          (PROGN (SETQ \EMUSCRATCH BASE)		 (SETQ \MAXDISKDAs (IQUOTIENT (IDIFFERENCE NWORDS (IPLUS \LENFP 8))					      2)))          (COND	    ((SETQ \ISFMAP (EMPOINTER (fetch (IFPAGE ISFMAP) of \InterfacePage)))	      (SETQ \ISFSCRATCHCAS (\ADDBASE [SETQ \ISFSCRATCHDAS					       (\ADDBASE \ISFMAP (IPLUS (fetch ISFEND of \ISFMAP)									(PROGN                                                              (* Leave a little room for off-by-one error in BCPL 							     code)									       2]					     (IPLUS (fetch ISFCHUNKSIZE of \ISFMAP)						    2)))	      (SETQ \ISFCHUNKSIZE (fetch ISFCHUNKSIZE of \ISFMAP))	      (replace DISKVERSION of \SWAPREQUESTBLOCK with (fetch FPVERSION of \ISFMAP))                                                             (* Fill in disk label info for all Lisp.virtualmem 							     requests)	      (\BLT (LOCF (fetch DISKSERIAL# of \SWAPREQUESTBLOCK))		    \ISFMAP WORDSPERCELL)	      (replace RETURNONCHECKERROR of \SWAPREQUESTBLOCK with NIL)	      (PROGN                                         (* Tell swapper how big vmem file is)		     (\M44DOEXTENDVMEMFILE)))	    (T (RAID "No ISF map"])(\TESTPARTITION  [LAMBDA (NUM)                                              (* bvm: "13-Feb-85 19:41")    (PROG ((HERE (.DISKPARTINSTR. 0)))          (RETURN (COND		    ((NEQ (.DISKPARTINSTR. (\DTEST NUM (QUOTE SMALLP)))			  0)                                 (* Partition switch succeeded, now restore original 							     partition)		      (.DISKPARTINSTR. HERE)		      T])(\ACTONDISKPAGES  [LAMBDA (DSK BUFFERS DAs DAorigin FID FIRSTPAGE LASTPAGE ACTION LASTNUMCHARSCONS LASTACTION 	       ReturnOnCheckError HINTLASTPAGE CAs)          (* bvm: "13-Feb-85 19:35")          (* performs indicated ACTION on pages FIRSTPAGE thru LASTPAGE of DSK (a disk object) for file whose alto id is FID.	  Returns page number of last page acted on, which may be less than LASTPAGE if end of file was encountered.	  BUFFERS is either NIL (don't care about the data) or else a buffer or list of buffers of data to be read/written.	  DAs is a vector of virtual disk addresses (words) for pages of the file, per alto conventions.	  DAorigin indicates which page (\GETBASE DAs 0) corresponds to; it should be no greater than FIRSTPAGE.	  LASTACTION, if supplied, is performed instead of ACTION on LASTPAGE. HINTLASTPAGE is hint of the last page of file, 	  to avoid chaining beyond the end of file. NUMCHARSCONS, if supplied, is a list, car of which will be smashed with 	  the NUMCHARS field of the last page acted on (this in lieu of multiple value return). If ReturnOnCheckError is true,	  returns (- (I + 64)), where I was the last page successfully acted on)    (PROG (EMBLOCK EMBUFS EMCAs EMDAs EMFID EMFIXEDCA RESULT STREAM LASTNC)          (COND	    ((EQ DSK \SYSDISK)	      (SETQ DSK \MAINDISK)))          [COND	    ((type? STREAM FID)	      (SETQ STREAM FID)	      (SETQ FID (fetch (ARRAYP BASE) of (fetch FID of FID]      RETRY          (UNINTERRUPTABLY              (\CLOCK0 (LOCF (fetch DISKTEMP0 of \MISCSTATS)))                                                             (* Note starting time)	      (PROG ((REQUEST \DISKREQUESTBLOCK))		    (.SETUPDISKBUFFERS. ACTION)		    (replace RETURNONCHECKERROR of REQUEST with ReturnOnCheckError)		    (replace DISKACTION of REQUEST with ACTION)		    (replace LASTDISKACTION of REQUEST with (COND							      ((AND LASTACTION (NEQ LASTACTION 0))								LASTACTION)							      (T ACTION)))		    (SETQ RESULT (\MISCAPPLY* (FUNCTION \DOACTONDISKPAGES)					      DSK REQUEST))		    (SETQ LASTNC (fetch CURRENTNUMCHARS of REQUEST)))	      [COND		((AND BUFFERS (NEQ LASTNC BYTESPERPAGE)		      (IGEQ RESULT 0)		      (DISKREADACTION? (OR (AND (EQ RESULT LASTPAGE)						LASTACTION)					   ACTION)))         (* Zero out everything past the last byte)		  (PROG [(BUF (OR EMFIXEDCA (EMPOINTER (\GETBASE EMCAs RESULT]		        (\CLEARBYTES BUF LASTNC (IDIFFERENCE BYTESPERPAGE LASTNC]	      [COND		((NOT (EMADDRESSP DAs))                      (* Possibly update the user's DAs from the emulator 							     copy)		  (\BLT DAs EMDAs (IPLUS LASTPAGE 2 (IMINUS DAorigin]                                                             (* If action was read, now copy from emu buffers into 							     user buffers)	      (COND		((LISTP BUFFERS)		  (for BUF in BUFFERS as (CA _ EMCAs) by (\ADDBASE CA 1) as N from FIRSTPAGE		     when (AND BUF (NOT (EMADDRESSP BUF))			       (DISKREADACTION? (OR (AND (EQ N LASTPAGE)							 LASTACTION)						    ACTION)))		     do (\BLT BUF (\VAG2 0 (\GETBASE CA 0))			      WORDSPERPAGE)))		((AND BUFFERS (NOT (EMADDRESSP BUFFERS))		      (DISKREADACTION? ACTION))		  (\BLT BUFFERS EMFIXEDCA WORDSPERPAGE)))	      [\BOXIPLUS (LOCF (fetch DISKIOTIME of \MISCSTATS))			 (\BOXIDIFFERENCE (\CLOCK0 (LOCF (fetch DISKTEMP1 of \MISCSTATS)))					  (LOCF (fetch DISKTEMP0 of \MISCSTATS]                                                             (* Note total time spent here)	      )          (COND	    ((ILESSP RESULT 0)	      (\DISKERROR (IMINUS RESULT)			  STREAM LASTNC)	      (GO RETRY))	    (T [COND		 (LASTNUMCHARSCONS (COND				     ((LISTP LASTNUMCHARSCONS)				       (RPLACA LASTNUMCHARSCONS LASTNC))				     (T (\PUTBASE LASTNUMCHARSCONS 0 LASTNC]	       (RETURN (SIGNED RESULT BITSPERWORD])(\WRITEDISKPAGES  [LAMBDA (DSK BUFFERS DAs DAorigin FID FIRSTPAGE LASTPAGE LASTACTION LASTNUMCHARSCONS LASTNUMCHARS 	       HINTLASTPAGE CAs)                             (* bvm: "19-Jan-85 16:24")          (* Write pages FIRSTPAGE thru LASTPAGE of DSK (a disk object) for file whose alto id is FID.	  Returns page number of last page acted on. BUFFERS is either NIL (don't care about the data) or else a buffer or 	  list of buffers of data to be written. DAs is a vector of virtual disk addresses (words) for pages of the file, per 	  alto conventions. DAorigin indicates which page (\GETBASE DAs 0) corresponds to; it should be no greater than 	  FIRSTPAGE. LASTACTION, if supplied, is performed instead of ACTION on LASTPAGE. HINTLASTPAGE is hint of the last 	  page of file, to avoid chaining beyond the end of file. NUMCHARSCONS, if supplied, is a list, car of which will be 	  smashed with the NUMCHARS field of the last page acted on (this in lieu of multiple value return). LASTNUMCHARS is 	  the nchars field to be written for LASTPAGE)    (PROG (EMBLOCK EMBUFS EMCAs EMDAs EMFID EMFIXEDCA RESULT STREAM)          (COND	    ((EQ DSK \SYSDISK)	      (SETQ DSK \MAINDISK)))          [COND	    ((type? STREAM FID)	      (SETQ STREAM FID)	      (SETQ FID (fetch (ARRAYP BASE) of (fetch FID of FID]          (\OPENDISKDESCRIPTOR DSK)      RETRY          (UNINTERRUPTABLY              (\CLOCK0 (LOCF (fetch DISKTEMP0 of \MISCSTATS)))	      [SETQ RESULT (PROG ((REQUEST \DISKREQUESTBLOCK))			         (.SETUPDISKBUFFERS. \DC.WRITED)			         (replace DISKNOALLOC of REQUEST with (EQ LASTACTION									  (UNSIGNED -1 BITSPERWORD)))			         (replace DISKWRITELASTNUMCHARS of REQUEST with (OR LASTNUMCHARS 										    BYTESPERPAGE))			         (RETURN (\MISCAPPLY* (FUNCTION \DOWRITEDISKPAGES)						      DSK REQUEST]	      [COND		((NOT (EMADDRESSP DAs))		  (\BLT DAs EMDAs (IPLUS LASTPAGE 2 (IMINUS DAorigin]	      [\BOXIPLUS (LOCF (fetch DISKIOTIME of \MISCSTATS))			 (\BOXIDIFFERENCE (\CLOCK0 (LOCF (fetch DISKTEMP1 of \MISCSTATS)))					  (LOCF (fetch DISKTEMP0 of \MISCSTATS]                                                             (* Note total time spent)	      )          (COND	    ((ILESSP RESULT 0)	      (\DISKERROR (IMINUS RESULT)			  STREAM)	      (GO RETRY))	    (T (RETURN (SIGNED RESULT BITSPERWORD])(\DISKERROR  [LAMBDA (ERRCODE STREAM LASTNC)                            (* bvm: "12-Mar-85 03:44")    (COND      (STREAM (M44.SIGNAL.DISK.ERROR ERRCODE (fetch FULLFILENAME of STREAM)))      (T (while T do (SELECTC ERRCODE			      (\DSK.HARD.ERROR (RAID "Hard Disk Error in Lisp.virtualmem.  Page = "						     (fetch (DSKOBJ CURRENTDISKPAGE) of \MAINDISK)))			      (\DSK.FULL.ERROR (RAID "Disk Full"))			      (RAID "Unknown disk error in Lisp.virtualmem" ERRCODE])(M44.SIGNAL.DISK.ERROR  [LAMBDA (ERRCODE FILENAME)                                 (* bvm: "17-Jan-85 17:46")          (* This is a separate function, without a backslash, so that user can OK from the break, in which case we return OK 	  from here, telling caller to try again)    (COND      [ERRCODE (bind (EC _(PROG1 ERRCODE (SETQ ERRCODE NIL))) while T		  do (SELECTC EC			      (\DSK.HARD.ERROR (LISPERROR "HARD DISK ERROR" FILENAME T))			      (\DSK.FULL.ERROR (LISPERROR "FILE SYSTEM RESOURCES EXCEEDED" FILENAME T)					       )			      (ERROR "Disk Error" FILENAME]      (T (QUOTE OK]))(DECLARE: EVAL@COMPILE DONTCOPY (DECLARE: EVAL@COMPILE (PUTPROPS .SETUPDISKBUFFERS. MACRO ((ACTION)                 (* bvm: "15-OCT-82 17:28")	   (SETQ EMBUFS \EMUDISKBUFFERS)	   (SETQ EMBLOCK \EMUSCRATCH)	   [COND	     ((ILESSP DAorigin (SUB1 FIRSTPAGE))	       [SETQ DAs (\ADDBASE DAs (SUB1 (IDIFFERENCE FIRSTPAGE DAorigin]	       [AND CAs (SETQ CAs (\ADDBASE CAs (SUB1 (IDIFFERENCE FIRSTPAGE DAorigin]	       (SETQ DAorigin (SUB1 FIRSTPAGE]	   [SETQ EMDAs (COND	       ((EMADDRESSP DAs)		 DAs)	       (T (\BLT EMBLOCK DAs (IPLUS LASTPAGE 2 (IMINUS DAorigin)))		  (PROG1 EMBLOCK (SETQ EMBLOCK (\ADDBASE EMBLOCK (IPLUS LASTPAGE 2 (IMINUS DAorigin]	   [COND	     [CAs (SETQ EMCAs (\ADDBASE CAs (IMINUS DAorigin]	     [(AND (LISTP BUFFERS)		   (OR (CDR BUFFERS)		       (PROGN (SETQ BUFFERS (CAR BUFFERS))   (* Treat singleton BUFFER as nonlist)			      NIL)))	       (SETQ EMCAs (\ADDBASE EMBLOCK (IMINUS FIRSTPAGE)))	       (for BUF in BUFFERS as N from FIRSTPAGE bind FIXEDBUF		  do [\PUTBASE EMBLOCK 0 (COND				 ((AND BUF (EMADDRESSP BUF))				   (\LOLOC BUF))				 ((AND (NULL BUF)				       FIXEDBUF))				 (T (PROG1 (\LOLOC EMBUFS)					   [COND					     ((DISKWRITEACTION? (OR (AND (EQ N LASTPAGE)									 LASTACTION)								    ACTION))					       (COND						 (BUF (\BLT EMBUFS BUF WORDSPERPAGE))						 (T (\CLEARWORDS EMBUFS WORDSPERPAGE)						    (SETQ FIXEDBUF (\LOLOC EMBUFS]					   (SETQ EMBUFS (\ADDBASE EMBUFS WORDSPERPAGE))					   (COND					     ((PTRGTP EMBUFS \EMUDISKBUFEND)					       (ERROR "Attempt to act on too many disk pages"]		     (SETQ EMBLOCK (\ADDBASE EMBLOCK 1]	     (T (SETQ EMFIXEDCA (COND		    ((AND BUFFERS (EMADDRESSP BUFFERS))		      BUFFERS)		    (T [COND			 ((DISKWRITEACTION? ACTION)          (* If writing, copy data into buffer)			   (COND			     (BUFFERS (\BLT EMBUFS BUFFERS WORDSPERPAGE))			     (T (\CLEARWORDS EMBUFS WORDSPERPAGE]		       EMBUFS]	   (replace DISKCAS of REQUEST with EMCAs)	   (replace FIXEDDISKBUFFER of REQUEST with EMFIXEDCA)	   (replace DISKDAS of REQUEST with (\ADDBASE EMDAs (IMINUS DAorigin)))	   (replace DISKVERSION of REQUEST with (fetch FPVERSION of FID))	   (\BLT (LOCF (fetch DISKSERIAL# of REQUEST))		 FID WORDSPERCELL)                           (* Fill in serial number for label)	   (replace DISKFIRSTPAGE of REQUEST with FIRSTPAGE)	   (replace DISKLASTPAGE of REQUEST with LASTPAGE)	   (replace DISKHINTLASTPAGE of REQUEST with (OR HINTLASTPAGE 0))))(PUTPROPS DISKWRITEACTION? MACRO ((ACTION)                   (* bvm: "15-OCT-82 17:06")				  (SELECTC ACTION					   ((LIST \DC.WRITEHLD \DC.WRITELD \DC.WRITED)					     T)					   NIL)))(PUTPROPS DISKREADACTION? MACRO ((ACTION)                    (* bvm: "15-OCT-82 17:06")				 (ILESSP ACTION \DC.WRITEHLD))))(PUTPROPS .DISKPARTINSTR. DOPVAL (1 SUBRCALL 8 1))(RPAQQ DISKCOMMANDS ((\DC.READHLD 54784)		     (\DC.READLD 54785)		     (\DC.READD 54786)		     (\DC.WRITEHLD 54787)		     (\DC.WRITELD 54788)		     (\DC.WRITED 54789)		     (\DC.SEEKONLY 54790)		     (\DC.NOOP 54791)		     (\DC.RESTORE 54891)))(DECLARE: EVAL@COMPILE (RPAQQ \DC.READHLD 54784)(RPAQQ \DC.READLD 54785)(RPAQQ \DC.READD 54786)(RPAQQ \DC.WRITEHLD 54787)(RPAQQ \DC.WRITELD 54788)(RPAQQ \DC.WRITED 54789)(RPAQQ \DC.SEEKONLY 54790)(RPAQQ \DC.NOOP 54791)(RPAQQ \DC.RESTORE 54891)(CONSTANTS (\DC.READHLD 54784)	   (\DC.READLD 54785)	   (\DC.READD 54786)	   (\DC.WRITEHLD 54787)	   (\DC.WRITELD 54788)	   (\DC.WRITED 54789)	   (\DC.SEEKONLY 54790)	   (\DC.NOOP 54791)	   (\DC.RESTORE 54891)))(RPAQQ DISKERRORS ((\DSK.HARD.ERROR 1101)		   (\DSK.FULL.ERROR 1102)))(DECLARE: EVAL@COMPILE (RPAQQ \DSK.HARD.ERROR 1101)(RPAQQ \DSK.FULL.ERROR 1102)(CONSTANTS (\DSK.HARD.ERROR 1101)	   (\DSK.FULL.ERROR 1102)))[DECLARE: EVAL@COMPILE (BLOCKRECORD DISKREQUEST ((DISKDAS FULLXPOINTER)             (* Vector of DAs to be acted on)			  (DISKCAS FULLXPOINTER)			  (FIXEDDISKBUFFER FULLXPOINTER)			  (DISKERRORCODE FULLXPOINTER)			  (CBCLEANUPFN FULLXPOINTER)			  (DISKFIRSTPAGE WORD)			  (DISKLASTPAGE WORD)			  (DISKHINTLASTPAGE WORD)			  (DISKVERSION WORD)                 (* These 3 words are for the disk label)			  (DISKSERIAL# FIXP)			  (DISKACTION WORD)			  (LASTDISKACTION WORD)			  (CURRENTNUMCHARS WORD)			  (LASTPAGEACTEDON WORD)			  (DISKWRITELASTNUMCHARS WORD)			  (RETURNONCHECKERROR FLAG)			  (DISKNOALLOC FLAG)			  (NIL BITS 14)			  (DISKCASTORAGE 20 WORD)			  (DISKDASTORAGE 60 WORD)            (* Or as much as you want)			  )			 [ACCESSFNS ((DISKFID (LOCF (fetch DISKVERSION of DATUM]			 (CREATE (\ALLOCBLOCK (FOLDHI (IPLUS \FIXEDLENDISKREQUEST 60)						      WORDSPERCELL))))(BLOCKRECORD ALTODSKOBJ ((NIL 8 WORD)                        (* Alto functions to implement generic ops)			 (DSKFPSYSDIR WORD)                  (* Short pointer to SYSDIR FP)			 (NIL 2 WORD)                        (* More alto fns)			 (DSKFPWORKINGDIR WORD)              (* Short pointer to FP of "working" dir)			 (DSKNAMEWORKINGDIR WORD)            (* Short pointer to bcpl string)			 (DSKLNPAGESIZE WORD)                (* ln{pagesize-in-words})			 (NIL 3 WORD)                        (* More alto cruft)			 (DSKKD WORD)                        (* Short pointer to DDHEADER)			 (DSKFPDISKDESCRIPTOR WORD)          (* Short pointer to DiskDescriptor FP)			 (DSKDRIVE# WORD)			 (DSKRETRYCOUNT WORD)			 (DSKTOTALERRORS WORD)			 (DSKLENCBZ WORD)			 (DSKLENCB WORD)			 (DSKDDHEADER 16 WORD)               (* Overlays DDHEADER)			 (NIL 2 WORD)			 (DSKDDMGR WORD)                     (* DD manager, for \FLUSHDISKDESCRIPTOR)			 (DSKLASTVDA WORD)                   (* VDA of last page allocated, for biasing search)			 (DSKSYSDIRBLK 5 WORD)			 (DSKDDBLK 5 WORD)			 (DSKWDBLK 5 WORD)			 (NIL 20 WORD)                       (* WorkingDir name)			 (DSKDDVDAS 17 WORD)                 (* VDAs for the data part of DD)			 )			[ACCESSFNS ALTODSKOBJ ((DDHEADER (LOCF (fetch DSKDDHEADER of DATUM])(BLOCKRECORD DDHEADER ((DD#DISKS WORD)		       (DD#TRACKS WORD)		       (DD#HEADS WORD)		       (DD#SECTORS WORD)		       (DDLASTSERIAL# FIXP)		       (NIL WORD)		       (DDBTSIZE WORD)                       (* Size of bittable in words)		       (DDDEFAULTVERSIONSKEPT WORD)		       (DDFREEPAGES WORD)		       (NIL 6 WORD)))(BLOCKRECORD CB ((CBQSTATUS BYTE)		 (CBNEXT POINTER)                            (* Link to next one)		 (SHORTCB POINTER)                           (* In alto space, what disk actually uses)		 (CBPAGENO WORD)                             (* The page number we intended to act on with this CB)		 )		(CREATE (\ALLOCBLOCK 3)))(BLOCKRECORD DISKLABEL ((DLNEXT WORD)			(DLPREVIOUS WORD)			(NIL WORD)			(DLNUMCHARS WORD)			(DLPAGENO WORD)			(DLFID 3 WORD)                       (* Version followed by 2-word serial number)			))(ACCESSFNS REALDA ((SECTOR (LRSH DATUM 12))		   (TRACK (LOGAND (LRSH DATUM 3)				  511))		   (HEAD (LOGAND (LRSH DATUM 2)				 1))		   (DISK (LOGAND (LRSH DATUM 1)				 1))		   (RESTORE (LOGAND DATUM 1))))(BLOCKRECORD SHORTCB ((CBLINK WORD)                          (* Short pointer to next in command chain, or zero)		      (CBSTATUS WORD)		      (CBCOMMAND WORD)		      (CBHEADERADDR WORD)                    (* Short pointer to header record, normally CBHEADER)		      (CBLABELADDR WORD)                     (* Short pointer to label record, normally either in 							     this CB or in the next cb in chain)		      (CBDATAADDR WORD)                      (* Short pointer to buffer of data)		      (CBWAKEUPS WORD)                       (* These two are always zero)		      (CBERRWAKEUPS WORD)		      (CBHEADER WORD)		      (CBDA WORD)                            (* Address of this disk block.							     May be filled in by previous access's label pointing at							     my CBHEADER)		      (CBLABNEXT WORD)                       (* Start of label field, if my CBLABELADDR points here)		      (CBLABPREV WORD)		      (CBLABBLANK WORD)		      (CBLABNUMCHARS WORD)		      (CBLABPAGENO WORD)		      (CBLABVERSION WORD)		      (CBLABSN1 WORD)		      (CBLABSN2 WORD)		      (CBTRUEPAGENO WORD)                    (* From here on is alto stuff that Lisp doesn't care 							     about)		      (CBCBZ WORD)		      (CBNEXTSHORTCB WORD))		     (BLOCKRECORD SHORTCB ((NIL WORD)				   (CBSECTOR BITS 4)				   (CBDONE BITS 4)				   (CBSEEKFAIL BITS 1)				   (CBSEEKING BITS 1)				   (CBNOTREADY BITS 1)				   (CBDATALATE BITS 1)				   (CBNOTRANSFER BITS 1)				   (CBCHECKSUMERR BITS 1)				   (CBFINALSTATUS BITS 2)				   (CBSEAL BYTE)				   (CBACTION BYTE)))		     (BLOCKRECORD SHORTCB ((NIL WORD)				   (NIL WORD)				   (CBSHORTSEAL BITS 5)				   (CBPARTITION BITS 3)				   (NIL BYTE))))(BLOCKRECORD FP ((FPSERIAL# FIXP)		 (FPVERSION WORD)		 (NIL WORD)		 (FPLEADERVDA WORD))		(BLOCKRECORD FP ((FPSERIALHI WORD)			      (FPSERIALLO WORD)			      (NIL 3 WORD))))(BLOCKRECORD DSKOBJ ((ddPOINTER FULLXPOINTER)          (* Either points at word 2 of this structure, or at DSKOBJ:LASTSERIAL#, so that we can maintain some fields in 	  parallel with alto OS for awhile. The next 6 words are arranged exactly as in the alto KDH structure, at least those	  fields we care about)		     (ddLASTSERIAL# FIXP)                    (* Last serial number given a file)		     (NIL WORD)		     (ddBITTABLESIZE WORD)                   (* Size of disk descriptor's bit table in words)		     (NIL WORD)		     (ddFREEPAGES WORD)		     (DSKPARTITION BYTE)                     (* 0 or explicit partition pointer)		     (ALTODSKOBJ XPOINTER)                   (* Pointer to alto BFSDSK structure, or NIL for disks 							     other than current partition)		     (SAWCHECKERROR FLAG)		     (DISKERRORCNT BITS 7)		     (SYSDIROFD POINTER)                     (* Stream onto SYSDIR.;1)		     (DDDIRTY FLAG)                          (* true if diskdescriptor needs writing)		     (DDVALID FLAG)                          (* True if DISKDESCRIPTOROFD field is ok.							     Invalidated on logout, etc)		     (DSKPASSWORDOK FLAG)                    (* True after password for this partition, if any, has 							     been validated)		     (NIL BITS 5)		     (DISKDESCRIPTOROFD POINTER)             (* Stream onto DiskDescriptor.;1)		     (CBQUEUE POINTER)                       (* Stuff for management of command blocks.							     No ref count because must not fault)		     (CBFREEPTR FULLXPOINTER)		     (CBPENDINGPTR FULLXPOINTER)		     (CBLASTPTR FULLXPOINTER)		     (CURRENTDAS FULLXPOINTER)               (* Vector of DAs currently being acted on)		     (DISKREQUEST FULLXPOINTER)		     (DISKDEVICENAME POINTER)                (* For retrieving the FDEV)		     (DISKLASTPAGEALLOC WORD)                (* Bias for new page search)                                                             (* Pointer to request subrecord)		     (CURRENTDISKPAGE WORD)		     (TOTALDISKERRORS WORD)		     (NDISKS WORD)                           (* Shape of disk. Info taken from disk descriptor)		     (NTRACKS WORD)		     (NHEADS WORD)		     (NSECTORS WORD)		     (RETRYCOUNT WORD))		    (CREATE (\ALLOCBLOCK 18))		    ddPOINTER _ NIL (BLOCKRECORD ddPOINTER ((DISKLASTSERIAL# FIXP)						  (NIL WORD)						  (DISKBITTABLESIZE WORD)						  (NIL WORD)						  (DISKFREEPAGES WORD))))(BLOCKRECORD \M44LeaderPage ((TimeCreate FIXP)			     (TimeWrite FIXP)			     (TimeRead FIXP)			     (NameCharCount BYTE)			     (NameChars 39 BYTE)			     (LeaderProps 210 WORD)			     (Spares 10 WORD)			     (PropertyPtr WORD)			     (ConsecutiveHint FLAG)			     (NIL BITS 7)			     (ChangeSerialNumber BYTE)			     (FIDDirectoryHint 5 WORD)			     (LastPageAddress WORD)			     (LastPageNumber WORD)			     (LastPageByteCount WORD))			    (BLOCKRECORD \M44LeaderPage ((NIL WORD)					  (TimeCreateLo WORD)					  (NIL WORD)					  (TimeWriteLo WORD)					  (NIL FIXP)					  (NIL 20 WORD)					  (NIL 210 WORD)					  (NIL 10 WORD)					  (PropertyBegin BYTE)					  (PropertyLength BYTE)))			    (CREATE (NCREATE (QUOTE VMEMPAGEP))))(ACCESSFNS M44STREAM ((FID (fetch F1 of DATUM)			   (replace F1 of DATUM with NEWVALUE))		      (FILEPAGEMAP (fetch F2 of DATUM)				   (replace F2 of DATUM with NEWVALUE))		      (LASTMAPPEDPAGE (fetch F3 of DATUM)				      (replace F3 of DATUM with NEWVALUE))		      (DIRINFO (fetch F4 of DATUM)			       (replace F4 of DATUM with NEWVALUE))		      (LEADERPAGE (fetch F5 of DATUM)				  (replace F5 of DATUM with NEWVALUE))		      (LastPage (fetch FW6 of DATUM)				(replace FW6 of DATUM with NEWVALUE))		      (LastOffset (fetch FW7 of DATUM)				  (replace FW7 of DATUM with NEWVALUE)))		     (ACCESSFNS M44STREAM ((DIRHOLEPTR (fetch F4 of DATUM)						       (replace F4 of DATUM with NEWVALUE))                                                             (* In dir stream only)				 ))		     (CREATE (create STREAM))		     LASTMAPPEDPAGE _ -1 LastPage _ 0 LastOffset _ 0)(ACCESSFNS FID ((W0 (\WORDELT DATUM 0)		    (SETA DATUM 0 NEWVALUE))		(W1 (\WORDELT DATUM 1)		    (SETA DATUM 1 NEWVALUE))		(W2 (\WORDELT DATUM 2)		    (SETA DATUM 2 NEWVALUE))		(W3 (\WORDELT DATUM 3)		    (SETA DATUM 3 NEWVALUE))		(W4 (\WORDELT DATUM 4)		    (SETA DATUM 4 NEWVALUE))		(FIDBLOCK (fetch (ARRAYP BASE) of DATUM)))	       (CREATE (ARRAY 5 (QUOTE SMALLPOSP)			      0 0)))](DECLARE: EVAL@COMPILE (RPAQQ \FILLINDA 65534)(RPAQQ \EOFDA 65535)(RPAQQ \LENFP 5)(RPAQQ \FP.DIRECTORYP 32768)(RPAQQ \INITPROPPTR 6866)(RPAQQ \DDBITTABSTART 32)(RPAQQ \NBYTES.DISKINFO 12)(RPAQQ \OFFSET.DISKLASTSERIAL# 8)(RPAQQ \NWORDS.DSKOBJ 36)(CONSTANTS (\FILLINDA 65534)	   (\EOFDA 65535)	   (\LENFP 5)	   (\FP.DIRECTORYP 32768)	   (\INITPROPPTR 6866)	   (\DDBITTABSTART 32)	   (\NBYTES.DISKINFO 12)	   (\OFFSET.DISKLASTSERIAL# 8)	   (\NWORDS.DSKOBJ 36)))(DECLARE: DOEVAL@COMPILE DONTCOPY(GLOBALVARS \EMUDISKBUFEND \EMUDISKBUFFERS \EMUSCRATCH \EMUSWAPBUFFERS \EXTRAISFBUF \ISFMAP 	    \ISFMAXCHUNK \ISFSCRATCHCAS \ISFSCRATCHDAS \#DISKBUFFERS \MAXDISKDAs \#SWAPBUFFERS 	    \SYSDISK \ISFCHUNKSIZE \MAINDISK \DISKREQUESTBLOCK \SWAPREQUESTBLOCK \DISKDEBUG 	    \MAXSWAPBUFFERS \SPAREDISKWRITEBUFFER \FREEPAGEFID \#EMUBUFFERS \EMUBUFFERS 	    \LASTVMEMFILEPAGE \M44.READY)))(* Super low level)(DEFINEQ(\ACTONVMEMPAGES  [LAMBDA (DSK BUFFERS DAs DAorigin FIRSTPAGE LASTPAGE ACTION LASTACTION HINTLASTPAGE CAs)                                                             (* bvm: "13-Feb-85 19:00")    (PROG ((REQUEST \SWAPREQUESTBLOCK))          (replace FIXEDDISKBUFFER of REQUEST with (COND						     (CAs (replace DISKCAS of REQUEST							     with (\ADDBASE CAs (IMINUS DAorigin)))							  NIL)						     (T BUFFERS)))          (replace DISKDAS of REQUEST with (\ADDBASE DAs (IMINUS DAorigin)))          (replace DISKFIRSTPAGE of REQUEST with FIRSTPAGE)          (replace DISKLASTPAGE of REQUEST with LASTPAGE)          (replace DISKHINTLASTPAGE of REQUEST with (OR HINTLASTPAGE 0))          (replace DISKACTION of REQUEST with ACTION)          (replace LASTDISKACTION of REQUEST with (COND						    ((AND LASTACTION (NEQ LASTACTION 0))						      LASTACTION)						    (T ACTION)))          (RETURN (\DOACTONDISKPAGES DSK REQUEST])(\WRITEVMEMPAGES  [LAMBDA (DSK BUFFERS DAs DAorigin FID FIRSTPAGE LASTPAGE LASTNUMCHARS HINTLASTPAGE CAs)                                                             (* bvm: "13-Feb-85 19:02")          (* * \WRITEDISKPAGES inside the junk context. Used by \M44DOEXTENDVMEMFILE)    (CHECK (NOT \INTERRUPTABLE))    (PROG ((REQUEST \DISKREQUESTBLOCK))          [COND	    (CAs (replace DISKCAS of REQUEST with (\ADDBASE CAs (IMINUS DAorigin]          (replace FIXEDDISKBUFFER of REQUEST with BUFFERS)          (replace DISKDAS of REQUEST with (\ADDBASE DAs (IMINUS DAorigin)))          (replace DISKVERSION of REQUEST with (fetch FPVERSION of FID))          (\BLT (LOCF (fetch DISKSERIAL# of REQUEST))		FID WORDSPERCELL)                            (* Fill in serial number for label)          (replace DISKFIRSTPAGE of REQUEST with FIRSTPAGE)          (replace DISKLASTPAGE of REQUEST with LASTPAGE)          (replace DISKHINTLASTPAGE of REQUEST with (OR HINTLASTPAGE 0))          (replace DISKNOALLOC of REQUEST with NIL)          (replace DISKWRITELASTNUMCHARS of REQUEST with (OR LASTNUMCHARS BYTESPERPAGE))          (RETURN (\DOWRITEDISKPAGES DSK REQUEST])(\DOACTONDISKPAGES  [LAMBDA (DSK REQUEST CLEANUPFN)                            (* bvm: "30-DEC-82 13:08")    (PROG ((CAS (fetch DISKCAS of REQUEST))	   (DAS (fetch DISKDAS of REQUEST))	   (FIRSTPAGE (fetch DISKFIRSTPAGE of REQUEST))	   (LASTPAGE (fetch DISKLASTPAGE of REQUEST))	   (BUFFER (fetch FIXEDDISKBUFFER of REQUEST))	   (HINTLASTPAGE (fetch DISKHINTLASTPAGE of REQUEST))	   (RETURNONCHECKERROR (fetch RETURNONCHECKERROR of REQUEST))	   CURRENTPAGE CB NEXTCB RESULT THISACTION)          (replace DISKREQUEST of DSK with REQUEST)          (replace CURRENTDAS of DSK with DAS)          (replace DISKERRORCNT of DSK with 0)          (replace SAWCHECKERROR of DSK with NIL)          (replace CBCLEANUPFN of REQUEST with CLEANUPFN)          (COND	    ((OR (NOT HINTLASTPAGE)		 (ILESSP HINTLASTPAGE FIRSTPAGE)		 (IGREATERP HINTLASTPAGE LASTPAGE))	      (SETQ HINTLASTPAGE LASTPAGE)))          (SETQ CURRENTPAGE FIRSTPAGE)          (* HINTLASTPAGE is used, if reasonable, to terminate activity before LASTPAGE so that we do not chain off the end 	  and seek to cylinder 0, a typical BFS bug. If the hint is wrong, we just resume from there, having wasted a disk 	  rotation)      RETRY          (replace CBLASTPTR of DSK with NIL)          (replace CBFREEPTR of DSK with (replace CBPENDINGPTR of DSK with (fetch CBQUEUE									      of DSK)))          (SETQ CB (\GETDISKCB DSK))                         (* Should never return NIL)          (SETQ RESULT HINTLASTPAGE)          (for PAGENO from CURRENTPAGE to HINTLASTPAGE until (COND							       ((EQ (\GETBASE DAS PAGENO)								    \EOFDA)                                                             (* At end of file, do no more)								 (SETQ RESULT (SUB1 PAGENO))								 T))	     do [SETQ THISACTION (COND		    ((EQ PAGENO LASTPAGE)		      (fetch LASTDISKACTION of REQUEST))		    (T (fetch DISKACTION of REQUEST]		[COND		  ((AND RETURNONCHECKERROR (fetch SAWCHECKERROR of DSK))                                                             (* No disk activity now, because cleanup waited for disk							     to stop)		    (replace LASTPAGEACTEDON of REQUEST with (SUB1 PAGENO))		    (RETURN (SETQ RESULT (LOGAND (IMINUS (IPLUS PAGENO -1 100Q))						 177777Q]		(COND		  ((NEQ THISACTION \DC.NOOP)		    (COND		      ((NULL (SETQ NEXTCB (\GETDISKCB DSK)))			(GO FAILURE)))		    [replace (CB CBLABELADDR) of CB		       with (\LOLOC (COND				      ((EQ (\GETBASE DAS (ADD1 PAGENO))					   \FILLINDA)        (* Chain to next cb, so that the next field from the 							     label of CB is written into the diskaddress field of 							     NEXTCB)					(LOCF (fetch (CB CBDA) of NEXTCB)))				      (T (LOCF (fetch (CB CBLABNEXT) of NEXTCB]		    (\DODISKCOMMAND DSK CB (OR BUFFER (EMPOINTER (\GETBASE CAS PAGENO)))				    (\GETBASE DAS PAGENO)				    PAGENO THISACTION)		    (SETQ CB NEXTCB)))	     finally (COND		       ((AND (fetch CBFREEPTR of DSK)			     (NEQ (fetch CBFREEPTR of DSK)				  (fetch CBNEXT of CB)))			 (RAID "Inconsistency in CBFREEPTR" CB)))		     (replace CBFREEPTR of DSK with CB)      (* "Put back" the last CB, since it is never used for a 							     command)		     (do                                     (* Wait for commands to complete)			 (SELECTQ (\CLEANUPDISKQUEUE DSK)				  (NIL (GO FAILURE))				  (T (RETURN))				  NIL))		     (COND		       ((AND (NEQ RESULT LASTPAGE)			     (NEQ (\GETBASE DAS (ADD1 RESULT))				  \EOFDA))                   (* Stopped before LASTPAGE because of a bad hint.							     Ignore hint and continue)			 (SETQ HINTLASTPAGE LASTPAGE)			 (SETQ CURRENTPAGE (ADD1 RESULT))			 (GO RETRY)))		     (replace LASTPAGEACTEDON of REQUEST with RESULT))          (RETURN RESULT)      FAILURE          (COND	    ((ILEQ (fetch DISKERRORCNT of DSK)		   (fetch RETRYCOUNT of DSK))	      (SETQ CURRENTPAGE (fetch CURRENTDISKPAGE of DSK))	      (GO RETRY)))          (RETURN (IMINUS \DSK.HARD.ERROR])(\DOWRITEDISKPAGES  [LAMBDA (DSK REQUEST)                                      (* bvm: "17-Jan-85 17:06")    (PROG ((CAS (fetch DISKCAS of REQUEST))	   (DAS (fetch DISKDAS of REQUEST))	   (FIRSTPAGE (fetch DISKFIRSTPAGE of REQUEST))	   (LASTPAGE (fetch DISKLASTPAGE of REQUEST))	   (BUFFER (fetch FIXEDDISKBUFFER of REQUEST))	   CURRENTPAGE CB FIRSTNEWPAGE NEXTNEWPAGE LASTVDA LAB)          [COND	    ((NOT (fetch DISKNOALLOC of REQUEST))            (* First try \ACTONDISKPAGES for any existing pages)	      [COND		((EQ (\GETBASE DAS FIRSTPAGE)		     \FILLINDA)                              (* This happens from createfile, no pages exist yet)		  (SETQ FIRSTNEWPAGE FIRSTPAGE))		(T [COND		     ((EQ (\GETBASE DAS (ADD1 FIRSTPAGE))			  \EOFDA)          (* FIRSTPAGE is the last existing page of the file, so we will have to rewrite its label anyway later on, so don't 	  do anything now)		       )		     (T                                      (* Some of these pages may not need to have their 							     labels written, so see how far we can get with just 							     \ACTONDISKPAGES ...)			(replace DISKACTION of REQUEST with (replace LASTDISKACTION of REQUEST							       with \DC.WRITED))			(replace RETURNONCHECKERROR of REQUEST with NIL)			(SETQ FIRSTPAGE (\DOACTONDISKPAGES DSK REQUEST))			(COND			  ((AND (EQ FIRSTPAGE LASTPAGE)				(EQ (fetch DISKWRITELASTNUMCHARS of REQUEST)				    (fetch CURRENTNUMCHARS of REQUEST)))                                                             (* All pages acted on, and byte count does not need to 							     be changed)			    (RETURN LASTPAGE))			  ((ILESSP FIRSTPAGE 0)              (* Error)			    (RETURN FIRSTPAGE]		   (SETQ FIRSTNEWPAGE (ADD1 FIRSTPAGE]	      (COND		((ILEQ FIRSTNEWPAGE LASTPAGE)          (* Need to allocate new pages. For this, we need a spare buffer for reading the new pages to make sure they are free	  pages)		  (replace FIXEDDISKBUFFER of REQUEST with \SPAREDISKWRITEBUFFER)		  (replace DISKACTION of REQUEST with (replace LASTDISKACTION of REQUEST							 with \DC.READLD))		  (SETQ NEXTNEWPAGE FIRSTNEWPAGE)		  (do (SETQ LASTVDA (\GETBASE DAS (SUB1 NEXTNEWPAGE)))		      (for I from NEXTNEWPAGE to LASTPAGE			 do (COND			      ((NOT (SETQ LASTVDA (\ASSIGNDISKPAGE DSK LASTVDA)))                                                             (* Disk full. Back out the pages we have assigned so 							     far)				(for J from FIRSTNEWPAGE to (SUB1 I)				   do (\M44MARKPAGEFREE DSK (\GETBASE DAS J))				      (\PUTBASE DAS J \FILLINDA))				(GO DISKFULL)))			    (\PUTBASE DAS I LASTVDA))        (* Now check that the pages are really free)		      (replace DISKFIRSTPAGE of REQUEST with NEXTNEWPAGE)		      (\DOACTONDISKPAGES DSK REQUEST (FUNCTION \CHECKFREEPAGE))           (* \CHECKFREEPAGE checks to make sure the page is really free, and if it is, stores its address in DAS.	  We now march thru DAS, compacting toward the front all the pages that are really free, then iterate allocating more 	  if necessary)		      (for I from NEXTNEWPAGE to LASTPAGE when (NEQ (SETQ LASTVDA (\GETBASE DAS I))								    \FILLINDA)			 do (\PUTBASE DAS NEXTNEWPAGE LASTVDA)			    (add NEXTNEWPAGE 1))		     repeatuntil (IGREATERP NEXTNEWPAGE LASTPAGE]          (replace DISKREQUEST of DSK with REQUEST)          (replace CURRENTDAS of DSK with DAS)          (replace DISKERRORCNT of DSK with 0)          (replace SAWCHECKERROR of DSK with NIL)          (replace CBCLEANUPFN of REQUEST with NIL)          (SETQ CURRENTPAGE FIRSTPAGE)      RETRY          (replace CBLASTPTR of DSK with NIL)          (replace CBFREEPTR of DSK with (replace CBPENDINGPTR of DSK with (fetch CBQUEUE									      of DSK)))          (for PAGENO from CURRENTPAGE to LASTPAGE	     do (COND		  ((NULL (SETQ CB (\GETDISKCB DSK)))		    (GO FAILURE)))		(COND		  ((OR (AND (EQ PAGENO LASTPAGE)			    (NEQ (fetch DISKWRITELASTNUMCHARS of REQUEST)				 BYTESPERPAGE))		       (EQ (\GETBASE DAS (ADD1 PAGENO))			   \FILLINDA))                       (* Mark end of file after this page)		    (\PUTBASE DAS (ADD1 PAGENO)			      \EOFDA)))                      (* Set up label with next and previous disk addresses, 							     numchars)		(SETQ LAB (LOCF (fetch (CB CBLABNEXT) of CB)))		[replace DLNEXT of LAB with (\REALDISKDA DSK (\GETBASE DAS (ADD1 PAGENO]		[replace DLPREVIOUS of LAB with (\REALDISKDA DSK (\GETBASE DAS (SUB1 PAGENO]		(replace DLNUMCHARS of LAB with (COND						  ((EQ PAGENO LASTPAGE)						    (fetch DISKWRITELASTNUMCHARS of REQUEST))						  (T BYTESPERPAGE)))		(replace (CB CBLABELADDR) of CB with (\LOLOC LAB))		(\DODISKCOMMAND DSK CB (OR BUFFER (EMPOINTER (\GETBASE CAS PAGENO)))				(\GETBASE DAS PAGENO)				PAGENO \DC.WRITELD)	     finally (do                                     (* Wait for commands to complete)			 (SELECTQ (\CLEANUPDISKQUEUE DSK)				  (NIL (GO FAILURE))				  (T (RETURN))				  NIL)))          (replace LASTPAGEACTEDON of REQUEST with LASTPAGE)          (RETURN LASTPAGE)      FAILURE          (COND	    ((ILEQ (fetch DISKERRORCNT of DSK)		   (fetch RETRYCOUNT of DSK))	      (SETQ CURRENTPAGE (fetch CURRENTDISKPAGE of DSK))	      (GO RETRY)))          (RETURN (IMINUS \DSK.HARD.ERROR))      DISKFULL          (RETURN (IMINUS \DSK.FULL.ERROR])(\CHECKFREEPAGE  [LAMBDA (DSK CB)                                           (* bvm: " 9-DEC-82 13:41")                                                             (* Check that CB got a free page, i.e. one whose file id							     is all -1)    (PROG [(FID (LOCF (fetch DLFID of (EMPOINTER (fetch (CB CBLABELADDR) of CB]          [FRPTQ 3 (PROGN (COND			    ((NEQ (\GETBASE FID 0)				  (UNSIGNED -1 BITSPERWORD))                                                             (* Oops, bittable was wrong, so nullify this guy's 							     address in caller)			      (\PUTBASE (fetch (DSKOBJ DISKDAS) of DSK)					(fetch (CB CBPAGENO) of CB)					\FILLINDA)			      (RETURN)))			  (SETQ FID (\ADDBASE FID 1]          (RETURN T])(\DODISKCOMMAND  [LAMBDA (DSK CB BUFFER VDA PAGENO ACTION NEXTCB)           (* bvm: "13-Feb-85 19:42")    (PROG ((SHORTCB (fetch SHORTCB of CB))	   LA NEXT LASTCB STATUS)          [replace CBHEADERADDR of SHORTCB with (\LOLOC (LOCF (fetch CBHEADER of SHORTCB]          (replace CBDATAADDR of SHORTCB with (\LOLOC BUFFER))          [COND	    ((EQ (SETQ LA (fetch CBLABELADDR of SHORTCB))		 0)                                          (* Fill this in only if caller hasn't)	      (replace CBLABELADDR of SHORTCB with (SETQ LA						     (\LOLOC (COND							       (NEXTCB (LOCF (fetch (CB CBDA)										of NEXTCB)))							       (T (LOCF (fetch (CB CBLABNEXT)									   of CB]          (SETQ LA (EMPOINTER LA))          (\BLT (LOCF (fetch DLFID of LA))		(fetch (DSKOBJ DISKFID) of DSK)		3)                                           (* Set serial number for label check)          (replace DLPAGENO of LA with PAGENO)          (replace CBPAGENO of CB with PAGENO)          [COND	    ((NEQ VDA \FILLINDA)	      (replace CBDA of SHORTCB with (\REALDISKDA DSK VDA]          (replace CBCOMMAND of SHORTCB	     with (IPLUS (SELECTC ACTION				  (\DC.READHLD \IDC.READHLD)				  (\DC.READLD \IDC.READLD)				  (\DC.READD \IDC.READD)				  (\DC.WRITEHLD \IDC.WRITEHLD)				  (\DC.WRITELD \IDC.WRITELD)				  (\DC.WRITED \IDC.WRITED)				  (\DC.SEEKONLY \IDC.SEEKONLY)				  (\DC.RESTORE (replace CBDA of SHORTCB						  with (ADD1 (LOGAND (fetch CBDA of SHORTCB)								     61440)))                                                             (* Track _ 0, Restore _ 1, so command is seek to track 							     zero)					       \IDC.SEEKONLY)				  (RAID "Invalid disk action" ACTION))			 (LLSH (fetch DSKPARTITION of DSK)			       8)))          (SETQ LASTCB (EMGETBASE \EM.DISKCOMMAND))          [COND	    ((NEQ LASTCB 0)                                  (* Disk is busy, queue CB up at end)	      (while (NEQ (SETQ NEXT (fetch CBLINK of (EMPOINTER LASTCB)))			  0)		 do (SETQ LASTCB NEXT))	      (replace CBLINK of (EMPOINTER LASTCB) with (\LOLOC SHORTCB]          [COND	    ((AND (EQ (EMGETBASE \EM.DISKCOMMAND)		      0)		  (OR (EQ LASTCB 0)		      (EQ (fetch CBDONE of SHORTCB)			  0)))          (* No CB's queued, so ours is the only one, and it hasn't been done yet. Careful here! If the last disk command got 	  an error, we don't want to do this. Also true if last disk command was never executed, which means that some earlier	  command got an error)	      (COND		((OR (NOT (SETQ LASTCB (fetch CBLASTPTR of DSK)))		     (AND (NEQ (SETQ STATUS (LOGAND (fetch (CB CBSTATUS) of LASTCB)						    \CBS.GOODMASK))			       0)			  (EQ (LOGAND STATUS \CBS.ERRORBITS)			      0)))		  (EMPUTBASE \EM.DISKCOMMAND (\LOLOC SHORTCB]          (replace CBQSTATUS of CB with \CB.PENDING)          (replace CBLASTPTR of DSK with CB)          (\BOXIPLUS (LOCF (fetch DISKOPS of \MISCSTATS))		     1])(\GETDISKCB  [LAMBDA (DSK)                                              (* bvm: "24-NOV-82 18:12")          (* Gets a new CB, clearing it out, or returns NIL if there are errors. In latter case, caller should retry 	  starting with CURRENTPAGE (set freely by \CLEANUPDISKQUEUE))    (PROG (CB)      LP  (RETURN (COND		    ((SETQ CB (fetch CBFREEPTR of DSK))		      [replace CBFREEPTR of DSK with (COND						       ((EQ (fetch CBNEXT of CB)							    (fetch CBPENDINGPTR of DSK))                                                             (* Circular buffer; when pointers are equal means 							     everyone is free. Free = NIL means nobody is free)							 NIL)						       (T (fetch CBNEXT of CB]		      (\CLEARCB CB)		      CB)		    ((NOT (\CLEANUPDISKQUEUE DSK))           (* an error occurred)		      NIL)		    (T                                       (* A CB was returned to the free queue)		       (GO LP])(\CLEARCB  [LAMBDA (CB)                                               (* bvm: "13-Feb-85 19:19")    (\CLEARWORDS (fetch SHORTCB of CB)		 \LENSHORTCB)    (replace CBQSTATUS of CB with \CB.FREE)    CB])(\CLEANUPDISKQUEUE  [LAMBDA (DSK)                                              (* bvm: "13-Feb-85 19:42")          (* Called to process pending CB's. If queue is empty and all is quiet, returns T. Returns NIL on errors, after 	  running error routine. Otherwise, returns a finished CB, which has also been placed on \FREEDISKCBS by this action)    (PROG ((CB (fetch CBPENDINGPTR of DSK))	   (FREE (fetch CBFREEPTR of DSK))	   SHORTCB LABEL LVDA)          (COND	    ((EQ CB FREE)	      (RETURN T)))      LP                                                     (* Wait for disk to finish something)          (SETQ SHORTCB (fetch SHORTCB of CB))          (COND	    ((EQ (fetch CBDONE of SHORTCB)		 0)                                          (* Command not done yet)	      [COND		((AND (EQ (EMGETBASE \EM.DISKCOMMAND)			  0)		      (EQ (fetch CBDONE of SHORTCB)			  0))                                (* Disk queue was flushed for some reason.							     Fake an error)		  (COND		    ((NEQ (fetch CBQSTATUS of CB)			  \CB.PENDING)		      (RETURN (RAID "No free CB's")))		    (T (replace CBSTATUS of SHORTCB with \CBS.FAKEERROR]                                                             (* Here is where some day we could block to let another							     process run)	      (GO LP)))                                      (* We now have CB free from the disk controller)          (replace CBPENDINGPTR of DSK with (fetch CBNEXT of CB))          (COND	    ((EQ CB (fetch CBLASTPTR of DSK))	      (replace CBLASTPTR of DSK with NIL)))          (* Remove from pending queue)          (replace CBSHORTSEAL of SHORTCB with 0)            (* Invalidate it as a disk command, just in case)          [COND	    ((NOT FREE)	      (replace CBFREEPTR of DSK with (SETQ FREE CB]                                                             (* Now clean up the transfer)          (COND	    ((EQ (fetch RESTORE of (fetch CBDA of SHORTCB))		 1)                                          (* This is our command, not user's, so nothing to 							     cleanup)	      (RETURN CB)))          [COND	    ((NEQ (LOGAND (fetch CBSTATUS of SHORTCB)			  \CBS.GOODMASK)		  \CBS.GOOD)                                 (* Error occurred)	      (repeatuntil (EQ (EMGETBASE \EM.DISKCOMMAND)			       0))                           (* Wait for disk to stop spinning)	      (COND		((NEQ (fetch TOTALDISKERRORS of DSK)		      MAX.SMALL.INTEGER)                     (* Keep this count for debugging)		  (add (fetch TOTALDISKERRORS of DSK)		       1)))	      (RETURN (COND			[(IGREATERP (add (fetch DISKERRORCNT of DSK)					 1)				    (fetch RETRYCOUNT of DSK))                                                             (* Hard error)			  (COND			    (\DISKDEBUG                      (* Error is normally fielded in a more benign place)					(RAID "Hard Disk Error.  ^N to continue" CB]			(T (COND			     ((EQ (fetch CBFINALSTATUS of SHORTCB)				  \CBS.CHECKERROR)			       (replace SAWCHECKERROR of DSK with T)))			   (replace CURRENTDISKPAGE of DSK with (fetch CBPAGENO of CB))			   (COND			     ((IGREATERP (fetch DISKERRORCNT of DSK)					 (LRSH (fetch RETRYCOUNT of DSK)					       1))           (* Half the tolerable errors.							     Initiate a Restore to let disk recalibrate)			       (EMPUTBASE \EM.DISKADDRESS (UNSIGNED -1 BITSPERWORD))                                                             (* This forces a seek)			       (\DODISKCOMMAND DSK (\GETDISKCB DSK)					       NIL					       (\VIRTUALDISKDA DSK (fetch CBDA of SHORTCB))					       (fetch CURRENTDISKPAGE of DSK)					       \DC.RESTORE)))			   NIL]          (SETQ LABEL (EMPOINTER (fetch CBLABELADDR of SHORTCB)))          (replace (DSKOBJ CURRENTNUMCHARS) of DSK with (fetch DLNUMCHARS of LABEL))          (replace DISKERRORCNT of DSK with 0)          (replace SAWCHECKERROR of DSK with NIL)          [COND	    ((fetch (DSKOBJ CBCLEANUPFN) of DSK)	      (APPLY* (fetch (DSKOBJ CBCLEANUPFN) of DSK)		      DSK CB))	    (T [SETQ LVDA (\ADDBASE (fetch CURRENTDAS of DSK)				    (SUB1 (fetch CBPAGENO of CB]	       [COND		 ((EQ (\GETBASE LVDA 2)		      \FILLINDA)                             (* Fill in Next address)		   (\PUTBASE LVDA 2 (\VIRTUALDISKDA DSK (fetch DLNEXT of LABEL]	       (COND		 ((EQ (\GETBASE LVDA 0)		      \FILLINDA)                             (* Fill in Previous address)		   (\PUTBASE LVDA 0 (\VIRTUALDISKDA DSK (fetch DLPREVIOUS of LABEL]          (RETURN CB])(\VIRTUALDISKDA  [LAMBDA (DSK REALDA)                                       (* bvm: "13-Feb-85 19:43")                                                             (* Converts a real disk address into a virtual one)    (COND      ((EQ REALDA 0)	\EOFDA)      (T (IPLUS (ITIMES (IPLUS (ITIMES (IPLUS (ITIMES (fetch DISK of REALDA)						      (fetch NTRACKS of DSK))					      (fetch TRACK of REALDA))				       (fetch NHEADS of DSK))			       (fetch HEAD of REALDA))			(fetch NSECTORS of DSK))		(fetch SECTOR of REALDA])(\REALDISKDA  [LAMBDA (DSK VDA)                                          (* bvm: "18-NOV-82 21:16")                                                             (* Returns a real disk address for given virtual 							     address)    (COND      ((EQ VDA \EOFDA)	0)      (T (PROG ((NSECTORS (fetch NSECTORS of DSK))		(NHEADS (fetch NHEADS of DSK))		(NTRACKS (fetch NTRACKS of DSK)))	       (RETURN (IPLUS (LLSH (IREMAINDER VDA NSECTORS)				    14Q)			      (LLSH (IREMAINDER (SETQ VDA (IQUOTIENT VDA NSECTORS))						NHEADS)				    2)			      (LLSH (IREMAINDER (SETQ VDA (IQUOTIENT VDA NHEADS))						NTRACKS)				    3)			      (LLSH (IQUOTIENT VDA NTRACKS)				    1]))(DECLARE: EVAL@COMPILE DONTCOPY (RPAQQ CBSTATUSCONSTANTS ((\CBS.ERRORBITS 183)			  (\CBS.GOODMASK 4023)			  (\CBS.GOOD 3840)			  (\CBS.FAKEERROR 3841)			  (\CBS.CHECKERROR 2)))(DECLARE: EVAL@COMPILE (RPAQQ \CBS.ERRORBITS 183)(RPAQQ \CBS.GOODMASK 4023)(RPAQQ \CBS.GOOD 3840)(RPAQQ \CBS.FAKEERROR 3841)(RPAQQ \CBS.CHECKERROR 2)(CONSTANTS (\CBS.ERRORBITS 183)	   (\CBS.GOODMASK 4023)	   (\CBS.GOOD 3840)	   (\CBS.FAKEERROR 3841)	   (\CBS.CHECKERROR 2)))(RPAQQ IDISKCOMMANDS ((\IDC.READHLD 18432)		      (\IDC.READLD 18496)		      (\IDC.READD 18512)		      (\IDC.WRITEHLD 18600)		      (\IDC.WRITELD 18536)		      (\IDC.WRITED 18520)		      (\IDC.SEEKONLY 18434)))(DECLARE: EVAL@COMPILE (RPAQQ \IDC.READHLD 18432)(RPAQQ \IDC.READLD 18496)(RPAQQ \IDC.READD 18512)(RPAQQ \IDC.WRITEHLD 18600)(RPAQQ \IDC.WRITELD 18536)(RPAQQ \IDC.WRITED 18520)(RPAQQ \IDC.SEEKONLY 18434)(CONSTANTS (\IDC.READHLD 18432)	   (\IDC.READLD 18496)	   (\IDC.READD 18512)	   (\IDC.WRITEHLD 18600)	   (\IDC.WRITELD 18536)	   (\IDC.WRITED 18520)	   (\IDC.SEEKONLY 18434)))(DECLARE: EVAL@COMPILE (RPAQQ \EM.DISKCOMMAND 337)(RPAQQ \EM.DISKADDRESS 339)(RPAQQ \FIXEDLENDISKREQUEST 42)(RPAQQ \DEFAULTDASTORAGELENGTH 60)(RPAQQ \LENCB 6)(RPAQQ \LENDSKOBJ 34)(RPAQQ \LENSHORTCB 18)(CONSTANTS (\EM.DISKCOMMAND 337)	   (\EM.DISKADDRESS 339)	   (\FIXEDLENDISKREQUEST 42)	   (\DEFAULTDASTORAGELENGTH 60)	   (\LENCB 6)	   (\LENDSKOBJ 34)	   (\LENSHORTCB 18)))(DECLARE: EVAL@COMPILE (RPAQQ \CB.PENDING 1)(RPAQQ \CB.FREE 0)(CONSTANTS (\CB.PENDING 1)	   (\CB.FREE 0))))(* At MAKEINIT time)(DEFINEQ(MAKEINITBFS  [LAMBDA NIL                                                (* bvm: " 8-DEC-82 13:10")                                                             (* Called at MAKEINIT time to create bfs structures)    (\LOCKCELL (SETQ \MAINDISK (create DSKOBJ))	       \LENDSKOBJ)    (replace DISKDEVICENAME of \MAINDISK with (EVQ (QUOTE DSK)))    (\LOCKCELL (SETQ \SWAPREQUESTBLOCK (create DISKREQUEST))	       (IPLUS \FIXEDLENDISKREQUEST \DEFAULTDASTORAGELENGTH))    (\LOCKCELL (SETQ \DISKREQUESTBLOCK (create DISKREQUEST))	       (IPLUS \FIXEDLENDISKREQUEST \DEFAULTDASTORAGELENGTH))    (to 3 bind PREV (CB _(create CB))       first (\LOCKCELL CB \LENCB)	     (SETQ PREV CB)       do (\LOCKCELL CB \LENCB)	  (SETQ PREV (create CB			     CBNEXT _ PREV))       finally (replace CBNEXT of CB with PREV)	       (replace CBQUEUE of \MAINDISK with CB))    (SETQ \FREEPAGEFID (\ALLOCBLOCK 3))                      (* FP or FID for free disk page is all -1)    (for I from 0 to 4 do (\PUTBASE \FREEPAGEFID I (UNSIGNED -1 BITSPERWORD]))(DECLARE: DONTCOPY (ADDTOVAR INITPTRS (\MAINDISK)		   (\SWAPREQUESTBLOCK)		   (\DISKREQUESTBLOCK)		   (\FREEPAGEFID))(ADDTOVAR INEWCOMS (FNS MAKEINITBFS))EVAL@COMPILE (ADDTOVAR DONTCOMPILEFNS MAKEINITBFS))(* Swap stuff)(DEFINEQ(\M44ACTONVMEMFILE  [LAMBDA (FIRSTPAGE BUFFER NPAGES WRITEFLG)                 (* bvm: "13-Feb-85 20:26")    (PROG ((LASTPAGE (IPLUS FIRSTPAGE NPAGES -1))	   (DAs \ISFSCRATCHDAS)	   (CAs \ISFSCRATCHCAS)	   (PAGE FIRSTPAGE)	   (BUF BUFFER)	   CHUNK RESULT)          [COND	    ((AND (IGEQ LASTPAGE (\GETBASE \ISFMAP (fetch ISFLAST of \ISFMAP)))		  (EQ (\LOOKUPFMAP FIRSTPAGE)		      \FILLINDA))	      (RETURN (RAID "Can't complete swap operation--page not in isf map"]          (while (IGREATERP NPAGES 0)	     do (SETQ CHUNK (IMIN NPAGES \ISFCHUNKSIZE))		(for I from 0 to (SUB1 CHUNK)		   do (\PUTBASE CAs I (\LOLOC BUF))		      (\PUTBASE DAs I (\LOOKUPFMAP (IPLUS PAGE I)))		      (SETQ BUF (\ADDBASE BUF WORDSPERPAGE)))		(\PUTBASE DAs CHUNK \FILLINDA)		[COND		  ((ILESSP (SETQ RESULT (\ACTONVMEMPAGES \MAINDISK NIL DAs PAGE PAGE							 (IPLUS PAGE CHUNK -1)							 (COND							   (WRITEFLG \DC.WRITED)							   (T \DC.READD))							 NIL NIL CAs))			   0)		    (\DISKERROR (IMINUS RESULT]		(SETQ NPAGES (IDIFFERENCE NPAGES CHUNK))		(SETQ PAGE (IPLUS PAGE CHUNK)))          (RETURN LASTPAGE])(\LOOKUPFMAP  [LAMBDA (PAGE)                                             (* bvm: "12-NOV-82 14:13")          (* Returns DA for PAGE out of \ISFMAP. The map consists of pairs <first page# of run> <da>, with the first entry 	  at \ISFMAPOFFSET and the last at \ISFMAP:ISFLAST being the first page beyond the scanned part of the file)    (PROG ((HI (fetch ISFLAST of \ISFMAP))	   (LO \ISFMAPOFFSET)	   MID)          [COND	    ((EQ PAGE (fetch ISFONEPAGE of \ISFMAP))         (* This is in case runtable overflows)	      (RETURN (fetch ISFONEDA of \ISFMAP]          (COND	    ((IGEQ PAGE (\GETBASE \ISFMAP HI))               (* Should never happen)	      (RETURN \FILLINDA)))          [while (IGREATERP HI (IPLUS LO 2))	     do (SETQ MID (FLOOR (FOLDLO (IPLUS LO HI)					 2)				 2))                         (* Do binary chop on map. Page numbers are all at even 							     offsets)		(COND		  ((IGEQ PAGE (\GETBASE \ISFMAP MID))		    (SETQ LO MID))		  (T (SETQ HI MID]          (SETQ LO (\ADDBASE \ISFMAP LO))          (RETURN (IPLUS (\GETBASE LO 1)			 (IDIFFERENCE PAGE (\GETBASE LO 0])(\M44EXTENDVMEMFILE  [LAMBDA (LASTPAGE)                                         (* bvm: "14-Feb-85 18:00")          (* * Extends vmem to at least LASTPAGE in length, returns actual final length)    (COND      (\M44.READY                                            (* Don't do this until EVENTFN has run for \MAINDISK --							     else disk descriptor messed up)		  (PROG ((OLDLASTPAGE \LASTVMEMFILEPAGE)			 ERRCODE FREE)		        (OR (fetch DDVALID of \MAINDISK)			    (\OPENDISKDESCRIPTOR \MAINDISK))          (* * BFS page allocation may be necessary, so take care of this before we enter a context where \NEWPAGE is illegal)		        [COND			  ((GREATERP (IDIFFERENCE LASTPAGE OLDLASTPAGE)				     (SETQ FREE (IDIFFERENCE (fetch (DSKOBJ DISKFREEPAGES)								of \MAINDISK)							     100)))                                                             (* Never use up the last of DSK for vmem)			    (SETQ LASTPAGE (IPLUS OLDLASTPAGE FREE]		        (COND			  ((AND (SETQ ERRCODE (\MISCAPPLY* (FUNCTION \M44DOEXTENDVMEMFILE)							   LASTPAGE))				(NEQ ERRCODE \DSK.FULL.ERROR))			    (\DISKERROR ERRCODE)))		        (\M44FLUSHDISKDESCRIPTOR \MAINDISK)		        [COND			  ((IGREATERP \LASTVMEMFILEPAGE OLDLASTPAGE)			    (ADD.PROCESS (QUOTE (\M44VMEMEXTENDED]		        (RETURN T])(\M44DOEXTENDVMEMFILE  [LAMBDA (LASTPAGE)                                         (* bvm: "14-Feb-85 23:31")          (* Called when LASTPAGE is not in the ISF map. Might simply need to look up some new pages; if we have already 	  scanned the whole file, however, we will need to extend the file itself. Returns error code on failure.	  If LASTPAGE is NIL just reads to the end of the vmem file)    (PROG ((FIRSTPAGE (AND LASTPAGE \LASTVMEMFILEPAGE))	   (SCRATCHBUF \SPAREDISKWRITEBUFFER)	   (DAs \ISFSCRATCHDAS)	   (LASTNEEDEDPAGE LASTPAGE)	   [LASTFULLPAGE (SUB1 (\GETBASE \ISFMAP (fetch ISFLAST of \ISFMAP]	   FIRSTDA NP LASTPAGEREAD LASTPAGEWRITTEN LASTPAGEADDR LASTPAGEOFFSET P1)          (* Use \SPAREDISKWRITEBUFFER as a scratch buf, assuming this is not called while \DOWRITEDISKPAGES is happening 	  (because \DOWRITEDISKPAGES is locked). If it turns out we actually need to invoke \DOWRITEDISKPAGES ourselves, then 	  we better not have been writing the disk anyway, in which case we steal a different disk buffer)          (AND FIRSTPAGE (SETQ FIRSTDA (\LOOKUPFMAP FIRSTPAGE)))          (while (OR (NULL LASTNEEDEDPAGE)		     (ILESSP LASTFULLPAGE LASTNEEDEDPAGE))	     do (SETQ NP (IDIFFERENCE \ISFCHUNKSIZE 2))		[\PUTBASE DAs 0 (COND			    ((EQ LASTFULLPAGE 0)			      \EOFDA)			    (T (\LOOKUPFMAP (SUB1 LASTFULLPAGE]		(\PUTBASE DAs 1 (\LOOKUPFMAP LASTFULLPAGE))                                                              (* Will operate on LASTFULLPAGE plus as many remaining 							     pages as desired. NP is number of new pages)		(for I from 2 to (IPLUS NP 2) do (\PUTBASE DAs I \FILLINDA))                                                              (* \FILLINDA for NP starting at first unknown page.							     Last one is bonus)		[COND		  ((ILESSP (SETQ LASTPAGEREAD (\ACTONVMEMPAGES \MAINDISK SCRATCHBUF DAs (SUB1 										     LASTFULLPAGE)							       LASTFULLPAGE							       (IPLUS LASTFULLPAGE NP)							       \DC.READD NIL (fetch ISFHINTLASTPAGE										of \ISFMAP)))			   0)		    (\DISKERROR (IMINUS LASTPAGEREAD]		(SETQ LASTPAGEOFFSET (IPLUS (IDIFFERENCE LASTPAGEREAD LASTFULLPAGE)					    2))              (* Offset in DAs of one past LASTPAGEREAD)		[COND		  ((OR (NEQ (fetch CURRENTNUMCHARS of \SWAPREQUESTBLOCK)			    BYTESPERPAGE)		       (EQ (\GETBASE DAs LASTPAGEOFFSET)			   \EOFDA))                          (* Read to EOF. The second condition should never be 							     needed, but if file is malformed at the end we would be							     in trouble)		    (COND		      ((ILEQ LASTPAGEOFFSET 3)               (* No pages were acted on, so extend simply)			(COND			  ((NULL LASTNEEDEDPAGE)			    (RETURN NIL)))			(PROG ((BUF \EMUDISKBUFFERS))			      (\CLEARWORDS BUF WORDSPERPAGE)                                                             (* Want to write new pages blankly, I think)			      (\PUTBASE DAs LASTPAGEOFFSET \FILLINDA)                                                             (* \ACTONDISKPAGES had set it to \EOFDA)			      (\PUTBASE DAs (IPLUS NP 3)					\EOFDA)          (* We will rewrite LASTPAGEREAD, making it a full page and linking it to the NP+1 new pages, the last of which is a 	  blank page (and not placed in the isfmap, which is a bit of a misfeature))			      [COND				((ILESSP (SETQ LASTPAGEWRITTEN (\WRITEVMEMPAGES \MAINDISK BUF DAs										(SUB1 LASTFULLPAGE)										\ISFMAP LASTPAGEREAD										(IPLUS LASTFULLPAGE 										       NP 1)										0))					 0)				  (RETURN (IMINUS LASTPAGEWRITTEN]			      (SETQ LASTPAGEADDR (\GETBASE DAs (IPLUS NP 2)))                                                             (* for rewriting leader page hint)			  ))		      (T           (* Too hard to do both. Fill in part of map now, and extend the file on the next iteration. Number of good pages 	  read was LASTPAGEREAD-1-LASTFULLPAGE)			 (SETQ NP (IDIFFERENCE LASTPAGEOFFSET 3]		[for I from 1 to NP		   do (\EXTENDISFMAP (IPLUS LASTFULLPAGE I)				     (\GETBASE DAs (ADD1 I)))		      (COND			((EQ (IPLUS LASTFULLPAGE I)			     FIRSTPAGE)			  (SETQ FIRSTDA (\GETBASE DAs (ADD1 I]		(SETQ LASTFULLPAGE (IPLUS LASTFULLPAGE NP)))          (AND FIRSTPAGE (\EXTENDISFMAP FIRSTPAGE FIRSTDA))                                                             (* just in case map is full, this will set ONEPAGE and 							     ONEDA for \LOOKUPFMAP)          [COND	    ((NEQ (fetch ISFREWRITE of \ISFMAP)		  0)                                         (* Write map back onto file)	      (PROG ((CAs \ISFSCRATCHCAS))		    (\PUTBASE DAs 0 \EOFDA)		    (\PUTBASE DAs 1 (fetch ISFDA0 of \ISFMAP))		    (\PUTBASE DAs 2 (fetch ISFDA1 of \ISFMAP))		    (\PUTBASE DAs 3 (fetch ISFDA2 of \ISFMAP))		    (\PUTBASE CAs 1 (\LOLOC SCRATCHBUF))		    (\PUTBASE CAs 2 (\LOLOC \ISFMAP))        (* Set up to write leader page and first data page of 							     file)		    (SETQ P1 (COND			(LASTPAGEWRITTEN                     (* File was extended, so need to rewrite leader page, 							     too)					 (\ACTONVMEMPAGES \MAINDISK NIL DAs -1 0 0 \DC.READD NIL NIL 							  CAs)                                                             (* Read leader page)					 (replace LastPageAddress of SCRATCHBUF with LASTPAGEADDR)					 (replace ISFHINTLASTPAGE of \ISFMAP					    with (replace LastPageNumber of SCRATCHBUF with 										  LASTPAGEWRITTEN))					 (replace LastPageByteCount of SCRATCHBUF with 0)					 0)			(T 1)))		    (\ACTONVMEMPAGES \MAINDISK NIL DAs -1 P1 1 \DC.WRITED NIL NIL CAs]      EXIT[SETQ \LASTVMEMFILEPAGE (SUB1 (\GETBASE \ISFMAP (fetch ISFLAST of \ISFMAP]                                                             (* Update pointer to true end, return NIL to signal 							     success)          (RETURN NIL])(\EXTENDISFMAP  [LAMBDA (PAGE DA)                                          (* bvm: "14-Feb-85 23:29")                                                             (* extend map to include the knowledge that DA is 							     address of PAGE)    (PROG ((LASTOFFSET (fetch ISFLAST of \ISFMAP))	   LASTPAGE LASTMAP)          (replace ISFONEPAGE of \ISFMAP with PAGE)          (replace ISFONEDA of \ISFMAP with DA)          (SETQ LASTMAP (\ADDBASE \ISFMAP (IDIFFERENCE LASTOFFSET 2)))                                                             (* LASTMAP points at the last Page, DA pair in map)          (COND	    ((NEQ (SETQ LASTPAGE (\GETBASE LASTMAP 2))		  PAGE)	      (RETURN)))          [COND	    ([EQ DA (IPLUS (\GETBASE LASTMAP 1)			   (IDIFFERENCE LASTPAGE (\GETBASE LASTMAP 0]                                                             (* Still in same chunk)	      (\PUTBASE LASTMAP 2 (ADD1 LASTPAGE)))	    (T                                               (* Start new chunk)	       (COND		 ((EQ LASTOFFSET (fetch ISFEND of \ISFMAP))                                                             (* No more space in map)		   (RETURN))		 (T (\PUTBASE LASTMAP 3 DA)                  (* DA corresponding to LASTPAGE=PAGE)		    (\PUTBASE LASTMAP 4 (ADD1 LASTPAGE))		    (replace ISFLAST of \ISFMAP with (IPLUS LASTOFFSET 2]          (RETURN T])(\M44VMEMEXTENDED  [LAMBDA NIL                                                (* bvm: "14-Feb-85 15:28")    (PROG ((NPIECES (\M44VMEMFRAGMENTS))	   W)          (COND	    ((IGREATERP NPIECES (ADD1 (OR \FRAGMENTATIONWARNED 0)))	      (SETQ W (CREATEW (QUOTE (400 700 600 100))			       "VMem fragmentation warning"))	      (printout W T "Your virtual memory backing file has been extended, and is now in " .I1 			NPIECES " segments." T T "This fragmentation may degrade swapping performance, so youmay want to rebuild your {DSK}LISP.VIRTUALMEM, making it larger.")	      (FLASHWINDOW W 4)	      (SETQ \FRAGMENTATIONWARNED NPIECES])(\M44VMEMFRAGMENTS  [LAMBDA NIL                                                (* bvm: "14-Feb-85 15:28")    (IQUOTIENT (IDIFFERENCE (fetch ISFLAST of \ISFMAP)			    \ISFMAPOFFSET)	       2]))(DECLARE: EVAL@COMPILE DONTCOPY [DECLARE: EVAL@COMPILE (BLOCKRECORD ISFMAP ((NIL 5 WORD)                            (* First 5 words are a FP)		     (ISFDA0 WORD)                           (* DA's of the first 3 pages of file)		     (ISFDA1 WORD)		     (ISFDA2 WORD)		     (ISFSEAL WORD)		     (ISFDISK WORD)                          (* points to a DSKOBJ for file)		     (NIL WORD)                              (* ZONE)		     (ISFLAST WORD)                          (* offset of last entry in map)		     (ISFEND WORD)                           (* Offset of end of space for map)		     (ISFONEPAGE WORD)                       (* Last page# added to map)		     (ISFONEDA WORD)                         (* its DA)		     (ISFREWRITE WORD)                       (* non-zero if map should be rewritten when file is 							     extended)		     (ISFCHUNKSIZE WORD)                     (* if file needs to be extended, do so in this size 							     unit)		     (ISFHINTLASTPAGE WORD)                  (* Hint of last page)		     (ISFMAPSTART WORD)          (* Map entries follow. Each is two words: the page number of the start of a run, followed by the vda of that first 	  page)		     ))](DECLARE: EVAL@COMPILE (RPAQQ \ISFMAPOFFSET 18)(CONSTANTS (\ISFMAPOFFSET 18)))(DECLARE: DOEVAL@COMPILE DONTCOPY(GLOBALVARS \FRAGMENTATIONWARNED)))(RPAQ? \DISKDEBUG )(RPAQ? \MAXSWAPBUFFERS 1)(RPAQ? \FRAGMENTATIONWARNED )(RPAQ? \M44.READY )(ADDTOVAR \SYSTEMCACHEVARS \FRAGMENTATIONWARNED \M44.READY)(DECLARE: DONTCOPY (ADDTOVAR INEWCOMS (ALLOCAL (ADDVARS (LOCKEDFNS ERROR RAID \M44ACTONVMEMFILE \ACTONVMEMFILESUBR 						\ACTONVMEMPAGES \CLEANUPDISKQUEUE \CLEARCB \DISKERROR 						\DOACTONDISKPAGES \DODISKCOMMAND \EXTENDISFMAP 						\M44DOEXTENDVMEMFILE \GETDISKCB \INITBFS 						\INSUREVMEMFILE \LISPERROR \LOOKUPFMAP \REALDISKDA 						\VIRTUALDISKDA \CLEARWORDS \TESTPARTITION)				     (LOCKEDVARS \DISKREQUESTBLOCK \SWAPREQUESTBLOCK \MAINDISK 						 \ISFCHUNKSIZE \EMUSCRATCH \EMUDISKBUFFERS 						 \EMUSWAPBUFFERS \EMUDISKBUFEND \MAXSWAPBUFFERS 						 \#DISKBUFFERS \InterfacePage \ISFMAP \ISFSCRATCHCAS 						 \ISFSCRATCHDAS \SYSDISK \#SWAPBUFFERS \MAXDISKDAs 						 %%STREAMTYPE# \DISKDEBUG \SPAREDISKWRITEBUFFER 						 \#EMUBUFFERS \EMUBUFFERS \LASTVMEMFILEPAGE)))))(PUTPROPS LLBFS COPYRIGHT ("Xerox Corporation" 1982 1983 1984 1985))(DECLARE: DONTCOPY  (FILEMAP (NIL (3846 15988 (\INITBFS 3856 . 7446) (\TESTPARTITION 7448 . 7871) (\ACTONDISKPAGES 7873 . 12171) (\WRITEDISKPAGES 12173 . 14786) (\DISKERROR 14788 . 15318) (M44.SIGNAL.DISK.ERROR 15320 . 15986)) (31617 56781 (\ACTONVMEMPAGES 31627 . 32728) (\WRITEVMEMPAGES 32730 . 34095) (\DOACTONDISKPAGES 34097 . 38487) (\DOWRITEDISKPAGES 38489 . 44727) (\CHECKFREEPAGE 44729 . 45522) (\DODISKCOMMAND 45524 . 48939) (\GETDISKCB 48941 . 49960) (\CLEARCB 49962 . 50199) (\CLEANUPDISKQUEUE 50201 . 55423) (\VIRTUALDISKDA 55425 . 56054) (\REALDISKDA 56056 . 56779)) (58516 59682 (MAKEINITBFS 58526 . 59680)) (59935 72833 (\M44ACTONVMEMFILE 59945 . 61247) (\LOOKUPFMAP 61249 . 62423) (\M44EXTENDVMEMFILE 62425 . 63880) (\M44DOEXTENDVMEMFILE 63882 . 70347) (\EXTENDISFMAP 70349 . 71910) (\M44VMEMEXTENDED 71912 . 72610) (\M44VMEMFRAGMENTS 72612 . 72831)))))STOP