|
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/kernel/verify.c#3 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "verify.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "logger.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "dataKVIO.h"
|
|
Packit Service |
310c69 |
#include "numeric.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Compare blocks of memory for equality.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This assumes the blocks are likely to be large; it's not well
|
|
Packit Service |
310c69 |
* optimized for comparing just a few bytes. This is desirable
|
|
Packit Service |
310c69 |
* because the Linux kernel memcmp() routine on x86 is not well
|
|
Packit Service |
310c69 |
* optimized for large blocks, and the performance penalty turns out
|
|
Packit Service |
310c69 |
* to be significant if you're doing lots of 4KB comparisons.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param pointerArgument1 first data block
|
|
Packit Service |
310c69 |
* @param pointerArgument2 second data block
|
|
Packit Service |
310c69 |
* @param length length of the data block
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return true iff the two blocks are equal
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result))
|
|
Packit Service |
310c69 |
static bool memoryEqual(void *pointerArgument1,
|
|
Packit Service |
310c69 |
void *pointerArgument2,
|
|
Packit Service |
310c69 |
size_t length)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
byte *pointer1 = pointerArgument1;
|
|
Packit Service |
310c69 |
byte *pointer2 = pointerArgument2;
|
|
Packit Service |
310c69 |
while (length >= sizeof(uint64_t)) {
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* GET_UNALIGNED is just for paranoia. (1) On x86_64 it is
|
|
Packit Service |
310c69 |
* treated the same as an aligned access. (2) In this use case,
|
|
Packit Service |
310c69 |
* one or both of the inputs will almost(?) always be aligned.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
if (GET_UNALIGNED(uint64_t, pointer1)
|
|
Packit Service |
310c69 |
!= GET_UNALIGNED(uint64_t, pointer2)) {
|
|
Packit Service |
310c69 |
return false;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
pointer1 += sizeof(uint64_t);
|
|
Packit Service |
310c69 |
pointer2 += sizeof(uint64_t);
|
|
Packit Service |
310c69 |
length -= sizeof(uint64_t);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
while (length > 0) {
|
|
Packit Service |
310c69 |
if (*pointer1 != *pointer2) {
|
|
Packit Service |
310c69 |
return false;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
pointer1++;
|
|
Packit Service |
310c69 |
pointer2++;
|
|
Packit Service |
310c69 |
length--;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
return true;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Verify the Albireo-provided deduplication advice, and invoke a
|
|
Packit Service |
310c69 |
* callback once the answer is available.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* After we've compared the stored data with the data to be written,
|
|
Packit Service |
310c69 |
* or after we've failed to be able to do so, the stored VIO callback
|
|
Packit Service |
310c69 |
* is queued to be run in the main (kvdoReqQ) thread.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* If the advice turns out to be stale and the deduplication session
|
|
Packit Service |
310c69 |
* is still active, submit a correction. (Currently the correction
|
|
Packit Service |
310c69 |
* must be sent before the callback can be invoked, if the dedupe
|
|
Packit Service |
310c69 |
* session is still live.)
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param item The workitem from the queue
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void verifyDuplicationWork(KvdoWorkItem *item)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
DataKVIO *dataKVIO = workItemAsDataKVIO(item);
|
|
Packit Service |
310c69 |
dataKVIOAddTraceRecord(dataKVIO, THIS_LOCATION("$F;j=dedupe;cb=verify"));
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (likely(memoryEqual(dataKVIO->dataBlock, dataKVIO->readBlock.data,
|
|
Packit Service |
310c69 |
VDO_BLOCK_SIZE))) {
|
|
Packit Service |
310c69 |
// Leave dataKVIO->dataVIO.isDuplicate set to true.
|
|
Packit Service |
310c69 |
} else {
|
|
Packit Service |
310c69 |
dataKVIO->dataVIO.isDuplicate = false;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
kvdoEnqueueDataVIOCallback(dataKVIO);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Verify the Albireo-provided deduplication advice, and invoke a
|
|
Packit Service |
310c69 |
* callback once the answer is available.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param dataKVIO The DataKVIO that we are looking to dedupe.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void verifyReadBlockCallback(DataKVIO *dataKVIO)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
dataKVIOAddTraceRecord(dataKVIO, THIS_LOCATION(NULL));
|
|
Packit Service |
310c69 |
int err = dataKVIO->readBlock.status;
|
|
Packit Service |
310c69 |
if (unlikely(err != 0)) {
|
|
Packit Service |
310c69 |
logDebug("%s: err %d", __func__, err);
|
|
Packit Service |
310c69 |
dataKVIO->dataVIO.isDuplicate = false;
|
|
Packit Service |
310c69 |
kvdoEnqueueDataVIOCallback(dataKVIO);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
launchDataKVIOOnCPUQueue(dataKVIO, verifyDuplicationWork, NULL,
|
|
Packit Service |
310c69 |
CPU_Q_ACTION_COMPRESS_BLOCK);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void kvdoVerifyDuplication(DataVIO *dataVIO)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(dataVIO->isDuplicate, "advice to verify must be valid");
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(dataVIO->duplicate.state != MAPPING_STATE_UNMAPPED,
|
|
Packit Service |
310c69 |
"advice to verify must not be a discard");
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(dataVIO->duplicate.pbn != ZERO_BLOCK,
|
|
Packit Service |
310c69 |
"advice to verify must not point to the zero block");
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(!dataVIO->isZeroBlock,
|
|
Packit Service |
310c69 |
"zeroed block should not have advice to verify");
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
TraceLocation location
|
|
Packit Service |
310c69 |
= THIS_LOCATION("verifyDuplication;dup=update(verify);io=verify");
|
|
Packit Service |
310c69 |
dataVIOAddTraceRecord(dataVIO, location);
|
|
Packit Service |
310c69 |
kvdoReadBlock(dataVIO, dataVIO->duplicate.pbn, dataVIO->duplicate.state,
|
|
Packit Service |
310c69 |
BIO_Q_ACTION_VERIFY, verifyReadBlockCallback);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool kvdoCompareDataVIOs(DataVIO *first, DataVIO *second)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
dataVIOAddTraceRecord(second, THIS_LOCATION(NULL));
|
|
Packit Service |
310c69 |
DataKVIO *a = dataVIOAsDataKVIO(first);
|
|
Packit Service |
310c69 |
DataKVIO *b = dataVIOAsDataKVIO(second);
|
|
Packit Service |
310c69 |
return memoryEqual(a->dataBlock, b->dataBlock, VDO_BLOCK_SIZE);
|
|
Packit Service |
310c69 |
}
|