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