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