/*
 * 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;
}
Beispiel #3
0
/*
 * 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;
}