2009-09-22 04:56:53 +00:00
|
|
|
/*
|
2010-06-01 08:01:25 +00:00
|
|
|
* Compressed RAM block device
|
2009-09-22 04:56:53 +00:00
|
|
|
*
|
2010-01-28 15:51:35 +00:00
|
|
|
* Copyright (C) 2008, 2009, 2010 Nitin Gupta
|
2009-09-22 04:56:53 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2010-06-01 08:01:25 +00:00
|
|
|
#ifndef _ZRAM_DRV_H_
|
|
|
|
#define _ZRAM_DRV_H_
|
2009-09-22 04:56:53 +00:00
|
|
|
|
2010-01-28 15:43:37 +00:00
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/mutex.h>
|
|
|
|
|
2009-09-22 04:56:53 +00:00
|
|
|
#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
|
2010-05-13 08:54:21 +00:00
|
|
|
* object. This is required to support memory defragmentation.
|
2009-09-22 04:56:53 +00:00
|
|
|
*/
|
|
|
|
struct zobj_header {
|
|
|
|
#if 0
|
|
|
|
u32 table_idx;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
/*-- Configurable parameters */
|
|
|
|
|
2010-06-01 08:01:25 +00:00
|
|
|
/* Default zram disk size: 25% of total RAM */
|
2009-09-22 04:56:53 +00:00
|
|
|
static const unsigned default_disksize_perc_ram = 25;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pages that compress to size greater than this are stored
|
|
|
|
* uncompressed in memory.
|
|
|
|
*/
|
2010-05-13 08:54:21 +00:00
|
|
|
static const unsigned max_zpage_size = PAGE_SIZE / 4 * 3;
|
2009-09-22 04:56:53 +00:00
|
|
|
|
|
|
|
/*
|
2010-05-13 08:54:21 +00:00
|
|
|
* NOTE: max_zpage_size must be less than or equal to:
|
2009-09-22 04:56:53 +00:00
|
|
|
* XV_MAX_ALLOC_SIZE - sizeof(struct zobj_header)
|
2010-05-13 08:54:21 +00:00
|
|
|
* otherwise, xv_malloc() would always return failure.
|
2009-09-22 04:56:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*-- 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)
|
2011-06-10 13:28:48 +00:00
|
|
|
#define ZRAM_LOGICAL_BLOCK_SHIFT 12
|
|
|
|
#define ZRAM_LOGICAL_BLOCK_SIZE (1 << ZRAM_LOGICAL_BLOCK_SHIFT)
|
|
|
|
#define ZRAM_SECTOR_PER_LOGICAL_BLOCK \
|
|
|
|
(1 << (ZRAM_LOGICAL_BLOCK_SHIFT - SECTOR_SHIFT))
|
2009-09-22 04:56:53 +00:00
|
|
|
|
2010-06-01 08:01:25 +00:00
|
|
|
/* Flags for zram pages (table[page_no].flags) */
|
|
|
|
enum zram_pageflags {
|
2009-09-22 04:56:53 +00:00
|
|
|
/* Page is stored uncompressed */
|
2010-06-01 08:01:25 +00:00
|
|
|
ZRAM_UNCOMPRESSED,
|
2009-09-22 04:56:53 +00:00
|
|
|
|
|
|
|
/* Page consists entirely of zeros */
|
2010-06-01 08:01:25 +00:00
|
|
|
ZRAM_ZERO,
|
2009-09-22 04:56:53 +00:00
|
|
|
|
2010-06-01 08:01:25 +00:00
|
|
|
__NR_ZRAM_PAGEFLAGS,
|
2009-09-22 04:56:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*-- Data structures */
|
|
|
|
|
2010-06-01 08:01:25 +00:00
|
|
|
/* Allocated for each disk page */
|
2009-09-22 04:56:53 +00:00
|
|
|
struct table {
|
|
|
|
struct page *page;
|
|
|
|
u16 offset;
|
|
|
|
u8 count; /* object ref count (not yet used) */
|
|
|
|
u8 flags;
|
2010-01-06 12:42:00 +00:00
|
|
|
} __attribute__((aligned(4)));
|
2009-09-22 04:56:53 +00:00
|
|
|
|
2010-06-01 08:01:25 +00:00
|
|
|
struct zram_stats {
|
2010-08-09 17:26:47 +00:00
|
|
|
u64 compr_size; /* compressed size of pages stored */
|
2009-09-22 04:56:53 +00:00
|
|
|
u64 num_reads; /* failed + successful */
|
|
|
|
u64 num_writes; /* --do-- */
|
2010-01-06 12:42:00 +00:00
|
|
|
u64 failed_reads; /* should NEVER! happen */
|
|
|
|
u64 failed_writes; /* can happen when memory is too low */
|
2010-06-01 08:01:25 +00:00
|
|
|
u64 invalid_io; /* non-page-aligned I/O requests */
|
2010-01-28 15:43:37 +00:00
|
|
|
u64 notify_free; /* no. of swap slot free notifications */
|
2009-09-22 04:56:53 +00:00
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
2010-06-01 08:01:25 +00:00
|
|
|
struct zram {
|
2009-09-22 04:56:53 +00:00
|
|
|
struct xv_pool *mem_pool;
|
|
|
|
void *compress_workmem;
|
|
|
|
void *compress_buffer;
|
|
|
|
struct table *table;
|
2010-01-28 15:43:37 +00:00
|
|
|
spinlock_t stat64_lock; /* protect 64-bit stats */
|
Staging: ramzswap: Support generic I/O requests
Currently, ramzwap devices (/dev/ramzswapX) can only
be used as swap disks since it was hard-coded to consider
only the first request in bio vector.
Now, we iterate over all the segments in an incoming
bio which allows us to handle all kinds of I/O requests.
ramzswap devices can still handle PAGE_SIZE aligned and
multiple of PAGE_SIZE sized I/O requests only. To ensure
that we get always get such requests only, we set following
request_queue attributes to PAGE_SIZE:
- physical_block_size
- logical_block_size
- io_min
- io_opt
Note: physical and logical block sizes were already set
equal to PAGE_SIZE and that seems to be sufficient to get
PAGE_SIZE aligned I/O.
Since we are no longer limited to handling swap requests
only, the next few patches rename ramzswap to zram. So,
the devices will then be called /dev/zram{0, 1, 2, ...}
Usage/Examples:
1) Use as /tmp storage
- mkfs.ext4 /dev/zram0
- mount /dev/zram0 /tmp
2) Use as swap:
- mkswap /dev/zram0
- swapon /dev/zram0 -p 10 # give highest priority to zram0
Performance:
- I/O benchamark done with 'dd' command. Details can be
found here:
http://code.google.com/p/compcache/wiki/zramperf
Summary:
- Maximum read speed (approx):
- ram disk: 1200 MB/sec
- zram disk: 600 MB/sec
- Maximum write speed (approx):
- ram disk: 500 MB/sec
- zram disk: 160 MB/sec
Issues:
- Double caching: We can potentially waste memory by having
two copies of a page -- one in page cache (uncompress) and
second in the device memory (compressed). However, during
reclaim, clean page cache pages are quickly freed, so this
does not seem to be a big problem.
- Stale data: Not all filesystems support issuing 'discard'
requests to underlying block devices. So, if such filesystems
are used over zram devices, we can accumulate lot of stale
data in memory. Even for filesystems to do support discard
(example, ext4), we need to see how effective it is.
- Scalability: There is only one (per-device) de/compression
buffer stats. This can lead to significant contention, especially
when used for generic (non-swap) purposes.
Signed-off-by: Nitin Gupta <ngupta@vflare.org>
Acked-by: Pekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-06-01 08:01:23 +00:00
|
|
|
struct mutex lock; /* protect compression buffers against
|
|
|
|
* concurrent writes */
|
2009-09-22 04:56:53 +00:00
|
|
|
struct request_queue *queue;
|
|
|
|
struct gendisk *disk;
|
|
|
|
int init_done;
|
2010-08-09 17:26:48 +00:00
|
|
|
/* Prevent concurrent execution of device init and reset */
|
|
|
|
struct mutex init_lock;
|
2009-09-22 04:56:53 +00:00
|
|
|
/*
|
2010-06-01 08:01:25 +00:00
|
|
|
* This is the limit on amount of *uncompressed* worth of data
|
|
|
|
* we can store in a disk.
|
2009-09-22 04:56:53 +00:00
|
|
|
*/
|
2010-08-09 17:26:47 +00:00
|
|
|
u64 disksize; /* bytes */
|
2009-09-22 04:56:53 +00:00
|
|
|
|
2010-06-01 08:01:25 +00:00
|
|
|
struct zram_stats stats;
|
2009-09-22 04:56:53 +00:00
|
|
|
};
|
|
|
|
|
2010-08-09 17:26:47 +00:00
|
|
|
extern struct zram *devices;
|
|
|
|
extern unsigned int num_devices;
|
|
|
|
#ifdef CONFIG_SYSFS
|
|
|
|
extern struct attribute_group zram_disk_attr_group;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern int zram_init_device(struct zram *zram);
|
|
|
|
extern void zram_reset_device(struct zram *zram);
|
2009-09-22 04:56:53 +00:00
|
|
|
|
2010-01-28 15:43:37 +00:00
|
|
|
#endif
|