|
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 |
}
|