|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
75d76b |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
75d76b |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
75d76b |
* of the License, or (at your option) any later version.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
75d76b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
75d76b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
75d76b |
* GNU General Public License for more details.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
75d76b |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
75d76b |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
75d76b |
* 02110-1301, USA.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
75d76b |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
75d76b |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
75d76b |
* of the License, or (at your option) any later version.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
75d76b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
75d76b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
75d76b |
* GNU General Public License for more details.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
75d76b |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
75d76b |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
75d76b |
* 02110-1301, USA.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/udsIndex.c#16 $
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "udsIndex.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "logger.h"
|
|
Packit Service |
75d76b |
#include "memoryAlloc.h"
|
|
Packit Service |
75d76b |
#include "murmur/MurmurHash3.h"
|
|
Packit Service |
75d76b |
#include "numeric.h"
|
|
Packit Service |
75d76b |
#include "stringUtils.h"
|
|
Packit Service |
75d76b |
#include "uds-block.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
typedef struct udsAttribute {
|
|
Packit Service |
75d76b |
struct attribute attr;
|
|
Packit Service |
75d76b |
const char *(*showString)(DedupeIndex *);
|
|
Packit Service |
75d76b |
} UDSAttribute;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
enum { UDS_Q_ACTION };
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// These are the values in the atomic dedupeContext.requestState field
|
|
Packit Service |
75d76b |
enum {
|
|
Packit Service |
75d76b |
// The UdsRequest object is not in use.
|
|
Packit Service |
75d76b |
UR_IDLE = 0,
|
|
Packit Service |
75d76b |
// The UdsRequest object is in use, and VDO is waiting for the result.
|
|
Packit Service |
75d76b |
UR_BUSY = 1,
|
|
Packit Service |
75d76b |
// The UdsRequest object is in use, but has timed out.
|
|
Packit Service |
75d76b |
UR_TIMED_OUT = 2,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
typedef enum {
|
|
Packit Service |
75d76b |
// The UDS index is closed
|
|
Packit Service |
75d76b |
IS_CLOSED = 0,
|
|
Packit Service |
75d76b |
// The UDS index session is opening or closing
|
|
Packit Service |
75d76b |
IS_CHANGING = 1,
|
|
Packit Service |
75d76b |
// The UDS index is open. There is a UDS index session.
|
|
Packit Service |
75d76b |
IS_OPENED = 2,
|
|
Packit Service |
75d76b |
} IndexState;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
typedef struct udsIndex {
|
|
Packit Service |
75d76b |
DedupeIndex common;
|
|
Packit Service |
75d76b |
struct kobject dedupeObject;
|
|
Packit Service |
75d76b |
RegisteredThread allocatingThread;
|
|
Packit Service |
75d76b |
char *indexName;
|
|
Packit Service |
75d76b |
UdsConfiguration configuration;
|
|
Packit Service |
75d76b |
struct uds_parameters udsParams;
|
|
Packit Service |
75d76b |
struct uds_index_session *indexSession;
|
|
Packit Service |
75d76b |
atomic_t active;
|
|
Packit Service |
75d76b |
// This spinlock protects the state fields and the starting of dedupe
|
|
Packit Service |
75d76b |
// requests.
|
|
Packit Service |
75d76b |
spinlock_t stateLock;
|
|
Packit Service |
75d76b |
KvdoWorkItem workItem; // protected by stateLock
|
|
Packit Service |
75d76b |
KvdoWorkQueue *udsQueue; // protected by stateLock
|
|
Packit Service |
75d76b |
unsigned int maximum; // protected by stateLock
|
|
Packit Service |
75d76b |
IndexState indexState; // protected by stateLock
|
|
Packit Service |
75d76b |
IndexState indexTarget; // protected by stateLock
|
|
Packit Service |
75d76b |
bool changing; // protected by stateLock
|
|
Packit Service |
75d76b |
bool createFlag; // protected by stateLock
|
|
Packit Service |
75d76b |
bool dedupeFlag; // protected by stateLock
|
|
Packit Service |
75d76b |
bool deduping; // protected by stateLock
|
|
Packit Service |
75d76b |
bool errorFlag; // protected by stateLock
|
|
Packit Service |
75d76b |
bool suspended; // protected by stateLock
|
|
Packit Service |
75d76b |
// This spinlock protects the pending list, the pending flag in each KVIO,
|
|
Packit Service |
75d76b |
// and the timeout list.
|
|
Packit Service |
75d76b |
spinlock_t pendingLock;
|
|
Packit Service |
75d76b |
struct list_head pendingHead; // protected by pendingLock
|
|
Packit Service |
75d76b |
struct timer_list pendingTimer; // protected by pendingLock
|
|
Packit Service |
75d76b |
bool startedTimer; // protected by pendingLock
|
|
Packit Service |
75d76b |
} UDSIndex;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Version 1: user space albireo index (limited to 32 bytes)
|
|
Packit Service |
75d76b |
// Version 2: kernel space albireo index (limited to 16 bytes)
|
|
Packit Service |
75d76b |
enum {
|
|
Packit Service |
75d76b |
UDS_ADVICE_VERSION = 2,
|
|
Packit Service |
75d76b |
// version byte + state byte + 64-bit little-endian PBN
|
|
Packit Service |
75d76b |
UDS_ADVICE_SIZE = 1 + 1 + sizeof(uint64_t),
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// We want to ensure that there is only one copy of the following constants.
|
|
Packit Service |
75d76b |
static const char *CLOSED = "closed";
|
|
Packit Service |
75d76b |
static const char *CLOSING = "closing";
|
|
Packit Service |
75d76b |
static const char *ERROR = "error";
|
|
Packit Service |
75d76b |
static const char *OFFLINE = "offline";
|
|
Packit Service |
75d76b |
static const char *ONLINE = "online";
|
|
Packit Service |
75d76b |
static const char *OPENING = "opening";
|
|
Packit Service |
75d76b |
static const char *SUSPENDED = "suspended";
|
|
Packit Service |
75d76b |
static const char *UNKNOWN = "unknown";
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static const char *indexStateToString(UDSIndex *index, IndexState state)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (index->suspended) {
|
|
Packit Service |
75d76b |
return SUSPENDED;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
switch (state) {
|
|
Packit Service |
75d76b |
case IS_CLOSED:
|
|
Packit Service |
75d76b |
// Closed. The errorFlag tells if it is because of an error.
|
|
Packit Service |
75d76b |
return index->errorFlag ? ERROR : CLOSED;
|
|
Packit Service |
75d76b |
case IS_CHANGING:
|
|
Packit Service |
75d76b |
// The indexTarget tells if we are opening or closing the index.
|
|
Packit Service |
75d76b |
return index->indexTarget == IS_OPENED ? OPENING : CLOSING;
|
|
Packit Service |
75d76b |
case IS_OPENED:
|
|
Packit Service |
75d76b |
// Opened. The dedupeFlag tells if we are online or offline.
|
|
Packit Service |
75d76b |
return index->dedupeFlag ? ONLINE : OFFLINE;
|
|
Packit Service |
75d76b |
default:
|
|
Packit Service |
75d76b |
return UNKNOWN;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Encode VDO duplicate advice into the newMetadata field of a UDS request.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param request The UDS request to receive the encoding
|
|
Packit Service |
75d76b |
* @param advice The advice to encode
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void encodeUDSAdvice(UdsRequest *request, DataLocation advice)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
size_t offset = 0;
|
|
Packit Service |
75d76b |
struct udsChunkData *encoding = &request->newMetadata;
|
|
Packit Service |
75d76b |
encoding->data[offset++] = UDS_ADVICE_VERSION;
|
|
Packit Service |
75d76b |
encoding->data[offset++] = advice.state;
|
|
Packit Service |
75d76b |
encodeUInt64LE(encoding->data, &offset, advice.pbn);
|
|
Packit Service |
75d76b |
BUG_ON(offset != UDS_ADVICE_SIZE);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Decode VDO duplicate advice from the oldMetadata field of a UDS request.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param request The UDS request containing the encoding
|
|
Packit Service |
75d76b |
* @param advice The DataLocation to receive the decoded advice
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return true if valid advice was found and decoded
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static bool decodeUDSAdvice(const UdsRequest *request, DataLocation *advice)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if ((request->status != UDS_SUCCESS) || !request->found) {
|
|
Packit Service |
75d76b |
return false;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
size_t offset = 0;
|
|
Packit Service |
75d76b |
const struct udsChunkData *encoding = &request->oldMetadata;
|
|
Packit Service |
75d76b |
byte version = encoding->data[offset++];
|
|
Packit Service |
75d76b |
if (version != UDS_ADVICE_VERSION) {
|
|
Packit Service |
75d76b |
logError("invalid UDS advice version code %u", version);
|
|
Packit Service |
75d76b |
return false;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
advice->state = encoding->data[offset++];
|
|
Packit Service |
75d76b |
decodeUInt64LE(encoding->data, &offset, &advice->pbn);
|
|
Packit Service |
75d76b |
BUG_ON(offset != UDS_ADVICE_SIZE);
|
|
Packit Service |
75d76b |
return true;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void finishIndexOperation(UdsRequest *udsRequest)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
DataKVIO *dataKVIO = container_of(udsRequest, DataKVIO,
|
|
Packit Service |
75d76b |
dedupeContext.udsRequest);
|
|
Packit Service |
75d76b |
DedupeContext *dedupeContext = &dataKVIO->dedupeContext;
|
|
Packit Service |
75d76b |
if (compareAndSwap32(&dedupeContext->requestState, UR_BUSY, UR_IDLE)) {
|
|
Packit Service |
75d76b |
KVIO *kvio = dataKVIOAsKVIO(dataKVIO);
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(kvio->layer->dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
spin_lock_bh(&index->pendingLock);
|
|
Packit Service |
75d76b |
if (dedupeContext->isPending) {
|
|
Packit Service |
75d76b |
list_del(&dedupeContext->pendingList);
|
|
Packit Service |
75d76b |
dedupeContext->isPending = false;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
spin_unlock_bh(&index->pendingLock);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
dedupeContext->status = udsRequest->status;
|
|
Packit Service |
75d76b |
if ((udsRequest->type == UDS_POST) || (udsRequest->type == UDS_QUERY)) {
|
|
Packit Service |
75d76b |
DataLocation advice;
|
|
Packit Service |
75d76b |
if (decodeUDSAdvice(udsRequest, &advice)) {
|
|
Packit Service |
75d76b |
setDedupeAdvice(dedupeContext, &advice);
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
setDedupeAdvice(dedupeContext, NULL);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
invokeDedupeCallback(dataKVIO);
|
|
Packit Service |
75d76b |
atomic_dec(&index->active);
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
compareAndSwap32(&dedupeContext->requestState, UR_TIMED_OUT, UR_IDLE);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void startExpirationTimer(UDSIndex *index, DataKVIO *dataKVIO)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (!index->startedTimer) {
|
|
Packit Service |
75d76b |
index->startedTimer = true;
|
|
Packit Service |
75d76b |
mod_timer(&index->pendingTimer,
|
|
Packit Service |
75d76b |
getAlbireoTimeout(dataKVIO->dedupeContext.submissionTime));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void startIndexOperation(KvdoWorkItem *item)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
KVIO *kvio = workItemAsKVIO(item);
|
|
Packit Service |
75d76b |
DataKVIO *dataKVIO = kvioAsDataKVIO(kvio);
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(kvio->layer->dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
DedupeContext *dedupeContext = &dataKVIO->dedupeContext;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
spin_lock_bh(&index->pendingLock);
|
|
Packit Service |
75d76b |
list_add_tail(&dedupeContext->pendingList, &index->pendingHead);
|
|
Packit Service |
75d76b |
dedupeContext->isPending = true;
|
|
Packit Service |
75d76b |
startExpirationTimer(index, dataKVIO);
|
|
Packit Service |
75d76b |
spin_unlock_bh(&index->pendingLock);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
UdsRequest *udsRequest = &dedupeContext->udsRequest;
|
|
Packit Service |
75d76b |
int status = udsStartChunkOperation(udsRequest);
|
|
Packit Service |
75d76b |
if (status != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
udsRequest->status = status;
|
|
Packit Service |
75d76b |
finishIndexOperation(udsRequest);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
|
|
Packit Service |
75d76b |
static void timeoutIndexOperations(struct timer_list *t)
|
|
Packit Service |
75d76b |
#else
|
|
Packit Service |
75d76b |
static void timeoutIndexOperations(unsigned long arg)
|
|
Packit Service |
75d76b |
#endif
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
|
|
Packit Service |
75d76b |
UDSIndex *index = from_timer(index, t, pendingTimer);
|
|
Packit Service |
75d76b |
#else
|
|
Packit Service |
75d76b |
UDSIndex *index = (UDSIndex *) arg;
|
|
Packit Service |
75d76b |
#endif
|
|
Packit Service |
75d76b |
LIST_HEAD(expiredHead);
|
|
Packit Service |
75d76b |
uint64_t timeoutJiffies = msecs_to_jiffies(albireoTimeoutInterval);
|
|
Packit Service |
75d76b |
unsigned long earliestSubmissionAllowed = jiffies - timeoutJiffies;
|
|
Packit Service |
75d76b |
spin_lock_bh(&index->pendingLock);
|
|
Packit Service |
75d76b |
index->startedTimer = false;
|
|
Packit Service |
75d76b |
while (!list_empty(&index->pendingHead)) {
|
|
Packit Service |
75d76b |
DataKVIO *dataKVIO = list_first_entry(&index->pendingHead, DataKVIO,
|
|
Packit Service |
75d76b |
dedupeContext.pendingList);
|
|
Packit Service |
75d76b |
DedupeContext *dedupeContext = &dataKVIO->dedupeContext;
|
|
Packit Service |
75d76b |
if (earliestSubmissionAllowed <= dedupeContext->submissionTime) {
|
|
Packit Service |
75d76b |
startExpirationTimer(index, dataKVIO);
|
|
Packit Service |
75d76b |
break;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
list_del(&dedupeContext->pendingList);
|
|
Packit Service |
75d76b |
dedupeContext->isPending = false;
|
|
Packit Service |
75d76b |
list_add_tail(&dedupeContext->pendingList, &expiredHead);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
spin_unlock_bh(&index->pendingLock);
|
|
Packit Service |
75d76b |
while (!list_empty(&expiredHead)) {
|
|
Packit Service |
75d76b |
DataKVIO *dataKVIO = list_first_entry(&expiredHead, DataKVIO,
|
|
Packit Service |
75d76b |
dedupeContext.pendingList);
|
|
Packit Service |
75d76b |
DedupeContext *dedupeContext = &dataKVIO->dedupeContext;
|
|
Packit Service |
75d76b |
list_del(&dedupeContext->pendingList);
|
|
Packit Service |
75d76b |
if (compareAndSwap32(&dedupeContext->requestState,
|
|
Packit Service |
75d76b |
UR_BUSY, UR_TIMED_OUT)) {
|
|
Packit Service |
75d76b |
dedupeContext->status = ETIMEDOUT;
|
|
Packit Service |
75d76b |
invokeDedupeCallback(dataKVIO);
|
|
Packit Service |
75d76b |
atomic_dec(&index->active);
|
|
Packit Service |
75d76b |
kvdoReportDedupeTimeout(dataKVIOAsKVIO(dataKVIO)->layer, 1);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void enqueueIndexOperation(DataKVIO *dataKVIO,
|
|
Packit Service |
75d76b |
UdsCallbackType operation)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
KVIO *kvio = dataKVIOAsKVIO(dataKVIO);
|
|
Packit Service |
75d76b |
DedupeContext *dedupeContext = &dataKVIO->dedupeContext;
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(kvio->layer->dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
dedupeContext->status = UDS_SUCCESS;
|
|
Packit Service |
75d76b |
dedupeContext->submissionTime = jiffies;
|
|
Packit Service |
75d76b |
if (compareAndSwap32(&dedupeContext->requestState, UR_IDLE, UR_BUSY)) {
|
|
Packit Service |
75d76b |
UdsRequest *udsRequest = &dataKVIO->dedupeContext.udsRequest;
|
|
Packit Service |
75d76b |
udsRequest->chunkName = *dedupeContext->chunkName;
|
|
Packit Service |
75d76b |
udsRequest->callback = finishIndexOperation;
|
|
Packit Service |
75d76b |
udsRequest->session = index->indexSession;
|
|
Packit Service |
75d76b |
udsRequest->type = operation;
|
|
Packit Service |
75d76b |
udsRequest->update = true;
|
|
Packit Service |
75d76b |
if ((operation == UDS_POST) || (operation == UDS_UPDATE)) {
|
|
Packit Service |
75d76b |
encodeUDSAdvice(udsRequest, getDedupeAdvice(dedupeContext));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
setupWorkItem(&kvio->enqueueable.workItem, startIndexOperation, NULL,
|
|
Packit Service |
75d76b |
UDS_Q_ACTION);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
if (index->deduping) {
|
|
Packit Service |
75d76b |
enqueueWorkQueue(index->udsQueue, &kvio->enqueueable.workItem);
|
|
Packit Service |
75d76b |
unsigned int active = atomic_inc_return(&index->active);
|
|
Packit Service |
75d76b |
if (active > index->maximum) {
|
|
Packit Service |
75d76b |
index->maximum = active;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
kvio = NULL;
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
atomicStore32(&dedupeContext->requestState, UR_IDLE);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
// A previous user of the KVIO had a dedupe timeout
|
|
Packit Service |
75d76b |
// and its request is still outstanding.
|
|
Packit Service |
75d76b |
atomic64_inc(&kvio->layer->dedupeContextBusy);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
if (kvio != NULL) {
|
|
Packit Service |
75d76b |
invokeDedupeCallback(dataKVIO);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void closeIndex(UDSIndex *index)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
// Change the index state so that getIndexStatistics will not try to
|
|
Packit Service |
75d76b |
// use the index session we are closing.
|
|
Packit Service |
75d76b |
index->indexState = IS_CHANGING;
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
int result = udsCloseIndex(index->indexSession);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
logErrorWithStringError(result, "Error closing index %s",
|
|
Packit Service |
75d76b |
index->indexName);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
index->indexState = IS_CLOSED;
|
|
Packit Service |
75d76b |
index->errorFlag |= result != UDS_SUCCESS;
|
|
Packit Service |
75d76b |
// ASSERTION: We leave in IS_CLOSED state.
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void openIndex(UDSIndex *index)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
// ASSERTION: We enter in IS_CLOSED state.
|
|
Packit Service |
75d76b |
bool createFlag = index->createFlag;
|
|
Packit Service |
75d76b |
index->createFlag = false;
|
|
Packit Service |
75d76b |
// Change the index state so that the it will be reported to the outside
|
|
Packit Service |
75d76b |
// world as "opening".
|
|
Packit Service |
75d76b |
index->indexState = IS_CHANGING;
|
|
Packit Service |
75d76b |
index->errorFlag = false;
|
|
Packit Service |
75d76b |
// Open the index session, while not holding the stateLock
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
int result = udsOpenIndex(createFlag ? UDS_CREATE : UDS_LOAD,
|
|
Packit Service |
75d76b |
index->indexName, &index->udsParams,
|
|
Packit Service |
75d76b |
index->configuration, index->indexSession);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
logErrorWithStringError(result, "Error opening index %s",
|
|
Packit Service |
75d76b |
index->indexName);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
if (!createFlag) {
|
|
Packit Service |
75d76b |
switch (result) {
|
|
Packit Service |
75d76b |
case UDS_CORRUPT_COMPONENT:
|
|
Packit Service |
75d76b |
case UDS_NO_INDEX:
|
|
Packit Service |
75d76b |
// Either there is no index, or there is no way we can recover the index.
|
|
Packit Service |
75d76b |
// We will be called again and try to create a new index.
|
|
Packit Service |
75d76b |
index->indexState = IS_CLOSED;
|
|
Packit Service |
75d76b |
index->createFlag = true;
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
default:
|
|
Packit Service |
75d76b |
break;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
if (result == UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
index->indexState = IS_OPENED;
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
index->indexState = IS_CLOSED;
|
|
Packit Service |
75d76b |
index->indexTarget = IS_CLOSED;
|
|
Packit Service |
75d76b |
index->errorFlag = true;
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
logInfo("Setting UDS index target state to error");
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
// ASSERTION: On success, we leave in IS_OPEN state.
|
|
Packit Service |
75d76b |
// ASSERTION: On failure, we leave in IS_CLOSED state.
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void changeDedupeState(KvdoWorkItem *item)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(item, UDSIndex, workItem);
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
// Loop until the index is in the target state and the create flag is
|
|
Packit Service |
75d76b |
// clear.
|
|
Packit Service |
75d76b |
while (!index->suspended &&
|
|
Packit Service |
75d76b |
((index->indexState != index->indexTarget) ||
|
|
Packit Service |
75d76b |
index->createFlag)) {
|
|
Packit Service |
75d76b |
if (index->indexState == IS_OPENED) {
|
|
Packit Service |
75d76b |
closeIndex(index);
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
openIndex(index);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
index->changing = false;
|
|
Packit Service |
75d76b |
index->deduping = index->dedupeFlag && (index->indexState == IS_OPENED);
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void launchDedupeStateChange(UDSIndex *index)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
// ASSERTION: We enter with the state_lock held.
|
|
Packit Service |
75d76b |
if (index->changing || index->suspended) {
|
|
Packit Service |
75d76b |
// Either a change is already in progress, or changes are
|
|
Packit Service |
75d76b |
// not allowed.
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (index->createFlag ||
|
|
Packit Service |
75d76b |
(index->indexState != index->indexTarget)) {
|
|
Packit Service |
75d76b |
index->changing = true;
|
|
Packit Service |
75d76b |
index->deduping = false;
|
|
Packit Service |
75d76b |
setupWorkItem(&index->workItem,
|
|
Packit Service |
75d76b |
changeDedupeState,
|
|
Packit Service |
75d76b |
NULL,
|
|
Packit Service |
75d76b |
UDS_Q_ACTION);
|
|
Packit Service |
75d76b |
enqueueWorkQueue(index->udsQueue, &index->workItem);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Online vs. offline changes happen immediately
|
|
Packit Service |
75d76b |
index->deduping = (index->dedupeFlag && !index->suspended &&
|
|
Packit Service |
75d76b |
(index->indexState == IS_OPENED));
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// ASSERTION: We exit with the state_lock held.
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void setTargetState(UDSIndex *index,
|
|
Packit Service |
75d76b |
IndexState target,
|
|
Packit Service |
75d76b |
bool changeDedupe,
|
|
Packit Service |
75d76b |
bool dedupe,
|
|
Packit Service |
75d76b |
bool setCreate)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
const char *oldState = indexStateToString(index, index->indexTarget);
|
|
Packit Service |
75d76b |
if (changeDedupe) {
|
|
Packit Service |
75d76b |
index->dedupeFlag = dedupe;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
if (setCreate) {
|
|
Packit Service |
75d76b |
index->createFlag = true;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
index->indexTarget = target;
|
|
Packit Service |
75d76b |
launchDedupeStateChange(index);
|
|
Packit Service |
75d76b |
const char *newState = indexStateToString(index, index->indexTarget);
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
if (oldState != newState) {
|
|
Packit Service |
75d76b |
logInfo("Setting UDS index target state to %s", newState);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void suspendUDSIndex(DedupeIndex *dedupeIndex, bool saveFlag)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
index->suspended = true;
|
|
Packit Service |
75d76b |
IndexState indexState = index->indexState;
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
if (indexState != IS_CLOSED) {
|
|
Packit Service |
75d76b |
int result = udsSuspendIndexSession(index->indexSession, saveFlag);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
logErrorWithStringError(result, "Error suspending dedupe index");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void resumeUDSIndex(DedupeIndex *dedupeIndex)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
int result = udsResumeIndexSession(index->indexSession);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
logErrorWithStringError(result, "Error resuming dedupe index");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
index->suspended = false;
|
|
Packit Service |
75d76b |
launchDedupeStateChange(index);
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void dumpUDSIndex(DedupeIndex *dedupeIndex, bool showQueue)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
const char *state = indexStateToString(index, index->indexState);
|
|
Packit Service |
75d76b |
const char *target = (index->changing
|
|
Packit Service |
75d76b |
? indexStateToString(index, index->indexTarget)
|
|
Packit Service |
75d76b |
: NULL);
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
logInfo("UDS index: state: %s", state);
|
|
Packit Service |
75d76b |
if (target != NULL) {
|
|
Packit Service |
75d76b |
logInfo("UDS index: changing to state: %s", target);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
if (showQueue) {
|
|
Packit Service |
75d76b |
dumpWorkQueue(index->udsQueue);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void finishUDSIndex(DedupeIndex *dedupeIndex)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
setTargetState(index, IS_CLOSED, false, false, false);
|
|
Packit Service |
75d76b |
udsDestroyIndexSession(index->indexSession);
|
|
Packit Service |
75d76b |
finishWorkQueue(index->udsQueue);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void freeUDSIndex(DedupeIndex *dedupeIndex)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
freeWorkQueue(&index->udsQueue);
|
|
Packit Service |
75d76b |
spin_lock_bh(&index->pendingLock);
|
|
Packit Service |
75d76b |
if (index->startedTimer) {
|
|
Packit Service |
75d76b |
del_timer_sync(&index->pendingTimer);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
spin_unlock_bh(&index->pendingLock);
|
|
Packit Service |
75d76b |
kobject_put(&index->dedupeObject);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static const char *getUDSStateName(DedupeIndex *dedupeIndex)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
const char *state = indexStateToString(index, index->indexState);
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
return state;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void getUDSStatistics(DedupeIndex *dedupeIndex, IndexStatistics *stats)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
spin_lock(&index->stateLock);
|
|
Packit Service |
75d76b |
IndexState indexState = index->indexState;
|
|
Packit Service |
75d76b |
stats->maxDedupeQueries = index->maximum;
|
|
Packit Service |
75d76b |
spin_unlock(&index->stateLock);
|
|
Packit Service |
75d76b |
stats->currDedupeQueries = atomic_read(&index->active);
|
|
Packit Service |
75d76b |
if (indexState == IS_OPENED) {
|
|
Packit Service |
75d76b |
UdsIndexStats indexStats;
|
|
Packit Service |
75d76b |
int result = udsGetIndexStats(index->indexSession, &indexStats);
|
|
Packit Service |
75d76b |
if (result == UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
stats->entriesIndexed = indexStats.entriesIndexed;
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
logErrorWithStringError(result, "Error reading index stats");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
UdsContextStats contextStats;
|
|
Packit Service |
75d76b |
result = udsGetIndexSessionStats(index->indexSession, &contextStats);
|
|
Packit Service |
75d76b |
if (result == UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
stats->postsFound = contextStats.postsFound;
|
|
Packit Service |
75d76b |
stats->postsNotFound = contextStats.postsNotFound;
|
|
Packit Service |
75d76b |
stats->queriesFound = contextStats.queriesFound;
|
|
Packit Service |
75d76b |
stats->queriesNotFound = contextStats.queriesNotFound;
|
|
Packit Service |
75d76b |
stats->updatesFound = contextStats.updatesFound;
|
|
Packit Service |
75d76b |
stats->updatesNotFound = contextStats.updatesNotFound;
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
logErrorWithStringError(result, "Error reading context stats");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static int processMessage(DedupeIndex *dedupeIndex, const char *name)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
if (strcasecmp(name, "index-close") == 0) {
|
|
Packit Service |
75d76b |
setTargetState(index, IS_CLOSED, false, false, false);
|
|
Packit Service |
75d76b |
return 0;
|
|
Packit Service |
75d76b |
} else if (strcasecmp(name, "index-create") == 0) {
|
|
Packit Service |
75d76b |
setTargetState(index, IS_OPENED, false, false, true);
|
|
Packit Service |
75d76b |
return 0;
|
|
Packit Service |
75d76b |
} else if (strcasecmp(name, "index-disable") == 0) {
|
|
Packit Service |
75d76b |
setTargetState(index, IS_OPENED, true, false, false);
|
|
Packit Service |
75d76b |
return 0;
|
|
Packit Service |
75d76b |
} else if (strcasecmp(name, "index-enable") == 0) {
|
|
Packit Service |
75d76b |
setTargetState(index, IS_OPENED, true, true, false);
|
|
Packit Service |
75d76b |
return 0;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
return -EINVAL;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void udsPost(DataKVIO *dataKVIO)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
enqueueIndexOperation(dataKVIO, UDS_POST);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void udsQuery(DataKVIO *dataKVIO)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
enqueueIndexOperation(dataKVIO, UDS_QUERY);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void startUDSIndex(DedupeIndex *dedupeIndex, bool createFlag)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
setTargetState(index, IS_OPENED, true, true, createFlag);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void stopUDSIndex(DedupeIndex *dedupeIndex)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(dedupeIndex, UDSIndex, common);
|
|
Packit Service |
75d76b |
setTargetState(index, IS_CLOSED, false, false, false);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void udsUpdate(DataKVIO *dataKVIO)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
enqueueIndexOperation(dataKVIO, UDS_UPDATE);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void dedupeKobjRelease(struct kobject *kobj)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(kobj, UDSIndex, dedupeObject);
|
|
Packit Service |
75d76b |
udsFreeConfiguration(index->configuration);
|
|
Packit Service |
75d76b |
FREE(index->indexName);
|
|
Packit Service |
75d76b |
FREE(index);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static ssize_t dedupeStatusShow(struct kobject *kobj,
|
|
Packit Service |
75d76b |
struct attribute *attr,
|
|
Packit Service |
75d76b |
char *buf)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSAttribute *ua = container_of(attr, UDSAttribute, attr);
|
|
Packit Service |
75d76b |
UDSIndex *index = container_of(kobj, UDSIndex, dedupeObject);
|
|
Packit Service |
75d76b |
if (ua->showString != NULL) {
|
|
Packit Service |
75d76b |
return sprintf(buf, "%s\n", ua->showString(&index->common));
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
return -EINVAL;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static ssize_t dedupeStatusStore(struct kobject *kobj,
|
|
Packit Service |
75d76b |
struct attribute *attr,
|
|
Packit Service |
75d76b |
const char *buf,
|
|
Packit Service |
75d76b |
size_t length)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return -EINVAL;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
static struct sysfs_ops dedupeSysfsOps = {
|
|
Packit Service |
75d76b |
.show = dedupeStatusShow,
|
|
Packit Service |
75d76b |
.store = dedupeStatusStore,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
static UDSAttribute dedupeStatusAttribute = {
|
|
Packit Service |
75d76b |
.attr = {.name = "status", .mode = 0444, },
|
|
Packit Service |
75d76b |
.showString = getUDSStateName,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
static struct attribute *dedupeAttributes[] = {
|
|
Packit Service |
75d76b |
&dedupeStatusAttribute.attr,
|
|
Packit Service |
75d76b |
NULL,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
static struct kobj_type dedupeKobjType = {
|
|
Packit Service |
75d76b |
.release = dedupeKobjRelease,
|
|
Packit Service |
75d76b |
.sysfs_ops = &dedupeSysfsOps,
|
|
Packit Service |
75d76b |
.default_attrs = dedupeAttributes,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void startUDSQueue(void *ptr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* Allow the UDS dedupe worker thread to do memory allocations. It will
|
|
Packit Service |
75d76b |
* only do allocations during the UDS calls that open or close an index,
|
|
Packit Service |
75d76b |
* but those allocations can safely sleep while reserving a large amount
|
|
Packit Service |
75d76b |
* of memory. We could use an allocationsAllowed boolean (like the base
|
|
Packit Service |
75d76b |
* threads do), but it would be an unnecessary embellishment.
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
UDSIndex *index = ptr;
|
|
Packit Service |
75d76b |
registerAllocatingThread(&index->allocatingThread, NULL);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
static void finishUDSQueue(void *ptr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
unregisterAllocatingThread();
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*****************************************************************************/
|
|
Packit Service |
75d76b |
int makeUDSIndex(KernelLayer *layer, DedupeIndex **indexPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UDSIndex *index;
|
|
Packit Service |
75d76b |
int result = ALLOCATE(1, UDSIndex, "UDS index data", &index);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = allocSprintf("index name", &index->indexName,
|
|
Packit Service |
75d76b |
"dev=%s offset=4096 size=%llu",
|
|
Packit Service |
75d76b |
layer->deviceConfig->parentDeviceName,
|
|
Packit Service |
75d76b |
getIndexRegionSize(layer->geometry) * VDO_BLOCK_SIZE);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
logError("Creating index name failed (%d)", result);
|
|
Packit Service |
75d76b |
FREE(index);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
index->udsParams = (struct uds_parameters) UDS_PARAMETERS_INITIALIZER;
|
|
Packit Service |
75d76b |
indexConfigToUdsParameters(&layer->geometry.indexConfig, &index->udsParams);
|
|
Packit Service |
75d76b |
result = indexConfigToUdsConfiguration(&layer->geometry.indexConfig,
|
|
Packit Service |
75d76b |
&index->configuration);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
FREE(index->indexName);
|
|
Packit Service |
75d76b |
FREE(index);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
udsConfigurationSetNonce(index->configuration,
|
|
Packit Service |
75d76b |
(UdsNonce) layer->geometry.nonce);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = udsCreateIndexSession(&index->indexSession);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
udsFreeConfiguration(index->configuration);
|
|
Packit Service |
75d76b |
FREE(index->indexName);
|
|
Packit Service |
75d76b |
FREE(index);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
static const KvdoWorkQueueType udsQueueType = {
|
|
Packit Service |
75d76b |
.start = startUDSQueue,
|
|
Packit Service |
75d76b |
.finish = finishUDSQueue,
|
|
Packit Service |
75d76b |
.actionTable = {
|
|
Packit Service |
75d76b |
{ .name = "uds_action", .code = UDS_Q_ACTION, .priority = 0 },
|
|
Packit Service |
75d76b |
},
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
result = makeWorkQueue(layer->threadNamePrefix, "dedupeQ",
|
|
Packit Service |
75d76b |
&layer->wqDirectory, layer, index, &udsQueueType, 1,
|
|
Packit Service |
75d76b |
&index->udsQueue);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
logError("UDS index queue initialization failed (%d)", result);
|
|
Packit Service |
75d76b |
udsDestroyIndexSession(index->indexSession);
|
|
Packit Service |
75d76b |
udsFreeConfiguration(index->configuration);
|
|
Packit Service |
75d76b |
FREE(index->indexName);
|
|
Packit Service |
75d76b |
FREE(index);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
kobject_init(&index->dedupeObject, &dedupeKobjType);
|
|
Packit Service |
75d76b |
result = kobject_add(&index->dedupeObject, &layer->kobj, "dedupe");
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeWorkQueue(&index->udsQueue);
|
|
Packit Service |
75d76b |
udsDestroyIndexSession(index->indexSession);
|
|
Packit Service |
75d76b |
udsFreeConfiguration(index->configuration);
|
|
Packit Service |
75d76b |
FREE(index->indexName);
|
|
Packit Service |
75d76b |
FREE(index);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
index->common.dump = dumpUDSIndex;
|
|
Packit Service |
75d76b |
index->common.free = freeUDSIndex;
|
|
Packit Service |
75d76b |
index->common.getDedupeStateName = getUDSStateName;
|
|
Packit Service |
75d76b |
index->common.getStatistics = getUDSStatistics;
|
|
Packit Service |
75d76b |
index->common.message = processMessage;
|
|
Packit Service |
75d76b |
index->common.post = udsPost;
|
|
Packit Service |
75d76b |
index->common.query = udsQuery;
|
|
Packit Service |
75d76b |
index->common.resume = resumeUDSIndex;
|
|
Packit Service |
75d76b |
index->common.start = startUDSIndex;
|
|
Packit Service |
75d76b |
index->common.stop = stopUDSIndex;
|
|
Packit Service |
75d76b |
index->common.suspend = suspendUDSIndex;
|
|
Packit Service |
75d76b |
index->common.finish = finishUDSIndex;
|
|
Packit Service |
75d76b |
index->common.update = udsUpdate;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
INIT_LIST_HEAD(&index->pendingHead);
|
|
Packit Service |
75d76b |
spin_lock_init(&index->pendingLock);
|
|
Packit Service |
75d76b |
spin_lock_init(&index->stateLock);
|
|
Packit Service |
75d76b |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
|
|
Packit Service |
75d76b |
timer_setup(&index->pendingTimer, timeoutIndexOperations, 0);
|
|
Packit Service |
75d76b |
#else
|
|
Packit Service |
75d76b |
setup_timer(&index->pendingTimer, timeoutIndexOperations,
|
|
Packit Service |
75d76b |
(unsigned long) index);
|
|
Packit Service |
75d76b |
#endif
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*indexPtr = &index->common;
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|