Blame source/vdo/base/adminState.c

Packit b55c50
/*
Packit b55c50
 * Copyright (c) 2020 Red Hat, Inc.
Packit b55c50
 *
Packit b55c50
 * This program is free software; you can redistribute it and/or
Packit b55c50
 * modify it under the terms of the GNU General Public License
Packit b55c50
 * as published by the Free Software Foundation; either version 2
Packit b55c50
 * of the License, or (at your option) any later version.
Packit b55c50
 * 
Packit b55c50
 * This program is distributed in the hope that it will be useful,
Packit b55c50
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b55c50
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b55c50
 * GNU General Public License for more details.
Packit b55c50
 * 
Packit b55c50
 * You should have received a copy of the GNU General Public License
Packit b55c50
 * along with this program; if not, write to the Free Software
Packit b55c50
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit b55c50
 * 02110-1301, USA. 
Packit b55c50
 *
Packit b55c50
 * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/adminState.c#14 $
Packit b55c50
 */
Packit b55c50
Packit b55c50
#include "adminState.h"
Packit b55c50
Packit b55c50
#include "logger.h"
Packit b55c50
#include "permassert.h"
Packit b55c50
Packit b55c50
#include "completion.h"
Packit b55c50
#include "types.h"
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
const char *getAdminStateCodeName(AdminStateCode code)
Packit b55c50
{
Packit b55c50
  switch (code) {
Packit b55c50
  case ADMIN_STATE_NORMAL_OPERATION:
Packit b55c50
    return "ADMIN_STATE_NORMAL_OPERATION";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_OPERATING:
Packit b55c50
    return "ADMIN_STATE_OPERATING";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_FORMATTING:
Packit b55c50
    return "ADMIN_STATE_FORMATTING";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_LOADING:
Packit b55c50
    return "ADMIN_STATE_LOADING";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_LOADING_FOR_RECOVERY:
Packit b55c50
    return "ADMIN_STATE_LOADING_FOR_RECOVERY";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_LOADING_FOR_REBUILD:
Packit b55c50
    return "ADMIN_STATE_LOADING_FOR_REBUILD";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_NEW:
Packit b55c50
    return "ADMIN_STATE_NEW";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_WAITING_FOR_RECOVERY:
Packit b55c50
    return "ADMIN_STATE_WAITING_FOR_RECOVERY";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_RECOVERING:
Packit b55c50
    return "ADMIN_STATE_RECOVERING";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_REBUILDING:
Packit b55c50
    return "ADMIN_STATE_REBUILDING";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_SAVING:
Packit b55c50
    return "ADMIN_STATE_SAVING";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_SAVED:
Packit b55c50
    return "ADMIN_STATE_SAVED";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_SCRUBBING:
Packit b55c50
    return "ADMIN_STATE_SCRUBBING";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_SAVE_FOR_SCRUBBING:
Packit b55c50
    return "ADMIN_STATE_SAVE_FOR_SCRUBBING";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_SUSPENDING:
Packit b55c50
    return "ADMIN_STATE_SUSPENDING";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_SUSPENDED:
Packit b55c50
    return "ADMIN_STATE_SUSPENDED";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_SUSPENDED_OPERATION:
Packit b55c50
    return "ADMIN_STATE_SUSPENDED_OPERATION";
Packit b55c50
Packit b55c50
  case ADMIN_STATE_RESUMING:
Packit b55c50
    return "ADMIN_STATE_RESUMING";
Packit b55c50
Packit b55c50
  default:
Packit b55c50
    return "INVALID ADMIN_STATE";
Packit b55c50
  }
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
const char *getAdminStateName(const AdminState *state)
Packit b55c50
{
Packit b55c50
  return getAdminStateCodeName(state->state);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
static AdminStateCode getNextState(AdminStateCode previousState,
Packit b55c50
                                   AdminStateCode operation)
Packit b55c50
{
Packit b55c50
  if (isQuiescingCode(operation)) {
Packit b55c50
    return ((operation & ADMIN_TYPE_MASK) | ADMIN_FLAG_QUIESCENT);
Packit b55c50
  }
Packit b55c50
Packit b55c50
  if (operation == ADMIN_STATE_SUSPENDED_OPERATION) {
Packit b55c50
    return previousState;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  return ADMIN_STATE_NORMAL_OPERATION;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Finish an operation if one is in progress. If there is a waiter, it will be
Packit b55c50
 * notified.
Packit b55c50
 *
Packit b55c50
 * @param state   The AdminState
Packit b55c50
 * @param result  The result of the operation
Packit b55c50
 *
Packit b55c50
 * @return true if an operation was in progress and has been
Packit b55c50
 *         finished.
Packit b55c50
 **/
Packit b55c50
static bool endOperation(AdminState *state, int result)
Packit b55c50
{
Packit b55c50
  if (!isOperating(state)) {
Packit b55c50
    return false;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  if (state->starting) {
Packit b55c50
    state->complete = true;
Packit b55c50
    if (state->waiter != NULL) {
Packit b55c50
      setCompletionResult(state->waiter, result);
Packit b55c50
    }
Packit b55c50
  } else {
Packit b55c50
    state->complete = false;
Packit b55c50
    state->state    = state->nextState;
Packit b55c50
    releaseCompletionWithResult(&state->waiter, result);
Packit b55c50
  }
Packit b55c50
Packit b55c50
  return true;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Begin an operation if it may be started given the current state.
Packit b55c50
 *
Packit b55c50
 * @param state      The AdminState
Packit b55c50
 * @param operation  The operation to begin
Packit b55c50
 * @param waiter     A completion to notify when the operation is complete; may
Packit b55c50
 *                   be NULL
Packit b55c50
 * @param initiator  The AdminInitiator to call if the operation may begin; may
Packit b55c50
 *                   be NULL
Packit b55c50
 *
Packit b55c50
 * @return VDO_SUCCESS or an error
Packit b55c50
 **/
Packit b55c50
__attribute__((warn_unused_result))
Packit b55c50
static int beginOperation(AdminState     *state,
Packit b55c50
                          AdminStateCode  operation,
Packit b55c50
                          VDOCompletion  *waiter,
Packit b55c50
                          AdminInitiator *initiator)
Packit b55c50
{
Packit b55c50
  int result;
Packit b55c50
  if (isOperating(state)
Packit b55c50
      || (isQuiescent(state) != isQuiescentOperation(operation))) {
Packit b55c50
    result = logErrorWithStringError(VDO_INVALID_ADMIN_STATE,
Packit b55c50
                                     "Can't start %s from %s",
Packit b55c50
                                     getAdminStateCodeName(operation),
Packit b55c50
                                     getAdminStateName(state));
Packit b55c50
  } else if (state->waiter != NULL) {
Packit b55c50
    result = logErrorWithStringError(VDO_COMPONENT_BUSY,
Packit b55c50
                                     "Can't start %s with extant waiter",
Packit b55c50
                                     getAdminStateCodeName(operation));
Packit b55c50
  } else {
Packit b55c50
    state->waiter    = waiter;
Packit b55c50
    state->nextState = getNextState(state->state, operation);
Packit b55c50
    state->state     = operation;
Packit b55c50
    if (initiator != NULL) {
Packit b55c50
      state->starting = true;
Packit b55c50
      initiator(state);
Packit b55c50
      state->starting = false;
Packit b55c50
      if (state->complete) {
Packit b55c50
        endOperation(state, VDO_SUCCESS);
Packit b55c50
      }
Packit b55c50
    }
Packit b55c50
Packit b55c50
    return VDO_SUCCESS;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  if (waiter != NULL) {
Packit b55c50
    finishCompletion(waiter, result);
Packit b55c50
  }
Packit b55c50
Packit b55c50
  return result;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Check the result of a state validation. If the result failed, log an invalid
Packit b55c50
 * state error and, if there is a waiter, notify it.
Packit b55c50
 *
Packit b55c50
 * @param valid   true if the code is of an appropriate type
Packit b55c50
 * @param code    The code which failed to be of the correct type
Packit b55c50
 * @param what    What the code failed to be, for logging
Packit b55c50
 * @param waiter  The completion to notify of the error; may be NULL
Packit b55c50
 *
Packit b55c50
 * @return The result of the check
Packit b55c50
 **/
Packit b55c50
static bool checkCode(bool            valid,
Packit b55c50
                      AdminStateCode  code,
Packit b55c50
                      const char     *what,
Packit b55c50
                      VDOCompletion  *waiter)
Packit b55c50
{
Packit b55c50
  if (valid) {
Packit b55c50
    return true;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  int result = logErrorWithStringError(VDO_INVALID_ADMIN_STATE,
Packit b55c50
                                       "%s is not a %s",
Packit b55c50
                                       getAdminStateCodeName(code), what);
Packit b55c50
  if (waiter != NULL) {
Packit b55c50
    finishCompletion(waiter, result);
Packit b55c50
  }
Packit b55c50
Packit b55c50
  return false;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool assertDrainOperation(AdminStateCode operation, VDOCompletion *waiter)
Packit b55c50
{
Packit b55c50
  return checkCode(isDrainOperation(operation), operation, "drain operation",
Packit b55c50
                   waiter);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool startDraining(AdminState     *state,
Packit b55c50
                   AdminStateCode  operation,
Packit b55c50
                   VDOCompletion  *waiter,
Packit b55c50
                   AdminInitiator *initiator)
Packit b55c50
{
Packit b55c50
  return (assertDrainOperation(operation, waiter)
Packit b55c50
          && (beginOperation(state, operation, waiter, initiator)
Packit b55c50
              == VDO_SUCCESS));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool finishDraining(AdminState *state)
Packit b55c50
{
Packit b55c50
  return finishDrainingWithResult(state, VDO_SUCCESS);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool finishDrainingWithResult(AdminState *state, int result)
Packit b55c50
{
Packit b55c50
  return (isDraining(state) && endOperation(state, result));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool assertLoadOperation(AdminStateCode operation, VDOCompletion *waiter)
Packit b55c50
{
Packit b55c50
  return checkCode(isLoadOperation(operation), operation, "load operation",
Packit b55c50
                   waiter);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool startLoading(AdminState     *state,
Packit b55c50
                  AdminStateCode  operation,
Packit b55c50
                  VDOCompletion  *waiter,
Packit b55c50
                  AdminInitiator *initiator)
Packit b55c50
{
Packit b55c50
  return (assertLoadOperation(operation, waiter)
Packit b55c50
          && (beginOperation(state, operation, waiter, initiator)
Packit b55c50
              == VDO_SUCCESS));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool finishLoading(AdminState *state)
Packit b55c50
{
Packit b55c50
  return finishLoadingWithResult(state, VDO_SUCCESS);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool finishLoadingWithResult(AdminState *state, int result)
Packit b55c50
{
Packit b55c50
  return (isLoading(state) && endOperation(state, result));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool assertResumeOperation(AdminStateCode operation, VDOCompletion *waiter)
Packit b55c50
{
Packit b55c50
  return checkCode(isResumeOperation(operation), operation, "resume operation",
Packit b55c50
                   waiter);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool startResuming(AdminState     *state,
Packit b55c50
                   AdminStateCode  operation,
Packit b55c50
                   VDOCompletion  *waiter,
Packit b55c50
                   AdminInitiator *initiator)
Packit b55c50
{
Packit b55c50
  return (assertResumeOperation(operation, waiter)
Packit b55c50
          && (beginOperation(state, operation, waiter, initiator)
Packit b55c50
              == VDO_SUCCESS));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool finishResuming(AdminState *state)
Packit b55c50
{
Packit b55c50
  return finishResumingWithResult(state, VDO_SUCCESS);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool finishResumingWithResult(AdminState *state, int result)
Packit b55c50
{
Packit b55c50
  return (isResuming(state) && endOperation(state, result));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
int resumeIfQuiescent(AdminState *state)
Packit b55c50
{
Packit b55c50
  if (!isQuiescent(state)) {
Packit b55c50
    return VDO_INVALID_ADMIN_STATE;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  state->state = ADMIN_STATE_NORMAL_OPERATION;
Packit b55c50
  return VDO_SUCCESS;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Check whether an AdminStateCode is an operation.
Packit b55c50
 *
Packit b55c50
 * @param code    The operation to check
Packit b55c50
 * @param waiter  The completion to notify if the code is not an operation; may
Packit b55c50
 *                be NULL
Packit b55c50
 *
Packit b55c50
 * @return true if the code is an operation
Packit b55c50
 **/
Packit b55c50
static bool assertOperation(AdminStateCode code, VDOCompletion *waiter)
Packit b55c50
{
Packit b55c50
  return checkCode(isOperation(code), code, "operation", waiter);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
int startOperation(AdminState *state, AdminStateCode operation)
Packit b55c50
{
Packit b55c50
  return (assertOperation(operation, NULL)
Packit b55c50
          ? beginOperation(state, operation, NULL, NULL)
Packit b55c50
          : VDO_INVALID_ADMIN_STATE);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool startOperationWithWaiter(AdminState     *state,
Packit b55c50
                              AdminStateCode  operation,
Packit b55c50
                              VDOCompletion  *waiter,
Packit b55c50
                              AdminInitiator *initiator)
Packit b55c50
{
Packit b55c50
  return (assertOperation(operation, waiter)
Packit b55c50
          && (beginOperation(state, operation, waiter, initiator)
Packit b55c50
              == VDO_SUCCESS));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool finishOperation(AdminState *state)
Packit b55c50
{
Packit b55c50
  return finishOperationWithResult(state, VDO_SUCCESS);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
bool finishOperationWithResult(AdminState *state, int result)
Packit b55c50
{
Packit b55c50
  return endOperation(state, result);
Packit b55c50
}