* [PATCH 0/3] zram: generic RAM based compressed R/W block devices
@ 2010-05-24 14:18 Nitin Gupta
2010-05-24 14:18 ` [PATCH 1/3] Support generic I/O requests Nitin Gupta
` (4 more replies)
0 siblings, 5 replies; 17+ messages in thread
From: Nitin Gupta @ 2010-05-24 14:18 UTC (permalink / raw)
To: Greg KH
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
Pages written to these disks are compressed and stored in memory
itself. These disks allow very fast I/O and compression provides
good amounts of memory savings.
This is enhancement over existing ramzswap driver which creates
virtual block devices (/dev/ramzswapX) which could be used only
as swap disks.
Now, with the ability to handle any kind of I/O request, zram
devices have lot more use cases:
- /tmp storage
- various caches under /var
- swap disks
- maybe even more! :)
Performance numbers can be found at:
http://code.google.com/p/compcache/wiki/zramperf
Patch 1 makes core changes to support handling generic I/O
requests. Subsequent patches rename ramzswap* files to zram*
and similar changes in code and documentation.
Nitin Gupta (3):
Support generic I/O requests
Rename ramzswap to zram in code.
Rename ramzswap to zram in documentation
drivers/staging/Kconfig | 2 +-
drivers/staging/Makefile | 2 +-
drivers/staging/ramzswap/Kconfig | 21 -
drivers/staging/ramzswap/Makefile | 3 -
drivers/staging/ramzswap/ramzswap.txt | 51 --
drivers/staging/ramzswap/ramzswap_drv.c | 837 -----------------------------
drivers/staging/ramzswap/ramzswap_drv.h | 167 ------
drivers/staging/ramzswap/ramzswap_ioctl.h | 42 --
drivers/staging/ramzswap/xvmalloc.c | 507 -----------------
drivers/staging/ramzswap/xvmalloc.h | 30 -
drivers/staging/ramzswap/xvmalloc_int.h | 86 ---
drivers/staging/zram/Kconfig | 24 +
drivers/staging/zram/Makefile | 3 +
drivers/staging/zram/xvmalloc.c | 507 +++++++++++++++++
drivers/staging/zram/xvmalloc.h | 30 +
drivers/staging/zram/xvmalloc_int.h | 86 +++
drivers/staging/zram/zram.txt | 62 +++
drivers/staging/zram/zram_drv.c | 809 ++++++++++++++++++++++++++++
drivers/staging/zram/zram_drv.h | 167 ++++++
drivers/staging/zram/zram_ioctl.h | 42 ++
20 files changed, 1732 insertions(+), 1746 deletions(-)
delete mode 100644 drivers/staging/ramzswap/Kconfig
delete mode 100644 drivers/staging/ramzswap/Makefile
delete mode 100644 drivers/staging/ramzswap/ramzswap.txt
delete mode 100644 drivers/staging/ramzswap/ramzswap_drv.c
delete mode 100644 drivers/staging/ramzswap/ramzswap_drv.h
delete mode 100644 drivers/staging/ramzswap/ramzswap_ioctl.h
delete mode 100644 drivers/staging/ramzswap/xvmalloc.c
delete mode 100644 drivers/staging/ramzswap/xvmalloc.h
delete mode 100644 drivers/staging/ramzswap/xvmalloc_int.h
create mode 100644 drivers/staging/zram/Kconfig
create mode 100644 drivers/staging/zram/Makefile
create mode 100644 drivers/staging/zram/xvmalloc.c
create mode 100644 drivers/staging/zram/xvmalloc.h
create mode 100644 drivers/staging/zram/xvmalloc_int.h
create mode 100644 drivers/staging/zram/zram.txt
create mode 100644 drivers/staging/zram/zram_drv.c
create mode 100644 drivers/staging/zram/zram_drv.h
create mode 100644 drivers/staging/zram/zram_ioctl.h
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 1/3] Support generic I/O requests
2010-05-24 14:18 [PATCH 0/3] zram: generic RAM based compressed R/W block devices Nitin Gupta
@ 2010-05-24 14:18 ` Nitin Gupta
2010-05-31 15:41 ` Minchan Kim
2010-05-24 14:18 ` [PATCH 2/3] Rename ramzswap to zram in code Nitin Gupta
` (3 subsequent siblings)
4 siblings, 1 reply; 17+ messages in thread
From: Nitin Gupta @ 2010-05-24 14:18 UTC (permalink / raw)
To: Greg KH
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
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>
---
---
drivers/staging/ramzswap/ramzswap_drv.c | 325 ++++++++++++++-----------------
1 files changed, 148 insertions(+), 177 deletions(-)
diff --git a/drivers/staging/ramzswap/ramzswap_drv.c b/drivers/staging/ramzswap/ramzswap_drv.c
index d14bf91..9d20d23 100644
--- a/drivers/staging/ramzswap/ramzswap_drv.c
+++ b/drivers/staging/ramzswap/ramzswap_drv.c
@@ -101,20 +101,6 @@ static void ramzswap_set_disksize(struct ramzswap *rzs, size_t totalram_bytes)
rzs->disksize &= PAGE_MASK;
}
-/*
- * Swap header (1st page of swap device) contains information
- * about a swap file/partition. Prepare such a header for the
- * given ramzswap device so that swapon can identify it as a
- * swap partition.
- */
-static void setup_swap_header(struct ramzswap *rzs, union swap_header *s)
-{
- s->info.version = 1;
- s->info.last_page = (rzs->disksize >> PAGE_SHIFT) - 1;
- s->info.nr_badpages = 0;
- memcpy(s->magic.magic, "SWAPSPACE2", 10);
-}
-
static void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
struct ramzswap_ioctl_stats *s)
{
@@ -202,31 +188,22 @@ out:
rzs->table[index].offset = 0;
}
-static int handle_zero_page(struct bio *bio)
+static void handle_zero_page(struct page *page, u32 index)
{
void *user_mem;
- struct page *page = bio->bi_io_vec[0].bv_page;
user_mem = kmap_atomic(page, KM_USER0);
memset(user_mem, 0, PAGE_SIZE);
kunmap_atomic(user_mem, KM_USER0);
flush_dcache_page(page);
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
}
-static int handle_uncompressed_page(struct ramzswap *rzs, struct bio *bio)
+static void handle_uncompressed_page(struct ramzswap *rzs,
+ struct page *page, u32 index)
{
- u32 index;
- struct page *page;
unsigned char *user_mem, *cmem;
- page = bio->bi_io_vec[0].bv_page;
- index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
-
user_mem = kmap_atomic(page, KM_USER0);
cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
rzs->table[index].offset;
@@ -236,79 +213,72 @@ static int handle_uncompressed_page(struct ramzswap *rzs, struct bio *bio)
kunmap_atomic(cmem, KM_USER1);
flush_dcache_page(page);
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
-}
-
-/*
- * Called when request page is not present in ramzswap.
- * This is an attempt to read before any previous write
- * to this location - this happens due to readahead when
- * swap device is read from user-space (e.g. during swapon)
- */
-static int handle_ramzswap_fault(struct ramzswap *rzs, struct bio *bio)
-{
- pr_debug("Read before write on swap device: "
- "sector=%lu, size=%u, offset=%u\n",
- (ulong)(bio->bi_sector), bio->bi_size,
- bio->bi_io_vec[0].bv_offset);
-
- /* Do nothing. Just return success */
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
}
static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
{
- int ret;
+
+ int i;
u32 index;
- size_t clen;
- struct page *page;
- struct zobj_header *zheader;
- unsigned char *user_mem, *cmem;
+ struct bio_vec *bvec;
rzs_stat64_inc(rzs, &rzs->stats.num_reads);
- page = bio->bi_io_vec[0].bv_page;
index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
+ bio_for_each_segment(bvec, bio, i) {
+ int ret;
+ size_t clen;
+ struct page *page;
+ struct zobj_header *zheader;
+ unsigned char *user_mem, *cmem;
- if (rzs_test_flag(rzs, index, RZS_ZERO))
- return handle_zero_page(bio);
+ page = bvec->bv_page;
- /* Requested page is not present in compressed area */
- if (!rzs->table[index].page)
- return handle_ramzswap_fault(rzs, bio);
+ if (rzs_test_flag(rzs, index, RZS_ZERO)) {
+ handle_zero_page(page, index);
+ continue;
+ }
- /* Page is stored uncompressed since it's incompressible */
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
- return handle_uncompressed_page(rzs, bio);
+ /* Requested page is not present in compressed area */
+ if (unlikely(!rzs->table[index].page)) {
+ pr_debug("Read before write on swap device: "
+ "sector=%lu, size=%u",
+ (ulong)(bio->bi_sector), bio->bi_size);
+ /* Do nothing */
+ continue;
+ }
- user_mem = kmap_atomic(page, KM_USER0);
- clen = PAGE_SIZE;
+ /* Page is stored uncompressed since it's incompressible */
+ if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED))) {
+ handle_uncompressed_page(rzs, page, index);
+ continue;
+ }
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
+ user_mem = kmap_atomic(page, KM_USER0);
+ clen = PAGE_SIZE;
- ret = lzo1x_decompress_safe(
- cmem + sizeof(*zheader),
- xv_get_object_size(cmem) - sizeof(*zheader),
- user_mem, &clen);
+ cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
+ rzs->table[index].offset;
- kunmap_atomic(user_mem, KM_USER0);
- kunmap_atomic(cmem, KM_USER1);
+ ret = lzo1x_decompress_safe(
+ cmem + sizeof(*zheader),
+ xv_get_object_size(cmem) - sizeof(*zheader),
+ user_mem, &clen);
- /* should NEVER happen */
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Decompression failed! err=%d, page=%u\n",
- ret, index);
- rzs_stat64_inc(rzs, &rzs->stats.failed_reads);
- goto out;
- }
+ kunmap_atomic(user_mem, KM_USER0);
+ kunmap_atomic(cmem, KM_USER1);
- flush_dcache_page(page);
+ /* should NEVER happen */
+ if (unlikely(ret != LZO_E_OK)) {
+ pr_err("Decompression failed! err=%d, page=%u\n",
+ ret, index);
+ rzs_stat64_inc(rzs, &rzs->stats.failed_reads);
+ goto out;
+ }
+
+ flush_dcache_page(page);
+ index++;
+ }
set_bit(BIO_UPTODATE, &bio->bi_flags);
bio_endio(bio, 0);
@@ -321,108 +291,120 @@ out:
static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
{
- int ret;
- u32 offset, index;
- size_t clen;
- struct zobj_header *zheader;
- struct page *page, *page_store;
- unsigned char *user_mem, *cmem, *src;
+ int i;
+ u32 index;
+ struct bio_vec *bvec;
rzs_stat64_inc(rzs, &rzs->stats.num_writes);
- page = bio->bi_io_vec[0].bv_page;
index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
- src = rzs->compress_buffer;
+ bio_for_each_segment(bvec, bio, i) {
+ int ret;
+ u32 offset;
+ size_t clen;
+ struct zobj_header *zheader;
+ struct page *page, *page_store;
+ unsigned char *user_mem, *cmem, *src;
- mutex_lock(&rzs->lock);
+ page = bvec->bv_page;
+ src = rzs->compress_buffer;
- user_mem = kmap_atomic(page, KM_USER0);
- if (page_zero_filled(user_mem)) {
- kunmap_atomic(user_mem, KM_USER0);
- mutex_unlock(&rzs->lock);
- rzs_stat_inc(&rzs->stats.pages_zero);
- rzs_set_flag(rzs, index, RZS_ZERO);
+ /*
+ * System overwrites unused sectors. Free memory associated
+ * with this sector now.
+ */
+ if (rzs->table[index].page ||
+ rzs_test_flag(rzs, index, RZS_ZERO))
+ ramzswap_free_page(rzs, index);
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
- }
+ mutex_lock(&rzs->lock);
- ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen,
- rzs->compress_workmem);
+ user_mem = kmap_atomic(page, KM_USER0);
+ if (page_zero_filled(user_mem)) {
+ kunmap_atomic(user_mem, KM_USER0);
+ mutex_unlock(&rzs->lock);
+ rzs_stat_inc(&rzs->stats.pages_zero);
+ rzs_set_flag(rzs, index, RZS_ZERO);
+ continue;
+ }
- kunmap_atomic(user_mem, KM_USER0);
+ ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen,
+ rzs->compress_workmem);
- if (unlikely(ret != LZO_E_OK)) {
- mutex_unlock(&rzs->lock);
- pr_err("Compression failed! err=%d\n", ret);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
- goto out;
- }
+ kunmap_atomic(user_mem, KM_USER0);
- /*
- * Page is incompressible. Store it as-is (uncompressed)
- * since we do not want to return too many swap write
- * errors which has side effect of hanging the system.
- */
- if (unlikely(clen > max_zpage_size)) {
- clen = PAGE_SIZE;
- page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
- if (unlikely(!page_store)) {
+ if (unlikely(ret != LZO_E_OK)) {
mutex_unlock(&rzs->lock);
- pr_info("Error allocating memory for incompressible "
- "page: %u\n", index);
+ pr_err("Compression failed! err=%d\n", ret);
rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
goto out;
}
- offset = 0;
- rzs_set_flag(rzs, index, RZS_UNCOMPRESSED);
- rzs_stat_inc(&rzs->stats.pages_expand);
- rzs->table[index].page = page_store;
- src = kmap_atomic(page, KM_USER0);
- goto memstore;
- }
+ /*
+ * Page is incompressible. Store it as-is (uncompressed)
+ * since we do not want to return too many swap write
+ * errors which has side effect of hanging the system.
+ */
+ if (unlikely(clen > max_zpage_size)) {
+ clen = PAGE_SIZE;
+ page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
+ if (unlikely(!page_store)) {
+ mutex_unlock(&rzs->lock);
+ pr_info("Error allocating memory for "
+ "incompressible page: %u\n", index);
+ rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
+ goto out;
+ }
+
+ offset = 0;
+ rzs_set_flag(rzs, index, RZS_UNCOMPRESSED);
+ rzs_stat_inc(&rzs->stats.pages_expand);
+ rzs->table[index].page = page_store;
+ src = kmap_atomic(page, KM_USER0);
+ goto memstore;
+ }
- if (xv_malloc(rzs->mem_pool, clen + sizeof(*zheader),
- &rzs->table[index].page, &offset,
- GFP_NOIO | __GFP_HIGHMEM)) {
- mutex_unlock(&rzs->lock);
- pr_info("Error allocating memory for compressed "
- "page: %u, size=%zu\n", index, clen);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
- goto out;
- }
+ if (xv_malloc(rzs->mem_pool, clen + sizeof(*zheader),
+ &rzs->table[index].page, &offset,
+ GFP_NOIO | __GFP_HIGHMEM)) {
+ mutex_unlock(&rzs->lock);
+ pr_info("Error allocating memory for compressed "
+ "page: %u, size=%zu\n", index, clen);
+ rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
+ goto out;
+ }
memstore:
- rzs->table[index].offset = offset;
+ rzs->table[index].offset = offset;
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
+ cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
+ rzs->table[index].offset;
#if 0
- /* Back-reference needed for memory defragmentation */
- if (!rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)) {
- zheader = (struct zobj_header *)cmem;
- zheader->table_idx = index;
- cmem += sizeof(*zheader);
- }
+ /* Back-reference needed for memory defragmentation */
+ if (!rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)) {
+ zheader = (struct zobj_header *)cmem;
+ zheader->table_idx = index;
+ cmem += sizeof(*zheader);
+ }
#endif
- memcpy(cmem, src, clen);
+ memcpy(cmem, src, clen);
- kunmap_atomic(cmem, KM_USER1);
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
- kunmap_atomic(src, KM_USER0);
+ kunmap_atomic(cmem, KM_USER1);
+ if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
+ kunmap_atomic(src, KM_USER0);
- /* Update stats */
- rzs->stats.compr_size += clen;
- rzs_stat_inc(&rzs->stats.pages_stored);
- if (clen <= PAGE_SIZE / 2)
- rzs_stat_inc(&rzs->stats.good_compress);
+ /* Update stats */
+ rzs->stats.compr_size += clen;
+ rzs_stat_inc(&rzs->stats.pages_stored);
+ if (clen <= PAGE_SIZE / 2)
+ rzs_stat_inc(&rzs->stats.good_compress);
- mutex_unlock(&rzs->lock);
+ mutex_unlock(&rzs->lock);
+ index++;
+ }
set_bit(BIO_UPTODATE, &bio->bi_flags);
bio_endio(bio, 0);
@@ -436,19 +418,17 @@ out:
/*
* Check if request is within bounds and page aligned.
*/
-static inline int valid_swap_request(struct ramzswap *rzs, struct bio *bio)
+static inline int valid_io_request(struct ramzswap *rzs, struct bio *bio)
{
if (unlikely(
(bio->bi_sector >= (rzs->disksize >> SECTOR_SHIFT)) ||
(bio->bi_sector & (SECTORS_PER_PAGE - 1)) ||
- (bio->bi_vcnt != 1) ||
- (bio->bi_size != PAGE_SIZE) ||
- (bio->bi_io_vec[0].bv_offset != 0))) {
+ (bio->bi_size & (PAGE_SIZE - 1)))) {
return 0;
}
- /* swap request is valid */
+ /* I/O request is valid */
return 1;
}
@@ -465,7 +445,7 @@ static int ramzswap_make_request(struct request_queue *queue, struct bio *bio)
return 0;
}
- if (!valid_swap_request(rzs, bio)) {
+ if (!valid_io_request(rzs, bio)) {
rzs_stat64_inc(rzs, &rzs->stats.invalid_io);
bio_io_error(bio);
return 0;
@@ -531,8 +511,6 @@ static int ramzswap_ioctl_init_device(struct ramzswap *rzs)
{
int ret;
size_t num_pages;
- struct page *page;
- union swap_header *swap_header;
if (rzs->init_done) {
pr_info("Device already initialized!\n");
@@ -566,19 +544,6 @@ static int ramzswap_ioctl_init_device(struct ramzswap *rzs)
}
memset(rzs->table, 0, num_pages * sizeof(*rzs->table));
- page = alloc_page(__GFP_ZERO);
- if (!page) {
- pr_err("Error allocating swap header page\n");
- ret = -ENOMEM;
- goto fail;
- }
- rzs->table[0].page = page;
- rzs_set_flag(rzs, 0, RZS_UNCOMPRESSED);
-
- swap_header = kmap(page);
- setup_swap_header(rzs, swap_header);
- kunmap(page);
-
set_capacity(rzs->disk, rzs->disksize >> SECTOR_SHIFT);
/* ramzswap devices sort of resembles non-rotational disks */
@@ -693,7 +658,7 @@ void ramzswap_slot_free_notify(struct block_device *bdev, unsigned long index)
return;
}
-static struct block_device_operations ramzswap_devops = {
+static const struct block_device_operations ramzswap_devops = {
.ioctl = ramzswap_ioctl,
.swap_slot_free_notify = ramzswap_slot_free_notify,
.owner = THIS_MODULE
@@ -737,8 +702,14 @@ static int create_device(struct ramzswap *rzs, int device_id)
/* Actual capacity set using RZSIO_SET_DISKSIZE_KB ioctl */
set_capacity(rzs->disk, 0);
+ /*
+ * To ensure that we always get PAGE_SIZE aligned
+ * and n*PAGE_SIZED sized I/O requests.
+ */
blk_queue_physical_block_size(rzs->disk->queue, PAGE_SIZE);
blk_queue_logical_block_size(rzs->disk->queue, PAGE_SIZE);
+ blk_queue_io_min(rzs->disk->queue, PAGE_SIZE);
+ blk_queue_io_opt(rzs->disk->queue, PAGE_SIZE);
add_disk(rzs->disk);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 2/3] Rename ramzswap to zram in code.
2010-05-24 14:18 [PATCH 0/3] zram: generic RAM based compressed R/W block devices Nitin Gupta
2010-05-24 14:18 ` [PATCH 1/3] Support generic I/O requests Nitin Gupta
@ 2010-05-24 14:18 ` Nitin Gupta
2010-05-24 15:31 ` Arnd Bergmann
2010-05-24 14:18 ` [PATCH 3/3] Rename ramzswap to zram in documentation Nitin Gupta
` (2 subsequent siblings)
4 siblings, 1 reply; 17+ messages in thread
From: Nitin Gupta @ 2010-05-24 14:18 UTC (permalink / raw)
To: Greg KH
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
Rename ramzswap to zram in code and also rename
files accordingly.
Automated renames in code:
- rzs* -> zram*
- ramzswap* -> zram*
- RZS -> ZRAM*
(somehow git is not allowing separate commits for
file renames and renames in code).
ramzswap devices are no longer limited to handling
swap requests only. They can now handle arbitrary
I/O requests. So, renaming ramzswap files to zram
to reflect this change. Next few patches will do
similar naming changes within code and documentation.
Changes are also made to various Kconfig and Makefile
so that this patch is compilable.
Signed-off-by: Nitin Gupta <ngupta@vflare.org>
---
drivers/staging/Kconfig | 2 +-
drivers/staging/Makefile | 2 +-
drivers/staging/ramzswap/Kconfig | 21 -
drivers/staging/ramzswap/Makefile | 3 -
drivers/staging/ramzswap/ramzswap.txt | 51 --
drivers/staging/ramzswap/ramzswap_drv.c | 808 ----------------------------
drivers/staging/ramzswap/ramzswap_drv.h | 167 ------
drivers/staging/ramzswap/ramzswap_ioctl.h | 42 --
drivers/staging/ramzswap/xvmalloc.c | 507 ------------------
drivers/staging/ramzswap/xvmalloc.h | 30 --
drivers/staging/ramzswap/xvmalloc_int.h | 86 ---
drivers/staging/zram/Kconfig | 24 +
drivers/staging/zram/Makefile | 3 +
drivers/staging/zram/xvmalloc.c | 507 ++++++++++++++++++
drivers/staging/zram/xvmalloc.h | 30 ++
drivers/staging/zram/xvmalloc_int.h | 86 +++
drivers/staging/zram/zram.txt | 51 ++
drivers/staging/zram/zram_drv.c | 809 +++++++++++++++++++++++++++++
drivers/staging/zram/zram_drv.h | 167 ++++++
drivers/staging/zram/zram_ioctl.h | 42 ++
20 files changed, 1721 insertions(+), 1717 deletions(-)
delete mode 100644 drivers/staging/ramzswap/Kconfig
delete mode 100644 drivers/staging/ramzswap/Makefile
delete mode 100644 drivers/staging/ramzswap/ramzswap.txt
delete mode 100644 drivers/staging/ramzswap/ramzswap_drv.c
delete mode 100644 drivers/staging/ramzswap/ramzswap_drv.h
delete mode 100644 drivers/staging/ramzswap/ramzswap_ioctl.h
delete mode 100644 drivers/staging/ramzswap/xvmalloc.c
delete mode 100644 drivers/staging/ramzswap/xvmalloc.h
delete mode 100644 drivers/staging/ramzswap/xvmalloc_int.h
create mode 100644 drivers/staging/zram/Kconfig
create mode 100644 drivers/staging/zram/Makefile
create mode 100644 drivers/staging/zram/xvmalloc.c
create mode 100644 drivers/staging/zram/xvmalloc.h
create mode 100644 drivers/staging/zram/xvmalloc_int.h
create mode 100644 drivers/staging/zram/zram.txt
create mode 100644 drivers/staging/zram/zram_drv.c
create mode 100644 drivers/staging/zram/zram_drv.h
create mode 100644 drivers/staging/zram/zram_ioctl.h
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index b5c3b30..32d5300 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -117,7 +117,7 @@ source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
-source "drivers/staging/ramzswap/Kconfig"
+source "drivers/staging/zram/Kconfig"
source "drivers/staging/wlags49_h2/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index e330dd5..cec25b0 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -39,7 +39,7 @@ obj-$(CONFIG_RAR_REGISTER) += rar_register/
obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
-obj-$(CONFIG_RAMZSWAP) += ramzswap/
+obj-$(CONFIG_ZRAM) += zram/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
diff --git a/drivers/staging/ramzswap/Kconfig b/drivers/staging/ramzswap/Kconfig
deleted file mode 100644
index 127b3c6..0000000
--- a/drivers/staging/ramzswap/Kconfig
+++ /dev/null
@@ -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 (only) be used as 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.
diff --git a/drivers/staging/ramzswap/Makefile b/drivers/staging/ramzswap/Makefile
deleted file mode 100644
index 507d7dc..0000000
--- a/drivers/staging/ramzswap/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-ramzswap-objs := ramzswap_drv.o xvmalloc.o
-
-obj-$(CONFIG_RAMZSWAP) += ramzswap.o
diff --git a/drivers/staging/ramzswap/ramzswap.txt b/drivers/staging/ramzswap/ramzswap.txt
deleted file mode 100644
index 9694acf..0000000
--- a/drivers/staging/ramzswap/ramzswap.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-ramzswap: Compressed RAM based swap device
--------------------------------------------
-
-Project home: http://compcache.googlecode.com/
-
-* Introduction
-
-The ramzswap module creates RAM based block devices which can (only) be used 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
diff --git a/drivers/staging/ramzswap/ramzswap_drv.c b/drivers/staging/ramzswap/ramzswap_drv.c
deleted file mode 100644
index 9d20d23..0000000
--- a/drivers/staging/ramzswap/ramzswap_drv.c
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
- * Compressed RAM based swap device
- *
- * Copyright (C) 2008, 2009, 2010 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
- */
-
-#define KMSG_COMPONENT "ramzswap"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-#include <linux/blkdev.h>
-#include <linux/buffer_head.h>
-#include <linux/device.h>
-#include <linux/genhd.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <linux/lzo.h>
-#include <linux/string.h>
-#include <linux/swap.h>
-#include <linux/swapops.h>
-#include <linux/vmalloc.h>
-
-#include "ramzswap_drv.h"
-
-/* Globals */
-static int ramzswap_major;
-static struct ramzswap *devices;
-
-/* Module params (documentation at end) */
-static unsigned int num_devices;
-
-static int rzs_test_flag(struct ramzswap *rzs, u32 index,
- enum rzs_pageflags flag)
-{
- return rzs->table[index].flags & BIT(flag);
-}
-
-static void rzs_set_flag(struct ramzswap *rzs, u32 index,
- enum rzs_pageflags flag)
-{
- rzs->table[index].flags |= BIT(flag);
-}
-
-static void rzs_clear_flag(struct ramzswap *rzs, u32 index,
- enum rzs_pageflags flag)
-{
- rzs->table[index].flags &= ~BIT(flag);
-}
-
-static int page_zero_filled(void *ptr)
-{
- unsigned int pos;
- unsigned long *page;
-
- page = (unsigned long *)ptr;
-
- for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
- if (page[pos])
- return 0;
- }
-
- return 1;
-}
-
-static void ramzswap_set_disksize(struct ramzswap *rzs, size_t totalram_bytes)
-{
- if (!rzs->disksize) {
- pr_info(
- "disk size not provided. You can use disksize_kb module "
- "param to specify size.\nUsing default: (%u%% of RAM).\n",
- default_disksize_perc_ram
- );
- rzs->disksize = default_disksize_perc_ram *
- (totalram_bytes / 100);
- }
-
- if (rzs->disksize > 2 * (totalram_bytes)) {
- pr_info(
- "There is little point creating a ramzswap of greater than "
- "twice the size of memory since we expect a 2:1 compression "
- "ratio. Note that ramzswap uses about 0.1%% of the size of "
- "the swap device when not in use so a huge ramzswap is "
- "wasteful.\n"
- "\tMemory Size: %zu kB\n"
- "\tSize you selected: %zu kB\n"
- "Continuing anyway ...\n",
- totalram_bytes >> 10, rzs->disksize
- );
- }
-
- rzs->disksize &= PAGE_MASK;
-}
-
-static void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
- struct ramzswap_ioctl_stats *s)
-{
- s->disksize = rzs->disksize;
-
-#if defined(CONFIG_RAMZSWAP_STATS)
- {
- struct ramzswap_stats *rs = &rzs->stats;
- size_t succ_writes, mem_used;
- unsigned int good_compress_perc = 0, no_compress_perc = 0;
-
- mem_used = xv_get_total_size_bytes(rzs->mem_pool)
- + (rs->pages_expand << PAGE_SHIFT);
- succ_writes = rzs_stat64_read(rzs, &rs->num_writes) -
- rzs_stat64_read(rzs, &rs->failed_writes);
-
- if (succ_writes && rs->pages_stored) {
- good_compress_perc = rs->good_compress * 100
- / rs->pages_stored;
- no_compress_perc = rs->pages_expand * 100
- / rs->pages_stored;
- }
-
- s->num_reads = rzs_stat64_read(rzs, &rs->num_reads);
- s->num_writes = rzs_stat64_read(rzs, &rs->num_writes);
- s->failed_reads = rzs_stat64_read(rzs, &rs->failed_reads);
- s->failed_writes = rzs_stat64_read(rzs, &rs->failed_writes);
- s->invalid_io = rzs_stat64_read(rzs, &rs->invalid_io);
- s->notify_free = rzs_stat64_read(rzs, &rs->notify_free);
- s->pages_zero = rs->pages_zero;
-
- s->good_compress_pct = good_compress_perc;
- s->pages_expand_pct = no_compress_perc;
-
- s->pages_stored = rs->pages_stored;
- s->pages_used = mem_used >> PAGE_SHIFT;
- s->orig_data_size = rs->pages_stored << PAGE_SHIFT;
- s->compr_data_size = rs->compr_size;
- s->mem_used_total = mem_used;
- }
-#endif /* CONFIG_RAMZSWAP_STATS */
-}
-
-static void ramzswap_free_page(struct ramzswap *rzs, size_t index)
-{
- u32 clen;
- void *obj;
-
- struct page *page = rzs->table[index].page;
- u32 offset = rzs->table[index].offset;
-
- if (unlikely(!page)) {
- /*
- * No memory is allocated for zero filled pages.
- * Simply clear zero page flag.
- */
- if (rzs_test_flag(rzs, index, RZS_ZERO)) {
- rzs_clear_flag(rzs, index, RZS_ZERO);
- rzs_stat_dec(&rzs->stats.pages_zero);
- }
- return;
- }
-
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED))) {
- clen = PAGE_SIZE;
- __free_page(page);
- rzs_clear_flag(rzs, index, RZS_UNCOMPRESSED);
- rzs_stat_dec(&rzs->stats.pages_expand);
- goto out;
- }
-
- obj = kmap_atomic(page, KM_USER0) + offset;
- clen = xv_get_object_size(obj) - sizeof(struct zobj_header);
- kunmap_atomic(obj, KM_USER0);
-
- xv_free(rzs->mem_pool, page, offset);
- if (clen <= PAGE_SIZE / 2)
- rzs_stat_dec(&rzs->stats.good_compress);
-
-out:
- rzs->stats.compr_size -= clen;
- rzs_stat_dec(&rzs->stats.pages_stored);
-
- rzs->table[index].page = NULL;
- rzs->table[index].offset = 0;
-}
-
-static void handle_zero_page(struct page *page, u32 index)
-{
- void *user_mem;
-
- user_mem = kmap_atomic(page, KM_USER0);
- memset(user_mem, 0, PAGE_SIZE);
- kunmap_atomic(user_mem, KM_USER0);
-
- flush_dcache_page(page);
-}
-
-static void handle_uncompressed_page(struct ramzswap *rzs,
- struct page *page, u32 index)
-{
- unsigned char *user_mem, *cmem;
-
- user_mem = kmap_atomic(page, KM_USER0);
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
-
- memcpy(user_mem, cmem, PAGE_SIZE);
- kunmap_atomic(user_mem, KM_USER0);
- kunmap_atomic(cmem, KM_USER1);
-
- flush_dcache_page(page);
-}
-
-static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
-{
-
- int i;
- u32 index;
- struct bio_vec *bvec;
-
- rzs_stat64_inc(rzs, &rzs->stats.num_reads);
-
- index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
- bio_for_each_segment(bvec, bio, i) {
- int ret;
- size_t clen;
- struct page *page;
- struct zobj_header *zheader;
- unsigned char *user_mem, *cmem;
-
- page = bvec->bv_page;
-
- if (rzs_test_flag(rzs, index, RZS_ZERO)) {
- handle_zero_page(page, index);
- continue;
- }
-
- /* Requested page is not present in compressed area */
- if (unlikely(!rzs->table[index].page)) {
- pr_debug("Read before write on swap device: "
- "sector=%lu, size=%u",
- (ulong)(bio->bi_sector), bio->bi_size);
- /* Do nothing */
- continue;
- }
-
- /* Page is stored uncompressed since it's incompressible */
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED))) {
- handle_uncompressed_page(rzs, page, index);
- continue;
- }
-
- user_mem = kmap_atomic(page, KM_USER0);
- clen = PAGE_SIZE;
-
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
-
- ret = lzo1x_decompress_safe(
- cmem + sizeof(*zheader),
- xv_get_object_size(cmem) - sizeof(*zheader),
- user_mem, &clen);
-
- kunmap_atomic(user_mem, KM_USER0);
- kunmap_atomic(cmem, KM_USER1);
-
- /* should NEVER happen */
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Decompression failed! err=%d, page=%u\n",
- ret, index);
- rzs_stat64_inc(rzs, &rzs->stats.failed_reads);
- goto out;
- }
-
- flush_dcache_page(page);
- index++;
- }
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
-
-out:
- bio_io_error(bio);
- return 0;
-}
-
-static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
-{
- int i;
- u32 index;
- struct bio_vec *bvec;
-
- rzs_stat64_inc(rzs, &rzs->stats.num_writes);
-
- index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
-
- bio_for_each_segment(bvec, bio, i) {
- int ret;
- u32 offset;
- size_t clen;
- struct zobj_header *zheader;
- struct page *page, *page_store;
- unsigned char *user_mem, *cmem, *src;
-
- page = bvec->bv_page;
- src = rzs->compress_buffer;
-
- /*
- * System overwrites unused sectors. Free memory associated
- * with this sector now.
- */
- if (rzs->table[index].page ||
- rzs_test_flag(rzs, index, RZS_ZERO))
- ramzswap_free_page(rzs, index);
-
- mutex_lock(&rzs->lock);
-
- user_mem = kmap_atomic(page, KM_USER0);
- if (page_zero_filled(user_mem)) {
- kunmap_atomic(user_mem, KM_USER0);
- mutex_unlock(&rzs->lock);
- rzs_stat_inc(&rzs->stats.pages_zero);
- rzs_set_flag(rzs, index, RZS_ZERO);
- continue;
- }
-
- ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen,
- rzs->compress_workmem);
-
- kunmap_atomic(user_mem, KM_USER0);
-
- if (unlikely(ret != LZO_E_OK)) {
- mutex_unlock(&rzs->lock);
- pr_err("Compression failed! err=%d\n", ret);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
- goto out;
- }
-
- /*
- * Page is incompressible. Store it as-is (uncompressed)
- * since we do not want to return too many swap write
- * errors which has side effect of hanging the system.
- */
- if (unlikely(clen > max_zpage_size)) {
- clen = PAGE_SIZE;
- page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
- if (unlikely(!page_store)) {
- mutex_unlock(&rzs->lock);
- pr_info("Error allocating memory for "
- "incompressible page: %u\n", index);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
- goto out;
- }
-
- offset = 0;
- rzs_set_flag(rzs, index, RZS_UNCOMPRESSED);
- rzs_stat_inc(&rzs->stats.pages_expand);
- rzs->table[index].page = page_store;
- src = kmap_atomic(page, KM_USER0);
- goto memstore;
- }
-
- if (xv_malloc(rzs->mem_pool, clen + sizeof(*zheader),
- &rzs->table[index].page, &offset,
- GFP_NOIO | __GFP_HIGHMEM)) {
- mutex_unlock(&rzs->lock);
- pr_info("Error allocating memory for compressed "
- "page: %u, size=%zu\n", index, clen);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
- goto out;
- }
-
-memstore:
- rzs->table[index].offset = offset;
-
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
-
-#if 0
- /* Back-reference needed for memory defragmentation */
- if (!rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)) {
- zheader = (struct zobj_header *)cmem;
- zheader->table_idx = index;
- cmem += sizeof(*zheader);
- }
-#endif
-
- memcpy(cmem, src, clen);
-
- kunmap_atomic(cmem, KM_USER1);
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
- kunmap_atomic(src, KM_USER0);
-
- /* Update stats */
- rzs->stats.compr_size += clen;
- rzs_stat_inc(&rzs->stats.pages_stored);
- if (clen <= PAGE_SIZE / 2)
- rzs_stat_inc(&rzs->stats.good_compress);
-
- mutex_unlock(&rzs->lock);
- index++;
- }
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
-
-out:
- bio_io_error(bio);
- return 0;
-}
-
-/*
- * Check if request is within bounds and page aligned.
- */
-static inline int valid_io_request(struct ramzswap *rzs, struct bio *bio)
-{
- if (unlikely(
- (bio->bi_sector >= (rzs->disksize >> SECTOR_SHIFT)) ||
- (bio->bi_sector & (SECTORS_PER_PAGE - 1)) ||
- (bio->bi_size & (PAGE_SIZE - 1)))) {
-
- return 0;
- }
-
- /* I/O request is valid */
- return 1;
-}
-
-/*
- * Handler function for all ramzswap I/O requests.
- */
-static int ramzswap_make_request(struct request_queue *queue, struct bio *bio)
-{
- int ret = 0;
- struct ramzswap *rzs = queue->queuedata;
-
- if (unlikely(!rzs->init_done)) {
- bio_io_error(bio);
- return 0;
- }
-
- if (!valid_io_request(rzs, bio)) {
- rzs_stat64_inc(rzs, &rzs->stats.invalid_io);
- bio_io_error(bio);
- return 0;
- }
-
- switch (bio_data_dir(bio)) {
- case READ:
- ret = ramzswap_read(rzs, bio);
- break;
-
- case WRITE:
- ret = ramzswap_write(rzs, bio);
- break;
- }
-
- return ret;
-}
-
-static void reset_device(struct ramzswap *rzs)
-{
- size_t index;
-
- /* Do not accept any new I/O request */
- rzs->init_done = 0;
-
- /* Free various per-device buffers */
- kfree(rzs->compress_workmem);
- free_pages((unsigned long)rzs->compress_buffer, 1);
-
- rzs->compress_workmem = NULL;
- rzs->compress_buffer = NULL;
-
- /* Free all pages that are still in this ramzswap device */
- for (index = 0; index < rzs->disksize >> PAGE_SHIFT; index++) {
- struct page *page;
- u16 offset;
-
- page = rzs->table[index].page;
- offset = rzs->table[index].offset;
-
- if (!page)
- continue;
-
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
- __free_page(page);
- else
- xv_free(rzs->mem_pool, page, offset);
- }
-
- vfree(rzs->table);
- rzs->table = NULL;
-
- xv_destroy_pool(rzs->mem_pool);
- rzs->mem_pool = NULL;
-
- /* Reset stats */
- memset(&rzs->stats, 0, sizeof(rzs->stats));
-
- rzs->disksize = 0;
-}
-
-static int ramzswap_ioctl_init_device(struct ramzswap *rzs)
-{
- int ret;
- size_t num_pages;
-
- if (rzs->init_done) {
- pr_info("Device already initialized!\n");
- return -EBUSY;
- }
-
- ramzswap_set_disksize(rzs, totalram_pages << PAGE_SHIFT);
-
- rzs->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
- if (!rzs->compress_workmem) {
- pr_err("Error allocating compressor working memory!\n");
- ret = -ENOMEM;
- goto fail;
- }
-
- rzs->compress_buffer = (void *)__get_free_pages(__GFP_ZERO, 1);
- if (!rzs->compress_buffer) {
- pr_err("Error allocating compressor buffer space\n");
- ret = -ENOMEM;
- goto fail;
- }
-
- num_pages = rzs->disksize >> PAGE_SHIFT;
- rzs->table = vmalloc(num_pages * sizeof(*rzs->table));
- if (!rzs->table) {
- pr_err("Error allocating ramzswap address table\n");
- /* To prevent accessing table entries during cleanup */
- rzs->disksize = 0;
- ret = -ENOMEM;
- goto fail;
- }
- memset(rzs->table, 0, num_pages * sizeof(*rzs->table));
-
- set_capacity(rzs->disk, rzs->disksize >> SECTOR_SHIFT);
-
- /* ramzswap devices sort of resembles non-rotational disks */
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, rzs->disk->queue);
-
- rzs->mem_pool = xv_create_pool();
- if (!rzs->mem_pool) {
- pr_err("Error creating memory pool\n");
- ret = -ENOMEM;
- goto fail;
- }
-
- rzs->init_done = 1;
-
- pr_debug("Initialization done!\n");
- return 0;
-
-fail:
- reset_device(rzs);
-
- pr_err("Initialization failed: err=%d\n", ret);
- return ret;
-}
-
-static int ramzswap_ioctl_reset_device(struct ramzswap *rzs)
-{
- if (rzs->init_done)
- reset_device(rzs);
-
- return 0;
-}
-
-static int ramzswap_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- int ret = 0;
- size_t disksize_kb;
-
- struct ramzswap *rzs = bdev->bd_disk->private_data;
-
- switch (cmd) {
- case RZSIO_SET_DISKSIZE_KB:
- if (rzs->init_done) {
- ret = -EBUSY;
- goto out;
- }
- if (copy_from_user(&disksize_kb, (void *)arg,
- _IOC_SIZE(cmd))) {
- ret = -EFAULT;
- goto out;
- }
- rzs->disksize = disksize_kb << 10;
- pr_info("Disk size set to %zu kB\n", disksize_kb);
- break;
-
- case RZSIO_GET_STATS:
- {
- struct ramzswap_ioctl_stats *stats;
- if (!rzs->init_done) {
- ret = -ENOTTY;
- goto out;
- }
- stats = kzalloc(sizeof(*stats), GFP_KERNEL);
- if (!stats) {
- ret = -ENOMEM;
- goto out;
- }
- ramzswap_ioctl_get_stats(rzs, stats);
- if (copy_to_user((void *)arg, stats, sizeof(*stats))) {
- kfree(stats);
- ret = -EFAULT;
- goto out;
- }
- kfree(stats);
- break;
- }
- case RZSIO_INIT:
- ret = ramzswap_ioctl_init_device(rzs);
- break;
-
- case RZSIO_RESET:
- /* Do not reset an active device! */
- if (bdev->bd_holders) {
- ret = -EBUSY;
- goto out;
- }
-
- /* Make sure all pending I/O is finished */
- if (bdev)
- fsync_bdev(bdev);
-
- ret = ramzswap_ioctl_reset_device(rzs);
- break;
-
- default:
- pr_info("Invalid ioctl %u\n", cmd);
- ret = -ENOTTY;
- }
-
-out:
- return ret;
-}
-
-void ramzswap_slot_free_notify(struct block_device *bdev, unsigned long index)
-{
- struct ramzswap *rzs;
-
- rzs = bdev->bd_disk->private_data;
- ramzswap_free_page(rzs, index);
- rzs_stat64_inc(rzs, &rzs->stats.notify_free);
-
- return;
-}
-
-static const struct block_device_operations ramzswap_devops = {
- .ioctl = ramzswap_ioctl,
- .swap_slot_free_notify = ramzswap_slot_free_notify,
- .owner = THIS_MODULE
-};
-
-static int create_device(struct ramzswap *rzs, int device_id)
-{
- int ret = 0;
-
- mutex_init(&rzs->lock);
- spin_lock_init(&rzs->stat64_lock);
-
- rzs->queue = blk_alloc_queue(GFP_KERNEL);
- if (!rzs->queue) {
- pr_err("Error allocating disk queue for device %d\n",
- device_id);
- ret = -ENOMEM;
- goto out;
- }
-
- blk_queue_make_request(rzs->queue, ramzswap_make_request);
- rzs->queue->queuedata = rzs;
-
- /* gendisk structure */
- rzs->disk = alloc_disk(1);
- if (!rzs->disk) {
- blk_cleanup_queue(rzs->queue);
- pr_warning("Error allocating disk structure for device %d\n",
- device_id);
- ret = -ENOMEM;
- goto out;
- }
-
- rzs->disk->major = ramzswap_major;
- rzs->disk->first_minor = device_id;
- rzs->disk->fops = &ramzswap_devops;
- rzs->disk->queue = rzs->queue;
- rzs->disk->private_data = rzs;
- snprintf(rzs->disk->disk_name, 16, "ramzswap%d", device_id);
-
- /* Actual capacity set using RZSIO_SET_DISKSIZE_KB ioctl */
- set_capacity(rzs->disk, 0);
-
- /*
- * To ensure that we always get PAGE_SIZE aligned
- * and n*PAGE_SIZED sized I/O requests.
- */
- blk_queue_physical_block_size(rzs->disk->queue, PAGE_SIZE);
- blk_queue_logical_block_size(rzs->disk->queue, PAGE_SIZE);
- blk_queue_io_min(rzs->disk->queue, PAGE_SIZE);
- blk_queue_io_opt(rzs->disk->queue, PAGE_SIZE);
-
- add_disk(rzs->disk);
-
- rzs->init_done = 0;
-
-out:
- return ret;
-}
-
-static void destroy_device(struct ramzswap *rzs)
-{
- if (rzs->disk) {
- del_gendisk(rzs->disk);
- put_disk(rzs->disk);
- }
-
- if (rzs->queue)
- blk_cleanup_queue(rzs->queue);
-}
-
-static int __init ramzswap_init(void)
-{
- int ret, dev_id;
-
- if (num_devices > max_num_devices) {
- pr_warning("Invalid value for num_devices: %u\n",
- num_devices);
- ret = -EINVAL;
- goto out;
- }
-
- ramzswap_major = register_blkdev(0, "ramzswap");
- if (ramzswap_major <= 0) {
- pr_warning("Unable to get major number\n");
- ret = -EBUSY;
- goto out;
- }
-
- if (!num_devices) {
- pr_info("num_devices not specified. Using default: 1\n");
- num_devices = 1;
- }
-
- /* Allocate the device array and initialize each one */
- pr_info("Creating %u devices ...\n", num_devices);
- devices = kzalloc(num_devices * sizeof(struct ramzswap), GFP_KERNEL);
- if (!devices) {
- ret = -ENOMEM;
- goto unregister;
- }
-
- for (dev_id = 0; dev_id < num_devices; dev_id++) {
- ret = create_device(&devices[dev_id], dev_id);
- if (ret)
- goto free_devices;
- }
-
- return 0;
-
-free_devices:
- while (dev_id)
- destroy_device(&devices[--dev_id]);
-unregister:
- unregister_blkdev(ramzswap_major, "ramzswap");
-out:
- return ret;
-}
-
-static void __exit ramzswap_exit(void)
-{
- int i;
- struct ramzswap *rzs;
-
- for (i = 0; i < num_devices; i++) {
- rzs = &devices[i];
-
- destroy_device(rzs);
- if (rzs->init_done)
- reset_device(rzs);
- }
-
- unregister_blkdev(ramzswap_major, "ramzswap");
-
- kfree(devices);
- pr_debug("Cleanup done!\n");
-}
-
-module_param(num_devices, uint, 0);
-MODULE_PARM_DESC(num_devices, "Number of ramzswap devices");
-
-module_init(ramzswap_init);
-module_exit(ramzswap_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
-MODULE_DESCRIPTION("Compressed RAM Based Swap Device");
diff --git a/drivers/staging/ramzswap/ramzswap_drv.h b/drivers/staging/ramzswap/ramzswap_drv.h
deleted file mode 100644
index 63c3042..0000000
--- a/drivers/staging/ramzswap/ramzswap_drv.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Compressed RAM based swap device
- *
- * Copyright (C) 2008, 2009, 2010 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 <linux/spinlock.h>
-#include <linux/mutex.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.
- */
-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;
-
-/*
- * Pages that compress to size greater than this are stored
- * uncompressed in memory.
- */
-static const unsigned max_zpage_size = PAGE_SIZE / 4 * 3;
-
-/*
- * NOTE: max_zpage_size must be less than or equal to:
- * XV_MAX_ALLOC_SIZE - sizeof(struct zobj_header)
- * 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)
-
-/* 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)));
-
-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; /* should NEVER! happen */
- u64 failed_writes; /* can happen when memory is too low */
- u64 invalid_io; /* non-swap I/O requests */
- u64 notify_free; /* no. of swap slot free notifications */
- 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 */
-#endif
-};
-
-struct ramzswap {
- struct xv_pool *mem_pool;
- void *compress_workmem;
- void *compress_buffer;
- struct table *table;
- spinlock_t stat64_lock; /* protect 64-bit stats */
- struct mutex lock;
- struct request_queue *queue;
- struct gendisk *disk;
- int init_done;
- /*
- * 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;
-};
-
-/*-- */
-
-/* Debugging and Stats */
-#if defined(CONFIG_RAMZSWAP_STATS)
-static void rzs_stat_inc(u32 *v)
-{
- *v = *v + 1;
-}
-
-static void rzs_stat_dec(u32 *v)
-{
- *v = *v - 1;
-}
-
-static void rzs_stat64_inc(struct ramzswap *rzs, u64 *v)
-{
- spin_lock(&rzs->stat64_lock);
- *v = *v + 1;
- spin_unlock(&rzs->stat64_lock);
-}
-
-static u64 rzs_stat64_read(struct ramzswap *rzs, u64 *v)
-{
- u64 val;
-
- spin_lock(&rzs->stat64_lock);
- val = *v;
- spin_unlock(&rzs->stat64_lock);
-
- return val;
-}
-#else
-#define rzs_stat_inc(v)
-#define rzs_stat_dec(v)
-#define rzs_stat64_inc(r, v)
-#define rzs_stat64_read(r, v)
-#endif /* CONFIG_RAMZSWAP_STATS */
-
-#endif
diff --git a/drivers/staging/ramzswap/ramzswap_ioctl.h b/drivers/staging/ramzswap/ramzswap_ioctl.h
deleted file mode 100644
index db94bcb..0000000
--- a/drivers/staging/ramzswap/ramzswap_ioctl.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Compressed RAM based swap device
- *
- * Copyright (C) 2008, 2009, 2010 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_
-
-struct ramzswap_ioctl_stats {
- u64 disksize; /* user specified or equal to backing swap
- * size (if present) */
- u64 num_reads; /* failed + successful */
- u64 num_writes; /* --do-- */
- u64 failed_reads; /* should NEVER! happen */
- u64 failed_writes; /* can happen when memory is too low */
- u64 invalid_io; /* non-swap I/O requests */
- u64 notify_free; /* no. of swap slot free notifications */
- 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;
-} __attribute__ ((packed, aligned(4)));
-
-#define RZSIO_SET_DISKSIZE_KB _IOW('z', 0, size_t)
-#define RZSIO_GET_STATS _IOR('z', 1, struct ramzswap_ioctl_stats)
-#define RZSIO_INIT _IO('z', 2)
-#define RZSIO_RESET _IO('z', 3)
-
-#endif
diff --git a/drivers/staging/ramzswap/xvmalloc.c b/drivers/staging/ramzswap/xvmalloc.c
deleted file mode 100644
index 3fdbb8a..0000000
--- a/drivers/staging/ramzswap/xvmalloc.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * xvmalloc memory allocator
- *
- * Copyright (C) 2008, 2009, 2010 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 to 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;
-}
diff --git a/drivers/staging/ramzswap/xvmalloc.h b/drivers/staging/ramzswap/xvmalloc.h
deleted file mode 100644
index 5b1a81a..0000000
--- a/drivers/staging/ramzswap/xvmalloc.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * xvmalloc memory allocator
- *
- * Copyright (C) 2008, 2009, 2010 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
diff --git a/drivers/staging/ramzswap/xvmalloc_int.h b/drivers/staging/ramzswap/xvmalloc_int.h
deleted file mode 100644
index e23ed5c..0000000
--- a/drivers/staging/ramzswap/xvmalloc_int.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * xvmalloc memory allocator
- *
- * Copyright (C) 2008, 2009, 2010 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 XV_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
diff --git a/drivers/staging/zram/Kconfig b/drivers/staging/zram/Kconfig
new file mode 100644
index 0000000..fad9ff5
--- /dev/null
+++ b/drivers/staging/zram/Kconfig
@@ -0,0 +1,24 @@
+config ZRAM
+ tristate "Compressed in-memory block device (zram)"
+ select LZO_COMPRESS
+ select LZO_DECOMPRESS
+ default n
+ help
+ Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
+ Pages written to these disks are compressed and stored in memory
+ itself. These disks allow very fast I/O and compression provides
+ good amounts of memory savings.
+
+ It has several use cases, for example: /tmp storage, use as swap
+ disks and maybe many more.
+
+ See zram.txt for more information.
+ Project home: http://compcache.googlecode.com/
+
+config ZRAM_STATS
+ bool "Enable zram stats"
+ depends on ZRAM
+ default y
+ help
+ Enable statistics collection for zram devices. This adds only a
+ minimal overhead. In unsure, say Y.
diff --git a/drivers/staging/zram/Makefile b/drivers/staging/zram/Makefile
new file mode 100644
index 0000000..b2c087a
--- /dev/null
+++ b/drivers/staging/zram/Makefile
@@ -0,0 +1,3 @@
+zram-objs := zram_drv.o xvmalloc.o
+
+obj-$(CONFIG_ZRAM) += zram.o
diff --git a/drivers/staging/zram/xvmalloc.c b/drivers/staging/zram/xvmalloc.c
new file mode 100644
index 0000000..3fdbb8a
--- /dev/null
+++ b/drivers/staging/zram/xvmalloc.c
@@ -0,0 +1,507 @@
+/*
+ * xvmalloc memory allocator
+ *
+ * Copyright (C) 2008, 2009, 2010 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 to 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;
+}
diff --git a/drivers/staging/zram/xvmalloc.h b/drivers/staging/zram/xvmalloc.h
new file mode 100644
index 0000000..5b1a81a
--- /dev/null
+++ b/drivers/staging/zram/xvmalloc.h
@@ -0,0 +1,30 @@
+/*
+ * xvmalloc memory allocator
+ *
+ * Copyright (C) 2008, 2009, 2010 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
diff --git a/drivers/staging/zram/xvmalloc_int.h b/drivers/staging/zram/xvmalloc_int.h
new file mode 100644
index 0000000..e23ed5c
--- /dev/null
+++ b/drivers/staging/zram/xvmalloc_int.h
@@ -0,0 +1,86 @@
+/*
+ * xvmalloc memory allocator
+ *
+ * Copyright (C) 2008, 2009, 2010 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 XV_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
diff --git a/drivers/staging/zram/zram.txt b/drivers/staging/zram/zram.txt
new file mode 100644
index 0000000..9694acf
--- /dev/null
+++ b/drivers/staging/zram/zram.txt
@@ -0,0 +1,51 @@
+ramzswap: Compressed RAM based swap device
+-------------------------------------------
+
+Project home: http://compcache.googlecode.com/
+
+* Introduction
+
+The ramzswap module creates RAM based block devices which can (only) be used 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
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
new file mode 100644
index 0000000..e962757
--- /dev/null
+++ b/drivers/staging/zram/zram_drv.c
@@ -0,0 +1,809 @@
+/*
+ * Compressed RAM block device
+ *
+ * Copyright (C) 2008, 2009, 2010 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
+ */
+
+#define KMSG_COMPONENT "zram"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/device.h>
+#include <linux/genhd.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/lzo.h>
+#include <linux/string.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
+#include <linux/vmalloc.h>
+
+#include "zram_drv.h"
+
+/* Globals */
+static int zram_major;
+static struct zram *devices;
+
+/* Module params (documentation at end) */
+static unsigned int num_devices;
+
+static int zram_test_flag(struct zram *zram, u32 index,
+ enum zram_pageflags flag)
+{
+ return zram->table[index].flags & BIT(flag);
+}
+
+static void zram_set_flag(struct zram *zram, u32 index,
+ enum zram_pageflags flag)
+{
+ zram->table[index].flags |= BIT(flag);
+}
+
+static void zram_clear_flag(struct zram *zram, u32 index,
+ enum zram_pageflags flag)
+{
+ zram->table[index].flags &= ~BIT(flag);
+}
+
+static int page_zero_filled(void *ptr)
+{
+ unsigned int pos;
+ unsigned long *page;
+
+ page = (unsigned long *)ptr;
+
+ for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
+ if (page[pos])
+ return 0;
+ }
+
+ return 1;
+}
+
+static void zram_set_disksize(struct zram *zram, size_t totalram_bytes)
+{
+ if (!zram->disksize) {
+ pr_info(
+ "disk size not provided. You can use disksize_kb module "
+ "param to specify size.\nUsing default: (%u%% of RAM).\n",
+ default_disksize_perc_ram
+ );
+ zram->disksize = default_disksize_perc_ram *
+ (totalram_bytes / 100);
+ }
+
+ if (zram->disksize > 2 * (totalram_bytes)) {
+ pr_info(
+ "There is little point creating a zram of greater than "
+ "twice the size of memory since we expect a 2:1 compression "
+ "ratio. Note that zram uses about 0.1%% of the size of "
+ "the swap device when not in use so a huge zram is "
+ "wasteful.\n"
+ "\tMemory Size: %zu kB\n"
+ "\tSize you selected: %zu kB\n"
+ "Continuing anyway ...\n",
+ totalram_bytes >> 10, zram->disksize
+ );
+ }
+
+ zram->disksize &= PAGE_MASK;
+}
+
+static void zram_ioctl_get_stats(struct zram *zram,
+ struct zram_ioctl_stats *s)
+{
+ s->disksize = zram->disksize;
+
+#if defined(CONFIG_ZRAM_STATS)
+ {
+ struct zram_stats *rs = &zram->stats;
+ size_t succ_writes, mem_used;
+ unsigned int good_compress_perc = 0, no_compress_perc = 0;
+
+ mem_used = xv_get_total_size_bytes(zram->mem_pool)
+ + (rs->pages_expand << PAGE_SHIFT);
+ succ_writes = zram_stat64_read(zram, &rs->num_writes) -
+ zram_stat64_read(zram, &rs->failed_writes);
+
+ if (succ_writes && rs->pages_stored) {
+ good_compress_perc = rs->good_compress * 100
+ / rs->pages_stored;
+ no_compress_perc = rs->pages_expand * 100
+ / rs->pages_stored;
+ }
+
+ s->num_reads = zram_stat64_read(zram, &rs->num_reads);
+ s->num_writes = zram_stat64_read(zram, &rs->num_writes);
+ s->failed_reads = zram_stat64_read(zram, &rs->failed_reads);
+ s->failed_writes = zram_stat64_read(zram, &rs->failed_writes);
+ s->invalid_io = zram_stat64_read(zram, &rs->invalid_io);
+ s->notify_free = zram_stat64_read(zram, &rs->notify_free);
+ s->pages_zero = rs->pages_zero;
+
+ s->good_compress_pct = good_compress_perc;
+ s->pages_expand_pct = no_compress_perc;
+
+ s->pages_stored = rs->pages_stored;
+ s->pages_used = mem_used >> PAGE_SHIFT;
+ s->orig_data_size = rs->pages_stored << PAGE_SHIFT;
+ s->compr_data_size = rs->compr_size;
+ s->mem_used_total = mem_used;
+ }
+#endif /* CONFIG_ZRAM_STATS */
+}
+
+static void zram_free_page(struct zram *zram, size_t index)
+{
+ u32 clen;
+ void *obj;
+
+ struct page *page = zram->table[index].page;
+ u32 offset = zram->table[index].offset;
+
+ if (unlikely(!page)) {
+ /*
+ * No memory is allocated for zero filled pages.
+ * Simply clear zero page flag.
+ */
+ if (zram_test_flag(zram, index, ZRAM_ZERO)) {
+ zram_clear_flag(zram, index, ZRAM_ZERO);
+ zram_stat_dec(&zram->stats.pages_zero);
+ }
+ return;
+ }
+
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
+ clen = PAGE_SIZE;
+ __free_page(page);
+ zram_clear_flag(zram, index, ZRAM_UNCOMPRESSED);
+ zram_stat_dec(&zram->stats.pages_expand);
+ goto out;
+ }
+
+ obj = kmap_atomic(page, KM_USER0) + offset;
+ clen = xv_get_object_size(obj) - sizeof(struct zobj_header);
+ kunmap_atomic(obj, KM_USER0);
+
+ xv_free(zram->mem_pool, page, offset);
+ if (clen <= PAGE_SIZE / 2)
+ zram_stat_dec(&zram->stats.good_compress);
+
+out:
+ zram->stats.compr_size -= clen;
+ zram_stat_dec(&zram->stats.pages_stored);
+
+ zram->table[index].page = NULL;
+ zram->table[index].offset = 0;
+}
+
+static void handle_zero_page(struct page *page, u32 index)
+{
+ void *user_mem;
+
+ user_mem = kmap_atomic(page, KM_USER0);
+ memset(user_mem, 0, PAGE_SIZE);
+ kunmap_atomic(user_mem, KM_USER0);
+
+ flush_dcache_page(page);
+}
+
+static void handle_uncompressed_page(struct zram *zram,
+ struct page *page, u32 index)
+{
+ unsigned char *user_mem, *cmem;
+
+ user_mem = kmap_atomic(page, KM_USER0);
+ cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
+ zram->table[index].offset;
+
+ memcpy(user_mem, cmem, PAGE_SIZE);
+ kunmap_atomic(user_mem, KM_USER0);
+ kunmap_atomic(cmem, KM_USER1);
+
+ flush_dcache_page(page);
+}
+
+static int zram_read(struct zram *zram, struct bio *bio)
+{
+
+ int i;
+ u32 index;
+ struct bio_vec *bvec;
+
+ zram_stat64_inc(zram, &zram->stats.num_reads);
+
+ index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
+ bio_for_each_segment(bvec, bio, i) {
+ int ret;
+ size_t clen;
+ struct page *page;
+ struct zobj_header *zheader;
+ unsigned char *user_mem, *cmem;
+
+ page = bvec->bv_page;
+
+ if (zram_test_flag(zram, index, ZRAM_ZERO)) {
+ handle_zero_page(page, index);
+ continue;
+ }
+
+ /* Requested page is not present in compressed area */
+ if (unlikely(!zram->table[index].page)) {
+ pr_debug("Read before write on swap device: "
+ "sector=%lu, size=%u",
+ (ulong)(bio->bi_sector), bio->bi_size);
+ /* Do nothing */
+ continue;
+ }
+
+ /* Page is stored uncompressed since it's incompressible */
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
+ handle_uncompressed_page(zram, page, index);
+ continue;
+ }
+
+ user_mem = kmap_atomic(page, KM_USER0);
+ clen = PAGE_SIZE;
+
+ cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
+ zram->table[index].offset;
+
+ ret = lzo1x_decompress_safe(
+ cmem + sizeof(*zheader),
+ xv_get_object_size(cmem) - sizeof(*zheader),
+ user_mem, &clen);
+
+ kunmap_atomic(user_mem, KM_USER0);
+ kunmap_atomic(cmem, KM_USER1);
+
+ /* should NEVER happen */
+ if (unlikely(ret != LZO_E_OK)) {
+ pr_err("Decompression failed! err=%d, page=%u\n",
+ ret, index);
+ zram_stat64_inc(zram, &zram->stats.failed_reads);
+ goto out;
+ }
+
+ flush_dcache_page(page);
+ index++;
+ }
+
+ set_bit(BIO_UPTODATE, &bio->bi_flags);
+ bio_endio(bio, 0);
+ return 0;
+
+out:
+ bio_io_error(bio);
+ return 0;
+}
+
+static int zram_write(struct zram *zram, struct bio *bio)
+{
+ int i;
+ u32 index;
+ struct bio_vec *bvec;
+
+ zram_stat64_inc(zram, &zram->stats.num_writes);
+
+ index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
+
+ bio_for_each_segment(bvec, bio, i) {
+ int ret;
+ u32 offset;
+ size_t clen;
+ struct zobj_header *zheader;
+ struct page *page, *page_store;
+ unsigned char *user_mem, *cmem, *src;
+
+ page = bvec->bv_page;
+ src = zram->compress_buffer;
+
+ /*
+ * System overwrites unused sectors. Free memory associated
+ * with this sector now.
+ */
+ if (zram->table[index].page ||
+ zram_test_flag(zram, index, ZRAM_ZERO))
+ zram_free_page(zram, index);
+
+ mutex_lock(&zram->lock);
+
+ user_mem = kmap_atomic(page, KM_USER0);
+ if (page_zero_filled(user_mem)) {
+ kunmap_atomic(user_mem, KM_USER0);
+ mutex_unlock(&zram->lock);
+ zram_stat_inc(&zram->stats.pages_zero);
+ zram_set_flag(zram, index, ZRAM_ZERO);
+ continue;
+ }
+
+ ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen,
+ zram->compress_workmem);
+
+ kunmap_atomic(user_mem, KM_USER0);
+
+ if (unlikely(ret != LZO_E_OK)) {
+ mutex_unlock(&zram->lock);
+ pr_err("Compression failed! err=%d\n", ret);
+ zram_stat64_inc(zram, &zram->stats.failed_writes);
+ goto out;
+ }
+
+ /*
+ * Page is incompressible. Store it as-is (uncompressed)
+ * since we do not want to return too many swap write
+ * errors which has side effect of hanging the system.
+ */
+ if (unlikely(clen > max_zpage_size)) {
+ clen = PAGE_SIZE;
+ page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
+ if (unlikely(!page_store)) {
+ mutex_unlock(&zram->lock);
+ pr_info("Error allocating memory for "
+ "incompressible page: %u\n", index);
+ zram_stat64_inc(zram,
+ &zram->stats.failed_writes);
+ goto out;
+ }
+
+ offset = 0;
+ zram_set_flag(zram, index, ZRAM_UNCOMPRESSED);
+ zram_stat_inc(&zram->stats.pages_expand);
+ zram->table[index].page = page_store;
+ src = kmap_atomic(page, KM_USER0);
+ goto memstore;
+ }
+
+ if (xv_malloc(zram->mem_pool, clen + sizeof(*zheader),
+ &zram->table[index].page, &offset,
+ GFP_NOIO | __GFP_HIGHMEM)) {
+ mutex_unlock(&zram->lock);
+ pr_info("Error allocating memory for compressed "
+ "page: %u, size=%zu\n", index, clen);
+ zram_stat64_inc(zram, &zram->stats.failed_writes);
+ goto out;
+ }
+
+memstore:
+ zram->table[index].offset = offset;
+
+ cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
+ zram->table[index].offset;
+
+#if 0
+ /* Back-reference needed for memory defragmentation */
+ if (!zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)) {
+ zheader = (struct zobj_header *)cmem;
+ zheader->table_idx = index;
+ cmem += sizeof(*zheader);
+ }
+#endif
+
+ memcpy(cmem, src, clen);
+
+ kunmap_atomic(cmem, KM_USER1);
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
+ kunmap_atomic(src, KM_USER0);
+
+ /* Update stats */
+ zram->stats.compr_size += clen;
+ zram_stat_inc(&zram->stats.pages_stored);
+ if (clen <= PAGE_SIZE / 2)
+ zram_stat_inc(&zram->stats.good_compress);
+
+ mutex_unlock(&zram->lock);
+ index++;
+ }
+
+ set_bit(BIO_UPTODATE, &bio->bi_flags);
+ bio_endio(bio, 0);
+ return 0;
+
+out:
+ bio_io_error(bio);
+ return 0;
+}
+
+/*
+ * Check if request is within bounds and page aligned.
+ */
+static inline int valid_io_request(struct zram *zram, struct bio *bio)
+{
+ if (unlikely(
+ (bio->bi_sector >= (zram->disksize >> SECTOR_SHIFT)) ||
+ (bio->bi_sector & (SECTORS_PER_PAGE - 1)) ||
+ (bio->bi_size & (PAGE_SIZE - 1)))) {
+
+ return 0;
+ }
+
+ /* I/O request is valid */
+ return 1;
+}
+
+/*
+ * Handler function for all zram I/O requests.
+ */
+static int zram_make_request(struct request_queue *queue, struct bio *bio)
+{
+ int ret = 0;
+ struct zram *zram = queue->queuedata;
+
+ if (unlikely(!zram->init_done)) {
+ bio_io_error(bio);
+ return 0;
+ }
+
+ if (!valid_io_request(zram, bio)) {
+ zram_stat64_inc(zram, &zram->stats.invalid_io);
+ bio_io_error(bio);
+ return 0;
+ }
+
+ switch (bio_data_dir(bio)) {
+ case READ:
+ ret = zram_read(zram, bio);
+ break;
+
+ case WRITE:
+ ret = zram_write(zram, bio);
+ break;
+ }
+
+ return ret;
+}
+
+static void reset_device(struct zram *zram)
+{
+ size_t index;
+
+ /* Do not accept any new I/O request */
+ zram->init_done = 0;
+
+ /* Free various per-device buffers */
+ kfree(zram->compress_workmem);
+ free_pages((unsigned long)zram->compress_buffer, 1);
+
+ zram->compress_workmem = NULL;
+ zram->compress_buffer = NULL;
+
+ /* Free all pages that are still in this zram device */
+ for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
+ struct page *page;
+ u16 offset;
+
+ page = zram->table[index].page;
+ offset = zram->table[index].offset;
+
+ if (!page)
+ continue;
+
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
+ __free_page(page);
+ else
+ xv_free(zram->mem_pool, page, offset);
+ }
+
+ vfree(zram->table);
+ zram->table = NULL;
+
+ xv_destroy_pool(zram->mem_pool);
+ zram->mem_pool = NULL;
+
+ /* Reset stats */
+ memset(&zram->stats, 0, sizeof(zram->stats));
+
+ zram->disksize = 0;
+}
+
+static int zram_ioctl_init_device(struct zram *zram)
+{
+ int ret;
+ size_t num_pages;
+
+ if (zram->init_done) {
+ pr_info("Device already initialized!\n");
+ return -EBUSY;
+ }
+
+ zram_set_disksize(zram, totalram_pages << PAGE_SHIFT);
+
+ zram->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+ if (!zram->compress_workmem) {
+ pr_err("Error allocating compressor working memory!\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ zram->compress_buffer = (void *)__get_free_pages(__GFP_ZERO, 1);
+ if (!zram->compress_buffer) {
+ pr_err("Error allocating compressor buffer space\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ num_pages = zram->disksize >> PAGE_SHIFT;
+ zram->table = vmalloc(num_pages * sizeof(*zram->table));
+ if (!zram->table) {
+ pr_err("Error allocating zram address table\n");
+ /* To prevent accessing table entries during cleanup */
+ zram->disksize = 0;
+ ret = -ENOMEM;
+ goto fail;
+ }
+ memset(zram->table, 0, num_pages * sizeof(*zram->table));
+
+ set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
+
+ /* zram devices sort of resembles non-rotational disks */
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
+
+ zram->mem_pool = xv_create_pool();
+ if (!zram->mem_pool) {
+ pr_err("Error creating memory pool\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ zram->init_done = 1;
+
+ pr_debug("Initialization done!\n");
+ return 0;
+
+fail:
+ reset_device(zram);
+
+ pr_err("Initialization failed: err=%d\n", ret);
+ return ret;
+}
+
+static int zram_ioctl_reset_device(struct zram *zram)
+{
+ if (zram->init_done)
+ reset_device(zram);
+
+ return 0;
+}
+
+static int zram_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ size_t disksize_kb;
+
+ struct zram *zram = bdev->bd_disk->private_data;
+
+ switch (cmd) {
+ case ZRAMIO_SET_DISKSIZE_KB:
+ if (zram->init_done) {
+ ret = -EBUSY;
+ goto out;
+ }
+ if (copy_from_user(&disksize_kb, (void *)arg,
+ _IOC_SIZE(cmd))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ zram->disksize = disksize_kb << 10;
+ pr_info("Disk size set to %zu kB\n", disksize_kb);
+ break;
+
+ case ZRAMIO_GET_STATS:
+ {
+ struct zram_ioctl_stats *stats;
+ if (!zram->init_done) {
+ ret = -ENOTTY;
+ goto out;
+ }
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ zram_ioctl_get_stats(zram, stats);
+ if (copy_to_user((void *)arg, stats, sizeof(*stats))) {
+ kfree(stats);
+ ret = -EFAULT;
+ goto out;
+ }
+ kfree(stats);
+ break;
+ }
+ case ZRAMIO_INIT:
+ ret = zram_ioctl_init_device(zram);
+ break;
+
+ case ZRAMIO_RESET:
+ /* Do not reset an active device! */
+ if (bdev->bd_holders) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Make sure all pending I/O is finished */
+ if (bdev)
+ fsync_bdev(bdev);
+
+ ret = zram_ioctl_reset_device(zram);
+ break;
+
+ default:
+ pr_info("Invalid ioctl %u\n", cmd);
+ ret = -ENOTTY;
+ }
+
+out:
+ return ret;
+}
+
+void zram_slot_free_notify(struct block_device *bdev, unsigned long index)
+{
+ struct zram *zram;
+
+ zram = bdev->bd_disk->private_data;
+ zram_free_page(zram, index);
+ zram_stat64_inc(zram, &zram->stats.notify_free);
+
+ return;
+}
+
+static const struct block_device_operations zram_devops = {
+ .ioctl = zram_ioctl,
+ .swap_slot_free_notify = zram_slot_free_notify,
+ .owner = THIS_MODULE
+};
+
+static int create_device(struct zram *zram, int device_id)
+{
+ int ret = 0;
+
+ mutex_init(&zram->lock);
+ spin_lock_init(&zram->stat64_lock);
+
+ zram->queue = blk_alloc_queue(GFP_KERNEL);
+ if (!zram->queue) {
+ pr_err("Error allocating disk queue for device %d\n",
+ device_id);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ blk_queue_make_request(zram->queue, zram_make_request);
+ zram->queue->queuedata = zram;
+
+ /* gendisk structure */
+ zram->disk = alloc_disk(1);
+ if (!zram->disk) {
+ blk_cleanup_queue(zram->queue);
+ pr_warning("Error allocating disk structure for device %d\n",
+ device_id);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ zram->disk->major = zram_major;
+ zram->disk->first_minor = device_id;
+ zram->disk->fops = &zram_devops;
+ zram->disk->queue = zram->queue;
+ zram->disk->private_data = zram;
+ snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
+
+ /* Actual capacity set using ZRAMIO_SET_DISKSIZE_KB ioctl */
+ set_capacity(zram->disk, 0);
+
+ /*
+ * To ensure that we always get PAGE_SIZE aligned
+ * and n*PAGE_SIZED sized I/O requests.
+ */
+ blk_queue_physical_block_size(zram->disk->queue, PAGE_SIZE);
+ blk_queue_logical_block_size(zram->disk->queue, PAGE_SIZE);
+ blk_queue_io_min(zram->disk->queue, PAGE_SIZE);
+ blk_queue_io_opt(zram->disk->queue, PAGE_SIZE);
+
+ add_disk(zram->disk);
+
+ zram->init_done = 0;
+
+out:
+ return ret;
+}
+
+static void destroy_device(struct zram *zram)
+{
+ if (zram->disk) {
+ del_gendisk(zram->disk);
+ put_disk(zram->disk);
+ }
+
+ if (zram->queue)
+ blk_cleanup_queue(zram->queue);
+}
+
+static int __init zram_init(void)
+{
+ int ret, dev_id;
+
+ if (num_devices > max_num_devices) {
+ pr_warning("Invalid value for num_devices: %u\n",
+ num_devices);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ zram_major = register_blkdev(0, "zram");
+ if (zram_major <= 0) {
+ pr_warning("Unable to get major number\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (!num_devices) {
+ pr_info("num_devices not specified. Using default: 1\n");
+ num_devices = 1;
+ }
+
+ /* Allocate the device array and initialize each one */
+ pr_info("Creating %u devices ...\n", num_devices);
+ devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
+ if (!devices) {
+ ret = -ENOMEM;
+ goto unregister;
+ }
+
+ for (dev_id = 0; dev_id < num_devices; dev_id++) {
+ ret = create_device(&devices[dev_id], dev_id);
+ if (ret)
+ goto free_devices;
+ }
+
+ return 0;
+
+free_devices:
+ while (dev_id)
+ destroy_device(&devices[--dev_id]);
+unregister:
+ unregister_blkdev(zram_major, "zram");
+out:
+ return ret;
+}
+
+static void __exit zram_exit(void)
+{
+ int i;
+ struct zram *zram;
+
+ for (i = 0; i < num_devices; i++) {
+ zram = &devices[i];
+
+ destroy_device(zram);
+ if (zram->init_done)
+ reset_device(zram);
+ }
+
+ unregister_blkdev(zram_major, "zram");
+
+ kfree(devices);
+ pr_debug("Cleanup done!\n");
+}
+
+module_param(num_devices, uint, 0);
+MODULE_PARM_DESC(num_devices, "Number of zram devices");
+
+module_init(zram_init);
+module_exit(zram_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
+MODULE_DESCRIPTION("Compressed RAM Block Device");
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
new file mode 100644
index 0000000..e324e29
--- /dev/null
+++ b/drivers/staging/zram/zram_drv.h
@@ -0,0 +1,167 @@
+/*
+ * Compressed RAM block device
+ *
+ * Copyright (C) 2008, 2009, 2010 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 _ZRAM_DRV_H_
+#define _ZRAM_DRV_H_
+
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+
+#include "zram_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.
+ */
+struct zobj_header {
+#if 0
+ u32 table_idx;
+#endif
+};
+
+/*-- Configurable parameters */
+
+/* Default zram disk size: 25% of total RAM */
+static const unsigned default_disksize_perc_ram = 25;
+
+/*
+ * Pages that compress to size greater than this are stored
+ * uncompressed in memory.
+ */
+static const unsigned max_zpage_size = PAGE_SIZE / 4 * 3;
+
+/*
+ * NOTE: max_zpage_size must be less than or equal to:
+ * XV_MAX_ALLOC_SIZE - sizeof(struct zobj_header)
+ * 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)
+
+/* Flags for zram pages (table[page_no].flags) */
+enum zram_pageflags {
+ /* Page is stored uncompressed */
+ ZRAM_UNCOMPRESSED,
+
+ /* Page consists entirely of zeros */
+ ZRAM_ZERO,
+
+ __NR_ZRAM_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)));
+
+struct zram_stats {
+ /* basic stats */
+ size_t compr_size; /* compressed size of pages stored -
+ * needed to enforce memlimit */
+ /* more stats */
+#if defined(CONFIG_ZRAM_STATS)
+ u64 num_reads; /* failed + successful */
+ u64 num_writes; /* --do-- */
+ u64 failed_reads; /* should NEVER! happen */
+ u64 failed_writes; /* can happen when memory is too low */
+ u64 invalid_io; /* non-swap I/O requests */
+ u64 notify_free; /* no. of swap slot free notifications */
+ 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 */
+#endif
+};
+
+struct zram {
+ struct xv_pool *mem_pool;
+ void *compress_workmem;
+ void *compress_buffer;
+ struct table *table;
+ spinlock_t stat64_lock; /* protect 64-bit stats */
+ struct mutex lock;
+ struct request_queue *queue;
+ struct gendisk *disk;
+ int init_done;
+ /*
+ * 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 zram_stats stats;
+};
+
+/*-- */
+
+/* Debugging and Stats */
+#if defined(CONFIG_ZRAM_STATS)
+static void zram_stat_inc(u32 *v)
+{
+ *v = *v + 1;
+}
+
+static void zram_stat_dec(u32 *v)
+{
+ *v = *v - 1;
+}
+
+static void zram_stat64_inc(struct zram *zram, u64 *v)
+{
+ spin_lock(&zram->stat64_lock);
+ *v = *v + 1;
+ spin_unlock(&zram->stat64_lock);
+}
+
+static u64 zram_stat64_read(struct zram *zram, u64 *v)
+{
+ u64 val;
+
+ spin_lock(&zram->stat64_lock);
+ val = *v;
+ spin_unlock(&zram->stat64_lock);
+
+ return val;
+}
+#else
+#define zram_stat_inc(v)
+#define zram_stat_dec(v)
+#define zram_stat64_inc(r, v)
+#define zram_stat64_read(r, v)
+#endif /* CONFIG_ZRAM_STATS */
+
+#endif
diff --git a/drivers/staging/zram/zram_ioctl.h b/drivers/staging/zram/zram_ioctl.h
new file mode 100644
index 0000000..eefefea
--- /dev/null
+++ b/drivers/staging/zram/zram_ioctl.h
@@ -0,0 +1,42 @@
+/*
+ * Compressed RAM block device
+ *
+ * Copyright (C) 2008, 2009, 2010 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 _ZRAM_IOCTL_H_
+#define _ZRAM_IOCTL_H_
+
+struct zram_ioctl_stats {
+ u64 disksize; /* user specified or equal to backing swap
+ * size (if present) */
+ u64 num_reads; /* failed + successful */
+ u64 num_writes; /* --do-- */
+ u64 failed_reads; /* should NEVER! happen */
+ u64 failed_writes; /* can happen when memory is too low */
+ u64 invalid_io; /* non-swap I/O requests */
+ u64 notify_free; /* no. of swap slot free notifications */
+ 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;
+} __attribute__ ((packed, aligned(4)));
+
+#define ZRAMIO_SET_DISKSIZE_KB _IOW('z', 0, size_t)
+#define ZRAMIO_GET_STATS _IOR('z', 1, struct zram_ioctl_stats)
+#define ZRAMIO_INIT _IO('z', 2)
+#define ZRAMIO_RESET _IO('z', 3)
+
+#endif
--
1.6.6.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 3/3] Rename ramzswap to zram in documentation
2010-05-24 14:18 [PATCH 0/3] zram: generic RAM based compressed R/W block devices Nitin Gupta
2010-05-24 14:18 ` [PATCH 1/3] Support generic I/O requests Nitin Gupta
2010-05-24 14:18 ` [PATCH 2/3] Rename ramzswap to zram in code Nitin Gupta
@ 2010-05-24 14:18 ` Nitin Gupta
2010-05-25 15:21 ` [PATCH 0/3] zram: generic RAM based compressed R/W block devices Minchan Kim
2010-05-28 16:08 ` Nitin Gupta
4 siblings, 0 replies; 17+ messages in thread
From: Nitin Gupta @ 2010-05-24 14:18 UTC (permalink / raw)
To: Greg KH
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
Changes:
- Included example to show usage as generic
(non-swap) disk with ext4 filesystem.
- Renamed rzscontrol with zramconfig to match
with new device naming.
Signed-off-by: Nitin Gupta <ngupta@vflare.org>
---
drivers/staging/zram/zram.txt | 51 +++++++++++++++++++++++++----------------
1 files changed, 31 insertions(+), 20 deletions(-)
diff --git a/drivers/staging/zram/zram.txt b/drivers/staging/zram/zram.txt
index 9694acf..8c4d2cd 100644
--- a/drivers/staging/zram/zram.txt
+++ b/drivers/staging/zram/zram.txt
@@ -1,46 +1,57 @@
-ramzswap: Compressed RAM based swap device
--------------------------------------------
+zram: Compressed in-memory block device
+---------------------------------------
Project home: http://compcache.googlecode.com/
* Introduction
-The ramzswap module creates RAM based block devices which can (only) be used 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.
+The zram module creates RAM based block devices: /dev/ramX (X = 0, 1, ...).
+Pages written to these disks are compressed and stored in memory itself.
+These disks allow very fast I/O and compression provides good amounts of
+memory savings.
-Individual ramzswap devices are configured and initialized using rzscontrol
-userspace utility as shown in examples below. See rzscontrol man page for more
-details.
+See project home for use cases, performance numbers and a lot more.
+
+Individual zram devices are configured and initialized using zramconfig
+userspace utility as shown in examples below. See zramconfig man page for
+more details.
* Usage
-Following shows a typical sequence of steps for using ramzswap.
+Following shows a typical sequence of steps for using zram.
1) Load Modules:
- modprobe ramzswap num_devices=4
- This creates 4 (uninitialized) devices: /dev/ramzswap{0,1,2,3}
+ modprobe zram num_devices=4
+ This creates 4 (uninitialized) devices: /dev/zram{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
+ Use zramconfig utility to configure and initialize individual
+ zram devices. For example:
+ zramconfig /dev/zram0 --init # uses default value of disksize_kb
+ zramconfig /dev/zram1 --disksize_kb=102400 # 100MB /dev/zram1
- *See rzscontrol man page for more details and examples*
+ *See zramconfig man page for more details and examples*
3) Activate:
- swapon /dev/ramzswap2 # or any other initialized ramzswap device
+ mkswap /dev/zram0
+ swapon /dev/zram0
+
+ mkfs.ext4 /dev/zram1
+ mount /dev/zram1 /tmp
4) Stats:
- rzscontrol /dev/ramzswap2 --stats
+ zramconfig /dev/zram0 --stats
+ zramconfig /dev/zram1 --stats
5) Deactivate:
- swapoff /dev/ramzswap2
+ swapoff /dev/zram0
+ umount /dev/zram1
6) Reset:
- rzscontrol /dev/ramzswap2 --reset
- (This frees all the memory allocated for this device).
+ zramconfig /dev/zram0 --reset
+ zramconfig /dev/zram1 --reset
+ (This frees memory allocated for the given device).
Please report any problems at:
--
1.6.6.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 2/3] Rename ramzswap to zram in code.
2010-05-24 14:18 ` [PATCH 2/3] Rename ramzswap to zram in code Nitin Gupta
@ 2010-05-24 15:31 ` Arnd Bergmann
2010-05-24 18:23 ` Nitin Gupta
0 siblings, 1 reply; 17+ messages in thread
From: Arnd Bergmann @ 2010-05-24 15:31 UTC (permalink / raw)
To: Nitin Gupta
Cc: Greg KH, Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins,
Cyp, driverdev, linux-kernel
On Monday 24 May 2010 16:18:04 Nitin Gupta wrote:
> Rename ramzswap to zram in code and also rename
> files accordingly.
>
> Automated renames in code:
> - rzs* -> zram*
> - ramzswap* -> zram*
> - RZS -> ZRAM*
When renaming files, the -M option to git-format-patch
helps making the patch more reviewable.
Arnd
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/3] Rename ramzswap to zram in code.
2010-05-24 15:31 ` Arnd Bergmann
@ 2010-05-24 18:23 ` Nitin Gupta
0 siblings, 0 replies; 17+ messages in thread
From: Nitin Gupta @ 2010-05-24 18:23 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Greg KH, Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins,
Cyp, driverdev, linux-kernel
(resending with -M option to git format-patch. Other patches
are not affected with this option. Thanks Arnd!)
Rename ramzswap to zram in code and also rename
files accordingly.
Automated renames in code:
- rzs* -> zram*
- ramzswap* -> zram*
- RZS -> ZRAM*
(somehow git is not allowing separate commits for
file renames and renames in code).
ramzswap devices are no longer limited to handling
swap requests only. They can now handle arbitrary
I/O requests. So, renaming ramzswap files to zram
to reflect this change. Next few patches will do
similar naming changes within code and documentation.
Changes are also made to various Kconfig and Makefile
so that this patch is compilable.
Signed-off-by: Nitin Gupta <ngupta@vflare.org>
---
drivers/staging/Kconfig | 2 +-
drivers/staging/Makefile | 2 +-
drivers/staging/ramzswap/Kconfig | 21 -
drivers/staging/ramzswap/Makefile | 3 -
drivers/staging/zram/Kconfig | 24 ++
drivers/staging/zram/Makefile | 3 +
drivers/staging/{ramzswap => zram}/xvmalloc.c | 0
drivers/staging/{ramzswap => zram}/xvmalloc.h | 0
drivers/staging/{ramzswap => zram}/xvmalloc_int.h | 0
.../{ramzswap/ramzswap.txt => zram/zram.txt} | 0
.../{ramzswap/ramzswap_drv.c => zram/zram_drv.c} | 429 ++++++++++----------
.../{ramzswap/ramzswap_drv.h => zram/zram_drv.h} | 56 ++--
.../ramzswap_ioctl.h => zram/zram_ioctl.h} | 16 +-
13 files changed, 280 insertions(+), 276 deletions(-)
delete mode 100644 drivers/staging/ramzswap/Kconfig
delete mode 100644 drivers/staging/ramzswap/Makefile
create mode 100644 drivers/staging/zram/Kconfig
create mode 100644 drivers/staging/zram/Makefile
rename drivers/staging/{ramzswap => zram}/xvmalloc.c (100%)
rename drivers/staging/{ramzswap => zram}/xvmalloc.h (100%)
rename drivers/staging/{ramzswap => zram}/xvmalloc_int.h (100%)
rename drivers/staging/{ramzswap/ramzswap.txt => zram/zram.txt} (100%)
rename drivers/staging/{ramzswap/ramzswap_drv.c => zram/zram_drv.c} (51%)
rename drivers/staging/{ramzswap/ramzswap_drv.h => zram/zram_drv.h} (77%)
rename drivers/staging/{ramzswap/ramzswap_ioctl.h => zram/zram_ioctl.h} (77%)
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index b5c3b30..32d5300 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -117,7 +117,7 @@ source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
-source "drivers/staging/ramzswap/Kconfig"
+source "drivers/staging/zram/Kconfig"
source "drivers/staging/wlags49_h2/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index e330dd5..cec25b0 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -39,7 +39,7 @@ obj-$(CONFIG_RAR_REGISTER) += rar_register/
obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
-obj-$(CONFIG_RAMZSWAP) += ramzswap/
+obj-$(CONFIG_ZRAM) += zram/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
diff --git a/drivers/staging/ramzswap/Kconfig b/drivers/staging/ramzswap/Kconfig
deleted file mode 100644
index 127b3c6..0000000
--- a/drivers/staging/ramzswap/Kconfig
+++ /dev/null
@@ -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 (only) be used as 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.
diff --git a/drivers/staging/ramzswap/Makefile b/drivers/staging/ramzswap/Makefile
deleted file mode 100644
index 507d7dc..0000000
--- a/drivers/staging/ramzswap/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-ramzswap-objs := ramzswap_drv.o xvmalloc.o
-
-obj-$(CONFIG_RAMZSWAP) += ramzswap.o
diff --git a/drivers/staging/zram/Kconfig b/drivers/staging/zram/Kconfig
new file mode 100644
index 0000000..fad9ff5
--- /dev/null
+++ b/drivers/staging/zram/Kconfig
@@ -0,0 +1,24 @@
+config ZRAM
+ tristate "Compressed in-memory block device (zram)"
+ select LZO_COMPRESS
+ select LZO_DECOMPRESS
+ default n
+ help
+ Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
+ Pages written to these disks are compressed and stored in memory
+ itself. These disks allow very fast I/O and compression provides
+ good amounts of memory savings.
+
+ It has several use cases, for example: /tmp storage, use as swap
+ disks and maybe many more.
+
+ See zram.txt for more information.
+ Project home: http://compcache.googlecode.com/
+
+config ZRAM_STATS
+ bool "Enable zram stats"
+ depends on ZRAM
+ default y
+ help
+ Enable statistics collection for zram devices. This adds only a
+ minimal overhead. In unsure, say Y.
diff --git a/drivers/staging/zram/Makefile b/drivers/staging/zram/Makefile
new file mode 100644
index 0000000..b2c087a
--- /dev/null
+++ b/drivers/staging/zram/Makefile
@@ -0,0 +1,3 @@
+zram-objs := zram_drv.o xvmalloc.o
+
+obj-$(CONFIG_ZRAM) += zram.o
diff --git a/drivers/staging/ramzswap/xvmalloc.c b/drivers/staging/zram/xvmalloc.c
similarity index 100%
rename from drivers/staging/ramzswap/xvmalloc.c
rename to drivers/staging/zram/xvmalloc.c
diff --git a/drivers/staging/ramzswap/xvmalloc.h b/drivers/staging/zram/xvmalloc.h
similarity index 100%
rename from drivers/staging/ramzswap/xvmalloc.h
rename to drivers/staging/zram/xvmalloc.h
diff --git a/drivers/staging/ramzswap/xvmalloc_int.h b/drivers/staging/zram/xvmalloc_int.h
similarity index 100%
rename from drivers/staging/ramzswap/xvmalloc_int.h
rename to drivers/staging/zram/xvmalloc_int.h
diff --git a/drivers/staging/ramzswap/ramzswap.txt b/drivers/staging/zram/zram.txt
similarity index 100%
rename from drivers/staging/ramzswap/ramzswap.txt
rename to drivers/staging/zram/zram.txt
diff --git a/drivers/staging/ramzswap/ramzswap_drv.c b/drivers/staging/zram/zram_drv.c
similarity index 51%
rename from drivers/staging/ramzswap/ramzswap_drv.c
rename to drivers/staging/zram/zram_drv.c
index 9d20d23..e962757 100644
--- a/drivers/staging/ramzswap/ramzswap_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -1,5 +1,5 @@
/*
- * Compressed RAM based swap device
+ * Compressed RAM block device
*
* Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
@@ -12,7 +12,7 @@
* Project home: http://compcache.googlecode.com
*/
-#define KMSG_COMPONENT "ramzswap"
+#define KMSG_COMPONENT "zram"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/module.h>
@@ -30,31 +30,31 @@
#include <linux/swapops.h>
#include <linux/vmalloc.h>
-#include "ramzswap_drv.h"
+#include "zram_drv.h"
/* Globals */
-static int ramzswap_major;
-static struct ramzswap *devices;
+static int zram_major;
+static struct zram *devices;
/* Module params (documentation at end) */
static unsigned int num_devices;
-static int rzs_test_flag(struct ramzswap *rzs, u32 index,
- enum rzs_pageflags flag)
+static int zram_test_flag(struct zram *zram, u32 index,
+ enum zram_pageflags flag)
{
- return rzs->table[index].flags & BIT(flag);
+ return zram->table[index].flags & BIT(flag);
}
-static void rzs_set_flag(struct ramzswap *rzs, u32 index,
- enum rzs_pageflags flag)
+static void zram_set_flag(struct zram *zram, u32 index,
+ enum zram_pageflags flag)
{
- rzs->table[index].flags |= BIT(flag);
+ zram->table[index].flags |= BIT(flag);
}
-static void rzs_clear_flag(struct ramzswap *rzs, u32 index,
- enum rzs_pageflags flag)
+static void zram_clear_flag(struct zram *zram, u32 index,
+ enum zram_pageflags flag)
{
- rzs->table[index].flags &= ~BIT(flag);
+ zram->table[index].flags &= ~BIT(flag);
}
static int page_zero_filled(void *ptr)
@@ -72,50 +72,50 @@ static int page_zero_filled(void *ptr)
return 1;
}
-static void ramzswap_set_disksize(struct ramzswap *rzs, size_t totalram_bytes)
+static void zram_set_disksize(struct zram *zram, size_t totalram_bytes)
{
- if (!rzs->disksize) {
+ if (!zram->disksize) {
pr_info(
"disk size not provided. You can use disksize_kb module "
"param to specify size.\nUsing default: (%u%% of RAM).\n",
default_disksize_perc_ram
);
- rzs->disksize = default_disksize_perc_ram *
+ zram->disksize = default_disksize_perc_ram *
(totalram_bytes / 100);
}
- if (rzs->disksize > 2 * (totalram_bytes)) {
+ if (zram->disksize > 2 * (totalram_bytes)) {
pr_info(
- "There is little point creating a ramzswap of greater than "
+ "There is little point creating a zram of greater than "
"twice the size of memory since we expect a 2:1 compression "
- "ratio. Note that ramzswap uses about 0.1%% of the size of "
- "the swap device when not in use so a huge ramzswap is "
+ "ratio. Note that zram uses about 0.1%% of the size of "
+ "the swap device when not in use so a huge zram is "
"wasteful.\n"
"\tMemory Size: %zu kB\n"
"\tSize you selected: %zu kB\n"
"Continuing anyway ...\n",
- totalram_bytes >> 10, rzs->disksize
+ totalram_bytes >> 10, zram->disksize
);
}
- rzs->disksize &= PAGE_MASK;
+ zram->disksize &= PAGE_MASK;
}
-static void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
- struct ramzswap_ioctl_stats *s)
+static void zram_ioctl_get_stats(struct zram *zram,
+ struct zram_ioctl_stats *s)
{
- s->disksize = rzs->disksize;
+ s->disksize = zram->disksize;
-#if defined(CONFIG_RAMZSWAP_STATS)
+#if defined(CONFIG_ZRAM_STATS)
{
- struct ramzswap_stats *rs = &rzs->stats;
+ struct zram_stats *rs = &zram->stats;
size_t succ_writes, mem_used;
unsigned int good_compress_perc = 0, no_compress_perc = 0;
- mem_used = xv_get_total_size_bytes(rzs->mem_pool)
+ mem_used = xv_get_total_size_bytes(zram->mem_pool)
+ (rs->pages_expand << PAGE_SHIFT);
- succ_writes = rzs_stat64_read(rzs, &rs->num_writes) -
- rzs_stat64_read(rzs, &rs->failed_writes);
+ succ_writes = zram_stat64_read(zram, &rs->num_writes) -
+ zram_stat64_read(zram, &rs->failed_writes);
if (succ_writes && rs->pages_stored) {
good_compress_perc = rs->good_compress * 100
@@ -124,12 +124,12 @@ static void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
/ rs->pages_stored;
}
- s->num_reads = rzs_stat64_read(rzs, &rs->num_reads);
- s->num_writes = rzs_stat64_read(rzs, &rs->num_writes);
- s->failed_reads = rzs_stat64_read(rzs, &rs->failed_reads);
- s->failed_writes = rzs_stat64_read(rzs, &rs->failed_writes);
- s->invalid_io = rzs_stat64_read(rzs, &rs->invalid_io);
- s->notify_free = rzs_stat64_read(rzs, &rs->notify_free);
+ s->num_reads = zram_stat64_read(zram, &rs->num_reads);
+ s->num_writes = zram_stat64_read(zram, &rs->num_writes);
+ s->failed_reads = zram_stat64_read(zram, &rs->failed_reads);
+ s->failed_writes = zram_stat64_read(zram, &rs->failed_writes);
+ s->invalid_io = zram_stat64_read(zram, &rs->invalid_io);
+ s->notify_free = zram_stat64_read(zram, &rs->notify_free);
s->pages_zero = rs->pages_zero;
s->good_compress_pct = good_compress_perc;
@@ -141,34 +141,34 @@ static void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
s->compr_data_size = rs->compr_size;
s->mem_used_total = mem_used;
}
-#endif /* CONFIG_RAMZSWAP_STATS */
+#endif /* CONFIG_ZRAM_STATS */
}
-static void ramzswap_free_page(struct ramzswap *rzs, size_t index)
+static void zram_free_page(struct zram *zram, size_t index)
{
u32 clen;
void *obj;
- struct page *page = rzs->table[index].page;
- u32 offset = rzs->table[index].offset;
+ struct page *page = zram->table[index].page;
+ u32 offset = zram->table[index].offset;
if (unlikely(!page)) {
/*
* No memory is allocated for zero filled pages.
* Simply clear zero page flag.
*/
- if (rzs_test_flag(rzs, index, RZS_ZERO)) {
- rzs_clear_flag(rzs, index, RZS_ZERO);
- rzs_stat_dec(&rzs->stats.pages_zero);
+ if (zram_test_flag(zram, index, ZRAM_ZERO)) {
+ zram_clear_flag(zram, index, ZRAM_ZERO);
+ zram_stat_dec(&zram->stats.pages_zero);
}
return;
}
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED))) {
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
clen = PAGE_SIZE;
__free_page(page);
- rzs_clear_flag(rzs, index, RZS_UNCOMPRESSED);
- rzs_stat_dec(&rzs->stats.pages_expand);
+ zram_clear_flag(zram, index, ZRAM_UNCOMPRESSED);
+ zram_stat_dec(&zram->stats.pages_expand);
goto out;
}
@@ -176,16 +176,16 @@ static void ramzswap_free_page(struct ramzswap *rzs, size_t index)
clen = xv_get_object_size(obj) - sizeof(struct zobj_header);
kunmap_atomic(obj, KM_USER0);
- xv_free(rzs->mem_pool, page, offset);
+ xv_free(zram->mem_pool, page, offset);
if (clen <= PAGE_SIZE / 2)
- rzs_stat_dec(&rzs->stats.good_compress);
+ zram_stat_dec(&zram->stats.good_compress);
out:
- rzs->stats.compr_size -= clen;
- rzs_stat_dec(&rzs->stats.pages_stored);
+ zram->stats.compr_size -= clen;
+ zram_stat_dec(&zram->stats.pages_stored);
- rzs->table[index].page = NULL;
- rzs->table[index].offset = 0;
+ zram->table[index].page = NULL;
+ zram->table[index].offset = 0;
}
static void handle_zero_page(struct page *page, u32 index)
@@ -199,14 +199,14 @@ static void handle_zero_page(struct page *page, u32 index)
flush_dcache_page(page);
}
-static void handle_uncompressed_page(struct ramzswap *rzs,
+static void handle_uncompressed_page(struct zram *zram,
struct page *page, u32 index)
{
unsigned char *user_mem, *cmem;
user_mem = kmap_atomic(page, KM_USER0);
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
+ cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
+ zram->table[index].offset;
memcpy(user_mem, cmem, PAGE_SIZE);
kunmap_atomic(user_mem, KM_USER0);
@@ -215,14 +215,14 @@ static void handle_uncompressed_page(struct ramzswap *rzs,
flush_dcache_page(page);
}
-static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
+static int zram_read(struct zram *zram, struct bio *bio)
{
int i;
u32 index;
struct bio_vec *bvec;
- rzs_stat64_inc(rzs, &rzs->stats.num_reads);
+ zram_stat64_inc(zram, &zram->stats.num_reads);
index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
bio_for_each_segment(bvec, bio, i) {
@@ -234,13 +234,13 @@ static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
page = bvec->bv_page;
- if (rzs_test_flag(rzs, index, RZS_ZERO)) {
+ if (zram_test_flag(zram, index, ZRAM_ZERO)) {
handle_zero_page(page, index);
continue;
}
/* Requested page is not present in compressed area */
- if (unlikely(!rzs->table[index].page)) {
+ if (unlikely(!zram->table[index].page)) {
pr_debug("Read before write on swap device: "
"sector=%lu, size=%u",
(ulong)(bio->bi_sector), bio->bi_size);
@@ -249,16 +249,16 @@ static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
}
/* Page is stored uncompressed since it's incompressible */
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED))) {
- handle_uncompressed_page(rzs, page, index);
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
+ handle_uncompressed_page(zram, page, index);
continue;
}
user_mem = kmap_atomic(page, KM_USER0);
clen = PAGE_SIZE;
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
+ cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
+ zram->table[index].offset;
ret = lzo1x_decompress_safe(
cmem + sizeof(*zheader),
@@ -272,7 +272,7 @@ static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
if (unlikely(ret != LZO_E_OK)) {
pr_err("Decompression failed! err=%d, page=%u\n",
ret, index);
- rzs_stat64_inc(rzs, &rzs->stats.failed_reads);
+ zram_stat64_inc(zram, &zram->stats.failed_reads);
goto out;
}
@@ -289,13 +289,13 @@ out:
return 0;
}
-static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
+static int zram_write(struct zram *zram, struct bio *bio)
{
int i;
u32 index;
struct bio_vec *bvec;
- rzs_stat64_inc(rzs, &rzs->stats.num_writes);
+ zram_stat64_inc(zram, &zram->stats.num_writes);
index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
@@ -308,36 +308,36 @@ static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
unsigned char *user_mem, *cmem, *src;
page = bvec->bv_page;
- src = rzs->compress_buffer;
+ src = zram->compress_buffer;
/*
* System overwrites unused sectors. Free memory associated
* with this sector now.
*/
- if (rzs->table[index].page ||
- rzs_test_flag(rzs, index, RZS_ZERO))
- ramzswap_free_page(rzs, index);
+ if (zram->table[index].page ||
+ zram_test_flag(zram, index, ZRAM_ZERO))
+ zram_free_page(zram, index);
- mutex_lock(&rzs->lock);
+ mutex_lock(&zram->lock);
user_mem = kmap_atomic(page, KM_USER0);
if (page_zero_filled(user_mem)) {
kunmap_atomic(user_mem, KM_USER0);
- mutex_unlock(&rzs->lock);
- rzs_stat_inc(&rzs->stats.pages_zero);
- rzs_set_flag(rzs, index, RZS_ZERO);
+ mutex_unlock(&zram->lock);
+ zram_stat_inc(&zram->stats.pages_zero);
+ zram_set_flag(zram, index, ZRAM_ZERO);
continue;
}
ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen,
- rzs->compress_workmem);
+ zram->compress_workmem);
kunmap_atomic(user_mem, KM_USER0);
if (unlikely(ret != LZO_E_OK)) {
- mutex_unlock(&rzs->lock);
+ mutex_unlock(&zram->lock);
pr_err("Compression failed! err=%d\n", ret);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
+ zram_stat64_inc(zram, &zram->stats.failed_writes);
goto out;
}
@@ -350,40 +350,41 @@ static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
clen = PAGE_SIZE;
page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
if (unlikely(!page_store)) {
- mutex_unlock(&rzs->lock);
+ mutex_unlock(&zram->lock);
pr_info("Error allocating memory for "
"incompressible page: %u\n", index);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
+ zram_stat64_inc(zram,
+ &zram->stats.failed_writes);
goto out;
}
offset = 0;
- rzs_set_flag(rzs, index, RZS_UNCOMPRESSED);
- rzs_stat_inc(&rzs->stats.pages_expand);
- rzs->table[index].page = page_store;
+ zram_set_flag(zram, index, ZRAM_UNCOMPRESSED);
+ zram_stat_inc(&zram->stats.pages_expand);
+ zram->table[index].page = page_store;
src = kmap_atomic(page, KM_USER0);
goto memstore;
}
- if (xv_malloc(rzs->mem_pool, clen + sizeof(*zheader),
- &rzs->table[index].page, &offset,
+ if (xv_malloc(zram->mem_pool, clen + sizeof(*zheader),
+ &zram->table[index].page, &offset,
GFP_NOIO | __GFP_HIGHMEM)) {
- mutex_unlock(&rzs->lock);
+ mutex_unlock(&zram->lock);
pr_info("Error allocating memory for compressed "
"page: %u, size=%zu\n", index, clen);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
+ zram_stat64_inc(zram, &zram->stats.failed_writes);
goto out;
}
memstore:
- rzs->table[index].offset = offset;
+ zram->table[index].offset = offset;
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
+ cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
+ zram->table[index].offset;
#if 0
/* Back-reference needed for memory defragmentation */
- if (!rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)) {
+ if (!zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)) {
zheader = (struct zobj_header *)cmem;
zheader->table_idx = index;
cmem += sizeof(*zheader);
@@ -393,16 +394,16 @@ memstore:
memcpy(cmem, src, clen);
kunmap_atomic(cmem, KM_USER1);
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
kunmap_atomic(src, KM_USER0);
/* Update stats */
- rzs->stats.compr_size += clen;
- rzs_stat_inc(&rzs->stats.pages_stored);
+ zram->stats.compr_size += clen;
+ zram_stat_inc(&zram->stats.pages_stored);
if (clen <= PAGE_SIZE / 2)
- rzs_stat_inc(&rzs->stats.good_compress);
+ zram_stat_inc(&zram->stats.good_compress);
- mutex_unlock(&rzs->lock);
+ mutex_unlock(&zram->lock);
index++;
}
@@ -418,10 +419,10 @@ out:
/*
* Check if request is within bounds and page aligned.
*/
-static inline int valid_io_request(struct ramzswap *rzs, struct bio *bio)
+static inline int valid_io_request(struct zram *zram, struct bio *bio)
{
if (unlikely(
- (bio->bi_sector >= (rzs->disksize >> SECTOR_SHIFT)) ||
+ (bio->bi_sector >= (zram->disksize >> SECTOR_SHIFT)) ||
(bio->bi_sector & (SECTORS_PER_PAGE - 1)) ||
(bio->bi_size & (PAGE_SIZE - 1)))) {
@@ -433,160 +434,160 @@ static inline int valid_io_request(struct ramzswap *rzs, struct bio *bio)
}
/*
- * Handler function for all ramzswap I/O requests.
+ * Handler function for all zram I/O requests.
*/
-static int ramzswap_make_request(struct request_queue *queue, struct bio *bio)
+static int zram_make_request(struct request_queue *queue, struct bio *bio)
{
int ret = 0;
- struct ramzswap *rzs = queue->queuedata;
+ struct zram *zram = queue->queuedata;
- if (unlikely(!rzs->init_done)) {
+ if (unlikely(!zram->init_done)) {
bio_io_error(bio);
return 0;
}
- if (!valid_io_request(rzs, bio)) {
- rzs_stat64_inc(rzs, &rzs->stats.invalid_io);
+ if (!valid_io_request(zram, bio)) {
+ zram_stat64_inc(zram, &zram->stats.invalid_io);
bio_io_error(bio);
return 0;
}
switch (bio_data_dir(bio)) {
case READ:
- ret = ramzswap_read(rzs, bio);
+ ret = zram_read(zram, bio);
break;
case WRITE:
- ret = ramzswap_write(rzs, bio);
+ ret = zram_write(zram, bio);
break;
}
return ret;
}
-static void reset_device(struct ramzswap *rzs)
+static void reset_device(struct zram *zram)
{
size_t index;
/* Do not accept any new I/O request */
- rzs->init_done = 0;
+ zram->init_done = 0;
/* Free various per-device buffers */
- kfree(rzs->compress_workmem);
- free_pages((unsigned long)rzs->compress_buffer, 1);
+ kfree(zram->compress_workmem);
+ free_pages((unsigned long)zram->compress_buffer, 1);
- rzs->compress_workmem = NULL;
- rzs->compress_buffer = NULL;
+ zram->compress_workmem = NULL;
+ zram->compress_buffer = NULL;
- /* Free all pages that are still in this ramzswap device */
- for (index = 0; index < rzs->disksize >> PAGE_SHIFT; index++) {
+ /* Free all pages that are still in this zram device */
+ for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
struct page *page;
u16 offset;
- page = rzs->table[index].page;
- offset = rzs->table[index].offset;
+ page = zram->table[index].page;
+ offset = zram->table[index].offset;
if (!page)
continue;
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
__free_page(page);
else
- xv_free(rzs->mem_pool, page, offset);
+ xv_free(zram->mem_pool, page, offset);
}
- vfree(rzs->table);
- rzs->table = NULL;
+ vfree(zram->table);
+ zram->table = NULL;
- xv_destroy_pool(rzs->mem_pool);
- rzs->mem_pool = NULL;
+ xv_destroy_pool(zram->mem_pool);
+ zram->mem_pool = NULL;
/* Reset stats */
- memset(&rzs->stats, 0, sizeof(rzs->stats));
+ memset(&zram->stats, 0, sizeof(zram->stats));
- rzs->disksize = 0;
+ zram->disksize = 0;
}
-static int ramzswap_ioctl_init_device(struct ramzswap *rzs)
+static int zram_ioctl_init_device(struct zram *zram)
{
int ret;
size_t num_pages;
- if (rzs->init_done) {
+ if (zram->init_done) {
pr_info("Device already initialized!\n");
return -EBUSY;
}
- ramzswap_set_disksize(rzs, totalram_pages << PAGE_SHIFT);
+ zram_set_disksize(zram, totalram_pages << PAGE_SHIFT);
- rzs->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
- if (!rzs->compress_workmem) {
+ zram->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+ if (!zram->compress_workmem) {
pr_err("Error allocating compressor working memory!\n");
ret = -ENOMEM;
goto fail;
}
- rzs->compress_buffer = (void *)__get_free_pages(__GFP_ZERO, 1);
- if (!rzs->compress_buffer) {
+ zram->compress_buffer = (void *)__get_free_pages(__GFP_ZERO, 1);
+ if (!zram->compress_buffer) {
pr_err("Error allocating compressor buffer space\n");
ret = -ENOMEM;
goto fail;
}
- num_pages = rzs->disksize >> PAGE_SHIFT;
- rzs->table = vmalloc(num_pages * sizeof(*rzs->table));
- if (!rzs->table) {
- pr_err("Error allocating ramzswap address table\n");
+ num_pages = zram->disksize >> PAGE_SHIFT;
+ zram->table = vmalloc(num_pages * sizeof(*zram->table));
+ if (!zram->table) {
+ pr_err("Error allocating zram address table\n");
/* To prevent accessing table entries during cleanup */
- rzs->disksize = 0;
+ zram->disksize = 0;
ret = -ENOMEM;
goto fail;
}
- memset(rzs->table, 0, num_pages * sizeof(*rzs->table));
+ memset(zram->table, 0, num_pages * sizeof(*zram->table));
- set_capacity(rzs->disk, rzs->disksize >> SECTOR_SHIFT);
+ set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
- /* ramzswap devices sort of resembles non-rotational disks */
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, rzs->disk->queue);
+ /* zram devices sort of resembles non-rotational disks */
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
- rzs->mem_pool = xv_create_pool();
- if (!rzs->mem_pool) {
+ zram->mem_pool = xv_create_pool();
+ if (!zram->mem_pool) {
pr_err("Error creating memory pool\n");
ret = -ENOMEM;
goto fail;
}
- rzs->init_done = 1;
+ zram->init_done = 1;
pr_debug("Initialization done!\n");
return 0;
fail:
- reset_device(rzs);
+ reset_device(zram);
pr_err("Initialization failed: err=%d\n", ret);
return ret;
}
-static int ramzswap_ioctl_reset_device(struct ramzswap *rzs)
+static int zram_ioctl_reset_device(struct zram *zram)
{
- if (rzs->init_done)
- reset_device(rzs);
+ if (zram->init_done)
+ reset_device(zram);
return 0;
}
-static int ramzswap_ioctl(struct block_device *bdev, fmode_t mode,
+static int zram_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
int ret = 0;
size_t disksize_kb;
- struct ramzswap *rzs = bdev->bd_disk->private_data;
+ struct zram *zram = bdev->bd_disk->private_data;
switch (cmd) {
- case RZSIO_SET_DISKSIZE_KB:
- if (rzs->init_done) {
+ case ZRAMIO_SET_DISKSIZE_KB:
+ if (zram->init_done) {
ret = -EBUSY;
goto out;
}
@@ -595,14 +596,14 @@ static int ramzswap_ioctl(struct block_device *bdev, fmode_t mode,
ret = -EFAULT;
goto out;
}
- rzs->disksize = disksize_kb << 10;
+ zram->disksize = disksize_kb << 10;
pr_info("Disk size set to %zu kB\n", disksize_kb);
break;
- case RZSIO_GET_STATS:
+ case ZRAMIO_GET_STATS:
{
- struct ramzswap_ioctl_stats *stats;
- if (!rzs->init_done) {
+ struct zram_ioctl_stats *stats;
+ if (!zram->init_done) {
ret = -ENOTTY;
goto out;
}
@@ -611,7 +612,7 @@ static int ramzswap_ioctl(struct block_device *bdev, fmode_t mode,
ret = -ENOMEM;
goto out;
}
- ramzswap_ioctl_get_stats(rzs, stats);
+ zram_ioctl_get_stats(zram, stats);
if (copy_to_user((void *)arg, stats, sizeof(*stats))) {
kfree(stats);
ret = -EFAULT;
@@ -620,11 +621,11 @@ static int ramzswap_ioctl(struct block_device *bdev, fmode_t mode,
kfree(stats);
break;
}
- case RZSIO_INIT:
- ret = ramzswap_ioctl_init_device(rzs);
+ case ZRAMIO_INIT:
+ ret = zram_ioctl_init_device(zram);
break;
- case RZSIO_RESET:
+ case ZRAMIO_RESET:
/* Do not reset an active device! */
if (bdev->bd_holders) {
ret = -EBUSY;
@@ -635,7 +636,7 @@ static int ramzswap_ioctl(struct block_device *bdev, fmode_t mode,
if (bdev)
fsync_bdev(bdev);
- ret = ramzswap_ioctl_reset_device(rzs);
+ ret = zram_ioctl_reset_device(zram);
break;
default:
@@ -647,90 +648,90 @@ out:
return ret;
}
-void ramzswap_slot_free_notify(struct block_device *bdev, unsigned long index)
+void zram_slot_free_notify(struct block_device *bdev, unsigned long index)
{
- struct ramzswap *rzs;
+ struct zram *zram;
- rzs = bdev->bd_disk->private_data;
- ramzswap_free_page(rzs, index);
- rzs_stat64_inc(rzs, &rzs->stats.notify_free);
+ zram = bdev->bd_disk->private_data;
+ zram_free_page(zram, index);
+ zram_stat64_inc(zram, &zram->stats.notify_free);
return;
}
-static const struct block_device_operations ramzswap_devops = {
- .ioctl = ramzswap_ioctl,
- .swap_slot_free_notify = ramzswap_slot_free_notify,
+static const struct block_device_operations zram_devops = {
+ .ioctl = zram_ioctl,
+ .swap_slot_free_notify = zram_slot_free_notify,
.owner = THIS_MODULE
};
-static int create_device(struct ramzswap *rzs, int device_id)
+static int create_device(struct zram *zram, int device_id)
{
int ret = 0;
- mutex_init(&rzs->lock);
- spin_lock_init(&rzs->stat64_lock);
+ mutex_init(&zram->lock);
+ spin_lock_init(&zram->stat64_lock);
- rzs->queue = blk_alloc_queue(GFP_KERNEL);
- if (!rzs->queue) {
+ zram->queue = blk_alloc_queue(GFP_KERNEL);
+ if (!zram->queue) {
pr_err("Error allocating disk queue for device %d\n",
device_id);
ret = -ENOMEM;
goto out;
}
- blk_queue_make_request(rzs->queue, ramzswap_make_request);
- rzs->queue->queuedata = rzs;
+ blk_queue_make_request(zram->queue, zram_make_request);
+ zram->queue->queuedata = zram;
/* gendisk structure */
- rzs->disk = alloc_disk(1);
- if (!rzs->disk) {
- blk_cleanup_queue(rzs->queue);
+ zram->disk = alloc_disk(1);
+ if (!zram->disk) {
+ blk_cleanup_queue(zram->queue);
pr_warning("Error allocating disk structure for device %d\n",
device_id);
ret = -ENOMEM;
goto out;
}
- rzs->disk->major = ramzswap_major;
- rzs->disk->first_minor = device_id;
- rzs->disk->fops = &ramzswap_devops;
- rzs->disk->queue = rzs->queue;
- rzs->disk->private_data = rzs;
- snprintf(rzs->disk->disk_name, 16, "ramzswap%d", device_id);
+ zram->disk->major = zram_major;
+ zram->disk->first_minor = device_id;
+ zram->disk->fops = &zram_devops;
+ zram->disk->queue = zram->queue;
+ zram->disk->private_data = zram;
+ snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
- /* Actual capacity set using RZSIO_SET_DISKSIZE_KB ioctl */
- set_capacity(rzs->disk, 0);
+ /* Actual capacity set using ZRAMIO_SET_DISKSIZE_KB ioctl */
+ set_capacity(zram->disk, 0);
/*
* To ensure that we always get PAGE_SIZE aligned
* and n*PAGE_SIZED sized I/O requests.
*/
- blk_queue_physical_block_size(rzs->disk->queue, PAGE_SIZE);
- blk_queue_logical_block_size(rzs->disk->queue, PAGE_SIZE);
- blk_queue_io_min(rzs->disk->queue, PAGE_SIZE);
- blk_queue_io_opt(rzs->disk->queue, PAGE_SIZE);
+ blk_queue_physical_block_size(zram->disk->queue, PAGE_SIZE);
+ blk_queue_logical_block_size(zram->disk->queue, PAGE_SIZE);
+ blk_queue_io_min(zram->disk->queue, PAGE_SIZE);
+ blk_queue_io_opt(zram->disk->queue, PAGE_SIZE);
- add_disk(rzs->disk);
+ add_disk(zram->disk);
- rzs->init_done = 0;
+ zram->init_done = 0;
out:
return ret;
}
-static void destroy_device(struct ramzswap *rzs)
+static void destroy_device(struct zram *zram)
{
- if (rzs->disk) {
- del_gendisk(rzs->disk);
- put_disk(rzs->disk);
+ if (zram->disk) {
+ del_gendisk(zram->disk);
+ put_disk(zram->disk);
}
- if (rzs->queue)
- blk_cleanup_queue(rzs->queue);
+ if (zram->queue)
+ blk_cleanup_queue(zram->queue);
}
-static int __init ramzswap_init(void)
+static int __init zram_init(void)
{
int ret, dev_id;
@@ -741,8 +742,8 @@ static int __init ramzswap_init(void)
goto out;
}
- ramzswap_major = register_blkdev(0, "ramzswap");
- if (ramzswap_major <= 0) {
+ zram_major = register_blkdev(0, "zram");
+ if (zram_major <= 0) {
pr_warning("Unable to get major number\n");
ret = -EBUSY;
goto out;
@@ -755,7 +756,7 @@ static int __init ramzswap_init(void)
/* Allocate the device array and initialize each one */
pr_info("Creating %u devices ...\n", num_devices);
- devices = kzalloc(num_devices * sizeof(struct ramzswap), GFP_KERNEL);
+ devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
if (!devices) {
ret = -ENOMEM;
goto unregister;
@@ -773,36 +774,36 @@ free_devices:
while (dev_id)
destroy_device(&devices[--dev_id]);
unregister:
- unregister_blkdev(ramzswap_major, "ramzswap");
+ unregister_blkdev(zram_major, "zram");
out:
return ret;
}
-static void __exit ramzswap_exit(void)
+static void __exit zram_exit(void)
{
int i;
- struct ramzswap *rzs;
+ struct zram *zram;
for (i = 0; i < num_devices; i++) {
- rzs = &devices[i];
+ zram = &devices[i];
- destroy_device(rzs);
- if (rzs->init_done)
- reset_device(rzs);
+ destroy_device(zram);
+ if (zram->init_done)
+ reset_device(zram);
}
- unregister_blkdev(ramzswap_major, "ramzswap");
+ unregister_blkdev(zram_major, "zram");
kfree(devices);
pr_debug("Cleanup done!\n");
}
module_param(num_devices, uint, 0);
-MODULE_PARM_DESC(num_devices, "Number of ramzswap devices");
+MODULE_PARM_DESC(num_devices, "Number of zram devices");
-module_init(ramzswap_init);
-module_exit(ramzswap_exit);
+module_init(zram_init);
+module_exit(zram_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
-MODULE_DESCRIPTION("Compressed RAM Based Swap Device");
+MODULE_DESCRIPTION("Compressed RAM Block Device");
diff --git a/drivers/staging/ramzswap/ramzswap_drv.h b/drivers/staging/zram/zram_drv.h
similarity index 77%
rename from drivers/staging/ramzswap/ramzswap_drv.h
rename to drivers/staging/zram/zram_drv.h
index 63c3042..e324e29 100644
--- a/drivers/staging/ramzswap/ramzswap_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -1,5 +1,5 @@
/*
- * Compressed RAM based swap device
+ * Compressed RAM block device
*
* Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
@@ -12,13 +12,13 @@
* Project home: http://compcache.googlecode.com
*/
-#ifndef _RAMZSWAP_DRV_H_
-#define _RAMZSWAP_DRV_H_
+#ifndef _ZRAM_DRV_H_
+#define _ZRAM_DRV_H_
#include <linux/spinlock.h>
#include <linux/mutex.h>
-#include "ramzswap_ioctl.h"
+#include "zram_ioctl.h"
#include "xvmalloc.h"
/*
@@ -41,7 +41,7 @@ struct zobj_header {
/*-- Configurable parameters */
-/* Default ramzswap disk size: 25% of total RAM */
+/* Default zram disk size: 25% of total RAM */
static const unsigned default_disksize_perc_ram = 25;
/*
@@ -63,15 +63,15 @@ static const unsigned max_zpage_size = PAGE_SIZE / 4 * 3;
#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT)
#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT)
-/* Flags for ramzswap pages (table[page_no].flags) */
-enum rzs_pageflags {
+/* Flags for zram pages (table[page_no].flags) */
+enum zram_pageflags {
/* Page is stored uncompressed */
- RZS_UNCOMPRESSED,
+ ZRAM_UNCOMPRESSED,
/* Page consists entirely of zeros */
- RZS_ZERO,
+ ZRAM_ZERO,
- __NR_RZS_PAGEFLAGS,
+ __NR_ZRAM_PAGEFLAGS,
};
/*-- Data structures */
@@ -87,12 +87,12 @@ struct table {
u8 flags;
} __attribute__((aligned(4)));
-struct ramzswap_stats {
+struct zram_stats {
/* basic stats */
size_t compr_size; /* compressed size of pages stored -
* needed to enforce memlimit */
/* more stats */
-#if defined(CONFIG_RAMZSWAP_STATS)
+#if defined(CONFIG_ZRAM_STATS)
u64 num_reads; /* failed + successful */
u64 num_writes; /* --do-- */
u64 failed_reads; /* should NEVER! happen */
@@ -106,7 +106,7 @@ struct ramzswap_stats {
#endif
};
-struct ramzswap {
+struct zram {
struct xv_pool *mem_pool;
void *compress_workmem;
void *compress_buffer;
@@ -123,45 +123,45 @@ struct ramzswap {
*/
size_t disksize; /* bytes */
- struct ramzswap_stats stats;
+ struct zram_stats stats;
};
/*-- */
/* Debugging and Stats */
-#if defined(CONFIG_RAMZSWAP_STATS)
-static void rzs_stat_inc(u32 *v)
+#if defined(CONFIG_ZRAM_STATS)
+static void zram_stat_inc(u32 *v)
{
*v = *v + 1;
}
-static void rzs_stat_dec(u32 *v)
+static void zram_stat_dec(u32 *v)
{
*v = *v - 1;
}
-static void rzs_stat64_inc(struct ramzswap *rzs, u64 *v)
+static void zram_stat64_inc(struct zram *zram, u64 *v)
{
- spin_lock(&rzs->stat64_lock);
+ spin_lock(&zram->stat64_lock);
*v = *v + 1;
- spin_unlock(&rzs->stat64_lock);
+ spin_unlock(&zram->stat64_lock);
}
-static u64 rzs_stat64_read(struct ramzswap *rzs, u64 *v)
+static u64 zram_stat64_read(struct zram *zram, u64 *v)
{
u64 val;
- spin_lock(&rzs->stat64_lock);
+ spin_lock(&zram->stat64_lock);
val = *v;
- spin_unlock(&rzs->stat64_lock);
+ spin_unlock(&zram->stat64_lock);
return val;
}
#else
-#define rzs_stat_inc(v)
-#define rzs_stat_dec(v)
-#define rzs_stat64_inc(r, v)
-#define rzs_stat64_read(r, v)
-#endif /* CONFIG_RAMZSWAP_STATS */
+#define zram_stat_inc(v)
+#define zram_stat_dec(v)
+#define zram_stat64_inc(r, v)
+#define zram_stat64_read(r, v)
+#endif /* CONFIG_ZRAM_STATS */
#endif
diff --git a/drivers/staging/ramzswap/ramzswap_ioctl.h b/drivers/staging/zram/zram_ioctl.h
similarity index 77%
rename from drivers/staging/ramzswap/ramzswap_ioctl.h
rename to drivers/staging/zram/zram_ioctl.h
index db94bcb..eefefea 100644
--- a/drivers/staging/ramzswap/ramzswap_ioctl.h
+++ b/drivers/staging/zram/zram_ioctl.h
@@ -1,5 +1,5 @@
/*
- * Compressed RAM based swap device
+ * Compressed RAM block device
*
* Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
@@ -12,10 +12,10 @@
* Project home: http://compcache.googlecode.com
*/
-#ifndef _RAMZSWAP_IOCTL_H_
-#define _RAMZSWAP_IOCTL_H_
+#ifndef _ZRAM_IOCTL_H_
+#define _ZRAM_IOCTL_H_
-struct ramzswap_ioctl_stats {
+struct zram_ioctl_stats {
u64 disksize; /* user specified or equal to backing swap
* size (if present) */
u64 num_reads; /* failed + successful */
@@ -34,9 +34,9 @@ struct ramzswap_ioctl_stats {
u64 mem_used_total;
} __attribute__ ((packed, aligned(4)));
-#define RZSIO_SET_DISKSIZE_KB _IOW('z', 0, size_t)
-#define RZSIO_GET_STATS _IOR('z', 1, struct ramzswap_ioctl_stats)
-#define RZSIO_INIT _IO('z', 2)
-#define RZSIO_RESET _IO('z', 3)
+#define ZRAMIO_SET_DISKSIZE_KB _IOW('z', 0, size_t)
+#define ZRAMIO_GET_STATS _IOR('z', 1, struct zram_ioctl_stats)
+#define ZRAMIO_INIT _IO('z', 2)
+#define ZRAMIO_RESET _IO('z', 3)
#endif
--
1.6.6.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] zram: generic RAM based compressed R/W block devices
2010-05-24 14:18 [PATCH 0/3] zram: generic RAM based compressed R/W block devices Nitin Gupta
` (2 preceding siblings ...)
2010-05-24 14:18 ` [PATCH 3/3] Rename ramzswap to zram in documentation Nitin Gupta
@ 2010-05-25 15:21 ` Minchan Kim
2010-05-28 16:08 ` Nitin Gupta
4 siblings, 0 replies; 17+ messages in thread
From: Minchan Kim @ 2010-05-25 15:21 UTC (permalink / raw)
To: Nitin Gupta
Cc: Greg KH, Pekka Enberg, Andrew Morton, Hugh Dickins, Cyp,
driverdev, linux-kernel
Hi, Nitin.
On Mon, May 24, 2010 at 07:48:02PM +0530, Nitin Gupta wrote:
> Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
> Pages written to these disks are compressed and stored in memory
> itself. These disks allow very fast I/O and compression provides
> good amounts of memory savings.
>
> This is enhancement over existing ramzswap driver which creates
> virtual block devices (/dev/ramzswapX) which could be used only
> as swap disks.
>
> Now, with the ability to handle any kind of I/O request, zram
> devices have lot more use cases:
> - /tmp storage
> - various caches under /var
> - swap disks
> - maybe even more! :)
Wow, it looks good to me.
As a matter of fact, when I saw your descriptoin, I thought we can merge
your feature into brd. But I changed my mind due to following as
First of all, ramfs supports direct I/O. So it's hard to support compression.
If we can select optionable config, it would make brd code complicated or ugly.
That's because ramzswap uses own allocator, compression, extended ioctl and so on.
And some users might regard write with important than read without considering space.
So it would be better to keep other block device for easy use and clear code.
I will review this code when I have a time.
Thanks, Nitin.
--
Kind regards,
Minchan Kim
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] zram: generic RAM based compressed R/W block devices
2010-05-24 14:18 [PATCH 0/3] zram: generic RAM based compressed R/W block devices Nitin Gupta
` (3 preceding siblings ...)
2010-05-25 15:21 ` [PATCH 0/3] zram: generic RAM based compressed R/W block devices Minchan Kim
@ 2010-05-28 16:08 ` Nitin Gupta
2010-05-28 16:26 ` Greg KH
4 siblings, 1 reply; 17+ messages in thread
From: Nitin Gupta @ 2010-05-28 16:08 UTC (permalink / raw)
To: Greg KH
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
Hi All,
On 05/24/2010 07:48 PM, Nitin Gupta wrote:
> Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
> Pages written to these disks are compressed and stored in memory
> itself. These disks allow very fast I/O and compression provides
> good amounts of memory savings.
>
> This is enhancement over existing ramzswap driver which creates
> virtual block devices (/dev/ramzswapX) which could be used only
> as swap disks.
>
> Now, with the ability to handle any kind of I/O request, zram
> devices have lot more use cases:
> - /tmp storage
> - various caches under /var
> - swap disks
> - maybe even more! :)
>
> Performance numbers can be found at:
> http://code.google.com/p/compcache/wiki/zramperf
>
Any reviews/comments, please?
I also performed iozone tests to stress zram:
http://code.google.com/p/compcache/wiki/zramIOzone
Note that the effect of pagecache could not be completely
avoided, even when pagecache was dropped every 1 second.
So, this iozone test should not be considered for speed
measurements but as a stress test only. For speed tests,
you can refer 'dd' test results included in changelog (patch 1).
No errors were observed during either iozone or dd tests.
Thanks,
Nitin
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] zram: generic RAM based compressed R/W block devices
2010-05-28 16:08 ` Nitin Gupta
@ 2010-05-28 16:26 ` Greg KH
2010-05-29 1:21 ` Nitin Gupta
2010-06-16 2:14 ` Nitin Gupta
0 siblings, 2 replies; 17+ messages in thread
From: Greg KH @ 2010-05-28 16:26 UTC (permalink / raw)
To: Nitin Gupta
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
On Fri, May 28, 2010 at 09:38:53PM +0530, Nitin Gupta wrote:
> Hi All,
>
> On 05/24/2010 07:48 PM, Nitin Gupta wrote:
> > Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
> > Pages written to these disks are compressed and stored in memory
> > itself. These disks allow very fast I/O and compression provides
> > good amounts of memory savings.
> >
> > This is enhancement over existing ramzswap driver which creates
> > virtual block devices (/dev/ramzswapX) which could be used only
> > as swap disks.
> >
> > Now, with the ability to handle any kind of I/O request, zram
> > devices have lot more use cases:
> > - /tmp storage
> > - various caches under /var
> > - swap disks
> > - maybe even more! :)
> >
> > Performance numbers can be found at:
> > http://code.google.com/p/compcache/wiki/zramperf
> >
>
> Any reviews/comments, please?
We are all busy with the .35-rc1 merge work at the moment, sorry.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] zram: generic RAM based compressed R/W block devices
2010-05-28 16:26 ` Greg KH
@ 2010-05-29 1:21 ` Nitin Gupta
2010-05-29 16:36 ` Greg KH
2010-06-16 2:14 ` Nitin Gupta
1 sibling, 1 reply; 17+ messages in thread
From: Nitin Gupta @ 2010-05-29 1:21 UTC (permalink / raw)
To: Greg KH
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
On 05/28/2010 09:56 PM, Greg KH wrote:
> On Fri, May 28, 2010 at 09:38:53PM +0530, Nitin Gupta wrote:
>> Hi All,
>>
>> On 05/24/2010 07:48 PM, Nitin Gupta wrote:
>>> Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
>>> Pages written to these disks are compressed and stored in memory
>>> itself. These disks allow very fast I/O and compression provides
>>> good amounts of memory savings.
>>>
>>> This is enhancement over existing ramzswap driver which creates
>>> virtual block devices (/dev/ramzswapX) which could be used only
>>> as swap disks.
>>>
>>> Now, with the ability to handle any kind of I/O request, zram
>>> devices have lot more use cases:
>>> - /tmp storage
>>> - various caches under /var
>>> - swap disks
>>> - maybe even more! :)
>>>
>>> Performance numbers can be found at:
>>> http://code.google.com/p/compcache/wiki/zramperf
>>>
>>
>> Any reviews/comments, please?
>
> We are all busy with the .35-rc1 merge work at the moment, sorry.
>
Thanks for your reply.
Ok, in the meantime, I will further test it and keep building upon it.
When rc1 workload is over, I think all this can be merged in linux-next?
Thanks,
Nitin
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] zram: generic RAM based compressed R/W block devices
2010-05-29 1:21 ` Nitin Gupta
@ 2010-05-29 16:36 ` Greg KH
0 siblings, 0 replies; 17+ messages in thread
From: Greg KH @ 2010-05-29 16:36 UTC (permalink / raw)
To: Nitin Gupta
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
On Sat, May 29, 2010 at 06:51:21AM +0530, Nitin Gupta wrote:
> On 05/28/2010 09:56 PM, Greg KH wrote:
> > On Fri, May 28, 2010 at 09:38:53PM +0530, Nitin Gupta wrote:
> >> Hi All,
> >>
> >> On 05/24/2010 07:48 PM, Nitin Gupta wrote:
> >>> Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
> >>> Pages written to these disks are compressed and stored in memory
> >>> itself. These disks allow very fast I/O and compression provides
> >>> good amounts of memory savings.
> >>>
> >>> This is enhancement over existing ramzswap driver which creates
> >>> virtual block devices (/dev/ramzswapX) which could be used only
> >>> as swap disks.
> >>>
> >>> Now, with the ability to handle any kind of I/O request, zram
> >>> devices have lot more use cases:
> >>> - /tmp storage
> >>> - various caches under /var
> >>> - swap disks
> >>> - maybe even more! :)
> >>>
> >>> Performance numbers can be found at:
> >>> http://code.google.com/p/compcache/wiki/zramperf
> >>>
> >>
> >> Any reviews/comments, please?
> >
> > We are all busy with the .35-rc1 merge work at the moment, sorry.
> >
>
> Thanks for your reply.
>
> Ok, in the meantime, I will further test it and keep building upon it.
> When rc1 workload is over, I think all this can be merged in linux-next?
Yes, I think so. It is in my queue to do so.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Support generic I/O requests
2010-05-24 14:18 ` [PATCH 1/3] Support generic I/O requests Nitin Gupta
@ 2010-05-31 15:41 ` Minchan Kim
2010-05-31 19:23 ` Nitin Gupta
0 siblings, 1 reply; 17+ messages in thread
From: Minchan Kim @ 2010-05-31 15:41 UTC (permalink / raw)
To: Nitin Gupta
Cc: Greg KH, Pekka Enberg, Andrew Morton, Hugh Dickins, Cyp,
driverdev, linux-kernel
Hi, Nitin.
Sorry for late review.
On Mon, 2010-05-24 at 19:48 +0530, Nitin Gupta wrote:
> 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.
Later, we could enhance it by per-cpu counter.
>
> Signed-off-by: Nitin Gupta <ngupta@vflare.org>
> ---
> ---
> drivers/staging/ramzswap/ramzswap_drv.c | 325 ++++++++++++++-----------------
> 1 files changed, 148 insertions(+), 177 deletions(-)
>
> diff --git a/drivers/staging/ramzswap/ramzswap_drv.c b/drivers/staging/ramzswap/ramzswap_drv.c
> index d14bf91..9d20d23 100644
> --- a/drivers/staging/ramzswap/ramzswap_drv.c
> +++ b/drivers/staging/ramzswap/ramzswap_drv.c
> @@ -101,20 +101,6 @@ static void ramzswap_set_disksize(struct ramzswap *rzs, size_t totalram_bytes)
> rzs->disksize &= PAGE_MASK;
> }
>
> -/*
> - * Swap header (1st page of swap device) contains information
> - * about a swap file/partition. Prepare such a header for the
> - * given ramzswap device so that swapon can identify it as a
> - * swap partition.
> - */
> -static void setup_swap_header(struct ramzswap *rzs, union swap_header *s)
> -{
> - s->info.version = 1;
> - s->info.last_page = (rzs->disksize >> PAGE_SHIFT) - 1;
> - s->info.nr_badpages = 0;
> - memcpy(s->magic.magic, "SWAPSPACE2", 10);
> -}
> -
> static void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
> struct ramzswap_ioctl_stats *s)
> {
> @@ -202,31 +188,22 @@ out:
> rzs->table[index].offset = 0;
> }
>
> -static int handle_zero_page(struct bio *bio)
> +static void handle_zero_page(struct page *page, u32 index)
It doesn't use index.
> {
> void *user_mem;
> - struct page *page = bio->bi_io_vec[0].bv_page;
>
> user_mem = kmap_atomic(page, KM_USER0);
> memset(user_mem, 0, PAGE_SIZE);
> kunmap_atomic(user_mem, KM_USER0);
>
> flush_dcache_page(page);
> -
> - set_bit(BIO_UPTODATE, &bio->bi_flags);
> - bio_endio(bio, 0);
> - return 0;
> }
>
> -static int handle_uncompressed_page(struct ramzswap *rzs, struct bio *bio)
> +static void handle_uncompressed_page(struct ramzswap *rzs,
> + struct page *page, u32 index)
> {
> - u32 index;
> - struct page *page;
> unsigned char *user_mem, *cmem;
>
> - page = bio->bi_io_vec[0].bv_page;
> - index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
> -
> user_mem = kmap_atomic(page, KM_USER0);
> cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
> rzs->table[index].offset;
> @@ -236,79 +213,72 @@ static int handle_uncompressed_page(struct ramzswap *rzs, struct bio *bio)
> kunmap_atomic(cmem, KM_USER1);
>
> flush_dcache_page(page);
> -
> - set_bit(BIO_UPTODATE, &bio->bi_flags);
> - bio_endio(bio, 0);
> - return 0;
> -}
> -
> -/*
> - * Called when request page is not present in ramzswap.
> - * This is an attempt to read before any previous write
> - * to this location - this happens due to readahead when
> - * swap device is read from user-space (e.g. during swapon)
> - */
> -static int handle_ramzswap_fault(struct ramzswap *rzs, struct bio *bio)
> -{
> - pr_debug("Read before write on swap device: "
> - "sector=%lu, size=%u, offset=%u\n",
> - (ulong)(bio->bi_sector), bio->bi_size,
> - bio->bi_io_vec[0].bv_offset);
> -
> - /* Do nothing. Just return success */
> - set_bit(BIO_UPTODATE, &bio->bi_flags);
> - bio_endio(bio, 0);
> - return 0;
> }
>
> static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
> {
> - int ret;
> +
> + int i;
> u32 index;
> - size_t clen;
> - struct page *page;
> - struct zobj_header *zheader;
> - unsigned char *user_mem, *cmem;
> + struct bio_vec *bvec;
>
> rzs_stat64_inc(rzs, &rzs->stats.num_reads);
>
> - page = bio->bi_io_vec[0].bv_page;
> index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
> + bio_for_each_segment(bvec, bio, i) {
> + int ret;
> + size_t clen;
> + struct page *page;
> + struct zobj_header *zheader;
> + unsigned char *user_mem, *cmem;
>
> - if (rzs_test_flag(rzs, index, RZS_ZERO))
> - return handle_zero_page(bio);
> + page = bvec->bv_page;
>
> - /* Requested page is not present in compressed area */
> - if (!rzs->table[index].page)
> - return handle_ramzswap_fault(rzs, bio);
> + if (rzs_test_flag(rzs, index, RZS_ZERO)) {
> + handle_zero_page(page, index);
> + continue;
> + }
>
> - /* Page is stored uncompressed since it's incompressible */
> - if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
> - return handle_uncompressed_page(rzs, bio);
> + /* Requested page is not present in compressed area */
> + if (unlikely(!rzs->table[index].page)) {
> + pr_debug("Read before write on swap device: "
^^^^
It's not ramzswap any more. It is zram. :)
> + "sector=%lu, size=%u",
> + (ulong)(bio->bi_sector), bio->bi_size);
> + /* Do nothing */
> + continue;
> + }
>
> - user_mem = kmap_atomic(page, KM_USER0);
> - clen = PAGE_SIZE;
> + /* Page is stored uncompressed since it's incompressible */
> + if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED))) {
> + handle_uncompressed_page(rzs, page, index);
> + continue;
> + }
>
> - cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
> - rzs->table[index].offset;
> + user_mem = kmap_atomic(page, KM_USER0);
> + clen = PAGE_SIZE;
>
> - ret = lzo1x_decompress_safe(
> - cmem + sizeof(*zheader),
> - xv_get_object_size(cmem) - sizeof(*zheader),
> - user_mem, &clen);
> + cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
> + rzs->table[index].offset;
>
> - kunmap_atomic(user_mem, KM_USER0);
> - kunmap_atomic(cmem, KM_USER1);
> + ret = lzo1x_decompress_safe(
> + cmem + sizeof(*zheader),
> + xv_get_object_size(cmem) - sizeof(*zheader),
> + user_mem, &clen);
>
> - /* should NEVER happen */
> - if (unlikely(ret != LZO_E_OK)) {
> - pr_err("Decompression failed! err=%d, page=%u\n",
> - ret, index);
> - rzs_stat64_inc(rzs, &rzs->stats.failed_reads);
> - goto out;
> - }
> + kunmap_atomic(user_mem, KM_USER0);
> + kunmap_atomic(cmem, KM_USER1);
>
> - flush_dcache_page(page);
> + /* should NEVER happen */
> + if (unlikely(ret != LZO_E_OK)) {
> + pr_err("Decompression failed! err=%d, page=%u\n",
> + ret, index);
> + rzs_stat64_inc(rzs, &rzs->stats.failed_reads);
> + goto out;
> + }
> +
> + flush_dcache_page(page);
> + index++;
> + }
>
> set_bit(BIO_UPTODATE, &bio->bi_flags);
> bio_endio(bio, 0);
> @@ -321,108 +291,120 @@ out:
>
> static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
> {
> - int ret;
> - u32 offset, index;
> - size_t clen;
> - struct zobj_header *zheader;
> - struct page *page, *page_store;
> - unsigned char *user_mem, *cmem, *src;
> + int i;
> + u32 index;
> + struct bio_vec *bvec;
>
> rzs_stat64_inc(rzs, &rzs->stats.num_writes);
>
> - page = bio->bi_io_vec[0].bv_page;
> index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
>
> - src = rzs->compress_buffer;
> + bio_for_each_segment(bvec, bio, i) {
> + int ret;
> + u32 offset;
> + size_t clen;
> + struct zobj_header *zheader;
> + struct page *page, *page_store;
> + unsigned char *user_mem, *cmem, *src;
>
> - mutex_lock(&rzs->lock);
> + page = bvec->bv_page;
> + src = rzs->compress_buffer;
>
> - user_mem = kmap_atomic(page, KM_USER0);
> - if (page_zero_filled(user_mem)) {
> - kunmap_atomic(user_mem, KM_USER0);
> - mutex_unlock(&rzs->lock);
> - rzs_stat_inc(&rzs->stats.pages_zero);
> - rzs_set_flag(rzs, index, RZS_ZERO);
> + /*
> + * System overwrites unused sectors. Free memory associated
> + * with this sector now.
> + */
> + if (rzs->table[index].page ||
> + rzs_test_flag(rzs, index, RZS_ZERO))
> + ramzswap_free_page(rzs, index);
>
> - set_bit(BIO_UPTODATE, &bio->bi_flags);
> - bio_endio(bio, 0);
> - return 0;
> - }
> + mutex_lock(&rzs->lock);
>
> - ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen,
> - rzs->compress_workmem);
> + user_mem = kmap_atomic(page, KM_USER0);
> + if (page_zero_filled(user_mem)) {
> + kunmap_atomic(user_mem, KM_USER0);
> + mutex_unlock(&rzs->lock);
> + rzs_stat_inc(&rzs->stats.pages_zero);
> + rzs_set_flag(rzs, index, RZS_ZERO);
> + continue;
> + }
>
> - kunmap_atomic(user_mem, KM_USER0);
> + ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen,
> + rzs->compress_workmem);
>
> - if (unlikely(ret != LZO_E_OK)) {
> - mutex_unlock(&rzs->lock);
> - pr_err("Compression failed! err=%d\n", ret);
> - rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
> - goto out;
> - }
> + kunmap_atomic(user_mem, KM_USER0);
>
> - /*
> - * Page is incompressible. Store it as-is (uncompressed)
> - * since we do not want to return too many swap write
> - * errors which has side effect of hanging the system.
> - */
> - if (unlikely(clen > max_zpage_size)) {
> - clen = PAGE_SIZE;
> - page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
> - if (unlikely(!page_store)) {
> + if (unlikely(ret != LZO_E_OK)) {
> mutex_unlock(&rzs->lock);
> - pr_info("Error allocating memory for incompressible "
> - "page: %u\n", index);
> + pr_err("Compression failed! err=%d\n", ret);
> rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
> goto out;
> }
>
> - offset = 0;
> - rzs_set_flag(rzs, index, RZS_UNCOMPRESSED);
> - rzs_stat_inc(&rzs->stats.pages_expand);
> - rzs->table[index].page = page_store;
> - src = kmap_atomic(page, KM_USER0);
> - goto memstore;
> - }
> + /*
> + * Page is incompressible. Store it as-is (uncompressed)
> + * since we do not want to return too many swap write
> + * errors which has side effect of hanging the system.
> + */
> + if (unlikely(clen > max_zpage_size)) {
> + clen = PAGE_SIZE;
> + page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
> + if (unlikely(!page_store)) {
> + mutex_unlock(&rzs->lock);
What's purpose of rzs->lock?
Please, Document it.
And please, take care of "swap" mentioned in comments.
I think code doesn't have big problem.
But my feel is we can clean up some portion of codes. But it's not a big
deal. It doesn't have any problem to work.
So I want to add zram into linux-next, too.
--
Kind regards,
Minchan Kim
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Support generic I/O requests
2010-05-31 15:41 ` Minchan Kim
@ 2010-05-31 19:23 ` Nitin Gupta
0 siblings, 0 replies; 17+ messages in thread
From: Nitin Gupta @ 2010-05-31 19:23 UTC (permalink / raw)
To: Minchan Kim
Cc: Greg KH, Pekka Enberg, Andrew Morton, Hugh Dickins, Cyp,
driverdev, linux-kernel
Hi Minchan,
On 05/31/2010 09:11 PM, Minchan Kim wrote:
>
> On Mon, 2010-05-24 at 19:48 +0530, Nitin Gupta wrote:
<snip>
>>
>> - 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.
>
> Later, we could enhance it by per-cpu counter.
>
Yes, currently we effectively use just 1 core due to a single
compression buffer. So, per-cpu buffers and counters should
really help.
>> -static int handle_zero_page(struct bio *bio)
>> +static void handle_zero_page(struct page *page, u32 index)
>
> It doesn't use index.
>
Ok, I will remove this argument.
>>
>> - /* Page is stored uncompressed since it's incompressible */
>> - if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
>> - return handle_uncompressed_page(rzs, bio);
>> + /* Requested page is not present in compressed area */
>> + if (unlikely(!rzs->table[index].page)) {
>> + pr_debug("Read before write on swap device: "
> ^^^^
> It's not ramzswap any more. It is zram. :)
>
I will correct this :)
>> + /*
>> + * Page is incompressible. Store it as-is (uncompressed)
>> + * since we do not want to return too many swap write
>> + * errors which has side effect of hanging the system.
>> + */
>> + if (unlikely(clen > max_zpage_size)) {
>> + clen = PAGE_SIZE;
>> + page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
>> + if (unlikely(!page_store)) {
>> + mutex_unlock(&rzs->lock);
>
> What's purpose of rzs->lock?
> Please, Document it.
>
Ok. I intentionally deferred much of the documentation for later patches
to reduce "side noise" for these patches. Anyways, I will document this
lock in "v2" patches.
> And please, take care of "swap" mentioned in comments.
>
Old habits die hard :) I will clean them up.
> I think code doesn't have big problem.
> But my feel is we can clean up some portion of codes. But it's not a big
> deal. It doesn't have any problem to work.
> So I want to add zram into linux-next, too.
>
I will be sending patch series with code commentary, cleanups and minor
fixes once this much enters linux-next.
Thanks for the review.
Nitin
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] zram: generic RAM based compressed R/W block devices
2010-05-28 16:26 ` Greg KH
2010-05-29 1:21 ` Nitin Gupta
@ 2010-06-16 2:14 ` Nitin Gupta
2010-06-16 18:43 ` Greg KH
1 sibling, 1 reply; 17+ messages in thread
From: Nitin Gupta @ 2010-06-16 2:14 UTC (permalink / raw)
To: Greg KH
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
Hi Greg,
On 05/28/2010 09:56 PM, Greg KH wrote:
> On Fri, May 28, 2010 at 09:38:53PM +0530, Nitin Gupta wrote:
>>
>> On 05/24/2010 07:48 PM, Nitin Gupta wrote:
>>> Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
>>> Pages written to these disks are compressed and stored in memory
>>> itself. These disks allow very fast I/O and compression provides
>>> good amounts of memory savings.
>>>
>>> This is enhancement over existing ramzswap driver which creates
>>> virtual block devices (/dev/ramzswapX) which could be used only
>>> as swap disks.
>>>
>>> Now, with the ability to handle any kind of I/O request, zram
>>> devices have lot more use cases:
>>> - /tmp storage
>>> - various caches under /var
>>> - swap disks
>>> - maybe even more! :)
>>>
>>> Performance numbers can be found at:
>>> http://code.google.com/p/compcache/wiki/zramperf
>>>
>>
>> Any reviews/comments, please?
>
> We are all busy with the .35-rc1 merge work at the moment, sorry.
>
Can you please apply these patches to linux-next? or maybe for .35-rc3/rc4 too?
Thanks,
Nitin
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] zram: generic RAM based compressed R/W block devices
2010-06-16 2:14 ` Nitin Gupta
@ 2010-06-16 18:43 ` Greg KH
2010-06-17 1:39 ` Nitin Gupta
0 siblings, 1 reply; 17+ messages in thread
From: Greg KH @ 2010-06-16 18:43 UTC (permalink / raw)
To: Nitin Gupta
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
On Wed, Jun 16, 2010 at 07:44:20AM +0530, Nitin Gupta wrote:
> Hi Greg,
>
> On 05/28/2010 09:56 PM, Greg KH wrote:
> > On Fri, May 28, 2010 at 09:38:53PM +0530, Nitin Gupta wrote:
> >>
> >> On 05/24/2010 07:48 PM, Nitin Gupta wrote:
> >>> Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
> >>> Pages written to these disks are compressed and stored in memory
> >>> itself. These disks allow very fast I/O and compression provides
> >>> good amounts of memory savings.
> >>>
> >>> This is enhancement over existing ramzswap driver which creates
> >>> virtual block devices (/dev/ramzswapX) which could be used only
> >>> as swap disks.
> >>>
> >>> Now, with the ability to handle any kind of I/O request, zram
> >>> devices have lot more use cases:
> >>> - /tmp storage
> >>> - various caches under /var
> >>> - swap disks
> >>> - maybe even more! :)
> >>>
> >>> Performance numbers can be found at:
> >>> http://code.google.com/p/compcache/wiki/zramperf
> >>>
> >>
> >> Any reviews/comments, please?
> >
> > We are all busy with the .35-rc1 merge work at the moment, sorry.
> >
>
> Can you please apply these patches to linux-next?
Yes, I'm working on it, I should get to it by the end of this week.
> or maybe for .35-rc3/rc4 too?
No, this is not a bugfix, why would it be acceptable for the .35 kernel
release?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] zram: generic RAM based compressed R/W block devices
2010-06-16 18:43 ` Greg KH
@ 2010-06-17 1:39 ` Nitin Gupta
2010-06-17 14:40 ` Greg KH
0 siblings, 1 reply; 17+ messages in thread
From: Nitin Gupta @ 2010-06-17 1:39 UTC (permalink / raw)
To: Greg KH
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
On 06/17/2010 12:13 AM, Greg KH wrote:
> On Wed, Jun 16, 2010 at 07:44:20AM +0530, Nitin Gupta wrote:
>> Hi Greg,
>>
>> On 05/28/2010 09:56 PM, Greg KH wrote:
>>> On Fri, May 28, 2010 at 09:38:53PM +0530, Nitin Gupta wrote:
>>>>
>>>> On 05/24/2010 07:48 PM, Nitin Gupta wrote:
>>>>> Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
>>>>> Pages written to these disks are compressed and stored in memory
>>>>> itself. These disks allow very fast I/O and compression provides
>>>>> good amounts of memory savings.
>>>>>
>>>>> This is enhancement over existing ramzswap driver which creates
>>>>> virtual block devices (/dev/ramzswapX) which could be used only
>>>>> as swap disks.
>>>>>
>>>>> Now, with the ability to handle any kind of I/O request, zram
>>>>> devices have lot more use cases:
>>>>> - /tmp storage
>>>>> - various caches under /var
>>>>> - swap disks
>>>>> - maybe even more! :)
>>>>>
>>>>> Performance numbers can be found at:
>>>>> http://code.google.com/p/compcache/wiki/zramperf
>>>>>
>>>>
>>>> Any reviews/comments, please?
>>>
>>> We are all busy with the .35-rc1 merge work at the moment, sorry.
>>>
>>
>> Can you please apply these patches to linux-next?
>
> Yes, I'm working on it, I should get to it by the end of this week.
>
>> or maybe for .35-rc3/rc4 too?
>
> No, this is not a bugfix, why would it be acceptable for the .35 kernel
> release?
>
Since its a staging driver, I thought any kind of changes can be pulled in
mainline too. Maybe I still don't understand how -staging works :)
Anyways, thanks for taking it in linux-next.
Nitin
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3] zram: generic RAM based compressed R/W block devices
2010-06-17 1:39 ` Nitin Gupta
@ 2010-06-17 14:40 ` Greg KH
0 siblings, 0 replies; 17+ messages in thread
From: Greg KH @ 2010-06-17 14:40 UTC (permalink / raw)
To: Nitin Gupta
Cc: Pekka Enberg, Andrew Morton, Minchan Kim, Hugh Dickins, Cyp,
driverdev, linux-kernel
On Thu, Jun 17, 2010 at 07:09:01AM +0530, Nitin Gupta wrote:
> On 06/17/2010 12:13 AM, Greg KH wrote:
> > On Wed, Jun 16, 2010 at 07:44:20AM +0530, Nitin Gupta wrote:
> >> Hi Greg,
> >>
> >> On 05/28/2010 09:56 PM, Greg KH wrote:
> >>> On Fri, May 28, 2010 at 09:38:53PM +0530, Nitin Gupta wrote:
> >>>>
> >>>> On 05/24/2010 07:48 PM, Nitin Gupta wrote:
> >>>>> Creates RAM based block devices: /dev/zramX (X = 0, 1, ...).
> >>>>> Pages written to these disks are compressed and stored in memory
> >>>>> itself. These disks allow very fast I/O and compression provides
> >>>>> good amounts of memory savings.
> >>>>>
> >>>>> This is enhancement over existing ramzswap driver which creates
> >>>>> virtual block devices (/dev/ramzswapX) which could be used only
> >>>>> as swap disks.
> >>>>>
> >>>>> Now, with the ability to handle any kind of I/O request, zram
> >>>>> devices have lot more use cases:
> >>>>> - /tmp storage
> >>>>> - various caches under /var
> >>>>> - swap disks
> >>>>> - maybe even more! :)
> >>>>>
> >>>>> Performance numbers can be found at:
> >>>>> http://code.google.com/p/compcache/wiki/zramperf
> >>>>>
> >>>>
> >>>> Any reviews/comments, please?
> >>>
> >>> We are all busy with the .35-rc1 merge work at the moment, sorry.
> >>>
> >>
> >> Can you please apply these patches to linux-next?
> >
> > Yes, I'm working on it, I should get to it by the end of this week.
> >
> >> or maybe for .35-rc3/rc4 too?
> >
> > No, this is not a bugfix, why would it be acceptable for the .35 kernel
> > release?
> >
>
> Since its a staging driver, I thought any kind of changes can be pulled in
> mainline too. Maybe I still don't understand how -staging works :)
staging works like any other part of the kernel tree when it comes to
merges with Linus, new stuff only goes in for the -rc1 release, bugfixes
only afterward.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2010-06-17 14:41 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-24 14:18 [PATCH 0/3] zram: generic RAM based compressed R/W block devices Nitin Gupta
2010-05-24 14:18 ` [PATCH 1/3] Support generic I/O requests Nitin Gupta
2010-05-31 15:41 ` Minchan Kim
2010-05-31 19:23 ` Nitin Gupta
2010-05-24 14:18 ` [PATCH 2/3] Rename ramzswap to zram in code Nitin Gupta
2010-05-24 15:31 ` Arnd Bergmann
2010-05-24 18:23 ` Nitin Gupta
2010-05-24 14:18 ` [PATCH 3/3] Rename ramzswap to zram in documentation Nitin Gupta
2010-05-25 15:21 ` [PATCH 0/3] zram: generic RAM based compressed R/W block devices Minchan Kim
2010-05-28 16:08 ` Nitin Gupta
2010-05-28 16:26 ` Greg KH
2010-05-29 1:21 ` Nitin Gupta
2010-05-29 16:36 ` Greg KH
2010-06-16 2:14 ` Nitin Gupta
2010-06-16 18:43 ` Greg KH
2010-06-17 1:39 ` Nitin Gupta
2010-06-17 14:40 ` Greg KH
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox