openafs-string-header-cleanup-20071030
[openafs.git] / src / tviced / serialize_state.c
1 /*
2  * Copyright 2006, Sine Nomine Associates and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * demand attach fs
12  * fileserver state serialization
13  */
14
15 #include <afsconfig.h>
16 #include <afs/param.h>
17
18 RCSID
19     ("$Header$");
20
21 #include <stdio.h>
22 #include <stdlib.h>             /* for malloc() */
23 #include <time.h>               /* ANSI standard location for time stuff */
24 #include <string.h>
25 #ifdef AFS_NT40_ENV
26 #include <fcntl.h>
27 #include <io.h>
28 #else
29 #include <sys/time.h>
30 #include <sys/file.h>
31 #endif
32 #include <afs/assert.h>
33 #include <sys/stat.h>
34
35 #include <afs/stds.h>
36
37 #include <rx/xdr.h>
38 #include <lwp.h>
39 #include <lock.h>
40 #include <afs/afsint.h>
41 #include <afs/rxgen_consts.h>
42 #include <afs/nfs.h>
43 #include <afs/errors.h>
44 #include <afs/ihandle.h>
45 #include <afs/vnode.h>
46 #include <afs/volume.h>
47 #include <afs/acl.h>
48 #include <afs/ptclient.h>
49 #include <afs/prs_fs.h>
50 #include <afs/afsutil.h>
51 #include <rx/rx.h>
52 #include <afs/cellconfig.h>
53 #include <stdlib.h>
54
55 #include "../viced/viced_prototypes.h"
56 #include "../viced/viced.h"
57 #include "../viced/host.h"
58 #include "../viced/callback.h"
59 #include "serialize_state.h"
60
61 /*@+fcnmacros +macrofcndecl@*/
62 #ifdef O_LARGEFILE
63 #ifdef S_SPLINT_S
64 extern off64_t afs_lseek(int FD, off64_t O, int F);
65 #endif /*S_SPLINT_S */
66 #define afs_lseek(FD, O, F)     lseek64(FD, (off64_t)(O), F)
67 #define afs_stat                stat64
68 #define afs_fstat               fstat64
69 #define afs_open                open64
70 #define afs_fopen               fopen64
71 #define afs_ftruncate           ftruncate64
72 #define afs_mmap                mmap64
73 #ifdef AFS_AIX_ENV
74 extern void * mmap64();  /* ugly hack since aix build env appears to be somewhat broken */
75 #endif
76 #else /* !O_LARGEFILE */
77 #ifdef S_SPLINT_S
78 extern off_t afs_lseek(int FD, off_t O, int F);
79 #endif /*S_SPLINT_S */
80 #define afs_lseek(FD, O, F)     lseek(FD, (off_t)(O), F)
81 #define afs_stat                stat
82 #define afs_fstat               fstat
83 #define afs_open                open
84 #define afs_fopen               fopen
85 #define afs_ftruncate           ftruncate
86 #define afs_mmap                mmap
87 #endif /* !O_LARGEFILE */
88 /*@=fcnmacros =macrofcndecl@*/
89
90
91 #ifdef AFS_DEMAND_ATTACH_FS
92
93 /*
94  * demand attach fs
95  * state dump routines
96  *
97  * in order to make state dump/restore as fast as possible,
98  * we use memory mapped files
99  *
100  * if this causes problems on certain platforms, the APIs
101  * have been written so that it will be very simple to go
102  * back to standard I/O for just those poorly written platforms
103  */
104 #ifndef _WIN32
105 #define FS_STATE_USE_MMAP
106 #endif
107
108 #ifdef FS_STATE_USE_MMAP
109 #define FS_STATE_INIT_FILESIZE (8 * 1024 * 1024)  /* truncate to 8MB initially */
110 #include <sys/mman.h>
111 #endif
112
113 static int fs_stateCreateDump(struct fs_dump_state * state);
114 static int fs_stateLoadDump(struct fs_dump_state * state);
115 static int fs_stateInvalidateDump(struct fs_dump_state * state);
116 static int fs_stateCommitDump(struct fs_dump_state * state);
117 static int fs_stateCloseDump(struct fs_dump_state * state);
118
119 #ifdef FS_STATE_USE_MMAP
120 static int fs_stateSizeFile(struct fs_dump_state * state);
121 static int fs_stateResizeFile(struct fs_dump_state * state, size_t min_add);
122 static int fs_stateTruncateFile(struct fs_dump_state * state);
123
124 static int fs_stateMapFile(struct fs_dump_state * state);
125 static int fs_stateUnmapFile(struct fs_dump_state * state);
126
127 static int fs_stateIncCursor(struct fs_dump_state * state, size_t len);
128 static int fs_stateCheckIOSafety(struct fs_dump_state * state,
129                                  size_t len);
130 #endif
131
132 static int fs_stateFillHeader(struct fs_state_header * hdr);
133 static int fs_stateCheckHeader(struct fs_state_header * hdr);
134
135 static int fs_stateAlloc(struct fs_dump_state * state);
136 static int fs_stateFree(struct fs_dump_state * state);
137
138 extern afsUUID FS_HostUUID;
139 extern char cml_version_number[];
140
141 /*
142  * demand attach fs
143  * save all fileserver state 
144  */
145 int
146 fs_stateSave(void)
147 {
148     int ret = 0, verified = 1;
149     struct fs_dump_state state;
150
151     /* save and restore need to be atomic wrt other host package operations */
152     H_LOCK; 
153
154     ViceLog(0, ("fs_stateSave: commencing fileserver state dump\n"));
155
156     if (fs_stateAlloc(&state)) {
157         ViceLog(0, ("fs_stateSave: memory allocation failed; dump aborted\n"));
158         ret = 1;
159         goto done;
160     }
161
162     /* XXX
163      * on busy servers, these checks will inevitably fail since stuff drops H_LOCK
164      * all over the place (with structs left in inconsistent states) while RPCs to
165      * clients happen (grumble, grumble, the host package needs to be rewritten...)
166      *
167      * the current hack is to force the background threads that deal with host and
168      * callback state offline early in the shutdown process, do VShutdown, come
169      * back and wait for those threads to die, THEN do the state dump
170      *
171      * BUT, this still has one flaw -- what do we do about rx worker threads that
172      * are blocked in the host package making an RPC call to a cm???
173      *
174      * perhaps we need a refcounter that keeps track of threads blocked in rpc calls
175      * with H_LOCK dropped (and the host struct likely left in an inconsistent state)
176      *
177      * or better yet, we need to associate a state machine with each host object
178      * (kind of like demand attach Volume structures).
179      *
180      * sigh. I suspect we'll need to revisit this issue
181      */
182
183     if (fs_state.options.fs_state_verify_before_save) {
184         ViceLog(0, ("fs_stateSave: performing internal consistency checks before proceeding with state dump\n"));
185
186         if (h_stateVerify(&state)) {
187             ViceLog(0, ("fs_stateSave: error: host table consistency checks failed; state dump will not be marked clean\n"));
188             verified = 0;
189             ret = 1;
190         }
191
192         if (cb_stateVerify(&state)) {
193             ViceLog(0, ("fs_stateSave: error: callback table consistency checks failed; state dump will not be marked clean\n"));
194             verified = 0;
195             ret = 1;
196         }
197
198         /* if a consistency check asserted the bail flag, reset it */
199         state.bail = 0;
200
201         ViceLog(0, ("fs_stateSave: proceeding with dump\n"));
202     }
203
204     if (fs_stateCreateDump(&state)) {
205         ViceLog(0, ("fs_stateSave: error: dump create failed\n"));
206         ret = 1;
207         goto done;
208     }
209
210     if (h_stateSave(&state)) {
211         ViceLog(0, ("fs_stateSave: error: host state dump failed\n"));
212         ret = 1;
213         goto done;
214     }
215
216     if (cb_stateSave(&state)) {
217         ViceLog(0, ("fs_stateSave: error: callback state dump failed\n"));
218         ret = 1;
219         goto done;
220     }
221
222     if (!verified) {
223         state.bail = 1;
224     }
225
226     if (fs_stateCommitDump(&state)) {
227         ViceLog(0, ("fs_stateSave: error: dump commit failed\n"));
228         ret = 1; 
229         goto done;
230     }
231
232     if (verified) {
233         ViceLog(0, ("fs_stateSave: fileserver state dump completed successfully\n"));
234     } else {
235         ViceLog(0, ("fs_stateSave: fileserver state dump completed, but not marked clean.\n"));
236         ViceLog(0, ("fs_stateSave: please save a copy of '%s' for use by technical support\n",
237                     state.fn));
238     }
239
240  done:
241     if (state.fd >= 0)
242         fs_stateCloseDump(&state);
243     fs_stateFree(&state);
244     H_UNLOCK;
245     return ret;
246 }
247
248 /*
249  * demand attach fs
250  * restore all fileserver state
251  *
252  * this function must appear as one atomic operation to the host and callback
253  * packages, hence H_LOCK is held for the entirety of the process.
254  */
255 int
256 fs_stateRestore(void)
257 {
258     int ret = 0;
259     struct fs_dump_state state;
260
261     /* save and restore need to be atomic wrt other host package operations */
262     H_LOCK;
263
264     ViceLog(0, ("fs_stateRestore: commencing fileserver state restore\n"));
265
266     if (fs_stateAlloc(&state)) {
267         ViceLog(0, ("fs_stateRestore: memory allocation failed\n"));
268         ret = 1;
269         goto done;
270     }
271
272     if (fs_stateLoadDump(&state)) {
273         ViceLog(0, ("fs_stateRestore: failed to load dump file '%s'\n", state.fn));
274         ret = 1;
275         goto done;
276     }
277
278     if (fs_stateInvalidateDump(&state)) {
279         ViceLog(0, ("fs_stateRestore: failed to invalidate dump file '%s'\n", state.fn));
280         ret = 1;
281         goto done;
282     }
283
284
285     if (state.flags.do_host_restore) {
286         if (h_stateRestore(&state)) {
287             ViceLog(0, ("fs_stateRestore: error: host state restore failed. exiting avoid further corruption\n"));
288             exit(0);
289         }
290         ViceLog(0, ("fs_stateRestore: host table restored\n"));
291
292         if (cb_stateRestore(&state)) {
293             ViceLog(0, ("fs_stateRestore: error: callback state restore failed. exiting to avoid further corruption\n"));
294             exit(0);
295         }
296         ViceLog(0, ("fs_stateRestore: FileEntry and CallBack tables restored\n"));
297
298         if (h_stateRestoreIndices(&state)) {
299             ViceLog(0, ("fs_stateRestore: error: host index remapping failed. exiting to avoid further corruption\n"));
300             exit(0);
301         }
302         ViceLog(0, ("fs_stateRestore: host table indices remapped\n"));
303
304         if (cb_stateRestoreIndices(&state)) {
305             ViceLog(0, ("fs_stateRestore: error: callback index remapping failed. exiting to avoid further corruption\n"));
306             exit(0);
307         }
308         ViceLog(0, ("fs_stateRestore: FileEntry and CallBack indices remapped\n"));
309     }
310
311     ViceLog(0, ("fs_stateRestore: restore phase complete\n"));
312
313     if (fs_state.options.fs_state_verify_after_restore) {
314         ViceLog(0, ("fs_stateRestore: beginning state verification phase\n"));
315
316         if (state.flags.do_host_restore) {
317             if (h_stateVerify(&state)) {
318                 ViceLog(0, ("fs_stateRestore: error: host table consistency checks failed; exiting to avoid further corruption\n"));
319                 exit(0);
320             }
321
322             if (cb_stateVerify(&state)) {
323                 ViceLog(0, ("fs_stateRestore: error: callback table consistency checks failed; exiting to avoid further corruption\n"));
324                 exit(0);
325             }
326         }
327
328         ViceLog(0, ("fs_stateRestore: fileserver state verification complete\n"));
329     }
330
331     ViceLog(0, ("fs_stateRestore: restore was successful\n"));
332
333  done:
334     if (state.fd >= 0) {
335         fs_stateInvalidateDump(&state);
336         fs_stateCloseDump(&state);
337     }
338     fs_stateFree(&state);
339     H_UNLOCK;
340     return ret;
341 }
342
343 static int
344 fs_stateCreateDump(struct fs_dump_state * state)
345 {
346     int fd, ret = 0;
347     char savedump[MAXPATHLEN];
348     struct afs_stat status;
349
350     afs_snprintf(savedump, sizeof(savedump), "%s.old", state->fn);
351
352     if (afs_stat(state->fn, &status) == 0) {
353         renamefile(state->fn, savedump);
354     }
355
356     if (((fd = afs_open(state->fn, 
357                         O_RDWR | O_CREAT | O_TRUNC, 
358                         S_IRUSR | S_IWUSR)) == -1) ||
359         (afs_fstat(fd, &status) == -1)) {
360         ViceLog(0, ("fs_stateCreateDump: failed to create state dump file '%s'\n",
361                     state->fn));
362         ret = 1;
363         goto done;
364     }
365
366     state->fd = fd;
367     state->mode = FS_STATE_DUMP_MODE;
368     memset(state->hdr, 0, sizeof(struct fs_state_header));
369     fs_stateIncEOF(state, sizeof(struct fs_state_header));
370
371 #ifdef FS_STATE_USE_MMAP
372     if (fs_stateSizeFile(state)) {
373         ViceLog(0, ("fs_stateCreateDump: failed to resize state dump file '%s'\n",
374                     state->fn));
375         ret = 1;
376         goto done;
377     }
378
379     if (fs_stateMapFile(state)) {
380         ViceLog(0, ("fs_stateCreateDump: failed to memory map state dump file '%s'\n",
381                     state->fn));
382         ret = 1;
383         goto done;
384     }
385 #endif
386
387     ret = fs_stateInvalidateDump(state);
388
389  done:
390     return ret;
391 }
392
393 static int
394 fs_stateInvalidateDump(struct fs_dump_state * state)
395 {
396     afs_uint64 z;
397     int ret = 0;
398     struct fs_state_header hdr;
399
400 #ifdef FS_STATE_USE_MMAP
401     if (state->mmap.map == NULL) {
402         return 1;
403     }
404 #endif
405
406     memcpy(&hdr, state->hdr, sizeof(hdr));
407     hdr.valid = 0;
408     ZeroInt64(z);
409
410     /* write a bogus header to flag dump in progress */
411     if (fs_stateWriteHeader(state, &z, &hdr, sizeof(hdr))) {
412         ViceLog(0, ("fs_stateInvalidateDump: failed to invalidate old dump file header '%s'\n",
413                     state->fn));
414         ret = 1;
415         goto done;
416     }
417     if (fs_stateSync(state)) {
418         ViceLog(0, ("fs_stateInvalidateDump: failed to sync changes to disk\n"));
419         ret = 1;
420         goto done;
421     }
422
423  done:
424     return ret;
425 }
426
427 static int
428 fs_stateCommitDump(struct fs_dump_state * state)
429 {
430     afs_uint64 z;
431     int ret = 0;
432
433     ZeroInt64(z);
434
435 #ifdef FS_STATE_USE_MMAP
436     if (fs_stateTruncateFile(state)) {
437         ViceLog(0, ("fs_stateCommitDump: failed to truncate dump file to proper size\n"));
438         ret = 1;
439         goto done;
440     }
441 #endif
442
443     /* ensure that all pending data I/Os for the state file have been committed 
444      * _before_ we make the metadata I/Os */
445     if (fs_stateSync(state)) {
446         ViceLog(0, ("fs_stateCommitDump: failed to sync changes to disk\n"));
447         ret = 1;
448         goto done;
449     }
450
451 #ifdef FS_STATE_USE_MMAP
452     /* XXX madvise may not exist on all platforms, so
453      * we may need to add some ifdefs at some point... */
454     {
455         madvise((((char *)state->mmap.map) + sizeof(struct fs_state_header)), 
456                 state->mmap.size - sizeof(struct fs_state_header), 
457                 MADV_DONTNEED);
458     }
459 #endif
460
461     /* build the header, and write it to disk */
462     fs_stateFillHeader(state->hdr);
463     if (state->bail) {
464         state->hdr->valid = 0;
465     }
466     if (fs_stateWriteHeader(state, &z, state->hdr, sizeof(struct fs_state_header))) {
467         ViceLog(0, ("fs_stateCommitDump: failed to write header to dump file '%s'\n",
468                     state->fn));
469         ret = 1;
470         goto done;
471     }
472     if (fs_stateSync(state)) {
473         ViceLog(0, ("fs_stateCommitDump: failed to sync new header to disk\n"));
474         ret = 1;
475         goto done;
476     }
477
478  done:
479     return ret;
480 }
481
482 static int
483 fs_stateLoadDump(struct fs_dump_state * state)
484 {
485     afs_uint64 z;
486     int fd, ret = 0;
487     struct afs_stat status;
488     afs_int32 now = FT_ApproxTime();
489
490     ZeroInt64(z);
491
492     if ((fd = afs_open(state->fn, O_RDWR)) == -1 ||
493         (afs_fstat(fd, &status) == -1)) {
494         ViceLog(0, ("fs_stateLoadDump: failed to load state dump file '%s'\n",
495                     state->fn));
496         ret = 1;
497         goto done;
498     }
499     state->fd = fd;
500     state->mode = FS_STATE_LOAD_MODE;
501     state->file_len = status.st_size;
502
503 #ifdef FS_STATE_USE_MMAP
504     if (fs_stateMapFile(state)) {
505         ViceLog(0, ("fs_stateLoadDump: failed to memory map state dump file '%s'\n",
506                     state->fn));
507         ret = 1;
508         goto done;
509     }
510 #endif
511
512     if (fs_stateReadHeader(state, &z, state->hdr, sizeof(struct fs_state_header))) {
513         ViceLog(0, ("fs_stateLoadDump: failed to read header from dump file '%s'\n",
514                     state->fn));
515         ret = 1;
516         goto done;
517     }
518
519     /* check the validity of the header */
520     if (fs_stateCheckHeader(state->hdr)) {
521         ViceLog(1, ("fs_stateLoadDump: header failed validity checks; not restoring '%s'\n",
522                     state->fn));
523         ret = 1;
524         goto done;
525     }
526
527     if ((state->hdr->timestamp + HOST_STATE_VALID_WINDOW) >= now) {
528         state->flags.do_host_restore = 1;
529     } else {
530         ViceLog(0, ("fs_stateLoadDump: warning: dump is too old for host and callback restore; skipping those steps\n"));
531     }
532
533  done:
534     return ret;
535 }
536
537 static int
538 fs_stateCloseDump(struct fs_dump_state * state)
539 {
540 #ifdef FS_STATE_USE_MMAP
541     fs_stateUnmapFile(state);
542 #endif
543     close(state->fd);
544     return 0;
545 }
546
547 int
548 fs_stateWrite(struct fs_dump_state * state,
549               void * buf, size_t len)
550 {
551     int ret = 0;
552
553 #ifdef FS_STATE_USE_MMAP
554     if (fs_stateCheckIOSafety(state, len)) {
555         if (fs_stateResizeFile(state, len)) {
556             ViceLog(0, ("fs_stateWrite: could not resize dump file '%s'\n",
557                         state->fn));
558             ret = 1;
559             goto done;
560         }
561     }
562             
563     memcpy(state->mmap.cursor, buf, len);
564     fs_stateIncCursor(state, len);
565 #else
566     if (write(state->fd, buf, len) != len) {
567         ViceLog(0, ("fs_stateWrite: write failed\n"));
568         ret = 1;
569         goto done;
570     }
571 #endif
572
573  done:
574     return ret;
575 }
576
577 int
578 fs_stateRead(struct fs_dump_state * state,
579              void * buf, size_t len)
580 {
581     int ret = 0;
582
583 #ifdef FS_STATE_USE_MMAP
584     if (fs_stateCheckIOSafety(state, len)) {
585         ViceLog(0, ("fs_stateRead: read beyond EOF for dump file '%s'\n",
586                     state->fn));
587         ret = 1;
588         goto done;
589     }
590
591     memcpy(buf, state->mmap.cursor, len);
592     fs_stateIncCursor(state, len);
593 #else
594     if (read(state->fd, buf, len) != len) {
595         ViceLog(0, ("fs_stateRead: read failed\n"));
596         ret = 1;
597         goto done;
598     }
599 #endif
600
601  done:
602     return ret;
603 }
604
605 int
606 fs_stateWriteV(struct fs_dump_state * state,
607                struct iovec * iov, int niov)
608 {
609     int i, ret = 0;
610     size_t len = 0;
611
612     for (i=0; i < niov; i++) {
613         len += iov[i].iov_len;
614     }
615
616 #ifdef FS_STATE_USE_MMAP
617     if (fs_stateCheckIOSafety(state, len)) {
618         if (fs_stateResizeFile(state, len)) {
619             ViceLog(0, ("fs_stateWrite: could not resize dump file '%s'\n",
620                         state->fn));
621             ret = 1;
622             goto done;
623         }
624     }
625
626     for (i=0; i < niov; i++) {
627         memcpy(state->mmap.cursor, iov[i].iov_base, iov[i].iov_len);
628         fs_stateIncCursor(state, iov[i].iov_len);
629     }
630 #else
631     if (writev(state->fd, iov, niov) != len) {
632         ViceLog(0, ("fs_stateWriteV: write failed\n"));
633         ret = 1;
634         goto done;
635     }
636 #endif
637
638  done:
639     return ret;
640 }
641
642 int
643 fs_stateReadV(struct fs_dump_state * state,
644               struct iovec * iov, int niov)
645 {
646     int i, ret = 0;
647     size_t len = 0;
648
649     for (i=0; i < niov; i++) {
650         len += iov[i].iov_len;
651     }
652
653 #ifdef FS_STATE_USE_MMAP
654     if (fs_stateCheckIOSafety(state, len)) {
655         ViceLog(0, ("fs_stateRead: read beyond EOF for dump file '%s'\n",
656                     state->fn));
657         ret = 1;
658         goto done;
659     }
660
661     for (i=0; i < niov; i++) {
662         memcpy(iov[i].iov_base, state->mmap.cursor, iov[i].iov_len);
663         fs_stateIncCursor(state, iov[i].iov_len);
664     }
665 #else
666     if (readv(state->fd, iov, niov) != len) {
667         ViceLog(0, ("fs_stateReadV: read failed\n"));
668         ret = 1;
669         goto done;
670     }
671 #endif
672
673  done:
674     return ret;
675 }
676
677 int
678 fs_stateWriteHeader(struct fs_dump_state * state,
679                     afs_uint64 * offset,
680                     void * hdr, size_t len)
681 {
682     int ret = 0;
683
684     if (fs_stateSeek(state, offset)) {
685         ViceLog(0, ("fs_stateWriteHeader: could not seek to correct position in dump file '%s'\n",
686                     state->fn));
687         ret = 1;
688         goto done;
689     }
690
691     if (fs_stateWrite(state, hdr, len)) {
692         ViceLog(0, ("fs_stateWriteHeader: write failed\n"));
693         ret = 1;
694         goto done;
695     }
696
697  done:
698     return ret;
699 }
700
701 int
702 fs_stateReadHeader(struct fs_dump_state * state,
703                    afs_uint64 * offset,
704                    void * hdr, size_t len)
705 {
706     int ret = 0;
707
708     if (fs_stateSeek(state, offset)) {
709         ViceLog(0, ("fs_stateReadHeader: could not seek to correct position in dump file '%s'\n",
710                     state->fn));
711         ret = 1;
712         goto done;
713     }
714
715     if (fs_stateRead(state, hdr,len)) {
716         ViceLog(0, ("fs_stateReadHeader: read failed\n"));
717         ret = 1;
718         goto done;
719     }
720
721  done:
722     return ret;
723 }
724
725 #ifdef FS_STATE_USE_MMAP
726 static int
727 fs_stateSizeFile(struct fs_dump_state * state)
728 {
729     int ret = 0;
730     state->file_len = FS_STATE_INIT_FILESIZE;
731     if (afs_ftruncate(state->fd, state->file_len) != 0)
732         ret = 1;
733     return ret;
734 }
735
736 static int
737 fs_stateResizeFile(struct fs_dump_state * state, size_t min_add)
738 {
739     int ret = 0;
740     afs_foff_t inc;
741
742 #ifdef FS_STATE_USE_MMAP
743     fs_stateUnmapFile(state);
744 #endif
745
746     inc = ((min_add / FS_STATE_INIT_FILESIZE)+1) * FS_STATE_INIT_FILESIZE;
747     state->file_len += inc;
748
749     if (afs_ftruncate(state->fd, state->file_len) != 0) {
750         ViceLog(0, ("fs_stateResizeFile: truncate failed\n"));
751         ret = 1;
752         goto done;
753     }
754
755 #ifdef FS_STATE_USE_MMAP
756     if (fs_stateMapFile(state)) {
757         ViceLog(0, ("fs_stateResizeFile: remapping memory mapped file failed\n"));
758         ret = 1;
759         goto done;
760     }
761 #endif
762
763  done:
764     return ret;
765 }
766
767 static int
768 fs_stateTruncateFile(struct fs_dump_state * state)
769 {
770     int ret = 0;
771
772 #ifdef AFS_LARGEFILE_ENV
773     if (afs_ftruncate(state->fd, state->eof_offset) != 0) {
774         ret = 1;
775     }
776 #else
777     afs_uint32 hi, lo;
778     SplitInt64(state->eof_offset, hi, lo);
779     if (afs_ftruncate(state->fd, lo) != 0) {
780         ret = 1;
781     }
782 #endif
783
784     return ret;
785 }
786 #endif
787
788 #ifdef FS_STATE_USE_MMAP
789 static int
790 fs_stateMapFile(struct fs_dump_state * state)
791 {
792     int ret = 0, flags;
793
794     switch(state->mode) {
795     case FS_STATE_LOAD_MODE:
796         flags = PROT_READ | PROT_WRITE;   /* loading involves a header invalidation */
797         break;
798     case FS_STATE_DUMP_MODE:
799         flags = PROT_WRITE;
800         break;
801     default:
802         ViceLog(0, ("fs_stateMapFile: invalid dump state mode\n"));
803         return 1;
804     }
805
806     state->mmap.map = afs_mmap(NULL, 
807                                state->file_len, 
808                                flags, 
809                                MAP_SHARED,
810                                state->fd, 
811                                0);
812
813     if (state->mmap.map == MAP_FAILED) {
814         state->mmap.size = 0;
815         state->mmap.map = NULL;
816         ViceLog(0, ("fs_stateMapFile: failed to memory map file '%s'\n",
817                     state->fn));
818         ret = 1;
819         goto done;
820     }
821
822     state->mmap.size = state->file_len;
823     state->mmap.cursor = state->mmap.map;
824     state->mmap.offset = 0;
825
826     /* for state loading, accesses will be sequential, so let's give
827      * the VM subsystem a heads up */
828     if (state->mode == FS_STATE_LOAD_MODE) {
829         /* XXX madvise may not exist on all platforms, so
830          * we may need to add some ifdefs at some point... */
831         flags = MADV_SEQUENTIAL | MADV_WILLNEED;
832 #ifdef AFS_SUN510_ENV
833         flags |= MADV_ACCESS_LWP;   /* added in solaris 9 12/02 */
834 #endif
835         madvise(state->mmap.map, state->mmap.size, flags);
836     }
837
838  done:
839     return ret;
840 }
841
842 static int
843 fs_stateUnmapFile(struct fs_dump_state * state)
844 {
845     int ret = 0;
846
847     if (munmap(state->mmap.map, state->mmap.size) == -1) {
848         ViceLog(0, ("fs_stateUnmapFile: failed to unmap dump file '%s'\n",
849                     state->fn));
850         ret = 1;
851         goto done;
852     }
853
854  done:
855     return ret;
856 }
857 #endif /* FS_STATE_USE_MMAP */
858
859 #ifdef FS_STATE_USE_MMAP
860 int
861 fs_stateSync(struct fs_dump_state * state)
862 {
863     int ret = 0;
864
865     msync(state->mmap.map, state->mmap.size, MS_SYNC);
866
867  done:
868     return ret;
869 }
870 #else /* !FS_STATE_USE_MMAP */
871 int
872 fs_stateSync(struct fs_dump_state * state)
873 {
874     int ret = 0;
875
876     if (fsync(state->fd) == -1)
877         ret = 1;
878
879  done:
880     return ret;
881 }
882 #endif /* !FS_STATE_USE_MMAP */
883
884 int
885 fs_stateIncEOF(struct fs_dump_state * state, afs_int32 len)
886 {
887     afs_uint64 temp;
888     FillInt64(temp, 0, len);
889     AddUInt64(state->eof_offset, temp, &state->eof_offset);
890     return 0;
891 }
892
893 #ifdef FS_STATE_USE_MMAP
894 static int
895 fs_stateIncCursor(struct fs_dump_state * state, size_t len)
896 {
897     char * p;
898
899     state->mmap.offset += len;
900
901     p = (char *) state->mmap.cursor;
902     p += len;
903     state->mmap.cursor = (void *) p;
904
905     return 0;
906 }
907
908 static int
909 fs_stateCheckIOSafety(struct fs_dump_state * state, size_t len)
910 {
911     int ret = 0;
912
913     if ((state->mmap.offset + len) > state->mmap.size) {
914         ret = 1;
915     }
916     return ret;
917 }
918 #endif /* FS_STATE_USE_MMAP */
919
920 #ifdef FS_STATE_USE_MMAP
921 int
922 fs_stateSeek(struct fs_dump_state * state, afs_uint64 * offset)
923 {
924     int ret = 0;
925     char * p;
926     afs_uint32 hi, lo;
927
928     SplitInt64(*offset, hi, lo);
929
930     /* update cursor */
931     p = (char *) state->mmap.map;
932 #ifdef AFS_64BIT_ENV
933     p += *offset;
934 #else
935     p += lo;
936 #endif
937     state->mmap.cursor = (void *) p;
938
939     /* update offset */
940 #ifdef AFS_LARGEFILE_ENV
941     state->mmap.offset = *offset;
942 #else
943     if (hi)
944         ret = 1;
945     state->mmap.offset = lo;
946 #endif
947
948     return ret;
949 }
950 #else /* !FS_STATE_USE_MMAP */
951 int
952 fs_stateSeek(struct fs_dump_state * state, afs_uint64 * offset)
953 {
954     int ret = 0;
955 #ifndef AFS_LARGEFILE_ENV
956     afs_uint32 high, low;
957     
958     SplitInt64(*offset, high, low);
959     if (high) {
960         ret = 1;
961         goto done;
962     }
963     
964     if (afs_lseek(state->fd, low, SEEK_SET) == -1)
965         ret = 1;
966 #else
967     if (afs_lseek(state->fd, *offset, SEEK_SET) == -1)
968         ret = 1;
969 #endif
970     return ret;
971 }
972 #endif /* !FS_STATE_USE_MMAP */
973
974 static int
975 fs_stateFillHeader(struct fs_state_header * hdr)
976 {
977     hdr->stamp.magic = FS_STATE_MAGIC;
978     hdr->stamp.version = FS_STATE_VERSION;
979 #ifdef SYS_NAME_ID
980     hdr->sys_name = SYS_NAME_ID;
981 #else
982     hdr->sys_name = 0xFFFFFFFF;
983 #endif
984     hdr->timestamp = FT_ApproxTime();
985     hdr->server_uuid = FS_HostUUID;
986     hdr->valid = 1;
987 #ifdef WORDS_BIGENDIAN
988     hdr->endianness = 1;
989 #else
990     hdr->endianness = 0;
991 #endif
992 #ifdef FS_STATS_DETAILED
993     hdr->stats_detailed = 1;
994 #else
995     hdr->stats_detailed = 0;
996 #endif
997     if (strlcpy(hdr->server_version_string, cml_version_number, sizeof(hdr->server_version_string))
998         >= sizeof(hdr->server_version_string)) {
999         ViceLog(0, ("fs_stateFillHeader: WARNING -- cml_version_number field truncated\n"));
1000     }
1001     return 0;
1002 }
1003
1004 static int
1005 fs_stateCheckHeader(struct fs_state_header * hdr)
1006 {
1007     int ret = 0;
1008
1009     if (!hdr->valid) {
1010         ViceLog(0, ("fs_stateCheckHeader: dump was previously flagged invalid\n"));
1011         ret = 1;
1012     }
1013 #ifdef WORDS_BIGENDIAN
1014     else if (!hdr->endianness) {
1015         ViceLog(0, ("fs_stateCheckHeader: wrong endianness\n"));
1016         ret = 1;
1017     }
1018 #else /* AFSLITTLE_ENDIAN */
1019     else if (hdr->endianness) {
1020         ViceLog(0, ("fs_stateCheckHeader: wrong endianness\n"));
1021         ret = 1;
1022     }
1023 #endif /* AFSLITTLE_ENDIAN */
1024
1025     else if (hdr->stamp.magic != FS_STATE_MAGIC) {
1026         ViceLog(0, ("fs_stateCheckHeader: invalid dump header\n"));
1027         ret = 1;
1028     }
1029     else if (hdr->stamp.version != FS_STATE_VERSION) {
1030         ViceLog(0, ("fs_stateCheckHeader: unknown dump format version number\n"));
1031         ret = 1;
1032     }
1033
1034 #ifdef FS_STATS_DETAILED
1035     else if (!hdr->stats_detailed) {
1036         ViceLog(0, ("fs_stateCheckHeader: wrong config flags\n"));
1037         ret = 1;
1038     }
1039 #else /* FS_STATS_DETAILED */
1040     else if (hdr->stats_detailed) {
1041         ViceLog(0, ("fs_stateCheckHeader: wrong config flags\n"));
1042         ret = 1;
1043     }
1044 #endif /* FS_STATS_DETAILED */
1045
1046     else if (!afs_uuid_equal(&hdr->server_uuid, &FS_HostUUID)) {
1047         ViceLog(0, ("fs_stateCheckHeader: server UUID does not match this server's UUID\n"));
1048         ret = 1;
1049     }
1050
1051     /* the cml_version_string is included for informational purposes only.  If someone ever
1052      * wants to limit state dump reloading based upon the contents of this string, just
1053      * uncomment the following code.  uncommenting this code is _strongly discouraged_ because
1054      * we already make use of the version stamps in the various dump headers to deal with
1055      * data structure version incompatabilities.
1056     else if (strncmp(hdr->server_version_string, cml_version_number, 
1057                      sizeof(hdr->server_version_string)) != 0) {
1058         ViceLog(0, ("fs_stateCheckHeader: dump from different server version\n"));
1059         ret = 1;
1060     }
1061     */
1062
1063     else if (strncmp(hdr->server_version_string, cml_version_number, 
1064                      sizeof(hdr->server_version_string)) != 0) {
1065         ViceLog(0, ("fs_stateCheckHeader: dump from different server version ; attempting state reload anyway\n"));
1066     }
1067
1068
1069     return ret;
1070 }
1071
1072 static int
1073 fs_stateAlloc(struct fs_dump_state * state)
1074 {
1075     int ret = 0;
1076     memset(state, 0, sizeof(struct fs_dump_state));
1077     state->fd = -1;
1078     state->fn = AFSDIR_SERVER_FSSTATE_FILEPATH;
1079     state->hdr = (struct fs_state_header *)malloc(sizeof(struct fs_state_header));
1080     state->h_hdr = (struct host_state_header *)malloc(sizeof(struct host_state_header));
1081     state->cb_hdr = (struct callback_state_header *)malloc(sizeof(struct callback_state_header));
1082     state->cb_timeout_hdr = (struct callback_state_timeout_header *)
1083       malloc(sizeof(struct callback_state_timeout_header));
1084     state->cb_fehash_hdr = (struct callback_state_fehash_header *)
1085       malloc(sizeof(struct callback_state_fehash_header));
1086     if ((state->hdr == NULL) || (state->h_hdr == NULL) || (state->cb_hdr == NULL) ||
1087         (state->cb_timeout_hdr == NULL) || (state->cb_fehash_hdr == NULL))
1088         ret = 1;
1089     return ret;
1090 }
1091
1092 static int
1093 fs_stateFree(struct fs_dump_state * state)
1094 {
1095     if (state->hdr)
1096         free(state->hdr);
1097     if (state->h_hdr)
1098         free(state->h_hdr);
1099     if (state->cb_hdr)
1100         free(state->cb_hdr);
1101     if (state->cb_timeout_hdr)
1102         free(state->cb_timeout_hdr);
1103     if (state->cb_fehash_hdr)
1104         free(state->cb_fehash_hdr);
1105     if (state->h_map.entries)
1106         free(state->h_map.entries);
1107     if (state->fe_map.entries)
1108         free(state->fe_map.entries);
1109     if (state->cb_map.entries)
1110         free(state->cb_map.entries);
1111     return 0;
1112 }
1113
1114 #endif /* AFS_DEMAND_ATTACH_FS */