|
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/base/vioPool.c#5 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "vioPool.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "logger.h"
|
|
Packit Service |
310c69 |
#include "memoryAlloc.h"
|
|
Packit Service |
310c69 |
#include "permassert.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "constants.h"
|
|
Packit Service |
310c69 |
#include "vio.h"
|
|
Packit Service |
310c69 |
#include "types.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* An VIOPool is a collection of preallocated VIOs.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
struct vioPool {
|
|
Packit Service |
310c69 |
/** The number of objects managed by the pool */
|
|
Packit Service |
310c69 |
size_t size;
|
|
Packit Service |
310c69 |
/** The list of objects which are available */
|
|
Packit Service |
310c69 |
RingNode available;
|
|
Packit Service |
310c69 |
/** The queue of requestors waiting for objects from the pool */
|
|
Packit Service |
310c69 |
WaitQueue waiting;
|
|
Packit Service |
310c69 |
/** The number of objects currently in use */
|
|
Packit Service |
310c69 |
size_t busyCount;
|
|
Packit Service |
310c69 |
/** The list of objects which are in use */
|
|
Packit Service |
310c69 |
RingNode busy;
|
|
Packit Service |
310c69 |
/** The number of requests when no object was available */
|
|
Packit Service |
310c69 |
uint64_t outageCount;
|
|
Packit Service |
310c69 |
/** The ID of the thread on which this pool may be used */
|
|
Packit Service |
310c69 |
ThreadID threadID;
|
|
Packit Service |
310c69 |
/** The buffer backing the pool's VIOs */
|
|
Packit Service |
310c69 |
char *buffer;
|
|
Packit Service |
310c69 |
/** The pool entries */
|
|
Packit Service |
310c69 |
VIOPoolEntry entries[];
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int makeVIOPool(PhysicalLayer *layer,
|
|
Packit Service |
310c69 |
size_t poolSize,
|
|
Packit Service |
310c69 |
ThreadID threadID,
|
|
Packit Service |
310c69 |
VIOConstructor *vioConstructor,
|
|
Packit Service |
310c69 |
void *context,
|
|
Packit Service |
310c69 |
VIOPool **poolPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
VIOPool *pool;
|
|
Packit Service |
310c69 |
int result = ALLOCATE_EXTENDED(VIOPool, poolSize, VIOPoolEntry, __func__,
|
|
Packit Service |
310c69 |
&pool);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
pool->threadID = threadID;
|
|
Packit Service |
310c69 |
initializeRing(&pool->available);
|
|
Packit Service |
310c69 |
initializeRing(&pool->busy);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ALLOCATE(poolSize * VDO_BLOCK_SIZE, char, "VIO pool buffer",
|
|
Packit Service |
310c69 |
&pool->buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
freeVIOPool(&pool);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
char *ptr = pool->buffer;
|
|
Packit Service |
310c69 |
for (size_t i = 0; i < poolSize; i++) {
|
|
Packit Service |
310c69 |
VIOPoolEntry *entry = &pool->entries[i];
|
|
Packit Service |
310c69 |
entry->buffer = ptr;
|
|
Packit Service |
310c69 |
entry->context = context;
|
|
Packit Service |
310c69 |
result = vioConstructor(layer, entry, ptr, &entry->vio);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
freeVIOPool(&pool);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
ptr += VDO_BLOCK_SIZE;
|
|
Packit Service |
310c69 |
initializeRing(&entry->node);
|
|
Packit Service |
310c69 |
pushRingNode(&pool->available, &entry->node);
|
|
Packit Service |
310c69 |
pool->size++;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*poolPtr = pool;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void freeVIOPool(VIOPool **poolPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (*poolPtr == NULL) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Remove all available entries from the object pool.
|
|
Packit Service |
310c69 |
VIOPool *pool = *poolPtr;
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(!hasWaiters(&pool->waiting),
|
|
Packit Service |
310c69 |
"VIO pool must not have any waiters when being freed");
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((pool->busyCount == 0),
|
|
Packit Service |
310c69 |
"VIO pool must not have %zu busy entries when being freed",
|
|
Packit Service |
310c69 |
pool->busyCount);
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(isRingEmpty(&pool->busy),
|
|
Packit Service |
310c69 |
"VIO pool must not have busy entries when being freed");
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
VIOPoolEntry *entry;
|
|
Packit Service |
310c69 |
while ((entry = asVIOPoolEntry(chopRingNode(&pool->available))) != NULL) {
|
|
Packit Service |
310c69 |
freeVIO(&entry->vio);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Make sure every VIOPoolEntry has been removed.
|
|
Packit Service |
310c69 |
for (size_t i = 0; i < pool->size; i++) {
|
|
Packit Service |
310c69 |
VIOPoolEntry *entry = &pool->entries[i];
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(isRingEmpty(&entry->node), "VIO Pool entry still in use:"
|
|
Packit Service |
310c69 |
" VIO is in use for physical block %" PRIu64
|
|
Packit Service |
310c69 |
" for operation %u",
|
|
Packit Service |
310c69 |
entry->vio->physical,
|
|
Packit Service |
310c69 |
entry->vio->operation);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
FREE(pool->buffer);
|
|
Packit Service |
310c69 |
FREE(pool);
|
|
Packit Service |
310c69 |
*poolPtr = NULL;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool isVIOPoolBusy(VIOPool *pool)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (pool->busyCount != 0);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int acquireVIOFromPool(VIOPool *pool, Waiter *waiter)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((pool->threadID == getCallbackThreadID()),
|
|
Packit Service |
310c69 |
"acquire from active VIOPool called from correct thread");
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (isRingEmpty(&pool->available)) {
|
|
Packit Service |
310c69 |
pool->outageCount++;
|
|
Packit Service |
310c69 |
return enqueueWaiter(&pool->waiting, waiter);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
pool->busyCount++;
|
|
Packit Service |
310c69 |
RingNode *entry = chopRingNode(&pool->available);
|
|
Packit Service |
310c69 |
pushRingNode(&pool->busy, entry);
|
|
Packit Service |
310c69 |
(*waiter->callback)(waiter, entry);
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void returnVIOToPool(VIOPool *pool, VIOPoolEntry *entry)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((pool->threadID == getCallbackThreadID()),
|
|
Packit Service |
310c69 |
"vio pool entry returned on same thread as it was acquired");
|
|
Packit Service |
310c69 |
entry->vio->completion.errorHandler = NULL;
|
|
Packit Service |
310c69 |
if (hasWaiters(&pool->waiting)) {
|
|
Packit Service |
310c69 |
notifyNextWaiter(&pool->waiting, NULL, entry);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
pushRingNode(&pool->available, &entry->node);
|
|
Packit Service |
310c69 |
--pool->busyCount;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
uint64_t getVIOPoolOutageCount(VIOPool *pool)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return pool->outageCount;
|
|
Packit Service |
310c69 |
}
|