|
|
1 # define INCLUDE_FILE_IO
2 # include "dgd.h"
3 # include "swap.h"
4
5 typedef struct _header_ { /* swap slot header */
6 struct _header_ *prev; /* previous in swap slot list */
7 struct _header_ *next; /* next in swap slot list */
8 sector sec; /* the sector that uses this slot */
9 sector swap; /* the swap sector (if any) */
10 bool dirty; /* has the swap slot been written to? */
11 } header;
12
13 static char *swapfile; /* swap file name */
14 static int swap; /* swap file descriptor */
15 static int dump; /* dump file descriptor */
16 static int restore; /* restore file descriptor */
17 static char *mem; /* swap slots in memory */
18 static sector *map, *smap; /* sector map, swap free map */
19 static sector mfree, sfree; /* free sector lists */
20 static char *bmap; /* sector bitmap */
21 static char *cbuf; /* sector buffer */
22 static sector cached; /* sector currently cached in cbuf */
23 static header *first, *last; /* first and last swap slot */
24 static header *lfree; /* free swap slot list */
25 static long slotsize; /* sizeof(header) + size of sector */
26 static unsigned int sectorsize; /* size of sector */
27 static unsigned int restoresecsize; /* size of sector in restore file */
28 static sector swapsize, cachesize; /* # of sectors in swap and cache */
29 static sector nsectors; /* total swap sectors */
30 static sector nfree; /* # free sectors */
31 static sector ssectors; /* sectors actually in swap file */
32 static sector dsectors, dcursec; /* dump sectors */
33
34 /*
35 * NAME: swap->init()
36 * DESCRIPTION: initialize the swap device
37 */
38 void sw_init(file, total, cache, secsize)
39 char *file;
40 register unsigned int total, cache;
41 unsigned int secsize;
42 {
43 register header *h;
44 register sector i;
45
46 /* allocate and initialize all tables */
47 swapfile = file;
48 swapsize = total;
49 cachesize = cache;
50 sectorsize = secsize;
51 slotsize = sizeof(header) + secsize;
52 mem = ALLOC(char, slotsize * cache);
53 map = ALLOC(sector, total);
54 smap = ALLOC(sector, total);
55 bmap = ALLOC(char, (total + 7) >> 3);
56 cbuf = ALLOC(char, secsize);
57 cached = SW_UNUSED;
58
59 /* 0 sectors allocated */
60 nsectors = 0;
61 ssectors = 0;
62 nfree = 0;
63 dsectors = 0;
64
65 /* init free sector maps */
66 mfree = SW_UNUSED;
67 sfree = SW_UNUSED;
68 lfree = h = (header *) mem;
69 for (i = cache - 1; i > 0; --i) {
70 h->sec = SW_UNUSED;
71 h->next = (header *) ((char *) h + slotsize);
72 h = h->next;
73 }
74 h->sec = SW_UNUSED;
75 h->next = (header *) NULL;
76
77 /* no swap slots in use yet */
78 first = (header *) NULL;
79 last = (header *) NULL;
80
81 swap = dump = -1;
82 }
83
84 /*
85 * NAME: swap->finish()
86 * DESCRIPTION: clean up swapfile
87 */
88 void sw_finish()
89 {
90 if (swap >= 0) {
91 char buf[STRINGSZ];
92
93 P_close(swap);
94 P_unlink(path_native(buf, swapfile));
95 }
96 if (dump >= 0) {
97 P_close(dump);
98 }
99 }
100
101 /*
102 * NAME: create()
103 * DESCRIPTION: create the swap file
104 */
105 static void sw_create()
106 {
107 char buf[STRINGSZ], *p;
108
109 memset(cbuf, '\0', sectorsize);
110 p = path_native(buf, swapfile);
111 P_unlink(p);
112 swap = P_open(p, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0600);
113 if (swap < 0 || P_write(swap, cbuf, sectorsize) < 0) {
114 fatal("cannot create swap file \"%s\"", swapfile);
115 }
116 }
117
118 /*
119 * NAME: copy()
120 * DESCRIPTION: copy sectors from dump to swap
121 */
122 static void copy(sec, n)
123 register sector sec, n;
124 {
125 dsectors -= n;
126
127 if (swap < 0) {
128 sw_create();
129 }
130
131 while (n > 0) {
132 while (!BTST(bmap, dcursec)) {
133 dcursec++;
134 }
135 P_lseek(dump, (map[dcursec] + 1L) * sectorsize, SEEK_SET);
136 if (P_read(dump, cbuf, sectorsize) <= 0) {
137 fatal("cannot read dump file");
138 }
139 P_lseek(swap, (sec + 1L) * sectorsize, SEEK_SET);
140 if (P_write(swap, cbuf, sectorsize) < 0) {
141 fatal("cannot write swap file");
142 }
143
144 BCLR(bmap, dcursec);
145 map[dcursec++] = sec++;
146 --n;
147 }
148 }
149
150 /*
151 * NAME: swap->newv()
152 * DESCRIPTION: initialize a new vector of sectors
153 */
154 void sw_newv(vec, size)
155 register sector *vec;
156 register unsigned int size;
157 {
158 while (mfree != SW_UNUSED) {
159 /* reuse a previously deleted sector */
160 if (size == 0) {
161 return;
162 }
163 mfree = map[*vec = mfree];
164 map[*vec++] = SW_UNUSED;
165 --nfree;
166 --size;
167 }
168
169 while (size > 0) {
170 /* allocate a new sector */
171 if (nsectors == swapsize) {
172 fatal("out of sectors");
173 }
174 BCLR(bmap, nsectors);
175 map[*vec++ = nsectors++] = SW_UNUSED;
176 --size;
177 }
178 }
179
180 /*
181 * NAME: swap->wipev()
182 * DESCRIPTION: wipe a vector of sectors
183 */
184 void sw_wipev(vec, size)
185 register sector *vec;
186 register unsigned int size;
187 {
188 register sector sec, i;
189 register header *h;
190
191 while (dsectors > 0) {
192 if (size == 0) {
193 return;
194 }
195 sec = *vec++;
196 i = map[sec];
197 if (i < cachesize && (h=(header *) (mem + i * slotsize))->sec == sec) {
198 i = h->swap;
199 h->swap = SW_UNUSED;
200 } else {
201 map[sec] = SW_UNUSED;
202 }
203 if (i != SW_UNUSED) {
204 if (BTST(bmap, sec)) {
205 /*
206 * free sector in dump file
207 */
208 BCLR(bmap, sec);
209 --dsectors;
210 } else {
211 /*
212 * replace by sector from dump file
213 */
214 copy(i, (sector) 1);
215 }
216 }
217 --size;
218 }
219
220 vec += size;
221 while (size > 0) {
222 sec = *--vec;
223 i = map[sec];
224 if (i < cachesize && (h=(header *) (mem + i * slotsize))->sec == sec) {
225 i = h->swap;
226 h->swap = SW_UNUSED;
227 } else {
228 map[sec] = SW_UNUSED;
229 }
230 if (i != SW_UNUSED) {
231 /*
232 * free sector in swap file
233 */
234 smap[i] = sfree;
235 sfree = i;
236 }
237 --size;
238 }
239 }
240
241 /*
242 * NAME: swap->delv()
243 * DESCRIPTION: delete a vector of swap sectors
244 */
245 void sw_delv(vec, size)
246 register sector *vec;
247 register unsigned int size;
248 {
249 register sector sec, i;
250 register header *h;
251
252 /*
253 * note: sectors must have been wiped before being deleted!
254 */
255 vec += size;
256 while (size > 0) {
257 sec = *--vec;
258 i = map[sec];
259 if (i < cachesize && (h=(header *) (mem + i * slotsize))->sec == sec) {
260 /*
261 * remove the swap slot from the first-last list
262 */
263 if (h != first) {
264 h->prev->next = h->next;
265 } else {
266 first = h->next;
267 if (first != (header *) NULL) {
268 first->prev = (header *) NULL;
269 }
270 }
271 if (h != last) {
272 h->next->prev = h->prev;
273 } else {
274 last = h->prev;
275 if (last != (header *) NULL) {
276 last->next = (header *) NULL;
277 }
278 }
279 /*
280 * put the cache slot in the free cache slot list
281 */
282 h->sec = SW_UNUSED;
283 h->next = lfree;
284 lfree = h;
285 }
286
287 /*
288 * put sec in free sector list
289 */
290 map[sec] = mfree;
291 mfree = sec;
292 nfree++;
293
294 --size;
295 }
296 }
297
298 /*
299 * NAME: swap->load()
300 * DESCRIPTION: reserve a swap slot for sector sec. If fill == TRUE, load it
301 * from the swap file if appropriate.
302 */
303 static header *sw_load(sec, fill)
304 sector sec;
305 bool fill;
306 {
307 register header *h;
308 register sector load, save;
309
310 load = map[sec];
311 if (load >= cachesize ||
312 (h=(header *) (mem + load * slotsize))->sec != sec) {
313 /*
314 * the sector is either unused or in the swap file
315 */
316 if (lfree != (header *) NULL) {
317 /*
318 * get swap slot from the free swap slot list
319 */
320 h = lfree;
321 lfree = h->next;
322 } else {
323 /*
324 * No free slot available, use the last one in the swap slot list
325 * instead.
326 */
327 h = last;
328 last = h->prev;
329 if (last != (header *) NULL) {
330 last->next = (header *) NULL;
331 }
332 save = h->swap;
333 if (h->dirty) {
334 /*
335 * Dump the sector to swap file
336 */
337
338 if (save == SW_UNUSED) {
339 /*
340 * allocate new sector in swap file
341 */
342 if (sfree == SW_UNUSED) {
343 save = ssectors++;
344 } else {
345 save = sfree;
346 sfree = smap[save];
347 }
348 }
349
350 if (swap < 0) {
351 sw_create();
352 }
353 P_lseek(swap, (save + 1L) * sectorsize, SEEK_SET);
354 if (P_write(swap, (char *) (h + 1), sectorsize) < 0) {
355 fatal("cannot write swap file");
356 }
357 }
358 map[h->sec] = save;
359 }
360 h->sec = sec;
361 h->swap = load;
362 h->dirty = FALSE;
363 /*
364 * The slot has been reserved. Update map.
365 */
366 map[sec] = ((long) h - (long) mem) / slotsize;
367
368 if (load != SW_UNUSED) {
369 if (dsectors > 0 && BTST(bmap, sec)) {
370 if (fill) {
371 /*
372 * load the sector from the dump file
373 */
374 P_lseek(dump, (load + 1L) * sectorsize, SEEK_SET);
375 if (P_read(dump, (char *) (h + 1), sectorsize) <= 0) {
376 fatal("cannot read dump file");
377 }
378 }
379
380 BCLR(bmap, sec);
381 --dsectors;
382
383 h->swap = SW_UNUSED;
384 h->dirty = TRUE;
385 } else if (fill) {
386 /*
387 * load the sector from the swap file
388 */
389 P_lseek(swap, (load + 1L) * sectorsize, SEEK_SET);
390 if (P_read(swap, (char *) (h + 1), sectorsize) <= 0) {
391 fatal("cannot read swap file");
392 }
393 }
394 } else if (fill) {
395 /* zero-fill new sector */
396 memset(h + 1, '\0', sectorsize);
397 }
398 } else {
399 /*
400 * The sector already had a slot. Remove it from the first-last list.
401 */
402 if (h != first) {
403 h->prev->next = h->next;
404 } else {
405 first = h->next;
406 }
407 if (h != last) {
408 h->next->prev = h->prev;
409 } else {
410 last = h->prev;
411 if (last != (header *) NULL) {
412 last->next = (header *) NULL;
413 }
414 }
415 }
416 /*
417 * put the sector at the head of the first-last list
418 */
419 h->prev = (header *) NULL;
420 h->next = first;
421 if (first != (header *) NULL) {
422 first->prev = h;
423 } else {
424 last = h; /* last was NULL too */
425 }
426 first = h;
427
428 return h;
429 }
430
431 /*
432 * NAME: swap->readv()
433 * DESCRIPTION: read bytes from a vector of sectors
434 */
435 void sw_readv(m, vec, size, idx)
436 register char *m;
437 register sector *vec;
438 register Uint size, idx;
439 {
440 register unsigned int len;
441
442 vec += idx / sectorsize;
443 idx %= sectorsize;
444 do {
445 len = (size > sectorsize - idx) ? sectorsize - idx : size;
446 memcpy(m, (char *) (sw_load(*vec++, TRUE) + 1) + idx, len);
447 idx = 0;
448 m += len;
449 } while ((size -= len) > 0);
450 }
451
452 /*
453 * NAME: swap->writev()
454 * DESCRIPTION: write bytes to a vector of sectors
455 */
456 void sw_writev(m, vec, size, idx)
457 register char *m;
458 register sector *vec;
459 register Uint size, idx;
460 {
461 register header *h;
462 register unsigned int len;
463
464 vec += idx / sectorsize;
465 idx %= sectorsize;
466 do {
467 len = (size > sectorsize - idx) ? sectorsize - idx : size;
468 h = sw_load(*vec++, (len != sectorsize));
469 h->dirty = TRUE;
470 memcpy((char *) (h + 1) + idx, m, len);
471 idx = 0;
472 m += len;
473 } while ((size -= len) > 0);
474 }
475
476 /*
477 * NAME: swap->dreadv()
478 * DESCRIPTION: restore bytes from a vector of sectors in dump file
479 */
480 void sw_dreadv(m, vec, size, idx)
481 register char *m;
482 register sector *vec;
483 register Uint size, idx;
484 {
485 register unsigned int len;
486
487 vec += idx / restoresecsize;
488 idx %= restoresecsize;
489 do {
490 len = (size > restoresecsize - idx) ? restoresecsize - idx : size;
491 if (*vec != cached) {
492 P_lseek(restore, (smap[*vec] + 1L) * restoresecsize, SEEK_SET);
493 if (P_read(restore, cbuf, restoresecsize) <= 0) {
494 fatal("cannot read dump file");
495 }
496 cached = *vec;
497 }
498 vec++;
499 memcpy(m, cbuf + idx, len);
500 idx = 0;
501 m += len;
502 } while ((size -= len) > 0);
503 }
504
505 /*
506 * NAME: swap->mapsize()
507 * DESCRIPTION: count the number of sectors required for size bytes + a map
508 */
509 sector sw_mapsize(size)
510 unsigned int size;
511 {
512 register sector i, n;
513
514 /* calculate the number of sectors required */
515 n = 0;
516 for (;;) {
517 i = (size + n * sizeof(sector) + sectorsize - 1) / sectorsize;
518 if (n == i) {
519 return n;
520 }
521 n = i;
522 }
523 }
524
525 /*
526 * NAME: swap->count()
527 * DESCRIPTION: return the number of sectors presently in use
528 */
529 sector sw_count()
530 {
531 return nsectors - nfree;
532 }
533
534 /*
535 * NAME: swap->copy()
536 * DESCRIPTION: copy sectors from dumpfile to swapfile
537 */
538 bool sw_copy()
539 {
540 if (dump >= 0) {
541 if (dsectors > 0) {
542 register sector n;
543
544 n = SWAPCHUNKSZ;
545 if (n > dsectors) {
546 n = dsectors;
547 }
548 copy(ssectors, n);
549 ssectors += n;
550 }
551 if (dsectors == 0) {
552 P_close(dump);
553 dump = -1;
554 return FALSE;
555 }
556 return TRUE;
557 }
558 return FALSE;
559 }
560
561
562 typedef struct {
563 Uint secsize; /* size of swap sector */
564 sector nsectors; /* # sectors */
565 sector ssectors; /* # swap sectors */
566 sector nfree; /* # free sectors */
567 sector mfree; /* free sector list */
568 } dump_header;
569
570 static char dh_layout[] = "idddd";
571
572 /*
573 * NAME: swap->dump()
574 * DESCRIPTION: dump swap file
575 */
576 int sw_dump(dumpfile)
577 char *dumpfile;
578 {
579 register header *h;
580 register sector sec;
581 char buffer[STRINGSZ + 4], buf1[STRINGSZ], buf2[STRINGSZ], *p, *q;
582 register sector n;
583 dump_header dh;
584
585 if (dump >= 0) {
586 if (dsectors > 0) {
587 /* copy remaining dump sectors */
588 n = dsectors;
589 copy(ssectors, n);
590 ssectors += n;
591 }
592 P_close(dump);
593 }
594 p = path_native(buf1, dumpfile);
595 sprintf(buffer, "%s.old", dumpfile);
596 q = path_native(buf2, buffer);
597 P_unlink(q);
598 P_rename(p, q);
599 if (swap < 0) {
600 sw_create();
601 }
602
603 /* flush the cache and adjust sector map */
604 for (h = last; h != (header *) NULL; h = h->prev) {
605 sec = h->swap;
606 if (h->dirty) {
607 /*
608 * Dump the sector to swap file
609 */
610 if (sec == SW_UNUSED) {
611 /*
612 * allocate new sector in swap file
613 */
614 if (sfree == SW_UNUSED) {
615 sec = ssectors++;
616 } else {
617 sec = sfree;
618 sfree = smap[sec];
619 }
620 h->swap = sec;
621 }
622 P_lseek(swap, (sec + 1L) * sectorsize, SEEK_SET);
623 if (P_write(swap, (char *) (h + 1), sectorsize) < 0) {
624 fatal("cannot write swap file");
625 }
626 }
627 map[h->sec] = sec;
628 }
629
630 /* move to dumpfile */
631 P_close(swap);
632 q = path_native(buf2, swapfile);
633 if (P_rename(q, p) < 0) {
634 /*
635 * The rename failed. Attempt to copy the dumpfile instead.
636 * This will take a long, long while, so keep the swapfile and
637 * dumpfile on the same file system if at all possible.
638 */
639 swap = P_open(q, O_RDWR | O_BINARY, 0);
640 dump = P_open(p, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0600);
641 if (swap < 0 || dump < 0) {
642 fatal("cannot move swap file");
643 }
644 /* copy initial sector */
645 if (P_read(swap, cbuf, sectorsize) <= 0) {
646 fatal("cannot read swap file");
647 }
648 if (P_write(dump, cbuf, sectorsize) < 0) {
649 fatal("cannot write dump file");
650 }
651 /* copy swap sectors */
652 for (n = ssectors; n > 0; --n) {
653 if (P_read(swap, cbuf, sectorsize) <= 0) {
654 fatal("cannot read swap file");
655 }
656 if (P_write(dump, cbuf, sectorsize) < 0) {
657 fatal("cannot write dump file");
658 }
659 }
660 } else {
661 /*
662 * The rename succeeded; reopen the new dumpfile.
663 */
664 dump = P_open(p, O_RDWR | O_BINARY, 0);
665 if (dump < 0) {
666 fatal("cannot reopen dump file");
667 }
668 swap = -1;
669 }
670
671 /* write header */
672 dh.secsize = sectorsize;
673 dh.nsectors = nsectors;
674 dh.ssectors = ssectors;
675 dh.nfree = nfree;
676 dh.mfree = mfree;
677 P_lseek(dump, sectorsize - (long) sizeof(dump_header), SEEK_SET);
678 if (P_write(dump, (char *) &dh, sizeof(dump_header)) < 0) {
679 fatal("cannot write swap header to dump file");
680 }
681
682 /* write map */
683 P_lseek(dump, (ssectors + 1L) * sectorsize, SEEK_SET);
684 if (P_write(dump, (char *) map, nsectors * sizeof(sector)) < 0) {
685 fatal("cannot write sector map to dump file");
686 }
687
688
689 if (swap < 0) {
690 /*
691 * the swapfile was moved
692 */
693
694 /* create bitmap */
695 dsectors = nsectors;
696 dcursec = 0;
697 memset(bmap, -1, (dsectors + 7) >> 3);
698 for (sec = mfree; sec != SW_UNUSED; sec = map[sec]) {
699 BCLR(bmap, sec);
700 --dsectors;
701 }
702
703 /* fix the sector map and bitmap */
704 for (h = last; h != (header *) NULL; h = h->prev) {
705 map[h->sec] = ((long) h - (long) mem) / slotsize;
706 h->swap = SW_UNUSED;
707 h->dirty = TRUE;
708 BCLR(bmap, h->sec);
709 --dsectors;
710 }
711
712 ssectors = 0;
713 sfree = SW_UNUSED;
714 } else {
715 /*
716 * the swapfile was copied
717 */
718
719 /* fix the sector map */
720 for (h = last; h != (header *) NULL; h = h->prev) {
721 map[h->sec] = ((long) h - (long) mem) / slotsize;
722 h->dirty = FALSE;
723 }
724 }
725
726 return dump;
727 }
728
729 /*
730 * NAME: swap->restore()
731 * DESCRIPTION: restore dump file
732 */
733 void sw_restore(fd, secsize)
734 int fd;
735 unsigned int secsize;
736 {
737 dump_header dh;
738
739 /* restore swap header */
740 P_lseek(fd, (long) secsize - (conf_dsize(dh_layout) & 0xff), SEEK_SET);
741 conf_dread(fd, (char *) &dh, dh_layout, (Uint) 1);
742 if (dh.secsize != secsize || dh.nsectors > swapsize) {
743 error("Wrong sector size or too many sectors in restore file");
744 }
745 restoresecsize = secsize;
746
747 /* seek beyond swap sectors */
748 P_lseek(fd, (dh.ssectors + 1L) * secsize, SEEK_SET);
749
750 /* restore swap map */
751 conf_dread(fd, (char *) smap, "d", (Uint) dh.nsectors);
752
753 restore = fd;
754 }
755
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.