Revert "ramzswap driver"

This reverts commit b675d5e9dd.
This commit is contained in:
Matt Sealey
2010-09-10 10:50:50 -05:00
parent eca81f9e46
commit 2d252c60b2
11 changed files with 0 additions and 2337 deletions

View File

@@ -125,7 +125,5 @@ source "drivers/staging/pata_rdc/Kconfig"
source "drivers/staging/udlfb/Kconfig"
source "drivers/staging/ramzswap/Kconfig"
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING

View File

@@ -1,21 +0,0 @@
config RAMZSWAP
tristate "Compressed in-memory swap device (ramzswap)"
depends on SWAP
select LZO_COMPRESS
select LZO_DECOMPRESS
default n
help
Creates virtual block devices which can be used (only) as a swap
disks. Pages swapped to these disks are compressed and stored in
memory itself.
See ramzswap.txt for more information.
Project home: http://compcache.googlecode.com/
config RAMZSWAP_STATS
bool "Enable ramzswap stats"
depends on RAMZSWAP
default y
help
Enable statistics collection for ramzswap. This adds only a minimal
overhead. In unsure, say Y.

View File

@@ -1,3 +0,0 @@
ramzswap-objs := ramzswap_drv.o xvmalloc.o
obj-$(CONFIG_RAMZSWAP) += ramzswap.o

View File

@@ -1,5 +0,0 @@
TODO:
- Add support for swap notifiers
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
Nitin Gupta <ngupta@vflare.org>

View File

@@ -1,51 +0,0 @@
ramzswap: Compressed RAM based swap device
-------------------------------------------
Project home: http://compcache.googlecode.com/
* Introduction
It creates RAM based block devices which can be used (only) as swap disks.
Pages swapped to these devices are compressed and stored in memory itself.
See project home for use cases, performance numbers and a lot more.
Individual ramzswap devices are configured and initialized using rzscontrol
userspace utility as shown in examples below. See rzscontrol man page for more
details.
* Usage
Following shows a typical sequence of steps for using ramzswap.
1) Load Modules:
modprobe ramzswap num_devices=4
This creates 4 (uninitialized) devices: /dev/ramzswap{0,1,2,3}
(num_devices parameter is optional. Default: 1)
2) Initialize:
Use rzscontrol utility to configure and initialize individual
ramzswap devices. Example:
rzscontrol /dev/ramzswap2 --init # uses default value of disksize_kb
*See rzscontrol man page for more details and examples*
3) Activate:
swapon /dev/ramzswap2 # or any other initialized ramzswap device
4) Stats:
rzscontrol /dev/ramzswap2 --stats
5) Deactivate:
swapoff /dev/ramzswap2
6) Reset:
rzscontrol /dev/ramzswap2 --reset
(This frees all the memory allocated for this device).
Please report any problems at:
- Mailing list: linux-mm-cc at laptop dot org
- Issue tracker: http://code.google.com/p/compcache/issues/list
Nitin Gupta
ngupta@vflare.org

File diff suppressed because it is too large Load Diff

View File

@@ -1,171 +0,0 @@
/*
* Compressed RAM based swap device
*
* Copyright (C) 2008, 2009 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
*
* Released under the terms of 3-clause BSD License
* Released under the terms of GNU General Public License Version 2.0
*
* Project home: http://compcache.googlecode.com
*/
#ifndef _RAMZSWAP_DRV_H_
#define _RAMZSWAP_DRV_H_
#include "ramzswap_ioctl.h"
#include "xvmalloc.h"
/*
* Some arbitrary value. This is just to catch
* invalid value for num_devices module parameter.
*/
static const unsigned max_num_devices = 32;
/*
* Stored at beginning of each compressed object.
*
* It stores back-reference to table entry which points to this
* object. This is required to support memory defragmentation or
* migrating compressed pages to backing swap disk.
*/
struct zobj_header {
#if 0
u32 table_idx;
#endif
};
/*-- Configurable parameters */
/* Default ramzswap disk size: 25% of total RAM */
static const unsigned default_disksize_perc_ram = 25;
static const unsigned default_memlimit_perc_ram = 15;
/*
* Max compressed page size when backing device is provided.
* Pages that compress to size greater than this are sent to
* physical swap disk.
*/
static const unsigned max_zpage_size_bdev = PAGE_SIZE / 2;
/*
* Max compressed page size when there is no backing dev.
* Pages that compress to size greater than this are stored
* uncompressed in memory.
*/
static const unsigned max_zpage_size_nobdev = PAGE_SIZE / 4 * 3;
/*
* NOTE: max_zpage_size_{bdev,nobdev} sizes must be
* less than or equal to:
* XV_MAX_ALLOC_SIZE - sizeof(struct zobj_header)
* since otherwise xv_malloc would always return failure.
*/
/*-- End of configurable params */
#define SECTOR_SHIFT 9
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT)
#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT)
/* Debugging and Stats */
#if defined(CONFIG_RAMZSWAP_STATS)
#define stat_inc(stat) ((stat)++)
#define stat_dec(stat) ((stat)--)
#else
#define stat_inc(x)
#define stat_dec(x)
#endif
/* Flags for ramzswap pages (table[page_no].flags) */
enum rzs_pageflags {
/* Page is stored uncompressed */
RZS_UNCOMPRESSED,
/* Page consists entirely of zeros */
RZS_ZERO,
__NR_RZS_PAGEFLAGS,
};
/*-- Data structures */
/*
* Allocated for each swap slot, indexed by page no.
* These table entries must fit exactly in a page.
*/
struct table {
struct page *page;
u16 offset;
u8 count; /* object ref count (not yet used) */
u8 flags;
} __attribute__((aligned(4)));;
/*
* Swap extent information in case backing swap is a regular
* file. These extent entries must fit exactly in a page.
*/
struct ramzswap_backing_extent {
pgoff_t phy_pagenum;
pgoff_t num_pages;
} __attribute__((aligned(4)));
struct ramzswap_stats {
/* basic stats */
size_t compr_size; /* compressed size of pages stored -
* needed to enforce memlimit */
/* more stats */
#if defined(CONFIG_RAMZSWAP_STATS)
u64 num_reads; /* failed + successful */
u64 num_writes; /* --do-- */
u64 failed_reads; /* can happen when memory is too low */
u64 failed_writes; /* should NEVER! happen */
u64 invalid_io; /* non-swap I/O requests */
u32 pages_zero; /* no. of zero filled pages */
u32 pages_stored; /* no. of pages currently stored */
u32 good_compress; /* % of pages with compression ratio<=50% */
u32 pages_expand; /* % of incompressible pages */
u64 bdev_num_reads; /* no. of reads on backing dev */
u64 bdev_num_writes; /* no. of writes on backing dev */
#endif
};
struct ramzswap {
struct xv_pool *mem_pool;
void *compress_workmem;
void *compress_buffer;
struct table *table;
struct mutex lock;
struct request_queue *queue;
struct gendisk *disk;
int init_done;
/*
* This is limit on compressed data size (stats.compr_size)
* Its applicable only when backing swap device is present.
*/
size_t memlimit; /* bytes */
/*
* This is limit on amount of *uncompressed* worth of data
* we can hold. When backing swap device is provided, it is
* set equal to device size.
*/
size_t disksize; /* bytes */
struct ramzswap_stats stats;
/* backing swap device info */
struct ramzswap_backing_extent *curr_extent;
struct list_head backing_swap_extent_list;
unsigned long num_extents;
char backing_swap_name[MAX_SWAP_NAME_LEN];
struct block_device *backing_swap;
struct file *swap_file;
};
/*-- */
#endif

View File

@@ -1,49 +0,0 @@
/*
* Compressed RAM based swap device
*
* Copyright (C) 2008, 2009 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
*
* Released under the terms of 3-clause BSD License
* Released under the terms of GNU General Public License Version 2.0
*
* Project home: http://compcache.googlecode.com
*/
#ifndef _RAMZSWAP_IOCTL_H_
#define _RAMZSWAP_IOCTL_H_
#define MAX_SWAP_NAME_LEN 128
struct ramzswap_ioctl_stats {
char backing_swap_name[MAX_SWAP_NAME_LEN];
u64 memlimit; /* only applicable if backing swap present */
u64 disksize; /* user specified or equal to backing swap
* size (if present) */
u64 num_reads; /* failed + successful */
u64 num_writes; /* --do-- */
u64 failed_reads; /* can happen when memory is too low */
u64 failed_writes; /* should NEVER! happen */
u64 invalid_io; /* non-swap I/O requests */
u32 pages_zero; /* no. of zero filled pages */
u32 good_compress_pct; /* no. of pages with compression ratio<=50% */
u32 pages_expand_pct; /* no. of incompressible pages */
u32 pages_stored;
u32 pages_used;
u64 orig_data_size;
u64 compr_data_size;
u64 mem_used_total;
u64 bdev_num_reads; /* no. of reads on backing dev */
u64 bdev_num_writes; /* no. of writes on backing dev */
} __attribute__ ((packed, aligned(4)));
#define RZSIO_SET_DISKSIZE_KB _IOW('z', 0, size_t)
#define RZSIO_SET_MEMLIMIT_KB _IOW('z', 1, size_t)
#define RZSIO_SET_BACKING_SWAP _IOW('z', 2, unsigned char[MAX_SWAP_NAME_LEN])
#define RZSIO_GET_STATS _IOR('z', 3, struct ramzswap_ioctl_stats)
#define RZSIO_INIT _IO('z', 4)
#define RZSIO_RESET _IO('z', 5)
#endif

View File

@@ -1,507 +0,0 @@
/*
* xvmalloc memory allocator
*
* Copyright (C) 2008, 2009 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
*
* Released under the terms of 3-clause BSD License
* Released under the terms of GNU General Public License Version 2.0
*/
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "xvmalloc.h"
#include "xvmalloc_int.h"
static void stat_inc(u64 *value)
{
*value = *value + 1;
}
static void stat_dec(u64 *value)
{
*value = *value - 1;
}
static int test_flag(struct block_header *block, enum blockflags flag)
{
return block->prev & BIT(flag);
}
static void set_flag(struct block_header *block, enum blockflags flag)
{
block->prev |= BIT(flag);
}
static void clear_flag(struct block_header *block, enum blockflags flag)
{
block->prev &= ~BIT(flag);
}
/*
* Given <page, offset> pair, provide a derefrencable pointer.
* This is called from xv_malloc/xv_free path, so it
* needs to be fast.
*/
static void *get_ptr_atomic(struct page *page, u16 offset, enum km_type type)
{
unsigned char *base;
base = kmap_atomic(page, type);
return base + offset;
}
static void put_ptr_atomic(void *ptr, enum km_type type)
{
kunmap_atomic(ptr, type);
}
static u32 get_blockprev(struct block_header *block)
{
return block->prev & PREV_MASK;
}
static void set_blockprev(struct block_header *block, u16 new_offset)
{
block->prev = new_offset | (block->prev & FLAGS_MASK);
}
static struct block_header *BLOCK_NEXT(struct block_header *block)
{
return (struct block_header *)
((char *)block + block->size + XV_ALIGN);
}
/*
* Get index of free list containing blocks of maximum size
* which is less than or equal to given size.
*/
static u32 get_index_for_insert(u32 size)
{
if (unlikely(size > XV_MAX_ALLOC_SIZE))
size = XV_MAX_ALLOC_SIZE;
size &= ~FL_DELTA_MASK;
return (size - XV_MIN_ALLOC_SIZE) >> FL_DELTA_SHIFT;
}
/*
* Get index of free list having blocks of size greater than
* or equal to requested size.
*/
static u32 get_index(u32 size)
{
if (unlikely(size < XV_MIN_ALLOC_SIZE))
size = XV_MIN_ALLOC_SIZE;
size = ALIGN(size, FL_DELTA);
return (size - XV_MIN_ALLOC_SIZE) >> FL_DELTA_SHIFT;
}
/**
* find_block - find block of at least given size
* @pool: memory pool to search from
* @size: size of block required
* @page: page containing required block
* @offset: offset within the page where block is located.
*
* Searches two level bitmap to locate block of at least
* the given size. If such a block is found, it provides
* <page, offset> to identify this block and returns index
* in freelist where we found this block.
* Otherwise, returns 0 and <page, offset> params are not touched.
*/
static u32 find_block(struct xv_pool *pool, u32 size,
struct page **page, u32 *offset)
{
ulong flbitmap, slbitmap;
u32 flindex, slindex, slbitstart;
/* There are no free blocks in this pool */
if (!pool->flbitmap)
return 0;
/* Get freelist index correspoding to this size */
slindex = get_index(size);
slbitmap = pool->slbitmap[slindex / BITS_PER_LONG];
slbitstart = slindex % BITS_PER_LONG;
/*
* If freelist is not empty at this index, we found the
* block - head of this list. This is approximate best-fit match.
*/
if (test_bit(slbitstart, &slbitmap)) {
*page = pool->freelist[slindex].page;
*offset = pool->freelist[slindex].offset;
return slindex;
}
/*
* No best-fit found. Search a bit further in bitmap for a free block.
* Second level bitmap consists of series of 32-bit chunks. Search
* further in the chunk where we expected a best-fit, starting from
* index location found above.
*/
slbitstart++;
slbitmap >>= slbitstart;
/* Skip this search if we were already at end of this bitmap chunk */
if ((slbitstart != BITS_PER_LONG) && slbitmap) {
slindex += __ffs(slbitmap) + 1;
*page = pool->freelist[slindex].page;
*offset = pool->freelist[slindex].offset;
return slindex;
}
/* Now do a full two-level bitmap search to find next nearest fit */
flindex = slindex / BITS_PER_LONG;
flbitmap = (pool->flbitmap) >> (flindex + 1);
if (!flbitmap)
return 0;
flindex += __ffs(flbitmap) + 1;
slbitmap = pool->slbitmap[flindex];
slindex = (flindex * BITS_PER_LONG) + __ffs(slbitmap);
*page = pool->freelist[slindex].page;
*offset = pool->freelist[slindex].offset;
return slindex;
}
/*
* Insert block at <page, offset> in freelist of given pool.
* freelist used depends on block size.
*/
static void insert_block(struct xv_pool *pool, struct page *page, u32 offset,
struct block_header *block)
{
u32 flindex, slindex;
struct block_header *nextblock;
slindex = get_index_for_insert(block->size);
flindex = slindex / BITS_PER_LONG;
block->link.prev_page = 0;
block->link.prev_offset = 0;
block->link.next_page = pool->freelist[slindex].page;
block->link.next_offset = pool->freelist[slindex].offset;
pool->freelist[slindex].page = page;
pool->freelist[slindex].offset = offset;
if (block->link.next_page) {
nextblock = get_ptr_atomic(block->link.next_page,
block->link.next_offset, KM_USER1);
nextblock->link.prev_page = page;
nextblock->link.prev_offset = offset;
put_ptr_atomic(nextblock, KM_USER1);
}
__set_bit(slindex % BITS_PER_LONG, &pool->slbitmap[flindex]);
__set_bit(flindex, &pool->flbitmap);
}
/*
* Remove block from head of freelist. Index 'slindex' identifies the freelist.
*/
static void remove_block_head(struct xv_pool *pool,
struct block_header *block, u32 slindex)
{
struct block_header *tmpblock;
u32 flindex = slindex / BITS_PER_LONG;
pool->freelist[slindex].page = block->link.next_page;
pool->freelist[slindex].offset = block->link.next_offset;
block->link.prev_page = 0;
block->link.prev_offset = 0;
if (!pool->freelist[slindex].page) {
__clear_bit(slindex % BITS_PER_LONG, &pool->slbitmap[flindex]);
if (!pool->slbitmap[flindex])
__clear_bit(flindex, &pool->flbitmap);
} else {
/*
* DEBUG ONLY: We need not reinitialize freelist head previous
* pointer to 0 - we never depend on its value. But just for
* sanity, lets do it.
*/
tmpblock = get_ptr_atomic(pool->freelist[slindex].page,
pool->freelist[slindex].offset, KM_USER1);
tmpblock->link.prev_page = 0;
tmpblock->link.prev_offset = 0;
put_ptr_atomic(tmpblock, KM_USER1);
}
}
/*
* Remove block from freelist. Index 'slindex' identifies the freelist.
*/
static void remove_block(struct xv_pool *pool, struct page *page, u32 offset,
struct block_header *block, u32 slindex)
{
u32 flindex;
struct block_header *tmpblock;
if (pool->freelist[slindex].page == page
&& pool->freelist[slindex].offset == offset) {
remove_block_head(pool, block, slindex);
return;
}
flindex = slindex / BITS_PER_LONG;
if (block->link.prev_page) {
tmpblock = get_ptr_atomic(block->link.prev_page,
block->link.prev_offset, KM_USER1);
tmpblock->link.next_page = block->link.next_page;
tmpblock->link.next_offset = block->link.next_offset;
put_ptr_atomic(tmpblock, KM_USER1);
}
if (block->link.next_page) {
tmpblock = get_ptr_atomic(block->link.next_page,
block->link.next_offset, KM_USER1);
tmpblock->link.prev_page = block->link.prev_page;
tmpblock->link.prev_offset = block->link.prev_offset;
put_ptr_atomic(tmpblock, KM_USER1);
}
}
/*
* Allocate a page and add it freelist of given pool.
*/
static int grow_pool(struct xv_pool *pool, gfp_t flags)
{
struct page *page;
struct block_header *block;
page = alloc_page(flags);
if (unlikely(!page))
return -ENOMEM;
stat_inc(&pool->total_pages);
spin_lock(&pool->lock);
block = get_ptr_atomic(page, 0, KM_USER0);
block->size = PAGE_SIZE - XV_ALIGN;
set_flag(block, BLOCK_FREE);
clear_flag(block, PREV_FREE);
set_blockprev(block, 0);
insert_block(pool, page, 0, block);
put_ptr_atomic(block, KM_USER0);
spin_unlock(&pool->lock);
return 0;
}
/*
* Create a memory pool. Allocates freelist, bitmaps and other
* per-pool metadata.
*/
struct xv_pool *xv_create_pool(void)
{
u32 ovhd_size;
struct xv_pool *pool;
ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
pool = kzalloc(ovhd_size, GFP_KERNEL);
if (!pool)
return NULL;
spin_lock_init(&pool->lock);
return pool;
}
void xv_destroy_pool(struct xv_pool *pool)
{
kfree(pool);
}
/**
* xv_malloc - Allocate block of given size from pool.
* @pool: pool to allocate from
* @size: size of block to allocate
* @page: page no. that holds the object
* @offset: location of object within page
*
* On success, <page, offset> identifies block allocated
* and 0 is returned. On failure, <page, offset> is set to
* 0 and -ENOMEM is returned.
*
* Allocation requests with size > XV_MAX_ALLOC_SIZE will fail.
*/
int xv_malloc(struct xv_pool *pool, u32 size, struct page **page,
u32 *offset, gfp_t flags)
{
int error;
u32 index, tmpsize, origsize, tmpoffset;
struct block_header *block, *tmpblock;
*page = NULL;
*offset = 0;
origsize = size;
if (unlikely(!size || size > XV_MAX_ALLOC_SIZE))
return -ENOMEM;
size = ALIGN(size, XV_ALIGN);
spin_lock(&pool->lock);
index = find_block(pool, size, page, offset);
if (!*page) {
spin_unlock(&pool->lock);
if (flags & GFP_NOWAIT)
return -ENOMEM;
error = grow_pool(pool, flags);
if (unlikely(error))
return error;
spin_lock(&pool->lock);
index = find_block(pool, size, page, offset);
}
if (!*page) {
spin_unlock(&pool->lock);
return -ENOMEM;
}
block = get_ptr_atomic(*page, *offset, KM_USER0);
remove_block_head(pool, block, index);
/* Split the block if required */
tmpoffset = *offset + size + XV_ALIGN;
tmpsize = block->size - size;
tmpblock = (struct block_header *)((char *)block + size + XV_ALIGN);
if (tmpsize) {
tmpblock->size = tmpsize - XV_ALIGN;
set_flag(tmpblock, BLOCK_FREE);
clear_flag(tmpblock, PREV_FREE);
set_blockprev(tmpblock, *offset);
if (tmpblock->size >= XV_MIN_ALLOC_SIZE)
insert_block(pool, *page, tmpoffset, tmpblock);
if (tmpoffset + XV_ALIGN + tmpblock->size != PAGE_SIZE) {
tmpblock = BLOCK_NEXT(tmpblock);
set_blockprev(tmpblock, tmpoffset);
}
} else {
/* This block is exact fit */
if (tmpoffset != PAGE_SIZE)
clear_flag(tmpblock, PREV_FREE);
}
block->size = origsize;
clear_flag(block, BLOCK_FREE);
put_ptr_atomic(block, KM_USER0);
spin_unlock(&pool->lock);
*offset += XV_ALIGN;
return 0;
}
/*
* Free block identified with <page, offset>
*/
void xv_free(struct xv_pool *pool, struct page *page, u32 offset)
{
void *page_start;
struct block_header *block, *tmpblock;
offset -= XV_ALIGN;
spin_lock(&pool->lock);
page_start = get_ptr_atomic(page, 0, KM_USER0);
block = (struct block_header *)((char *)page_start + offset);
/* Catch double free bugs */
BUG_ON(test_flag(block, BLOCK_FREE));
block->size = ALIGN(block->size, XV_ALIGN);
tmpblock = BLOCK_NEXT(block);
if (offset + block->size + XV_ALIGN == PAGE_SIZE)
tmpblock = NULL;
/* Merge next block if its free */
if (tmpblock && test_flag(tmpblock, BLOCK_FREE)) {
/*
* Blocks smaller than XV_MIN_ALLOC_SIZE
* are not inserted in any free list.
*/
if (tmpblock->size >= XV_MIN_ALLOC_SIZE) {
remove_block(pool, page,
offset + block->size + XV_ALIGN, tmpblock,
get_index_for_insert(tmpblock->size));
}
block->size += tmpblock->size + XV_ALIGN;
}
/* Merge previous block if its free */
if (test_flag(block, PREV_FREE)) {
tmpblock = (struct block_header *)((char *)(page_start) +
get_blockprev(block));
offset = offset - tmpblock->size - XV_ALIGN;
if (tmpblock->size >= XV_MIN_ALLOC_SIZE)
remove_block(pool, page, offset, tmpblock,
get_index_for_insert(tmpblock->size));
tmpblock->size += block->size + XV_ALIGN;
block = tmpblock;
}
/* No used objects in this page. Free it. */
if (block->size == PAGE_SIZE - XV_ALIGN) {
put_ptr_atomic(page_start, KM_USER0);
spin_unlock(&pool->lock);
__free_page(page);
stat_dec(&pool->total_pages);
return;
}
set_flag(block, BLOCK_FREE);
if (block->size >= XV_MIN_ALLOC_SIZE)
insert_block(pool, page, offset, block);
if (offset + block->size + XV_ALIGN != PAGE_SIZE) {
tmpblock = BLOCK_NEXT(block);
set_flag(tmpblock, PREV_FREE);
set_blockprev(tmpblock, offset);
}
put_ptr_atomic(page_start, KM_USER0);
spin_unlock(&pool->lock);
}
u32 xv_get_object_size(void *obj)
{
struct block_header *blk;
blk = (struct block_header *)((char *)(obj) - XV_ALIGN);
return blk->size;
}
/*
* Returns total memory used by allocator (userdata + metadata)
*/
u64 xv_get_total_size_bytes(struct xv_pool *pool)
{
return pool->total_pages << PAGE_SHIFT;
}

View File

@@ -1,30 +0,0 @@
/*
* xvmalloc memory allocator
*
* Copyright (C) 2008, 2009 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
*
* Released under the terms of 3-clause BSD License
* Released under the terms of GNU General Public License Version 2.0
*/
#ifndef _XV_MALLOC_H_
#define _XV_MALLOC_H_
#include <linux/types.h>
struct xv_pool;
struct xv_pool *xv_create_pool(void);
void xv_destroy_pool(struct xv_pool *pool);
int xv_malloc(struct xv_pool *pool, u32 size, struct page **page,
u32 *offset, gfp_t flags);
void xv_free(struct xv_pool *pool, struct page *page, u32 offset);
u32 xv_get_object_size(void *obj);
u64 xv_get_total_size_bytes(struct xv_pool *pool);
#endif

View File

@@ -1,86 +0,0 @@
/*
* xvmalloc memory allocator
*
* Copyright (C) 2008, 2009 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
*
* Released under the terms of 3-clause BSD License
* Released under the terms of GNU General Public License Version 2.0
*/
#ifndef _XV_MALLOC_INT_H_
#define _XV_MALLOC_INT_H_
#include <linux/kernel.h>
#include <linux/types.h>
/* User configurable params */
/* Must be power of two */
#define XV_ALIGN_SHIFT 2
#define XV_ALIGN (1 << XV_ALIGN_SHIFT)
#define XV_ALIGN_MASK (XV_ALIGN - 1)
/* This must be greater than sizeof(link_free) */
#define XV_MIN_ALLOC_SIZE 32
#define XV_MAX_ALLOC_SIZE (PAGE_SIZE - XV_ALIGN)
/* Free lists are separated by FL_DELTA bytes */
#define FL_DELTA_SHIFT 3
#define FL_DELTA (1 << FL_DELTA_SHIFT)
#define FL_DELTA_MASK (FL_DELTA - 1)
#define NUM_FREE_LISTS ((XV_MAX_ALLOC_SIZE - XV_MIN_ALLOC_SIZE) \
/ FL_DELTA + 1)
#define MAX_FLI DIV_ROUND_UP(NUM_FREE_LISTS, BITS_PER_LONG)
/* End of user params */
enum blockflags {
BLOCK_FREE,
PREV_FREE,
__NR_BLOCKFLAGS,
};
#define FLAGS_MASK XV_ALIGN_MASK
#define PREV_MASK (~FLAGS_MASK)
struct freelist_entry {
struct page *page;
u16 offset;
u16 pad;
};
struct link_free {
struct page *prev_page;
struct page *next_page;
u16 prev_offset;
u16 next_offset;
};
struct block_header {
union {
/* This common header must be ALIGN bytes */
u8 common[XV_ALIGN];
struct {
u16 size;
u16 prev;
};
};
struct link_free link;
};
struct xv_pool {
ulong flbitmap;
ulong slbitmap[MAX_FLI];
spinlock_t lock;
struct freelist_entry freelist[NUM_FREE_LISTS];
/* stats */
u64 total_pages;
};
#endif