!******************************
!* FILE SYSTEM HANDLER *
!* FSYS1S/FSYS1Y *
!* DATE: 24.FEB.81 *
!******************************
!*W.S.C. 25TH AUGUST 1976
!*B.G. 27.MAR.78
!*THIS HANDLER IS THE FILE SYSTEM UTILITY TO REPLACE THE
!*EXISTING ONE IN DEIMOS TO PERMIT A FILE SYSTEM TO BE
!*CREATED ON THE AMPEX 9500 DISC AS WELL AS THE RK05'S.
!*IT IS A CONCEPTUAL COPY OF THE RK05 FILE SYSTEM HANDLER
!*EXCEPT THAT A BUFFER POOL IS USED FOR BLOCK DESCRIPTORS
!*AND DIRECTORY BLOCKS.
!*THE CODE IS SHARED BY 3 SYSTEM SLOTS,4 FOR THE RK05'S,
!*AND 9,15 FOR THE AMPEX DISC.THE AMPEX DISC IS LOGICALLY
!*DIVIDED INTO TWO,UNITS 2&3.
!* A FURTHER DISC IS CATERED FOR IN SLOT 28
!*THE CLOCK IS USED TO WRITE BLOCKS BACK EVERY 10SECS
!*(BLOCK DESCRIPTOR BLOCKS).DIRECTORY BLOCKS ARE ALWAYS
!*WRITTEN BACK AS SOON AS POSSIBLE AFTER A CHANGE.
!*TUNEABLE PARAMETERS
!* NBUF=NUMBER OF BUFFERS IN POOL-1(MUST BE>0)
!* SECS::LENGTH OF TIME BETWEEN INSPECTING BUFFER
!* POOL FOR WRITING BACK TO DISC.
!*THE FOLLOWING FACILITIES ARE OFFERED
!* EXAMINE A FILE
!* GET NEXT BLOCK OF A FILE
!* DESTROY A FILE
!* CREATE A FILE
!* APPEND A BLOCK TO A FILE
!* RENAME A FILE
!* RENAME A TEMPORARY FILE
!*STACK=300 STREAMS=0
!**********************************************************
!**********************************************************
CONTROL K'101011'; !SYSTEM+FAST ROUTINE ENTRY
SYSTEMROUTINESPEC LINKIN(INTEGER SER)
SYSTEMROUTINESPEC ALARM(INTEGER TICKS)
SYSTEMINTEGERFNSPEC GETID
PERMROUTINESPEC SVC(INTEGER EP, R0, R1)
PERMINTEGERMAPSPEC INTEGER(INTEGER N)
PERMBYTEINTEGERMAPSPEC BYTEINTEGER(INTEGER N)
PERMINTEGERFNSPEC ADDR(BYTEINTEGERNAME N)
PERMINTEGERFNSPEC ACC
RECORDFORMAT DD(INTEGER X)
PERMRECORD (DD) MAPSPEC RECORD(INTEGER X)
CONSTRECORD (DD) NAME NULL = 0
BEGIN
!*********************************************************
!************* DATA AREAS &DECLARATIONS **********
!*********************************************************
!*SYSTEM SLOTS/DISC
CONSTINTEGER MAX DRIVES = 4
CONSTBYTEINTEGERARRAY SERV(0:MAX DRIVES) = 3, 3, 8, 14, 28
!*DIRECTORY BLOCK AREAS/DISC
CONSTINTEGERARRAY DIRBLK(0:MAX DRIVES) = K'220',0, K'1100'(2) C
, K'220'
!*BLOCK DESCRIPTOR BASE/DISC
CONSTBYTEINTEGERARRAY BLKLST(0:MAX DRIVES) = K'100',0, K'100' C
(2), K'100'
!*FREE BLOCK START/DISC
CONSTINTEGERARRAY FBLOCK(0:MAX DRIVES) = K'400',0, K'1500'(2) C
, K'400'
OWNINTEGERARRAY FIRST FREE(0:MAX DRIVES) = K'400',0, K'1500' C
(2), K'400'
! INITIALLY IS IDENTICAL TO
! FBLOCK
!*TOP OF DISC
CONSTINTEGERARRAY LASTBL(0:MAX DRIVES) = 9200,0, K'175000'(2) C
, 9200
!*REQUEST TYPES
CONSTINTEGER EXAMINE = 0
CONSTINTEGER GET NEXT = 1
CONSTINTEGER DESTROY = 2
CONSTINTEGER CREATE = 3
CONSTINTEGER APPEND = 4
CONSTINTEGER RENAME = 5
CONSTINTEGER RENAME TEMP = 6
CONSTINTEGER RENAME FSYS = 7
CONSTINTEGER DIR BLK NO = 8
!*SYSTEM CONSTANTS
CONSTINTEGER DREAD = 0, DWRITE = 1
!MODES
CONSTINTEGER CLOCK INT = 0
CONSTINTEGER MY SEG = 4, MSA = K'100000'
!*SYSTEM SLOTS
CONSTINTEGER RKSER = 4
CONSTINTEGER AMP1SER = 9
CONSTINTEGER AMP2SER = 15
CONSTINTEGER RKBSER = 29
SWITCH REQUEST(0:DIR BLK NO)
INTEGER ID, SEG, I, BK, NO, NOSAVE, PR, EXIT, SEG2
OWNINTEGER DRIVE, FNO
!*MESSAGE FORMATS
RECORDFORMAT PF(BYTEINTEGER SERVICE, REPLY, INTEGER A1, A2, A3)
RECORDFORMAT P2F(BYTEINTEGER SERVICE, REPLY, INTEGER A1, C
INTEGERNAME A2, INTEGER A3)
RECORD (PF)P, PX
!*DISC BUFFER POOL
CONSTINTEGER SECS = 5; !BUFFER WRITE BACK TIME
CONSTINTEGER NBUF = 1; !NUMBER OF BUFFERS-1(MUST BE>0)
RECORDFORMAT XF(INTEGER X)
RECORDFORMAT BF(INTEGER DRIVE, BLOCK, WRM, RECORD (XF) C
ARRAY BLK(0:255))
!*WRM IS A WRITE MARKER TO SAY THAT BLOCK HAS BEEN
!*ALTERED AND MUST BE WRITTEN BACK TO DISC.
OWNRECORD (BF) ARRAY B(0:NBUF)
OWNINTEGER BLAST = 0; !LAST BUFFER USED IN POOL
OWNRECORD (BF) NAME BX; !POINTS TO CURRENT BUFFER RECORD
!*FORMATS FOR BLOCK DESCRIPTORS AND DIRECTORY BLOCKS
RECORDFORMAT BLKF(INTEGER PR, NEXT)
!BLOCK DESCRIPTOR
RECORDFORMAT N1F(BYTEINTEGERARRAY NAME(0:5))
RECORDFORMAT N2F(INTEGER A, B, C)
! TWO FORMS OF THE FILE NAME
RECORDFORMAT INFF(BYTEINTEGER UNIT, FSYS, RECORD (N1F)N)
! FILE DESCRIPTOR
RECORDFORMAT INF2F(BYTEINTEGER UNIT, FSYS, RECORD (N2F)N)
RECORDFORMAT FILEF(RECORD (N1F)N, INTEGER FIRST, PR)
!DIRECTORY ENTRY
RECORDFORMAT FILE2F(RECORD (N2F)N, INTEGER FIRST, PR)
OWNRECORD (BLKF) ARRAYNAME BLKA
RECORD (FILEF) ARRAYNAME FA
OWNRECORD (FILEF) NAME F
RECORD (BLKF) NAME BLK
RECORD (BLKF)SAVE BLK
RECORD (INFF) NAME INF, INF2
RECORD (INFF)G
!***********************************************
!* E V E N T S
!! %ON %EVENT 15 %START; ! DISC I/O FAIL
!! %IF PX_SERVICE = 0 %THEN -> RESTART; ! IN TIMER SECTION
!! -> REPLY
!! %FINISH
!**********************************************
!****************************************************************
!******************************************************************
!*ROUTINE DA
!*CALLS DISC HANDLER TO READ IN A BLOCK
!* NB: THIS ROUTINE ASSUMES THAT BX POINTS TO THE BLOCK DESCRIPTOR
ROUTINE DA(INTEGER MODE)
RECORD (P2F)P
INTEGER DRIVE
DRIVE = BX_DRIVE
P_A3 = BX_BLOCK; ! COMPILER ERROR FORCES THIS
P_SERVICE = SERV(DRIVE)
P_REPLY = ID
IF DRIVE = 1 THEN P_A3 = P_A3!K'020000'
P_A1 = MODE
IF MODE # D READ THEN BX_WRM = 0
! CLEAR THE WRITE MARKER
P_A2 == BX_BLK(0)
PONOFF(P)
IF P_A1 # 0 THENSIGNAL 15, 15
END
!*******************************************************
!*RECORD MAP LOAD
!*LOADS REQUESTED BLOCK INTO CORE IF IT IS NOT ALREADY THERE
!*AND RETURNS A POINTER TO THE START OF THE RECORD BX
!*WHICH IS SET UP TO CURRENT ENTRY IN THE BUFFER POOL
!*DRIVE IS ASSUMED TO BE SET UP. ********
!* THE ROUTINE ALSO SETS UP GLOBAL BX AS A SIDE EFFECT
RECORD (BF) MAP LOAD(INTEGER BLOCK)
INTEGER I, TEMP
!*CHECK IF BLOCK ALREADY IN POOL
CYCLE I = NBUF, -1, 0
BX == B(I)
IF BX_DRIVE = DRIVE AND BX_BLOCK = BLOCK START
RESULT == BX
FINISH
REPEAT
!*BLOCK NOT IN POOL
BX == B(BLAST)
BLAST = BLAST+1
IF BLAST > NBUF THEN BLAST = 0
IF BX_WRM # 0 START ; !WRITE BACK OLD BLOCK
DA(DWRITE)
FINISH
BX_DRIVE = DRIVE
BX_BLOCK = BLOCK
DA(DREAD); !READ IN NEW BLOCK
RESULT == BX
END
!************************************************************
!*RECORD MAP EXAM
!*TO READ IN CORRECT DIRECTORY BLOCK
!*AND FIND REQUIRED ENTRY
RECORD (FILEF) MAP EXAM(RECORD (INFF) NAME INF)
INTEGER N, J, K, HIT, T
RECORD (N2F) NAME FILE
RECORD (N2F) NAME INFO
RECORD (FILE2F) NAME F
!*SET UP DRIVE NUMBER,0,1 RK05
!2,3 AMPEX
DRIVE = INF_UNIT
INFO == INF_N; ! POINT TO NAME PART
!*SET UP DIRECTORY BLOCK FOR SCAN
T = DIRBLK(DRIVE)
N = T+INF_FSYS; ! MAP TO USERS DIRECTORY
UNTIL N > T+2 CYCLE ; ! SYSTEM OCCUPIES 3 BLOCKS
FA == LOAD(N)_BLK
!*LOOK FOR MATCH
CYCLE J = 0, 1, 50
FNO = J; ! GLOBAL FOR CREATE
F == FA(J); ! POINT TO TARGET ENTRY
FILE == F_N; ! MOST CONVENIENT FORMATR
IF FILE_A = INFO_A AND FILE_B = INFO_B AND FILE_C = C
INFO_C THENRESULT == F
REPEAT
N = N+1
REPEAT
RESULT == NULL
END
!******************************************************************
!*RECORD MAP GET BLOCK
!*RETURNS POINTER TO CORRECT BLOCK DESCRIPTOR
!*AFTER CALLING LOAD TO READ IT INTO CORE
RECORD (BLKF) MAP GET BLOCK(INTEGER BLOCK NO)
INTEGER POS, PT
POS = BLOCK NO >> 7+BLKLST(DRIVE)
!BLOCK DESC BLOCK
BLKA == LOAD(POS)_BLK
RESULT == BLKA(BLOCK NO&K'177')
! OFFSET INTO BLOCK
END
!**********************************************************
!*INTEGER FUNCTION APPENDB
!*RETURNS NEXT FREE BLOCK NUMBER
INTEGERFN APPENDB(INTEGER LAST)
INTEGER WRAP
WRAP = 0
CYCLE
LAST = LAST+1
IF LAST = LASTBL(DRIVE) START
IF WRAP = 0 THENRESULT = 0
WRAP = WRAP+1
LAST = FBLOCK(DRIVE)
FINISH
BLK == GET BLOCK(LAST)
IF BLK_PR = 0 THENRESULT = LAST
REPEAT
END
ROUTINE REWRITE DIR
INTEGER I
CYCLE I = NBUF, -1, 0
IF B(I)_WRM # 0 START
BX == B(I)
DA(DWRITE)
FINISH
REPEAT
END
!*****************************************************************
!*************************************************************
!*************************************************************
!*MAIN CONTROL LOOP
!*LINK TO SYSTEM SLOTS
LINKIN(RKSER); LINKIN(AMP1SER); LINKIN(AMP2SER); LINKIN(RKBSER)
ID = GETID
ALARM(SECS*50); !SET CLOCK FOR SECS SECONDS
RESTART:
CYCLE
P_SERVICE = 0
POFF(P)
!*IF CLOCK TICK CHECK IF BUFFER POOL NEEDS WRITING
IF P_REPLY = CLOCK INT START
ALARM(SECS*50)
PX_SERVICE = 0; ! FOR EVENT 15 HANDLING
REWRITE DIR
CONTINUE
FINISH
!*NOT A CLOCK TICK--REQUEST FOR SERVICE
PX_SERVICE = P_REPLY
PX_REPLY = P_SERVICE
PX_A2 = P_A2
!*GET CALLERS BLOCK
NO = 0
SEG = P_A2 >> 13
IF SEG = 0 THENSIGNAL 36, 36
MAP VIRT(P_REPLY, SEG, MY SEG)
INF == RECORD(MSA+(P_A2&K'17777')); INF2 == INF
-> REQUEST(P_A1)
!*
!**
!***** EXAMINE FILE
!**
!*
REQUEST(EXAMINE):
!*P_A2 HAS ADDRESS OF DESCRIPTOR
!*EXAMINE FINDS THE FILE ENTRY IN THE DIRECTORY BLOCK
!*AND RETURNS THE FIRST BLOCK'S NUMBER IN THE FILE
!*TO THE CALLER.
NO = 0
F == EXAM(INF)
UNLESS F == NULL THEN NO = F_FIRST
IF DRIVE = 1 AND NO # 0 THEN NO = NO!K'020000'
-> REPLY
WRITE DIR: DA(DWRITE); !PUT DIRECTORY BLOCK BACK
REWRITE DIR; ! PUT LIST BLOCKS BACK
REPLY: MAP VIRT(0, -1, MYSEG); !RELEASE SEGMENT
PX_A1 = NO
PON(PX)
CONTINUE
!*
!**
!***** GET NEXT
!**
!*
REQUEST(GET NEXT):
!*P_A2=FILE DESCRIPTOR,P_A3=LAST BLOCK
!*GET NEXT IS GIVEN A BLOCK OF A FILE AND RETURNS
!*THE NEXT BLOCK IN THE FILE BY LOOKING AT THE LINK IN
!*THE BLOCK DESCRIPTOR.IT ALSO READS THE BLOCK DECRIPTOR
!*ENTRY FOR THE NEXT BLOCK TO CHECK THE PROTECT CODE.
DRIVE = INF_UNIT
BK = P_A3
IF DRIVE = 1 THEN BK = BK&K'17777'
BLK == GET BLOCK(BK); !GET PREVIOUS BLOCK
PR = BLK_PR; NO = BLK_NEXT
IF NO # 0 START
BLK == GET BLOCK(NO)
IF BLK_PR # PR THEN NO =- 1 ELSESTART
!! NO = -1 IS A PROTECT CODE ERROR
IF DRIVE = 1 THEN NO = NO!K'020000'
FINISH
FINISH
-> REPLY
!*
!**
!***** DESTROY
!**
!*
REQUEST(DESTROY):
!*DESTROY REMOVES THE FILE'S NAME FROM THE DIRECTORY
!*BLOCK AND GOES DOWN THE BLOCK DESCRIPTOR ENTRIES FOR
!*THAT FILE SETTING ALL THE LINKS AND PROTECT CODES TO
!*ZERO(CHECKING THE PROTECT CODES AS IT GOES.)
EXIT = 0; !TAKE NORMAL EXIT
DESTF:
NO = 1; ! FILE DOES NOT EXIST
F == EXAM(INF)
UNLESS F == NULL START
NO = 0
BK = F_FIRST; PR = F_PR
F = 0; ! DELETE NAME ETC
F_PR = PR; ! RESTORE "PR"
DA(DWRITE); !WRITE BLOCK BACK IMMEDIATELY
UNTIL BK = 0 CYCLE
!DELETE ALL LINKS AND PR
BLK == GET BLOCK(BK)
IF BLK_PR # PR START
NO =- 1; !CORRUPT FILE!!!
EXIT
FINISH
IF FBLOCK(DRIVE) <= BK < FIRST FREE(DRIVE) THEN C
FIRST FREE(DRIVE) = BK
BK = BLK_NEXT
BLK = 0; ! ZERO PR AND NEXT
BX_WRM = BX_WRM+1
REPEAT
FINISH
-> WRITE DIR IF EXIT = 0
-> REN TMP; !BACK TO RENAME TEMP
!*
!**
!***** CREATE FILE
!**
!*
REQUEST(CREATE):
!*A FILE IS CREATED BY FINDING AN EMPTY SLOT IN THE DIRECTORY
!*BLOCK AND COPYING THE NAME INTO IT.A FREE BLOCK IS THEN FOUND
!*AND IS DEEMED TO BE THE FIRST BLOCK OF THE FILE.A LINK TO
!*THIS BLOCK IS SET UP AND THE PROTECT CODE CALCULATED AND
!*INSERTED INTO THE BLOCK DESCRIPTOR.
DRIVE = INF_UNIT
NOSAVE = 0
NOSAVE = APPENDB(FIRST FREE(DRIVE))
IF NOSAVE # 0 START
G_FSYS = INF_FSYS
G_UNIT = INF_UNIT
F == EXAM(G); !FIND EMPTY SLOT
UNLESS F == NULL START
NO = NOSAVE
F_N = INF_N; ! COPY NAME
BX_WRM = BX_WRM+1
F_PR = ((F_PR+K'010000')&K'170000')!INF_FSYS << 6!FNO
F_PR = K'010000' IF F_PR = 0
! IN CASE OF ZERO PR
F_FIRST = NO
PR = F_PR
DA(D WRITE); !PUT DIRECTORY BLOCK BACK
BLK == GET BLOCK(NO); !GET BLOCK DESCRIPTOR BACK
BLK_PR = PR
BX_WRM = BX_WRM+1
FIRST FREE(DRIVE) = NO
IF DRIVE = 1 THEN NO = NO!K'020000'
FINISH
FINISH
-> REPLY
!*
!**
!***** APPEND BLOCK
!**
!*
REQUEST(APPEND):
!*TO APPEND A BLOCK TO A FILE THE CURRENT LAST BLOCK
!*DESCRIPTOR ENTRY IS INSPECTED FOR THE PROTECT CODE.
!*THE NEXT FREE BLOCK'S DESCRIPTOR IS THEN
!*UPDATED WITH THIS CODE AND A LINK TO THIS BLOCK
!*IS INSERTED IN THE LAST DESCRIPTOR ENTRY.
DRIVE = INF_UNIT
BK = P_A3; !GET LAST BLOCK
IF DRIVE = 1 THEN BK = BK&K'17777'
BLK == GET BLOCK(BK); !GET LAST BLOCK
PR = BLK_PR
NO = APPENDB(BK); !GET NEW LAST BLOCK
IF NO # 0 START
BLK_NEXT = 0
BLK_PR = PR
BX_WRM = BX_WRM+1
FIRST FREE(DRIVE) = NO
BLK == GET BLOCK(BK); !GET PREVIUOS LAST BLOCK TO
! INSERT LINK
BLK_NEXT = NO
IF DRIVE = 1 THEN NO = NO!K'020000'
BX_WRM = BX_WRM+1
FINISH
-> REPLY
!*
!**
!***** RENAME FILE
!**
!*
REQUEST(RENAME):
REQUEST(RENAME FSYS): ! FILES IN DIFFERENT FSYS
!*P_A2HAS EXISTING,P_A3 HAS NEW FILE DESCRIPTOR
!*IF THE NEW FILE DOES NOT ALREADY EXIST THEN THE OLD
!*FILE NAME IN THE DIRECTORY BLOCK IS REPLACED BY
!*THE NEW.
NO =- 1
SEG2 = P_A3 >> 13
IF SEG2 = SEG START
INF2 == RECORD(MSA+(P_A3&K'17777'))
IF INF_UNIT = INF2_UNIT START
IF P_A1 = RENAME FSYS START
G_FSYS = INF2_FSYS
G_UNIT = INF2_UNIT
F == EXAM(G)
UNLESS F == NULL START
F == EXAM(INF); ! GET EXISTING FILE
UNLESS F == NULL START ; ! DOESN'T EXIST
BK = F_FIRST; PR = F_PR
F = 0; ! ZERO NAME RECORD
BX_WRM = BX_WRM+1
DA(D WRITE)
F == EXAM(G); ! GET EMPTY SLOT AGAIN
F_N = INF2_N; ! COPY NAME
F_FIRST = BK; F_PR = PR
!! BX_WRM = BX_WRM+1 (WRITE DIR WRITES BACK)
NO = 0
FINISH
FINISH
ELSE
F == EXAM(INF2); !CHECK NEW FILE DOES NOT EXIST
IF F == NULL START
F == EXAM(INF)
IF F == NULL THEN NO = 1 ELSESTART
F_N = INF2_N; ! COPY NAME
!! BX_WRM = BX_WRM+1 (WRITE DIR WRITES BACK)
NO = 0
FINISH
FINISH
FINISH
FINISH
FINISH
-> WRITE DIR
!*
!**
!***** RENAME TEMPORARY FILE
!**
!*
REQUEST(RENAME TEMP):
!*THIS RENAMES A TEMPORARY FILE IN THE SENSE THAT IT REMOVES
!*THE TEMP FILE MARKER AND DESTROYS THE FILE.
EXIT = 1; !SPECIAL EXIT FORM DIRECTORY
INF_N_NAME(0) = INF_N_NAME(0)&X'FF7F'
!REMOVE TEMP MARKER
-> DESTF
REN TMP:
INF_N_NAME(0) = INF_N_NAME(0)!X'0080'
!PUT BACK MARKER
F == EXAM(INF)
IF F == NULL THEN NO =- 1 ELSESTART
F_N_NAME(0) = F_N_NAME(0)&X'FF7F'
!NOT TEMP NOW
!! BX_WRM = BX_WRM+1 (WRITE DIR WRITES BACK)
NO = 0
FINISH
-> WRITE DIR
REQUEST(DIR BLK NO): ! GIVE BLOCK NO OF DIRECTORY
NO = DIRBLK(INF_UNIT)+INF_FSYS
-> REPLY
REPEAT
ENDOFPROGRAM
!NOT TEMP NOW
REQUEST(DIR BLK NO): ! GIVE BLOCK NO OF DIRECTORY