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