|
Packit Service |
b3514a |
/*
|
|
Packit Service |
b3514a |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
b3514a |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
b3514a |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
b3514a |
* of the License, or (at your option) any later version.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
b3514a |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
b3514a |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
b3514a |
* GNU General Public License for more details.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
b3514a |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
b3514a |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
b3514a |
* 02110-1301, USA.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/vio.c#5 $
|
|
Packit Service |
b3514a |
*/
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#include "vio.h"
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#include "logger.h"
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#include "dataVIO.h"
|
|
Packit Service |
b3514a |
#include "vdoInternal.h"
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#ifdef __KERNEL__
|
|
Packit Service |
b3514a |
#include <linux/ratelimit.h>
|
|
Packit Service |
b3514a |
#endif
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**********************************************************************/
|
|
Packit Service |
b3514a |
void freeVIO(VIO **vioPtr)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
VIO *vio = *vioPtr;
|
|
Packit Service |
b3514a |
if (vio == NULL) {
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
vio->completion.layer->freeVIO(vioPtr);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**********************************************************************/
|
|
Packit Service |
b3514a |
void initializeVIO(VIO *vio,
|
|
Packit Service |
b3514a |
VIOType type,
|
|
Packit Service |
b3514a |
VIOPriority priority,
|
|
Packit Service |
b3514a |
VDOCompletion *parent,
|
|
Packit Service |
b3514a |
VDO *vdo,
|
|
Packit Service |
b3514a |
PhysicalLayer *layer)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
vio->vdo = vdo;
|
|
Packit Service |
b3514a |
vio->type = type;
|
|
Packit Service |
b3514a |
vio->priority = priority;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
VDOCompletion *completion = vioAsCompletion(vio);
|
|
Packit Service |
b3514a |
initializeCompletion(completion, VIO_COMPLETION, layer);
|
|
Packit Service |
b3514a |
completion->parent = parent;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**********************************************************************/
|
|
Packit Service |
b3514a |
void vioDoneCallback(VDOCompletion *completion)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
VIO *vio = asVIO(completion);
|
|
Packit Service |
b3514a |
completion->callback = vio->callback;
|
|
Packit Service |
b3514a |
completion->errorHandler = vio->errorHandler;
|
|
Packit Service |
b3514a |
completeCompletion(completion);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**********************************************************************/
|
|
Packit Service |
b3514a |
const char *getVIOReadWriteFlavor(const VIO *vio)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
if (isReadVIO(vio)) {
|
|
Packit Service |
b3514a |
return "read";
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
return (isWriteVIO(vio) ? "write" : "read-modify-write");
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**********************************************************************/
|
|
Packit Service |
b3514a |
void updateVIOErrorStats(VIO *vio, const char *format, ...)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
int priority;
|
|
Packit Service |
b3514a |
int result = vioAsCompletion(vio)->result;
|
|
Packit Service |
b3514a |
switch (result) {
|
|
Packit Service |
b3514a |
case VDO_READ_ONLY:
|
|
Packit Service |
b3514a |
atomicAdd64(&vio->vdo->errorStats.readOnlyErrorCount, 1);
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
case VDO_NO_SPACE:
|
|
Packit Service |
b3514a |
atomicAdd64(&vio->vdo->errorStats.noSpaceErrorCount, 1);
|
|
Packit Service |
b3514a |
priority = LOG_DEBUG;
|
|
Packit Service |
b3514a |
break;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
default:
|
|
Packit Service |
b3514a |
priority = LOG_ERR;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#ifdef __KERNEL__
|
|
Packit Service |
b3514a |
static DEFINE_RATELIMIT_STATE(errorLimiter, DEFAULT_RATELIMIT_INTERVAL,
|
|
Packit Service |
b3514a |
DEFAULT_RATELIMIT_BURST);
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
if (!__ratelimit(&errorLimiter)) {
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
#endif
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
va_list args;
|
|
Packit Service |
b3514a |
va_start(args, format);
|
|
Packit Service |
b3514a |
vLogWithStringError(priority, result, format, args);
|
|
Packit Service |
b3514a |
va_end(args);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Handle an error from a metadata I/O.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param completion The VIO
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static void handleMetadataIOError(VDOCompletion *completion)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
VIO *vio = asVIO(completion);
|
|
Packit Service |
b3514a |
updateVIOErrorStats(vio,
|
|
Packit Service |
b3514a |
"Completing %s VIO of type %u for physical block %"
|
|
Packit Service |
b3514a |
PRIu64 " with error",
|
|
Packit Service |
b3514a |
getVIOReadWriteFlavor(vio), vio->type, vio->physical);
|
|
Packit Service |
b3514a |
vioDoneCallback(completion);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**********************************************************************/
|
|
Packit Service |
b3514a |
void launchMetadataVIO(VIO *vio,
|
|
Packit Service |
b3514a |
PhysicalBlockNumber physical,
|
|
Packit Service |
b3514a |
VDOAction *callback,
|
|
Packit Service |
b3514a |
VDOAction *errorHandler,
|
|
Packit Service |
b3514a |
VIOOperation operation)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
vio->operation = operation;
|
|
Packit Service |
b3514a |
vio->physical = physical;
|
|
Packit Service |
b3514a |
vio->callback = callback;
|
|
Packit Service |
b3514a |
vio->errorHandler = errorHandler;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
VDOCompletion *completion = vioAsCompletion(vio);
|
|
Packit Service |
b3514a |
resetCompletion(completion);
|
|
Packit Service |
b3514a |
completion->callback = vioDoneCallback;
|
|
Packit Service |
b3514a |
completion->errorHandler = handleMetadataIOError;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
if (isReadVIO(vio)) {
|
|
Packit Service |
b3514a |
completion->layer->readMetadata(vio);
|
|
Packit Service |
b3514a |
} else {
|
|
Packit Service |
b3514a |
completion->layer->writeMetadata(vio);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Handle a flush error.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param completion The flush VIO
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static void handleFlushError(VDOCompletion *completion)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
logErrorWithStringError(completion->result, "Error flushing layer");
|
|
Packit Service |
b3514a |
completion->errorHandler = asVIO(completion)->errorHandler;
|
|
Packit Service |
b3514a |
completeCompletion(completion);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**********************************************************************/
|
|
Packit Service |
b3514a |
void launchFlush(VIO *vio, VDOAction *callback, VDOAction *errorHandler)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
VDOCompletion *completion = vioAsCompletion(vio);
|
|
Packit Service |
b3514a |
resetCompletion(completion);
|
|
Packit Service |
b3514a |
completion->callback = callback;
|
|
Packit Service |
b3514a |
completion->errorHandler = handleFlushError;
|
|
Packit Service |
b3514a |
vio->errorHandler = errorHandler;
|
|
Packit Service |
b3514a |
vio->operation = VIO_FLUSH_BEFORE;
|
|
Packit Service |
b3514a |
vio->physical = ZERO_BLOCK;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
PhysicalLayer *layer = completion->layer;
|
|
Packit Service |
b3514a |
if (layer->getWritePolicy(layer) == WRITE_POLICY_SYNC) {
|
|
Packit Service |
b3514a |
// XXX It is dangerous to be subtly dropping flushes possibly
|
|
Packit Service |
b3514a |
// needed for correctness in sync mode.
|
|
Packit Service |
b3514a |
finishCompletion(completion, VDO_SUCCESS);
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
layer->flush(vio);
|
|
Packit Service |
b3514a |
}
|