|
Packit Service |
7e342f |
/*
|
|
Packit Service |
7e342f |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
7e342f |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
7e342f |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
7e342f |
* of the License, or (at your option) any later version.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
7e342f |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
7e342f |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
7e342f |
* GNU General Public License for more details.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
7e342f |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
7e342f |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
7e342f |
* 02110-1301, USA.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/instanceNumber.c#1 $
|
|
Packit Service |
7e342f |
*/
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
#include "instanceNumber.h"
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
#include <linux/bitops.h>
|
|
Packit Service |
7e342f |
#include <linux/mutex.h>
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
#include "memoryAlloc.h"
|
|
Packit Service |
7e342f |
#include "numUtils.h"
|
|
Packit Service |
7e342f |
#include "permassert.h"
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/*
|
|
Packit Service |
7e342f |
* Track in-use instance numbers using a flat bit array.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* O(n) run time isn't ideal, but if we have 1000 VDO devices in use
|
|
Packit Service |
7e342f |
* simultaneously we still only need to scan 16 words, so it's not
|
|
Packit Service |
7e342f |
* likely to be a big deal compared to other resource usage.
|
|
Packit Service |
7e342f |
*/
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
enum {
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* This minimum size for the bit array creates a numbering space of 0-999,
|
|
Packit Service |
7e342f |
* which allows successive starts of the same volume to have different
|
|
Packit Service |
7e342f |
* instance numbers in any reasonably-sized test. Changing instances on
|
|
Packit Service |
7e342f |
* restart allows vdoMonReport to detect that the ephemeral stats have reset
|
|
Packit Service |
7e342f |
* to zero.
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
BIT_COUNT_MINIMUM = 1000,
|
|
Packit Service |
7e342f |
/** Grow the bit array by this many bits when needed */
|
|
Packit Service |
7e342f |
BIT_COUNT_INCREMENT = 100,
|
|
Packit Service |
7e342f |
};
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
static struct mutex instanceNumberLock;
|
|
Packit Service |
7e342f |
static unsigned int bitCount;
|
|
Packit Service |
7e342f |
static unsigned long *words;
|
|
Packit Service |
7e342f |
static unsigned int instanceCount;
|
|
Packit Service |
7e342f |
static unsigned int nextInstance;
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* Return the number of bytes needed to store a bit array of the specified
|
|
Packit Service |
7e342f |
* capacity in an array of unsigned longs.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* @param bitCount The number of bits the array must hold
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* @return the number of bytes needed for the array reperesentation
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
static size_t getBitArraySize(unsigned int bitCount)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
// Round up to a multiple of the word size and convert to a byte count.
|
|
Packit Service |
7e342f |
return (computeBucketCount(bitCount, BITS_PER_LONG) * sizeof(unsigned long));
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* Re-allocate the bitmap word array so there will more instance numbers that
|
|
Packit Service |
7e342f |
* can be allocated. Since the array is initially NULL, this also initializes
|
|
Packit Service |
7e342f |
* the array the first time we allocate an instance number.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* @return UDS_SUCCESS or an error code from the allocation
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
static int growBitArray(void)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
unsigned int newCount = maxUInt(bitCount + BIT_COUNT_INCREMENT,
|
|
Packit Service |
7e342f |
BIT_COUNT_MINIMUM);
|
|
Packit Service |
7e342f |
unsigned long *newWords;
|
|
Packit Service |
7e342f |
int result = reallocateMemory(words,
|
|
Packit Service |
7e342f |
getBitArraySize(bitCount),
|
|
Packit Service |
7e342f |
getBitArraySize(newCount),
|
|
Packit Service |
7e342f |
"instance number bit array",
|
|
Packit Service |
7e342f |
&newWords);
|
|
Packit Service |
7e342f |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
7e342f |
return result;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
bitCount = newCount;
|
|
Packit Service |
7e342f |
words = newWords;
|
|
Packit Service |
7e342f |
return UDS_SUCCESS;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static int allocateKVDOInstanceLocked(unsigned int *instancePtr)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
// If there are no unallocated instances, grow the bit array.
|
|
Packit Service |
7e342f |
if (instanceCount >= bitCount) {
|
|
Packit Service |
7e342f |
int result = growBitArray();
|
|
Packit Service |
7e342f |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
7e342f |
return result;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
// There must be a zero bit somewhere now. Find it, starting just after the
|
|
Packit Service |
7e342f |
// last instance allocated.
|
|
Packit Service |
7e342f |
unsigned int instance = find_next_zero_bit(words, bitCount, nextInstance);
|
|
Packit Service |
7e342f |
if (instance >= bitCount) {
|
|
Packit Service |
7e342f |
// Nothing free after nextInstance, so wrap around to instance zero.
|
|
Packit Service |
7e342f |
instance = find_first_zero_bit(words, bitCount);
|
|
Packit Service |
7e342f |
int result = ASSERT(instance < bitCount, "impossibly, no zero bit found");
|
|
Packit Service |
7e342f |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
7e342f |
return result;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
__set_bit(instance, words);
|
|
Packit Service |
7e342f |
instanceCount += 1;
|
|
Packit Service |
7e342f |
nextInstance = instance + 1;
|
|
Packit Service |
7e342f |
*instancePtr = instance;
|
|
Packit Service |
7e342f |
return UDS_SUCCESS;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
int allocateKVDOInstance(unsigned int *instancePtr)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
mutex_lock(&instanceNumberLock);
|
|
Packit Service |
7e342f |
int result = allocateKVDOInstanceLocked(instancePtr);
|
|
Packit Service |
7e342f |
mutex_unlock(&instanceNumberLock);
|
|
Packit Service |
7e342f |
return result;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
void releaseKVDOInstance(unsigned int instance)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
mutex_lock(&instanceNumberLock);
|
|
Packit Service |
7e342f |
if (instance >= bitCount) {
|
|
Packit Service |
7e342f |
ASSERT_LOG_ONLY(false, "instance number %u must be less than bit count %u",
|
|
Packit Service |
7e342f |
instance, bitCount);
|
|
Packit Service |
7e342f |
} else if (test_bit(instance, words) == 0) {
|
|
Packit Service |
7e342f |
ASSERT_LOG_ONLY(false, "instance number %u must be allocated", instance);
|
|
Packit Service |
7e342f |
} else {
|
|
Packit Service |
7e342f |
__clear_bit(instance, words);
|
|
Packit Service |
7e342f |
instanceCount -= 1;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
mutex_unlock(&instanceNumberLock);
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
void initializeInstanceNumberTracking(void)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
mutex_init(&instanceNumberLock);
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
void cleanUpInstanceNumberTracking(void)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
ASSERT_LOG_ONLY(instanceCount == 0,
|
|
Packit Service |
7e342f |
"should have no instance numbers still in use, but have %u",
|
|
Packit Service |
7e342f |
instanceCount);
|
|
Packit Service |
7e342f |
FREE(words);
|
|
Packit Service |
7e342f |
words = NULL;
|
|
Packit Service |
7e342f |
bitCount = 0;
|
|
Packit Service |
7e342f |
instanceCount = 0;
|
|
Packit Service |
7e342f |
nextInstance = 0;
|
|
Packit Service |
7e342f |
mutex_destroy(&instanceNumberLock);
|
|
Packit Service |
7e342f |
}
|