/* * demand attach fs * save all fileserver state */ int fs_stateSave(void) { int ret = 0, verified = 1; struct fs_dump_state state; /* save and restore need to be atomic wrt other host package operations */ H_LOCK; ViceLog(0, ("fs_stateSave: commencing fileserver state dump\n")); if (fs_stateAlloc(&state)) { ViceLog(0, ("fs_stateSave: memory allocation failed; dump aborted\n")); ret = 1; goto done; } /* XXX * on busy servers, these checks will inevitably fail since stuff drops H_LOCK * all over the place (with structs left in inconsistent states) while RPCs to * clients happen (grumble, grumble, the host package needs to be rewritten...) * * the current hack is to force the background threads that deal with host and * callback state offline early in the shutdown process, do VShutdown, come * back and wait for those threads to die, THEN do the state dump * * BUT, this still has one flaw -- what do we do about rx worker threads that * are blocked in the host package making an RPC call to a cm??? * * perhaps we need a refcounter that keeps track of threads blocked in rpc calls * with H_LOCK dropped (and the host struct likely left in an inconsistent state) * * or better yet, we need to associate a state machine with each host object * (kind of like demand attach Volume structures). * * sigh. I suspect we'll need to revisit this issue */ if (fs_state.options.fs_state_verify_before_save) { ViceLog(0, ("fs_stateSave: performing internal consistency checks before proceeding with state dump\n")); if (h_stateVerify(&state)) { ViceLog(0, ("fs_stateSave: error: host table consistency checks failed; state dump will not be marked clean\n")); verified = 0; ret = 1; } if (cb_stateVerify(&state)) { ViceLog(0, ("fs_stateSave: error: callback table consistency checks failed; state dump will not be marked clean\n")); verified = 0; ret = 1; } /* if a consistency check asserted the bail flag, reset it */ state.bail = 0; ViceLog(0, ("fs_stateSave: proceeding with dump\n")); } if (fs_stateCreateDump(&state)) { ViceLog(0, ("fs_stateSave: error: dump create failed\n")); ret = 1; goto done; } if (h_stateSave(&state)) { ViceLog(0, ("fs_stateSave: error: host state dump failed\n")); ret = 1; goto done; } if (cb_stateSave(&state)) { ViceLog(0, ("fs_stateSave: error: callback state dump failed\n")); ret = 1; goto done; } if (!verified) { state.bail = 1; } if (fs_stateCommitDump(&state)) { ViceLog(0, ("fs_stateSave: error: dump commit failed\n")); ret = 1; goto done; } if (verified) { ViceLog(0, ("fs_stateSave: fileserver state dump completed successfully\n")); } else { ViceLog(0, ("fs_stateSave: fileserver state dump completed, but not marked clean.\n")); ViceLog(0, ("fs_stateSave: please save a copy of '%s' for use by technical support\n", state.fn)); } done: if (fs_stateFileOpen(&state)) fs_stateCloseDump(&state); fs_stateFree(&state); H_UNLOCK; return ret; }
/* * demand attach fs * restore all fileserver state * * this function must appear as one atomic operation to the host and callback * packages, hence H_LOCK is held for the entirety of the process. */ int fs_stateRestore(void) { int ret = 0; struct fs_dump_state state; /* save and restore need to be atomic wrt other host package operations */ H_LOCK; ViceLog(0, ("fs_stateRestore: commencing fileserver state restore\n")); if (fs_stateAlloc(&state)) { ViceLog(0, ("fs_stateRestore: memory allocation failed\n")); ret = 1; goto done; } if (fs_stateLoadDump(&state)) { ViceLog(0, ("fs_stateRestore: failed to load dump file '%s'\n", state.fn)); ret = 1; goto done; } if (fs_stateInvalidateDump(&state)) { ViceLog(0, ("fs_stateRestore: failed to invalidate dump file '%s'\n", state.fn)); ret = 1; goto done; } if (state.flags.do_host_restore) { if (h_stateRestore(&state)) { ViceLog(0, ("fs_stateRestore: error: host state restore failed. exiting avoid further corruption\n")); exit(0); } ViceLog(0, ("fs_stateRestore: host table restored\n")); if (cb_stateRestore(&state)) { ViceLog(0, ("fs_stateRestore: error: callback state restore failed. exiting to avoid further corruption\n")); exit(0); } ViceLog(0, ("fs_stateRestore: FileEntry and CallBack tables restored\n")); if (h_stateRestoreIndices(&state)) { ViceLog(0, ("fs_stateRestore: error: host index remapping failed. exiting to avoid further corruption\n")); exit(0); } ViceLog(0, ("fs_stateRestore: host table indices remapped\n")); if (cb_stateRestoreIndices(&state)) { ViceLog(0, ("fs_stateRestore: error: callback index remapping failed. exiting to avoid further corruption\n")); exit(0); } ViceLog(0, ("fs_stateRestore: FileEntry and CallBack indices remapped\n")); } ViceLog(0, ("fs_stateRestore: restore phase complete\n")); if (fs_state.options.fs_state_verify_after_restore) { ViceLog(0, ("fs_stateRestore: beginning state verification phase\n")); if (state.flags.do_host_restore) { if (h_stateVerify(&state)) { ViceLog(0, ("fs_stateRestore: error: host table consistency checks failed; exiting to avoid further corruption\n")); exit(0); } if (cb_stateVerify(&state)) { ViceLog(0, ("fs_stateRestore: error: callback table consistency checks failed; exiting to avoid further corruption\n")); exit(0); } } ViceLog(0, ("fs_stateRestore: fileserver state verification complete\n")); } ViceLog(0, ("fs_stateRestore: restore was successful\n")); done: if (state.fd >= 0) { fs_stateInvalidateDump(&state); fs_stateCloseDump(&state); } fs_stateFree(&state); H_UNLOCK; return ret; }
/* * demand attach fs * save all fileserver state */ int fs_stateSave(void) { int ret = 0, verified = 1; struct fs_dump_state state; /* save and restore need to be atomic wrt other host package operations */ H_LOCK; ViceLog(0, ("fs_stateSave: commencing fileserver state dump\n")); if (fs_stateAlloc(&state)) { ViceLog(0, ("fs_stateSave: memory allocation failed; dump aborted\n")); ret = 1; goto done; } /* XXX * on busy servers, these checks will inevitably fail since stuff drops H_LOCK * all over the place (with structs left in inconsistent states) while RPCs to * clients happen (grumble, grumble, the host package needs to be rewritten...) * * the current hack is to force the background threads that deal with host and * callback state offline early in the shutdown process, do VShutdown, come * back and wait for those threads to die, THEN do the state dump * * BUT, this still has one flaw -- what do we do about rx worker threads that * are blocked in the host package making an RPC call to a cm??? * * currently we try to detect if a host struct is in an inconsistent state * when we go to save it to disk, and just skip the hosts that we think may * be inconsistent (see h_isBusy_r in host.c). This has the problem of causing * more InitCallBackState's when we come back up, but the number of hosts in * such a state should be small. In the future, we could try to lock hosts * (with some deadline so we don't wait forever) before serializing, but at * least for now it does not seem worth the trouble. */ if (fs_state.options.fs_state_verify_before_save) { ViceLog(0, ("fs_stateSave: performing internal consistency checks before proceeding with state dump\n")); if (h_stateVerify(&state)) { ViceLog(0, ("fs_stateSave: error: host table consistency checks failed; state dump will not be marked clean\n")); verified = 0; ret = 1; } if (cb_stateVerify(&state)) { ViceLog(0, ("fs_stateSave: error: callback table consistency checks failed; state dump will not be marked clean\n")); verified = 0; ret = 1; } /* if a consistency check asserted the bail flag, reset it */ state.bail = 0; ViceLog(0, ("fs_stateSave: proceeding with dump\n")); } if (fs_stateCreateDump(&state)) { ViceLog(0, ("fs_stateSave: error: dump create failed\n")); ret = 1; goto done; } if (h_stateSave(&state)) { ViceLog(0, ("fs_stateSave: error: host state dump failed\n")); ret = 1; goto done; } if (cb_stateSave(&state)) { ViceLog(0, ("fs_stateSave: error: callback state dump failed\n")); ret = 1; goto done; } if (!verified) { state.bail = 1; } if (fs_stateCommitDump(&state)) { ViceLog(0, ("fs_stateSave: error: dump commit failed\n")); ret = 1; goto done; } if (verified) { ViceLog(0, ("fs_stateSave: fileserver state dump completed successfully\n")); } else { ViceLog(0, ("fs_stateSave: fileserver state dump completed, but not marked clean.\n")); ViceLog(0, ("fs_stateSave: please save a copy of '%s' for use by technical support\n", state.fn)); } done: if (fs_stateFileOpen(&state)) fs_stateCloseDump(&state); fs_stateFree(&state); H_UNLOCK; return ret; }