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