aboutsummaryrefslogtreecommitdiff
path: root/sys/fmio/fmsync.x
blob: 7c7d81124fa8d0ec0fb5a12180d228a15b5a298c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include	<syserr.h>
include	<mach.h>
include	<knet.h>
include	"fmio.h"

define	SZB_SHORT	(SZB_CHAR*SZ_SHORT)

# FM_SYNC -- Update any buffered portions of the datafile on disk which have
# been modified since the last update.

procedure fm_sync (fm)

pointer	fm			#I FMIO descriptor

pointer	sp, ip, op, dhbuf, pgbuf, pti, dh, ft, pt
int	maxpages, nbytes, npti, p1, p2, d1, d2, dp, i
int	szbpage, chan, buflen, status, npte_perpage
int	fmio_extend()
long	clktime()

begin
	if (FM_MODE(fm) == READ_ONLY)
	    return

	call smark (sp)
	chan = FM_CHAN(fm)
	szbpage = FM_SZBPAGE(fm)
	npte_perpage = szbpage / SZB_SHORT

	call intr_disable()

	# Get more page table space (pages).  During a normal file extend
	# occurring while writing to a file, PTEs for *data* pages are added
	# to the incore global page table and to the PT for the lfile.
	# The additional pages needed to store the PT and PTI as they grow
	# are however not allocated during i/o.  We wait and do this at sync
	# time to provide maximal separation of the data pages and PT pages,
	# rendering both as contiguous as possible.

	# Check for page table index overflow (datafile too large).
	npti = (FM_PTNPTE(fm) + npte_perpage-1) / npte_perpage
	if (npti > FM_PTILEN(fm)) {
	    call fmio_posterr (fm, SYS_FMPTIOVFL, FM_DFNAME(fm))

	    # Truncate the page table to try to recover the datafile with
	    # some loss of data.

	    npti = FM_PTILEN(fm)
	    FM_PTNPTE(fm) = npti * npte_perpage - (npti - FM_PTINPTI(fm))
	}

	# Allocate the page table pages.
	for (p1=FM_PTINPTI(fm)+1;  p1 <= npti;  p1=p1+1) {
	    dp = fmio_extend (fm, PT_LFILE, 1)
	    if (dp != ERR) {
		Memi[FM_PTINDEX(fm)+p1-1] = dp
		FM_PTINPTI(fm) = p1
		FM_DHMODIFIED(fm) = YES
	    } else
		call fmio_posterr (fm, SYS_FMPTIOVFL, FM_DFNAME(fm))
	}

	# Update the datafile header area.
	if (FM_DHMODIFIED(fm) != NO) {
	    # Allocate a buffer to hold the encoded datafile header area.
	    buflen = (FM_DATASTART(fm) - 1) / (SZ_STRUCT * SZB_CHAR)
	    call salloc (dhbuf, buflen, TY_STRUCT)

	    # Encode and output the datafile header.
	    call salloc (dh, LEN_DHSTRUCT, TY_STRUCT)

	    DH_MAGIC(dh)	 = FMIO_MAGIC
	    DH_DFVERSION(dh)	 = FM_DFVERSION(fm)
	    DH_SZBPAGE(dh)	 = szbpage
	    DH_NLFILES(dh)	 = FM_NLFILES(fm)
	    DH_FTOFF(dh)	 = FM_FTOFF(fm)
	    DH_FTLASTNF(dh)	 = FM_FTLASTNF(fm)
	    DH_PTIOFF(dh)	 = FM_PTIOFF(fm)
	    DH_PTILEN(dh)	 = FM_PTILEN(fm)
	    DH_PTINPTI(dh)	 = FM_PTINPTI(fm)
	    DH_PTLEN(dh)	 = FM_PTLEN(fm)
	    DH_PTNPTE(dh)	 = FM_PTNPTE(fm)
	    DH_DATASTART(dh)	 = FM_DATASTART(fm)

	    call miipak32 (Memi[dh], Memi[dhbuf], LEN_DHSTRUCT, TY_STRUCT)

	    # Output the file table.
	    ft = FM_FTABLE(fm)
	    op = dhbuf + FM_FTOFF(fm) - 1
	    do i = 0, FM_NLFILES(fm) {
		ip = ft + i * LEN_FTE
		FT_FSIZE(op) = LF_FSIZE(ip)
		FT_FLAGS(op) = and (LFF_SAVE, LF_FLAGS(ip))
		op = op + LEN_FTEX
	    }

	    op = dhbuf + FM_FTOFF(fm) - 1
	    call miipak32 (Memi[op], Memi[op],
		(FM_NLFILES(fm) + 1) * LEN_FTEX, TY_INT)

	    # Output the page table index.
	    call miipak32 (Memi[FM_PTINDEX(fm)], Memi[dhbuf+FM_PTIOFF(fm)-1],
		FM_PTILEN(fm), TY_INT)

	    # Update the whole thing on disk.
	    call zawrbf (chan, Memi[dhbuf], FM_DATASTART(fm)-1, 1)
	    call zawtbf (chan, status)
	    if (status == ERR)
		call fmio_posterr (fm, SYS_FMWRERR, FM_DFNAME(fm))

	    FM_DHMODIFIED(fm) = NO
	}

	# Don't cache these pointers before calling fmio_extend!
	pt  = FM_PTABLE(fm)
	pti = FM_PTINDEX(fm)

	# Update the page table itself, stored in the data pages.
	if (FM_PTNPTE(fm) > FM_PTLUPTE(fm)) {

	    # Determine the max transfer size.
	    maxpages = FM_MAXBUFSIZE(fm) / szbpage
	    if (maxpages <= 0)
		maxpages = DEF_BIGBUFNP
	    
	    # Get an output temporary buffer if we have to swap on output.
	    if (BYTE_SWAP2 == YES)
		call salloc (pgbuf, maxpages * szbpage / SZB_SHORT, TY_SHORT)

	    # Determine the PT page containing the LUPTE+1.
	    p1 = FM_PTLUPTE(fm) / npte_perpage + 1

	    # Update that and all following PT pages.
	    npti = FM_PTINPTI(fm)
	    for (;  p1 <= npti;  p1=p2) {
		# Get a contiguous range of page table pages.
		d1 = Memi[pti+p1-1]
		for (p2=p1+1;  p2 <= npti;  p2=p2+1) {
		    d2 = Memi[pti+p2-1]
		    if (d2-d1 != p2-p1 || p2-p1 >= maxpages)
			break
		}

		# Swap the data and set IP for the output transfer.
		ip = pt + (p1 - 1) * npte_perpage
		nbytes = (min(npti+1,p2) - p1) * szbpage
		if (BYTE_SWAP2 == YES) {
		    call bswap2 (Mems[ip], 1, Mems[pgbuf], 1, nbytes)
		    ip = pgbuf
		}

		# Update the pages.
		call zawrbf (chan, Mems[ip], nbytes,
		    (d1-1) * szbpage + FM_DATASTART(fm))
		call zawtbf (chan, status)
		if (status < nbytes)
		    call fmio_posterr (fm, SYS_FMWRERR, FM_DFNAME(fm))
	    }

	    FM_PTLUPTE(fm) = FM_PTNPTE(fm)
	}

	FM_LSYNCTIME(fm) = clktime(0)
	call intr_enable()

	call sfree (sp)
end