Remove --disable-largefile-fileserver
[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     if (afs_ftruncate(state->fd, state->eof_offset) != 0) {
771         ret = 1;
772     }
773
774     return ret;
775 }
776 #endif
777
778 #ifdef FS_STATE_USE_MMAP
779 static int
780 fs_stateMapFile(struct fs_dump_state * state)
781 {
782     int ret = 0, flags;
783
784     switch(state->mode) {
785     case FS_STATE_LOAD_MODE:
786         flags = PROT_READ | PROT_WRITE;   /* loading involves a header invalidation */
787         break;
788     case FS_STATE_DUMP_MODE:
789         flags = PROT_WRITE;
790         break;
791     default:
792         ViceLog(0, ("fs_stateMapFile: invalid dump state mode\n"));
793         return 1;
794     }
795
796     state->mmap.map = afs_mmap(NULL, 
797                                state->file_len, 
798                                flags, 
799                                MAP_SHARED,
800                                state->fd, 
801                                0);
802
803     if (state->mmap.map == MAP_FAILED) {
804         state->mmap.size = 0;
805         state->mmap.map = NULL;
806         ViceLog(0, ("fs_stateMapFile: failed to memory map file '%s'\n",
807                     state->fn));
808         ret = 1;
809         goto done;
810     }
811
812     state->mmap.size = state->file_len;
813     state->mmap.cursor = state->mmap.map;
814     state->mmap.offset = 0;
815
816     /* for state loading, accesses will be sequential, so let's give
817      * the VM subsystem a heads up */
818     if (state->mode == FS_STATE_LOAD_MODE) {
819         /* XXX madvise may not exist on all platforms, so
820          * we may need to add some ifdefs at some point... */
821         flags = MADV_SEQUENTIAL | MADV_WILLNEED;
822 #ifdef AFS_SUN510_ENV
823         flags |= MADV_ACCESS_LWP;   /* added in solaris 9 12/02 */
824 #endif
825         madvise(state->mmap.map, state->mmap.size, flags);
826     }
827
828  done:
829     return ret;
830 }
831
832 static int
833 fs_stateUnmapFile(struct fs_dump_state * state)
834 {
835     int ret = 0;
836
837     if (munmap(state->mmap.map, state->mmap.size) == -1) {
838         ViceLog(0, ("fs_stateUnmapFile: failed to unmap dump file '%s'\n",
839                     state->fn));
840         ret = 1;
841         goto done;
842     }
843
844  done:
845     return ret;
846 }
847 #endif /* FS_STATE_USE_MMAP */
848
849 #ifdef FS_STATE_USE_MMAP
850 int
851 fs_stateSync(struct fs_dump_state * state)
852 {
853     int ret = 0;
854
855     msync(state->mmap.map, state->mmap.size, MS_SYNC);
856
857     return ret;
858 }
859 #else /* !FS_STATE_USE_MMAP */
860 int
861 fs_stateSync(struct fs_dump_state * state)
862 {
863     int ret = 0;
864
865     if (fsync(state->fd) == -1)
866         ret = 1;
867
868  done:
869     return ret;
870 }
871 #endif /* !FS_STATE_USE_MMAP */
872
873 int
874 fs_stateIncEOF(struct fs_dump_state * state, afs_int32 len)
875 {
876     afs_uint64 temp;
877     FillInt64(temp, 0, len);
878     AddUInt64(state->eof_offset, temp, &state->eof_offset);
879     return 0;
880 }
881
882 #ifdef FS_STATE_USE_MMAP
883 static int
884 fs_stateIncCursor(struct fs_dump_state * state, size_t len)
885 {
886     char * p;
887
888     state->mmap.offset += len;
889
890     p = (char *) state->mmap.cursor;
891     p += len;
892     state->mmap.cursor = (void *) p;
893
894     return 0;
895 }
896
897 static int
898 fs_stateCheckIOSafety(struct fs_dump_state * state, size_t len)
899 {
900     int ret = 0;
901
902     if ((state->mmap.offset + len) > state->mmap.size) {
903         ret = 1;
904     }
905     return ret;
906 }
907 #endif /* FS_STATE_USE_MMAP */
908
909 #ifdef FS_STATE_USE_MMAP
910 int
911 fs_stateSeek(struct fs_dump_state * state, afs_uint64 * offset)
912 {
913     int ret = 0;
914     char * p;
915     afs_uint32 hi, lo;
916
917     SplitInt64(*offset, hi, lo);
918
919     /* update cursor */
920     p = (char *) state->mmap.map;
921 #ifdef AFS_64BIT_ENV
922     p += *offset;
923 #else
924     p += lo;
925 #endif
926     state->mmap.cursor = (void *) p;
927
928     /* update offset */
929     state->mmap.offset = *offset;
930
931     return ret;
932 }
933 #else /* !FS_STATE_USE_MMAP */
934 int
935 fs_stateSeek(struct fs_dump_state * state, afs_uint64 * offset)
936 {
937     int ret = 0;
938
939     if (afs_lseek(state->fd, *offset, SEEK_SET) == -1)
940         ret = 1;
941
942     return ret;
943 }
944 #endif /* !FS_STATE_USE_MMAP */
945
946 static int
947 fs_stateFillHeader(struct fs_state_header * hdr)
948 {
949     hdr->stamp.magic = FS_STATE_MAGIC;
950     hdr->stamp.version = FS_STATE_VERSION;
951 #ifdef SYS_NAME_ID
952     hdr->sys_name = SYS_NAME_ID;
953 #else
954     hdr->sys_name = 0xFFFFFFFF;
955 #endif
956     hdr->timestamp = FT_ApproxTime();
957     hdr->server_uuid = FS_HostUUID;
958     hdr->valid = 1;
959 #ifdef WORDS_BIGENDIAN
960     hdr->endianness = 1;
961 #else
962     hdr->endianness = 0;
963 #endif
964 #ifdef FS_STATS_DETAILED
965     hdr->stats_detailed = 1;
966 #else
967     hdr->stats_detailed = 0;
968 #endif
969     if (strlcpy(hdr->server_version_string, cml_version_number, sizeof(hdr->server_version_string))
970         >= sizeof(hdr->server_version_string)) {
971         ViceLog(0, ("fs_stateFillHeader: WARNING -- cml_version_number field truncated\n"));
972     }
973     return 0;
974 }
975
976 static int
977 fs_stateCheckHeader(struct fs_state_header * hdr)
978 {
979     int ret = 0;
980
981     if (!hdr->valid) {
982         ViceLog(0, ("fs_stateCheckHeader: dump was previously flagged invalid\n"));
983         ret = 1;
984     }
985 #ifdef WORDS_BIGENDIAN
986     else if (!hdr->endianness) {
987         ViceLog(0, ("fs_stateCheckHeader: wrong endianness\n"));
988         ret = 1;
989     }
990 #else /* AFSLITTLE_ENDIAN */
991     else if (hdr->endianness) {
992         ViceLog(0, ("fs_stateCheckHeader: wrong endianness\n"));
993         ret = 1;
994     }
995 #endif /* AFSLITTLE_ENDIAN */
996
997     else if (hdr->stamp.magic != FS_STATE_MAGIC) {
998         ViceLog(0, ("fs_stateCheckHeader: invalid dump header\n"));
999         ret = 1;
1000     }
1001     else if (hdr->stamp.version != FS_STATE_VERSION) {
1002         ViceLog(0, ("fs_stateCheckHeader: unknown dump format version number\n"));
1003         ret = 1;
1004     }
1005
1006 #ifdef FS_STATS_DETAILED
1007     else if (!hdr->stats_detailed) {
1008         ViceLog(0, ("fs_stateCheckHeader: wrong config flags\n"));
1009         ret = 1;
1010     }
1011 #else /* FS_STATS_DETAILED */
1012     else if (hdr->stats_detailed) {
1013         ViceLog(0, ("fs_stateCheckHeader: wrong config flags\n"));
1014         ret = 1;
1015     }
1016 #endif /* FS_STATS_DETAILED */
1017
1018     else if (!afs_uuid_equal(&hdr->server_uuid, &FS_HostUUID)) {
1019         ViceLog(0, ("fs_stateCheckHeader: server UUID does not match this server's UUID\n"));
1020         ret = 1;
1021     }
1022
1023     /* the cml_version_string is included for informational purposes only.  If someone ever
1024      * wants to limit state dump reloading based upon the contents of this string, just
1025      * uncomment the following code.  uncommenting this code is _strongly discouraged_ because
1026      * we already make use of the version stamps in the various dump headers to deal with
1027      * data structure version incompatabilities.
1028     else if (strncmp(hdr->server_version_string, cml_version_number, 
1029                      sizeof(hdr->server_version_string)) != 0) {
1030         ViceLog(0, ("fs_stateCheckHeader: dump from different server version\n"));
1031         ret = 1;
1032     }
1033     */
1034
1035     else if (strncmp(hdr->server_version_string, cml_version_number, 
1036                      sizeof(hdr->server_version_string)) != 0) {
1037         ViceLog(0, ("fs_stateCheckHeader: dump from different server version ; attempting state reload anyway\n"));
1038     }
1039
1040
1041     return ret;
1042 }
1043
1044 static int
1045 fs_stateAlloc(struct fs_dump_state * state)
1046 {
1047     int ret = 0;
1048     memset(state, 0, sizeof(struct fs_dump_state));
1049     state->fd = -1;
1050     state->fn = (char *)AFSDIR_SERVER_FSSTATE_FILEPATH;
1051     state->hdr = (struct fs_state_header *)malloc(sizeof(struct fs_state_header));
1052     state->h_hdr = (struct host_state_header *)malloc(sizeof(struct host_state_header));
1053     state->cb_hdr = (struct callback_state_header *)malloc(sizeof(struct callback_state_header));
1054     state->cb_timeout_hdr = (struct callback_state_timeout_header *)
1055       malloc(sizeof(struct callback_state_timeout_header));
1056     state->cb_fehash_hdr = (struct callback_state_fehash_header *)
1057       malloc(sizeof(struct callback_state_fehash_header));
1058     if ((state->hdr == NULL) || (state->h_hdr == NULL) || (state->cb_hdr == NULL) ||
1059         (state->cb_timeout_hdr == NULL) || (state->cb_fehash_hdr == NULL))
1060         ret = 1;
1061     return ret;
1062 }
1063
1064 static int
1065 fs_stateFree(struct fs_dump_state * state)
1066 {
1067     if (state->hdr)
1068         free(state->hdr);
1069     if (state->h_hdr)
1070         free(state->h_hdr);
1071     if (state->cb_hdr)
1072         free(state->cb_hdr);
1073     if (state->cb_timeout_hdr)
1074         free(state->cb_timeout_hdr);
1075     if (state->cb_fehash_hdr)
1076         free(state->cb_fehash_hdr);
1077     if (state->h_map.entries)
1078         free(state->h_map.entries);
1079     if (state->fe_map.entries)
1080         free(state->fe_map.entries);
1081     if (state->cb_map.entries)
1082         free(state->cb_map.entries);
1083     return 0;
1084 }
1085
1086 #endif /* AFS_DEMAND_ATTACH_FS */