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