/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* BSD 3 Clause License
*
* Copyright (c) 2007, The Storage Networking Industry Association.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* - Neither the name of The Storage Networking Industry Association (SNIA)
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bitmap.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <tlm.h>
/*
* Hash table size.
*/
/*
* Maximum number of chunk that can be cached.
*/
/*
* Size of bitmap table.
*/
/*
* Bit_MAP Word SIZE. This should be equal to 'sizeof (int)'.
*/
#define BMAP_WSIZE (sizeof (int))
/*
* Bit_MAP Bit Per Word.
*/
/*
* Chunk of bit map in each node.
*/
/*
* Bitmap flags.
*/
/*
* Macros of bitmap flags.
*/
/*
* Calculate the memory size in bytes needed for the specified length
* of bitmap.
*/
/*
* Chunk flags.
*/
/*
* Macros on chunk flags.
*/
/*
* When loading a bitmap chunk, if it is new set the bitmap
* can be set according to the initial value of bits.
* Otherwise, it should be loaded from the file.
*/
#define BMAP_OLD_CHUNK 0
/*
* Each chunk holds the followin information:
* - A flag showing the status of the chunk, like being ditry or not.
* - Its offset in bits from the beginning of the vector.
* - Its length in bits.
* - Its memory length in use in bytes.
* - The bitmap vector.
*
* In addition to the above information, each chunk can be on two lists:
* one the hash list, the other LRU list. The hash list is a MRU list,
* meaning the MRU entry is at the head of the list.
*
* All the chunks are in the LRU list. When a chunk is needed and there is
* no more room for allocating chunks, the first entry of this list is
* reclaimed.
*/
typedef struct dbmap_chunk {
typedef struct dbitmap {
char *bm_fname;
int bm_fd;
} dbitmap_t;
/*
* Disk bitmap table. Upon allocating a dbitmap, one slot
* of this table will be used.
*/
/*
* Each chunk holds the followin information:
* - Its offset in bits from the beginning of the vector.
* - Its length in bits.
* - Its memory length in use in bytes.
* - The bitmap vector.
*
* In addition to the above information, each chunk can be on a list:
* one the hash list. The hash list is a MRU list, meaning that the
* MRU entry is at the head of the list.
*/
typedef struct bmap_chunk {
} bmap_chunk_t;
typedef struct bitmap {
} bitmap_t;
/*
* Statistics gathering structure.
*/
typedef struct bitmap_stats {
/*
* Disk bitmap table. Upon allocating a bitmap, one slot
* of this table will be used.
*/
/*
* Global instance of statistics variable.
*/
/*
* bmd2bmp
*
* Convert bitmap descriptor to bitmap pointer.
*/
static bitmap_t *
{
return (NULL);
}
/*
* bmd_alloc
*
* Allocate a bitmap descriptor. Sets the INUSE flag of the slot.
*/
static int
bmd_alloc(void)
{
int i;
if (!BMAP_IS_INUSE(bmp)) {
return (i);
}
return (-1);
}
/*
* bmd_free
*
* Free a bitmap descriptor. Clears the INUSE flag of the slot.
*/
static void
{
if (bmp)
}
/*
* bmp_set
*
* Generic function to set bit in a chunk. This can set or unset the
* specified bit.
*/
static inline int
{
int rv;
uint_t v;
rv = 0;
} else
return (rv);
}
/*
* bmp_get
*
* Generic function to get bit in a chunk.
*/
static inline int
{
int rv;
} else
return (rv);
}
/*
* bm_chuck_setup
*
* Set up the properties of the new chunk and position it in the hash list.
*/
static bmap_chunk_t *
{
int h;
if (l >= BMAP_CHUNK_BITS) {
} else {
cl = l;
}
if (BMAP_IS_INIT_ONES(bmp))
else
return (cp);
}
/*
* bm_chunk_new
*
* Create a new chunk and keep track of memory used.
*/
static bmap_chunk_t *
{
if (cp) {
} else {
}
}
return (cp);
}
/*
* bm_chunk_alloc
*
* Allocate a chunk and return it. If the cache for the chunks is not
* fully used, a new chunk is created.
*/
static bmap_chunk_t *
{
else
return (cp);
}
/*
* hash_free
*
* Free all chunks on the hash list.
*/
void
{
if (!hp)
return;
while (!TAILQ_EMPTY(hp)) {
}
}
/*
* bm_chunks_free
*
* Release the memory allocated for the chunks.
*/
static void
{
int i;
for (i = 0; i < BMAP_HASH_SIZE; hp++, i++)
}
/*
* bm_chunk_repositions
*
* Re-position the chunk in the MRU hash table.
*/
static void
{
return;
}
}
/*
* bm_chunk_find
*
* Find and return the chunks which holds the specified bit. Allocate
* the chunk if necessary and re-position it in the hash table lists.
*/
static bmap_chunk_t *
{
int h;
if (!bmp)
return (NULL);
return (cp);
}
}
}
/*
* bmp_setval
*
* Set a range of bits in the bitmap specified by the vector.
*/
static int
{
int rv;
return (-EINVAL);
} else {
}
do {
if (!cp)
return (-ERANGE);
if (rv != 0)
return (rv);
}
return (0);
}
/*
* bmp_getval
*
* Get a range of bits in the bitmap specified by the vector.
*/
static int
{
int rv;
return (-EINVAL);
cnt = 0;
*ip = 0;
do {
if (!cp)
return (-ERANGE);
if (rv < 0)
return (rv);
*++ip = 0;
cnt = 0;
}
}
return (0);
}
/*
* hash_init
*
* Initialize the hash table lists head.
*/
static void
{
int i;
for (i = 0; i < BMAP_HASH_SIZE; hp++, i++) {
TAILQ_INIT(hp);
}
}
/*
* bm_alloc
*
* Allocate a bit map and return a handle to it.
*
* The hash table list are empty at this point. They are allocated
* on demand.
*/
int
{
int bmd;
if (len == 0)
return (-1);
if (bmd < 0)
return (bmd);
if (set)
else
return (bmd);
}
/*
* bm_free
*
* Free memory allocated for the bitmap.
*/
int
{
int rv;
rv = 0;
} else
rv = -1;
return (rv);
}
/*
* bm_getiov
*
* Get bits specified by the array of vectors.
*/
int
{
int i;
int rv;
if (!iop)
else if (iop->bmio_iovcnt <= 0)
else {
rv = 0;
if (!vp)
return (-EINVAL);
}
}
return (rv);
}
/*
* bm_setiov
*
* Set bits specified by the array of vectors.
*/
int
{
int i;
int rv;
if (!iop)
else if (iop->bmio_iovcnt <= 0)
else {
rv = 0;
}
return (rv);
}
/*
* bmd2dbmp
*
* Convert bitmap descriptor to bitmap pointer.
*/
static dbitmap_t *
{
return (NULL);
}
/*
* dbmp2bmd
*
* Convert bitmap pointer to bitmap descriptor.
*/
static int
{
int bmd;
bmd = -1;
return (bmd);
}
/*
* dbmd_alloc
*
* Allocate a bitmap descriptor.
* Sets the INUSE flag of the slot.
*/
static int
dbmd_alloc(void)
{
int i;
if (!BMAP_IS_INUSE(bmp)) {
return (i);
}
return (-1);
}
/*
* dbmd_free
*
* Free a bitmap descriptor.
* Clears the INUSE flag of the slot.
*/
static void
{
if (bmp)
}
/*
* dbmp_set
*
* Generic function to set bit in a chunk. This can
* set or unset the specified bit.
*/
static inline int
{
int rv;
uint_t v;
rv = 0;
} else
return (rv);
}
/*
* dbmp_getlen
*
* Get length of the bitmap.
*/
static u_quad_t
{
}
/*
* dbmp_get
*
* Generic function to get bit in a chunk.
*/
static inline int
{
int rv;
} else
return (rv);
}
/*
* dbm_chunk_seek
*
* Seek in the file where the chunk is saved or should be saved.
*/
static int
{
int rv;
if (!bmp)
rv = -1;
else {
}
return (rv);
}
/*
* dbm_chunk_flush
*
* Save a chunk to file.
*/
static int
{
int rv;
rv = -1;
rv = -1;
rv = -1;
else
rv = 0;
return (rv);
}
/*
* dbm_chunk_load
*
* Load a chunk from a file. If the chunk is a new one,
* instead of reading from the disk, the memory for the
* chunk is set to either all zeros or to all ones.
* Otherwise, if the chunk is not a new one, it's read
* from the disk.
*
* The new chunk is positioned in the LRU and hash table
* after its data is ready.
*/
static dbmap_chunk_t *
{
int h;
if (l >= BMAP_CHUNK_BITS) {
} else {
cl = l;
}
if (new == BMAP_NEW_CHUNK) {
if (BMAP_IS_INIT_ONES(bmp))
else
} else { /* BMAP_OLD_CHUNK */
}
if (cp) {
}
return (cp);
}
/*
* dbm_chunk_new
*
* Create a new chunk and keep track of memory used.
*/
static dbmap_chunk_t *
{
if (cp) {
} else
}
return (cp);
}
/*
* dbm_chunk_alloc
*
* Allocate a chunk and return it. If the cache for the
* chunks is not fully used, a new chunk is created.
* Otherwise, the first chunk from the LRU list is reclaimed,
* loaded and returned.
*/
static dbmap_chunk_t *
{
int h;
if (BMAP_CIS_DIRTY(cp))
}
/*
* dbm_chunks_free
*
* Release the memory allocated for the chunks.
*/
static void
{
if (!bmp)
return;
if (!headp)
return;
while (!TAILQ_EMPTY(headp)) {
}
}
/*
* dbm_chunk_reposition
*
* Re-position the chunk in the LRU and the hash table.
*/
static void
{
}
}
}
/*
* dbm_chunk_find
*
* Find and return the chunks which holds the specified bit.
* Allocate the chunk if necessary and re-position it in the
* LRU and hash table lists.
*/
static dbmap_chunk_t *
{
int h;
if (!bmp)
return (NULL);
return (cp);
}
}
}
/*
* dbmp_setval
*
* Set a range of bits in the bitmap specified by the
* vector.
*/
static int
{
int rv;
return (-EINVAL);
} else {
}
do {
if (!cp)
return (-ERANGE);
if (rv != 0)
return (rv);
}
return (0);
}
/*
* dbmp_getval
*
* Get a range of bits in the bitmap specified by the
* vector.
*/
static int
{
int rv;
return (-EINVAL);
cnt = 0;
*ip = 0;
do {
if (!cp)
return (-ERANGE);
if (rv < 0)
return (rv);
*++ip = 0;
cnt = 0;
}
}
return (0);
}
/*
* dbyte_apply_ifset
*
* Apply the function on the set bits of the specified word.
*/
static int
void *arg)
{
int bmd;
int rv;
u_quad_t l;
rv = 0;
l = dbmp_getlen(bmp);
if (b & 1) {
break;
}
b >>= 1;
}
return (rv);
}
/*
* dbm_chunk_apply_ifset
*
* Apply the function on the set bits of the specified chunk.
*/
static int
void *arg)
{
int rv;
uint_t i, m;
u_quad_t q;
rv = 0;
if (*bp) {
if (rv != 0)
break;
}
return (rv);
}
/*
* swfile_trunc
*
* Truncate the rest of the swap file.
*/
static int
{
int rv;
/*
* Get the current offset and truncate whatever is
* after this point.
*/
rv = 0;
rv = -1;
rv = -1;
return (rv);
}
/*
* swfile_init
*
* Initialize the swap file. The necessary disk space is
* reserved by writing to the swap file for swapping the
*/
static int
{
u_quad_t i, n;
n = len / BMAP_CHUNK_BITS;
for (i = 0; i < n; i++)
return (-1);
return (-1);
return (swfile_trunc(fd));
}
/*
* dbm_alloc
*
* Allocate a bit map and return a handle to it.
*
* The swap file is created if it does not exist.
* The file is truncated if it exists and is larger
* than needed amount.
*
* The hash table and LRU list are empty at this point.
*/
int
{
int fd;
int bmd;
return (-1);
/*
* When allocating bitmap, make sure there is enough
* disk space by allocating needed disk space, for
* writing back the dirty chunks when swaping them out.
*/
bmd = dbmd_alloc();
if (bmd < 0)
return (bmd);
bmd = -1;
bmd = -1;
bmd = -1;
bmd = -1;
} else {
if (set)
else
}
return (bmd);
}
/*
* dbm_free
*
* Free memory allocated for the bitmap and remove its swap file.
*/
int
{
int rv;
rv = 0;
} else
rv = -1;
return (rv);
}
/*
* dbm_getlen
*
* Return length of the bitmap.
*/
{
return (dbmp_getlen(bmp));
}
/*
* dbm_set
*
* Set a range of bits.
*/
int
{
}
/*
* dbm_getiov
*
* Get bits specified by the array of vectors.
*/
int
{
int i;
int rv;
if (!iop)
else if (iop->bmio_iovcnt <= 0)
else {
rv = 0;
if (!vp)
return (-EINVAL);
}
}
return (rv);
}
/*
* dbm_setiov
*
* Set bits specified by the array of vectors.
*/
int
{
int i;
int rv;
if (!iop)
else if (iop->bmio_iovcnt <= 0)
else {
rv = 0;
}
return (rv);
}
/*
* dbm_apply_ifset
*
* Call the callback function for each set bit in the bitmap and
* pass the 'arg' and bit number as its argument.
*/
int
{
int rv;
u_quad_t q;
return (-EINVAL);
rv = 0;
if (!cp) {
break;
}
if (rv != 0)
break;
}
return (rv);
}
/*
* bm_set
*
* Set a range of bits.
*/
int
{
}
/*
* bm_get
*
* Get a range of bits.
*/
int
{
}
/*
* bm_getone
*
* Get only one bit.
*/
int
{
uint_t i;
return (i ? 1 : 0);
return (0);
}
/*
* dbm_get
*
* Get a range of bits.
*/
int
{
}
/*
* dbm_getone
*
* Get only one bit.
*/
int
{
uint_t i;
return (i ? 1 : 0);
return (0);
}