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