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