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