Blame source/vdo/kernel/instanceNumber.c

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
}