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