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