Blame source/vdo/base/completion.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/completion.c#10 $
Packit b55c50
 */
Packit b55c50
Packit b55c50
#include "completion.h"
Packit b55c50
Packit b55c50
#include "logger.h"
Packit b55c50
#include "statusCodes.h"
Packit b55c50
Packit b55c50
static const char *VDO_COMPLETION_TYPE_NAMES[] = {
Packit b55c50
  // Keep UNSET_COMPLETION_TYPE at the top.
Packit b55c50
  "UNSET_COMPLETION_TYPE",
Packit b55c50
Packit b55c50
  // Keep the rest of these in sorted order. If you add or remove an entry,
Packit b55c50
  // be sure to update the corresponding list in completion.h.
Packit b55c50
  "ACTION_COMPLETION",
Packit b55c50
  "ADMIN_COMPLETION",
Packit b55c50
  "ASYNC_ACTION_CONTEXT",
Packit b55c50
  "BLOCK_ALLOCATOR_COMPLETION",
Packit b55c50
  "BLOCK_MAP_RECOVERY_COMPLETION",
Packit b55c50
  "CHECK_IDENTIFIER_COMPLETION",
Packit b55c50
  "EXTERNAL_COMPLETION",
Packit b55c50
  "FLUSH_NOTIFICATION_COMPLETION",
Packit b55c50
  "GENERATION_FLUSHED_COMPLETION",
Packit b55c50
  "HEARTBEAT_COMPLETION",
Packit b55c50
  "LOCK_COUNTER_COMPLETION",
Packit b55c50
  "PARTITION_COPY_COMPLETION",
Packit b55c50
  "READ_ONLY_MODE_COMPLETION",
Packit b55c50
  "READ_ONLY_REBUILD_COMPLETION",
Packit b55c50
  "RECOVERY_COMPLETION",
Packit b55c50
  "REFERENCE_COUNT_REBUILD_COMPLETION",
Packit b55c50
  "SLAB_SCRUBBER_COMPLETION",
Packit b55c50
  "SUB_TASK_COMPLETION",
Packit b55c50
  "TEST_COMPLETION",
Packit b55c50
  "VDO_COMMAND_COMPLETION",
Packit b55c50
  "VDO_COMMAND_SUB_COMPLETION",
Packit b55c50
  "VDO_EXTENT_COMPLETION",
Packit b55c50
  "VDO_PAGE_COMPLETION",
Packit b55c50
  "VIO_COMPLETION",
Packit b55c50
  "WRAPPING_COMPLETION",
Packit b55c50
};
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void initializeCompletion(VDOCompletion         *completion,
Packit b55c50
                          VDOCompletionType      type,
Packit b55c50
                          PhysicalLayer         *layer)
Packit b55c50
{
Packit b55c50
  memset(completion, 0, sizeof(*completion));
Packit b55c50
  completion->layer = layer;
Packit b55c50
  completion->type  = type;
Packit b55c50
  resetCompletion(completion);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
int initializeEnqueueableCompletion(VDOCompletion      *completion,
Packit b55c50
                                    VDOCompletionType   type,
Packit b55c50
                                    PhysicalLayer      *layer)
Packit b55c50
{
Packit b55c50
  initializeCompletion(completion, type, layer);
Packit b55c50
  return ((layer->createEnqueueable == NULL)
Packit b55c50
          ? VDO_SUCCESS : layer->createEnqueueable(completion));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void resetCompletion(VDOCompletion *completion)
Packit b55c50
{
Packit b55c50
  completion->result   = VDO_SUCCESS;
Packit b55c50
  completion->complete = false;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Assert that a completion is not complete.
Packit b55c50
 *
Packit b55c50
 * @param completion The completion to check
Packit b55c50
 **/
Packit b55c50
static inline void assertIncomplete(VDOCompletion *completion)
Packit b55c50
{
Packit b55c50
  ASSERT_LOG_ONLY(!completion->complete, "completion is not complete");
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void setCompletionResult(VDOCompletion *completion, int result)
Packit b55c50
{
Packit b55c50
  assertIncomplete(completion);
Packit b55c50
  if (completion->result == VDO_SUCCESS) {
Packit b55c50
    completion->result = result;
Packit b55c50
  }
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Check whether a completion's callback must be enqueued, or if it can be run
Packit b55c50
 * on the current thread. Side effect: clears the requeue flag if it is set,
Packit b55c50
 * so the caller MUST requeue if this returns true.
Packit b55c50
 *
Packit b55c50
 * @param completion  The completion whose callback is to be invoked
Packit b55c50
 *
Packit b55c50
 * @return false if the callback must be run on this thread
Packit b55c50
 *         true  if the callback must be enqueued
Packit b55c50
 **/
Packit b55c50
__attribute__((warn_unused_result))
Packit b55c50
static inline bool requiresEnqueue(VDOCompletion *completion)
Packit b55c50
{
Packit b55c50
  if (completion->requeue) {
Packit b55c50
    completion->requeue = false;
Packit b55c50
    return true;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  ThreadID callbackThread = completion->callbackThreadID;
Packit b55c50
  return (callbackThread != completion->layer->getCurrentThreadID());
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void invokeCallback(VDOCompletion *completion)
Packit b55c50
{
Packit b55c50
  if (requiresEnqueue(completion)) {
Packit b55c50
    if (completion->enqueueable != NULL) {
Packit b55c50
      completion->layer->enqueue(completion->enqueueable);
Packit b55c50
      return;
Packit b55c50
    }
Packit b55c50
    ASSERT_LOG_ONLY(false,
Packit b55c50
                    "non-enqueueable completion (type %s) on correct thread",
Packit b55c50
                    getCompletionTypeName(completion->type));
Packit b55c50
  }
Packit b55c50
Packit b55c50
  runCallback(completion);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void continueCompletion(VDOCompletion *completion, int result)
Packit b55c50
{
Packit b55c50
  setCompletionResult(completion, result);
Packit b55c50
  invokeCallback(completion);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void completeCompletion(VDOCompletion *completion)
Packit b55c50
{
Packit b55c50
  assertIncomplete(completion);
Packit b55c50
  completion->complete = true;
Packit b55c50
  if (completion->callback != NULL) {
Packit b55c50
    invokeCallback(completion);
Packit b55c50
  }
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void releaseCompletion(VDOCompletion **completionPtr)
Packit b55c50
{
Packit b55c50
  VDOCompletion *completion = *completionPtr;
Packit b55c50
  if (completion == NULL) {
Packit b55c50
    return;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  *completionPtr = NULL;
Packit b55c50
  completeCompletion(completion);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void releaseCompletionWithResult(VDOCompletion **completionPtr, int result)
Packit b55c50
{
Packit b55c50
  if (*completionPtr == NULL) {
Packit b55c50
    return;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  setCompletionResult(*completionPtr, result);
Packit b55c50
  releaseCompletion(completionPtr);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void finishParentCallback(VDOCompletion *completion)
Packit b55c50
{
Packit b55c50
  finishCompletion((VDOCompletion *) completion->parent, completion->result);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void preserveErrorAndContinue(VDOCompletion *completion)
Packit b55c50
{
Packit b55c50
  if (completion->parent != NULL) {
Packit b55c50
    setCompletionResult(completion->parent, completion->result);
Packit b55c50
  }
Packit b55c50
Packit b55c50
  resetCompletion(completion);
Packit b55c50
  invokeCallback(completion);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
const char *getCompletionTypeName(VDOCompletionType completionType)
Packit b55c50
{
Packit b55c50
  // Try to catch failures to update the array when the enum values change.
Packit b55c50
  STATIC_ASSERT(COUNT_OF(VDO_COMPLETION_TYPE_NAMES)
Packit b55c50
                == (MAX_COMPLETION_TYPE - UNSET_COMPLETION_TYPE));
Packit b55c50
Packit b55c50
  if (completionType >= MAX_COMPLETION_TYPE) {
Packit b55c50
    static char numeric[100];
Packit b55c50
    snprintf(numeric, 99, "%d (%#x)", completionType, completionType);
Packit b55c50
    return numeric;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  return VDO_COMPLETION_TYPE_NAMES[completionType];
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
void destroyEnqueueable(VDOCompletion *completion)
Packit b55c50
{
Packit b55c50
  if ((completion == NULL) || (completion->layer == NULL)
Packit b55c50
      || (completion->layer->destroyEnqueueable == NULL)) {
Packit b55c50
    return;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  completion->layer->destroyEnqueueable(&completion->enqueueable);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**********************************************************************/
Packit b55c50
int assertCompletionType(VDOCompletionType actual,
Packit b55c50
                         VDOCompletionType expected)
Packit b55c50
{
Packit b55c50
  return ASSERT((expected == actual),
Packit b55c50
                "completion type is %s instead of %s",
Packit b55c50
                getCompletionTypeName(actual),
Packit b55c50
                getCompletionTypeName(expected));
Packit b55c50
}