Blame source/vdo/base/adminState.c

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