Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1463017 > unrolled thread

[RFC PATCH 00/16] dm-inplace-compression block device

Started byRam Pai <linuxram@us.ibm.com>
First post2016-08-15 19:40 +0200
Last post2016-08-15 19:50 +0200
Articles 14 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [RFC PATCH 00/16] dm-inplace-compression block device Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 15/16] DM: Add sysfs parameters to track total memory saved and allocated. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 06/16] DM: separate out compression and decompression routines. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 12/16] DM: release unneeded buffer as soon as possible. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 14/16] DM: Wasted bio copy. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 11/16] DM: Try to avoid temporary buffer allocation to hold compressed data. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 13/16] DM: macros to set and get the state of the request. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 03/16] DM: Error if enough space is not available. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 16/16] DM: add documentation for dm-inplace-compress. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 09/16] DM: Delay allocation of decompression buffer during read. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:40 +0200
    [RFC PATCH 04/16] DM: Ensure that the read request is within the device range. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:50 +0200
    [RFC PATCH 07/16] DM: Optimize memory allocated to hold compressed buffer. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:50 +0200
    [RFC PATCH 10/16] DM: Try to use the bio buffer for decompression instead of allocating one. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:50 +0200
    [RFC PATCH 05/16] DM: allocation/free helper routines. Ram Pai <linuxram@us.ibm.com> - 2016-08-15 19:50 +0200

#1463017 — [RFC PATCH 00/16] dm-inplace-compression block device

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 00/16] dm-inplace-compression block device
Message-ID<s6u1H-59-7@gated-at.bofh.it>
This patch series provides a generic device-mapper inplace compression device.
Originally written by Shaohua Li.
https://www.redhat.com/archives/dm-devel/2013-December/msg00143.html

I have optimized the code and used it as a compressed swap device supporting
exterme levels of swap traffic using a NVMe device as a backend.

Comments from Alasdair have been incorporated.
https://www.redhat.com/archives/dm-devel/2013-December/msg00144.html

Testing:

This patch is tested thoroughly as a swap device on Power machine only.  More
testing is needed before it can be used as a generic compression device.

Your comments to improve the code is very much appreciated.

Ram Pai (15):
  DM: Ability to choose the compressor.
  DM: Error if enough space is not available.
  DM: Ensure that the read request is within the device range.
  DM: allocation/free helper routines.
  DM: separate out compression and decompression routines.
  DM: Optimize memory allocated to hold compressed buffer.
  DM: Tag a magicmarker at the end of each compressed segment.
  DM: Delay allocation of decompression buffer during read.
  DM: Try to use the bio buffer for decompression instead of allocating
    one.
  DM: Try to avoid temporary buffer allocation to hold compressed data.
  DM: release unneeded buffer as soon as possible.
  DM: macros to set and get the state of the request.
  DM: Wasted bio copy.
  DM: Add sysfs parameters to track total memory saved and allocated.
  DM: add documentation for dm-inplace-compress.

Shaohua Li (1):
  DM: dm-inplace-compress: a compressed DM target for SSD

 .../device-mapper/dm-inplace-compress.text         |  138 ++
 drivers/md/Kconfig                                 |    6 +
 drivers/md/Makefile                                |    1 +
 drivers/md/dm-inplace-compress.c                   | 1792 ++++++++++++++++++++
 drivers/md/dm-inplace-compress.h                   |  162 ++
 5 files changed, 2099 insertions(+)
 create mode 100644 Documentation/device-mapper/dm-inplace-compress.text
 create mode 100644 drivers/md/dm-inplace-compress.c
 create mode 100644 drivers/md/dm-inplace-compress.h

-- 
1.8.3.1

[toc] | [next] | [standalone]


#1463018 — [RFC PATCH 15/16] DM: Add sysfs parameters to track total memory saved and allocated.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 15/16] DM: Add sysfs parameters to track total memory saved and allocated.
Message-ID<s6u1H-59-19@gated-at.bofh.it>
In reply to#1463017
Add parameters to monitor the memory efficiency of the module.
dm_icomp_total_alloc_size: total memory currently in use.
dm_icomp_total_bio_save: total memory allocation saved by the optimizations.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |   36 ++++++++++++++++++++++++++++++++++--
 1 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index 31b144b..0a7790a 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -82,6 +82,23 @@ static int dm_icomp_compressor_param_set(const char *val,
 	return 0;
 }
 
+static const struct kernel_param_ops dm_icomp_alloc_param_ops = {
+	.set    = param_set_ulong,
+	.get    = param_get_ulong,
+};
+
+static atomic64_t dm_icomp_total_alloc_size;
+#define DMCP_ALLOC(s) {atomic64_add(s, &dm_icomp_total_alloc_size); }
+#define DMCP_FREE_ALLOC(s) {atomic64_sub(s, &dm_icomp_total_alloc_size); }
+module_param_cb(dm_icomp_total_alloc_size, &dm_icomp_alloc_param_ops,
+				&dm_icomp_total_alloc_size, 0644);
+
+static atomic64_t dm_icomp_total_bio_save;
+#define DMCP_ALLOC_SAVE(s) {atomic64_add(s, &dm_icomp_total_bio_save); }
+module_param_cb(dm_icomp_total_bio_save, &dm_icomp_alloc_param_ops,
+				&dm_icomp_total_bio_save, 0644);
+
+
 static struct kmem_cache *dm_icomp_req_cachep;
 static struct kmem_cache *dm_icomp_io_range_cachep;
 static struct kmem_cache *dm_icomp_meta_io_cachep;
@@ -616,6 +633,9 @@ static int dm_icomp_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 	atomic64_set(&info->compressed_write_size, 0);
 	atomic64_set(&info->uncompressed_write_size, 0);
 	atomic64_set(&info->meta_write_size, 0);
+	atomic64_set(&dm_icomp_total_alloc_size, 0);
+	atomic64_set(&dm_icomp_total_bio_save, 0);
+
 	ti->num_flush_bios = 1;
 	/* ti->num_discard_bios = 1; */
 	ti->private = info;
@@ -781,18 +801,28 @@ static void dm_icomp_get_req(struct dm_icomp_req *req)
 
 static void *dm_icomp_kmalloc(size_t size, gfp_t flags)
 {
-	return  kmalloc(size, flags);
+	void *addr = kmalloc(size, flags);
+
+	if (addr)
+		DMCP_ALLOC(size);
+	return addr;
 }
 
 static void *dm_icomp_krealloc(void *addr, size_t size,
 		 size_t orig_size, gfp_t flags)
 {
-	return krealloc(addr, size, flags);
+	void *taddr = krealloc(addr, size, flags);
+
+	DMCP_FREE_ALLOC(orig_size);
+	if (taddr)
+		DMCP_ALLOC(size);
+	return taddr;
 }
 
 static void dm_icomp_kfree(void *addr, unsigned int size)
 {
 	kfree(addr);
+	DMCP_FREE_ALLOC(size);
 }
 
 static void dm_icomp_release_decomp_buffer(struct dm_icomp_io_range *io)
@@ -1056,6 +1086,8 @@ static struct dm_icomp_io_range *dm_icomp_create_io_write_range(
 	io->decomp_kmap = (segments == 1);
 	if (!io->decomp_kmap)
 		dm_icomp_bio_copy(req->bio, 0, io->decomp_data, size, true);
+	else
+		DMCP_ALLOC_SAVE(size);
 
 	return io;
 }
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463019 — [RFC PATCH 06/16] DM: separate out compression and decompression routines.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 06/16] DM: separate out compression and decompression routines.
Message-ID<s6u1H-59-25@gated-at.bofh.it>
In reply to#1463017
Simplify the code by separating out the compression and decompression routines.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |  127 +++++++++++++++++++++-----------------
 1 files changed, 71 insertions(+), 56 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index c11567c..5c39169 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -793,8 +793,8 @@ static void dm_icomp_kfree(void *addr, unsigned int size)
 
 static void dm_icomp_free_io_range(struct dm_icomp_io_range *io)
 {
-	kfree(io->decomp_data);
-	kfree(io->comp_data);
+	dm_icomp_kfree(io->decomp_data, io->decomp_len);
+	dm_icomp_kfree(io->comp_data, io->comp_len);
 	kmem_cache_free(dm_icomp_io_range_cachep, io);
 }
 
@@ -861,12 +861,12 @@ static struct dm_icomp_io_range *dm_icomp_create_io_range(
 	if (!io)
 		return NULL;
 
-	io->comp_data = kmalloc(dm_icomp_compressor_len(req->info, comp_len),
-								GFP_NOIO);
-	io->decomp_data = kmalloc(decomp_len, GFP_NOIO);
+	io->comp_data = dm_icomp_kmalloc(
+		dm_icomp_compressor_len(req->info, comp_len), GFP_NOIO);
+	io->decomp_data = dm_icomp_kmalloc(decomp_len, GFP_NOIO);
 	if (!io->decomp_data || !io->comp_data) {
-		kfree(io->decomp_data);
-		kfree(io->comp_data);
+		dm_icomp_kfree(io->decomp_data, io->decomp_len);
+		dm_icomp_kfree(io->comp_data, io->comp_len);
 		kmem_cache_free(dm_icomp_io_range_cachep, io);
 		return NULL;
 	}
@@ -928,51 +928,66 @@ static void dm_icomp_bio_copy(struct bio *bio, off_t bio_off, void *buf,
  * We store the actual compressed len in the last u32 of the payload.
  * If there is no free space, we add 512 to the payload size.
  */
-static int dm_icomp_io_range_comp(struct dm_icomp_info *info, void *comp_data,
-	unsigned int *comp_len, void *decomp_data, unsigned int decomp_len,
-	bool do_comp)
+static int dm_icomp_io_range_compress(struct dm_icomp_info *info,
+		struct dm_icomp_io_range *io, unsigned int *comp_len,
+		void *decomp_data, unsigned int decomp_len)
 {
-	struct crypto_comp *tfm;
+	unsigned int actual_comp_len = io->comp_len;
 	u32 *addr;
-	unsigned int actual_comp_len;
+	struct crypto_comp *tfm =  info->tfm[get_cpu()];
 	int ret;
 
-	if (do_comp) {
-		actual_comp_len = *comp_len;
-
-		tfm = info->tfm[get_cpu()];
-		ret = crypto_comp_compress(tfm, decomp_data, decomp_len,
-			comp_data, &actual_comp_len);
-		put_cpu();
+	ret = crypto_comp_compress(tfm, decomp_data, decomp_len,
+		io->comp_data, &actual_comp_len);
 
-		atomic64_add(decomp_len, &info->uncompressed_write_size);
-		if (ret || decomp_len < actual_comp_len + sizeof(u32) + 512) {
-			*comp_len = decomp_len;
-			atomic64_add(*comp_len, &info->compressed_write_size);
-			return 1;
-		}
+	put_cpu();
+	if (ret < 0)
+		DMWARN("CO Error %d ", ret);
 
-		*comp_len = round_up(actual_comp_len, 512);
-		if (*comp_len - actual_comp_len < sizeof(u32))
-			*comp_len += 512;
+	atomic64_add(decomp_len, &info->uncompressed_write_size);
+	if (ret || decomp_len < actual_comp_len + sizeof(u32) + 512) {
+		*comp_len = decomp_len;
 		atomic64_add(*comp_len, &info->compressed_write_size);
-		addr = comp_data + *comp_len;
-		addr--;
-		*addr = cpu_to_le32(actual_comp_len);
-	} else {
-		if (*comp_len == decomp_len)
-			return 1;
-		addr = comp_data + *comp_len;
-		addr--;
-		actual_comp_len = le32_to_cpu(*addr);
-
-		tfm = info->tfm[get_cpu()];
-		ret = crypto_comp_decompress(tfm, comp_data, actual_comp_len,
-			decomp_data, &decomp_len);
-		put_cpu();
-		if (ret)
-			return -EINVAL;
+		return 1;
 	}
+
+	*comp_len = round_up(actual_comp_len, 512);
+	if (*comp_len - actual_comp_len < sizeof(u32))
+		*comp_len += 512;
+	atomic64_add(*comp_len, &info->compressed_write_size);
+	addr = io->comp_data + *comp_len;
+	addr--;
+	*addr = cpu_to_le32(actual_comp_len);
+	return 0;
+}
+
+/*
+ * return value:
+ * < 0 : error
+ * == 0 : ok
+ * == 1 : ok, but comp/decomp is skipped
+ */
+static int dm_icomp_io_range_decompress(struct dm_icomp_info *info,
+	void *comp_data, unsigned int comp_len, void *decomp_data,
+	unsigned int decomp_len)
+{
+	struct crypto_comp *tfm;
+	u32 *addr;
+	int ret;
+
+	if (comp_len == decomp_len)
+		return 1;
+
+	addr = comp_data + comp_len;
+	addr--;
+	comp_len = le32_to_cpu(*addr);
+
+	tfm = info->tfm[get_cpu()];
+	ret = crypto_comp_decompress(tfm, comp_data, comp_len,
+		decomp_data, &decomp_len);
+	put_cpu();
+	if (ret)
+		return -EINVAL;
 	return 0;
 }
 
@@ -993,8 +1008,8 @@ static void dm_icomp_handle_read_decomp(struct dm_icomp_req *req)
 		io->io_region.sector -= req->info->data_start;
 
 		/* Do decomp here */
-		ret = dm_icomp_io_range_comp(req->info, io->comp_data,
-			&io->comp_len, io->decomp_data, io->decomp_len, false);
+		ret = dm_icomp_io_range_decompress(req->info, io->comp_data,
+			io->comp_len, io->decomp_data, io->decomp_len);
 		if (ret < 0) {
 			req->result = -EIO;
 			return;
@@ -1140,8 +1155,8 @@ static int dm_icomp_handle_write_modify(struct dm_icomp_io_range *io,
 	io->io_region.sector -= req->info->data_start;
 
 	/* decompress original data */
-	ret = dm_icomp_io_range_comp(req->info, io->comp_data, &io->comp_len,
-			io->decomp_data, io->decomp_len, false);
+	ret = dm_icomp_io_range_decompress(req->info, io->comp_data,
+		io->comp_len, io->decomp_data, io->decomp_len);
 	if (ret < 0) {
 		req->result = -EINVAL;
 		return -EIO;
@@ -1164,11 +1179,11 @@ static int dm_icomp_handle_write_modify(struct dm_icomp_io_range *io,
 			   ((req->bio->bi_iter.bi_sector - start) << 9),
 			   bio_sectors(req->bio) << 9, true);
 
-			kfree(io->comp_data);
+			dm_icomp_kfree(io->comp_data, io->comp_len);
 			/* New compressed len might be bigger */
-			io->comp_data = kmalloc(
-				dm_icomp_compressor_len(req->info,
-					io->decomp_len), GFP_NOIO);
+			io->comp_data = dm_icomp_kmalloc(
+				dm_icomp_compressor_len(
+				req->info, io->decomp_len), GFP_NOIO);
 			io->comp_len = io->decomp_len;
 			if (!io->comp_data) {
 				req->result = -ENOMEM;
@@ -1197,8 +1212,8 @@ static int dm_icomp_handle_write_modify(struct dm_icomp_io_range *io,
 
 	/* assume compress less data uses less space (at least 4k lsess data) */
 	comp_len = io->comp_len;
-	ret = dm_icomp_io_range_comp(req->info, io->comp_data, &comp_len,
-		io->decomp_data + (offset << 9), count << 9, true);
+	ret = dm_icomp_io_range_compress(req->info, io, &comp_len,
+		io->decomp_data + (offset << 9), count << 9);
 	if (ret < 0) {
 		req->result = -EIO;
 		return -EIO;
@@ -1260,8 +1275,8 @@ static void dm_icomp_handle_write_comp(struct dm_icomp_req *req)
 
 	/* compress data */
 	comp_len = io->comp_len;
-	ret = dm_icomp_io_range_comp(req->info, io->comp_data, &comp_len,
-		io->decomp_data, count << 9, true);
+	ret = dm_icomp_io_range_compress(req->info, io, &comp_len,
+			io->decomp_data, count << 9);
 	if (ret < 0) {
 		dm_icomp_free_io_range(io);
 		req->result = -EIO;
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463020 — [RFC PATCH 12/16] DM: release unneeded buffer as soon as possible.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 12/16] DM: release unneeded buffer as soon as possible.
Message-ID<s6u1I-59-27@gated-at.bofh.it>
In reply to#1463017
Done to conserve as much free space as possible.  Waiting to release till the
bio is done will unneccesarily hog up memory.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index bc1cf70..b1c3e5f 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -977,7 +977,7 @@ static struct dm_icomp_io_range *dm_icomp_create_io_read_range(
 	io->comp_kmap = (segments == 1);
 	/* note down the requested length for decompress buffer.
 	 * but dont allocate it yet.
-	 /
+	 */
 	io->decomp_req_len = decomp_len;
 	return io;
 }
@@ -1375,8 +1375,13 @@ static int dm_icomp_handle_write_modify(struct dm_icomp_io_range *io,
 	}
 
 	dm_icomp_get_req(req);
-	if (ret == 1)
+
+	if (ret == 1) {
 		io->io_req.mem.ptr.addr = io->decomp_data + (offset << 9);
+		dm_icomp_release_comp_buffer(io);
+	} else
+		dm_icomp_release_decomp_buffer(io);
+
 	io->io_region.count = comp_len >> 9;
 	io->io_region.sector = start + req->info->data_start;
 
@@ -1443,8 +1448,11 @@ static void dm_icomp_handle_write_comp(struct dm_icomp_req *req)
 	io->io_region.sector = req->bio->bi_iter.bi_sector +
 			 req->info->data_start;
 
-	if (ret == 1)
+	if (ret == 1) {
 		io->io_req.mem.ptr.addr = io->decomp_data;
+		dm_icomp_release_comp_buffer(io);
+	} else
+		dm_icomp_release_decomp_buffer(io);
 
 	io->io_region.count = comp_len >> 9;
 	io->io_req.bi_rw = req->bio->bi_rw;
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463021 — [RFC PATCH 14/16] DM: Wasted bio copy.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 14/16] DM: Wasted bio copy.
Message-ID<s6u1I-59-45@gated-at.bofh.it>
In reply to#1463017
No point doing it.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index 55a515b..31b144b 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -1434,7 +1434,6 @@ static void dm_icomp_handle_write_comp(struct dm_icomp_req *req)
 		req->result = -EIO;
 		return;
 	}
-	dm_icomp_bio_copy(req->bio, 0, io->decomp_data, count << 9, true);
 
 	/* compress data */
 	comp_len = io->comp_len;
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463024 — [RFC PATCH 11/16] DM: Try to avoid temporary buffer allocation to hold compressed data.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 11/16] DM: Try to avoid temporary buffer allocation to hold compressed data.
Message-ID<s6u1I-59-35@gated-at.bofh.it>
In reply to#1463017
The read path
a) allocates a temporary buffer to hold the compressed data.
b) reads the compressed data into the temporary buffer.
c) decompresses the compressed data into the caller's bio-buffer.

We know that the caller's bio-buffer will be atleast as large as the compressed
data.  So we could save a buffer allocation in step (a) if we use caller's
bio-buffer to read in the compressed data from the disk. NOTE: this is not
possible all the time, but is possible if the destination within the bio-buffer
falls within the same segment.

This saves us from holding the temporary buffer across read boundaries.  Which
is a huge advantage especially if we are operating under acute memory
starvation; mostly when this block device is used as a swap device.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |  185 ++++++++++++++++++-------------------
 drivers/md/dm-inplace-compress.h |    1 +
 2 files changed, 91 insertions(+), 95 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index f6b95e3..bc1cf70 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -810,10 +810,15 @@ static void dm_icomp_release_comp_buffer(struct dm_icomp_io_range *io)
 {
 	if (!io->comp_data)
 		return;
-	dm_icomp_kfree(io->comp_data, io->comp_len);
+
+	if (io->comp_kmap)
+		kunmap(io->comp_data);
+	else
+		dm_icomp_kfree(io->comp_data, io->comp_len);
 
 	io->comp_data = NULL;
 	io->comp_len = 0;
+	io->comp_kmap = false;
 }
 
 static void dm_icomp_free_io_range(struct dm_icomp_io_range *io)
@@ -857,6 +862,39 @@ static void dm_icomp_put_req(struct dm_icomp_req *req)
 	kmem_cache_free(dm_icomp_req_cachep, req);
 }
 
+static void dm_icomp_bio_copy(struct bio *bio, off_t bio_off, void *buf,
+		ssize_t len, bool to_buf)
+{
+	struct bio_vec bv;
+	struct bvec_iter iter;
+	off_t buf_off = 0;
+	ssize_t size;
+	void *addr;
+
+	WARN_ON(bio_off + len > (bio_sectors(bio) << 9));
+
+	bio_for_each_segment(bv, bio, iter) {
+		int length = bv.bv_len;
+
+		if (bio_off >= length) {
+			bio_off -= length;
+			continue;
+		}
+		addr = kmap_atomic(bv.bv_page);
+		size = min_t(ssize_t, len, length - bio_off);
+		if (to_buf)
+			memcpy(buf + buf_off, addr + bio_off + bv.bv_offset,
+			size);
+		else
+			memcpy(addr + bio_off + bv.bv_offset, buf + buf_off,
+			size);
+		kunmap_atomic(addr);
+		bio_off = 0;
+		buf_off += size;
+		len -= size;
+	}
+}
+
 static void dm_icomp_io_range_done(unsigned long error, void *context)
 {
 	struct dm_icomp_io_range *io = context;
@@ -886,7 +924,7 @@ static inline int dm_icomp_compressor_maxlen(struct dm_icomp_info *info,
  * comp_data
  */
 static struct dm_icomp_io_range *dm_icomp_create_io_range(
-		struct dm_icomp_req *req, int comp_len)
+		struct dm_icomp_req *req)
 {
 	struct dm_icomp_io_range *io;
 
@@ -894,120 +932,67 @@ static struct dm_icomp_io_range *dm_icomp_create_io_range(
 	if (!io)
 		return NULL;
 
-	io->comp_data = dm_icomp_kmalloc(comp_len, GFP_NOIO);
-	if (!io->comp_data) {
-		kmem_cache_free(dm_icomp_io_range_cachep, io);
-		return NULL;
-	}
-
 	io->io_req.notify.fn = dm_icomp_io_range_done;
 	io->io_req.notify.context = io;
 	io->io_req.client = req->info->io_client;
 	io->io_req.mem.type = DM_IO_KMEM;
-	io->io_req.mem.ptr.addr = io->comp_data;
 	io->io_req.mem.offset = 0;
 
 	io->io_region.bdev = req->info->dev->bdev;
-
-	io->comp_len = comp_len;
 	io->req = req;
 
-	io->decomp_data = NULL;
-	io->decomp_real_data = NULL;
-	io->decomp_len = 0;
-	io->decomp_kmap = false;
-	io->decomp_req_len = 0;
+	io->comp_data = io->decomp_data = io->decomp_real_data = NULL;
+	io->comp_len = io->decomp_len = io->decomp_req_len = 0;
+	io->comp_kmap = io->decomp_kmap = false;
 	return io;
 }
 
 static struct dm_icomp_io_range *dm_icomp_create_io_read_range(
 		struct dm_icomp_req *req, int comp_len, int decomp_len)
 {
-	struct dm_icomp_io_range *io = dm_icomp_create_io_range(req, comp_len);
-
-	if (io) {
-		/* note down the requested length for decompress buffer.
-		 * but dont allocate it yet.
-		 */
-		io->decomp_req_len = decomp_len;
-	}
-	return io;
-}
+	struct bio *bio = req->bio;
+	sector_t size  = bio_sectors(bio)<<9;
+	int segments = bio_segments(bio);
+	void *addr;
+	struct dm_icomp_io_range *io = dm_icomp_create_io_range(req);
 
-static int dm_icomp_update_io_read_range(struct dm_icomp_io_range *io,
-		struct bio *bio, ssize_t bio_off)
-{
-	struct bvec_iter iter;
-	struct bio_vec bv;
-	bool just_use = false;
+	if (!io)
+		return NULL;
 
-	if (io->decomp_len)
-		return 0;
+	/* try reusing the bio buffer for compress data. */
+	if (segments == 1) {
+		struct bio_vec bv = bio_iovec(bio);
 
-	/* use a bio buffer long enough to hold the uncompressed data */
-	bio_for_each_segment(bv, bio, iter) {
-		int avail_len;
-		int length = bv.bv_len;
+		WARN_ON(size < comp_len);
+		addr = kmap(bv.bv_page);
+	} else
+		addr  = dm_icomp_kmalloc(comp_len, GFP_NOIO);
 
-		if (!just_use && bio_off >= length) {
-			bio_off -= length;
-			continue;
-		}
-		avail_len = just_use ? length : length-bio_off;
-		if (avail_len >= io->decomp_req_len) {
-			io->decomp_real_data = kmap(bv.bv_page);
-			io->decomp_data = io->decomp_real_data + bio_off;
-			io->decomp_len = io->decomp_req_len = avail_len;
-			io->decomp_kmap = true;
-			return 0;
-		}
-		just_use = true;
+	if (!addr) {
+		kmem_cache_free(dm_icomp_io_range_cachep, io);
+		return NULL;
 	}
+	io->comp_data = io->io_req.mem.ptr.addr = addr;
+	io->comp_len = comp_len;
+	io->comp_kmap = (segments == 1);
+	/* note down the requested length for decompress buffer.
+	 * but dont allocate it yet.
+	 /
+	io->decomp_req_len = decomp_len;
+	return io;
+}
 
-	/* none available. :( Allocate one */
+static int dm_icomp_update_io_read_range(struct dm_icomp_io_range *io)
+{
 	io->decomp_data = dm_icomp_kmalloc(io->decomp_req_len, GFP_NOIO);
 	if (!io->decomp_data)
 		return 1;
 	io->decomp_real_data = io->decomp_data;
 	io->decomp_len = io->decomp_req_len;
 	io->decomp_kmap = false;
-
 	return 0;
 }
 
-static void dm_icomp_bio_copy(struct bio *bio, off_t bio_off, void *buf,
-		ssize_t len, bool to_buf)
-{
-	struct bio_vec bv;
-	struct bvec_iter iter;
-	off_t buf_off = 0;
-	ssize_t size;
-	void *addr;
-
-	WARN_ON(bio_off + len > (bio_sectors(bio) << 9));
-
-	bio_for_each_segment(bv, bio, iter) {
-		int length = bv.bv_len;
-
-		if (bio_off >= length) {
-			bio_off -= length;
-			continue;
-		}
-		addr = kmap_atomic(bv.bv_page);
-		size = min_t(ssize_t, len, length - bio_off);
-		if (to_buf)
-			memcpy(buf + buf_off, addr + bio_off + bv.bv_offset,
-				size);
-		else
-			memcpy(addr + bio_off + bv.bv_offset, buf + buf_off,
-				size);
-		kunmap_atomic(addr);
-		bio_off = 0;
-		buf_off += size;
-		len -= size;
-	}
-}
-
 static int dm_icomp_mod_to_max_io_range(struct dm_icomp_info *info,
 			 struct dm_icomp_io_range *io)
 {
@@ -1030,13 +1015,26 @@ static int dm_icomp_mod_to_max_io_range(struct dm_icomp_info *info,
 static struct dm_icomp_io_range *dm_icomp_create_io_write_range(
 		struct dm_icomp_req *req)
 {
-	struct dm_icomp_io_range *io;
 	struct bio *bio = req->bio;
 	sector_t size  = bio_sectors(req->bio)<<9;
 	int segments = bio_segments(bio);
 	int comp_len = dm_icomp_compressor_len(req->info, size);
 	void *addr;
+	struct dm_icomp_io_range *io = dm_icomp_create_io_range(req);
+
+	if (!io)
+		return NULL;
+
+	addr = dm_icomp_kmalloc(comp_len, GFP_NOIO);
+	if (!addr) {
+		kmem_cache_free(dm_icomp_io_range_cachep, io);
+		return NULL;
+	}
+	io->comp_data = io->io_req.mem.ptr.addr = addr;
+	io->comp_len = comp_len;
+	io->comp_kmap = false;
 
+	/* try reusing the bio buffer for decomp data. */
 	if (segments == 1) {
 		struct bio_vec bv = bio_iovec(bio);
 
@@ -1044,21 +1042,18 @@ static struct dm_icomp_io_range *dm_icomp_create_io_write_range(
 	} else
 		addr  = dm_icomp_kmalloc(size, GFP_NOIO);
 
-	if (!addr)
-		return NULL;
-
-	io = dm_icomp_create_io_range(req, comp_len);
-	if (!io) {
-		(segments == 1) ?  kunmap(addr) : dm_icomp_kfree(addr, size);
+	if (!addr) {
+		dm_icomp_kfree(io->comp_data, comp_len);
+		kmem_cache_free(dm_icomp_io_range_cachep, io);
 		return NULL;
 	}
-
 	io->decomp_data = io->decomp_real_data = addr;
 	io->decomp_len = size;
 
 	io->decomp_kmap = (segments == 1);
 	if (!io->decomp_kmap)
 		dm_icomp_bio_copy(req->bio, 0, io->decomp_data, size, true);
+
 	return io;
 }
 
@@ -1176,7 +1171,7 @@ static void dm_icomp_handle_read_decomp(struct dm_icomp_req *req)
 			src_off = (req->bio->bi_iter.bi_sector -
 				io->io_region.sector) << 9;
 
-		if (dm_icomp_update_io_read_range(io, req->bio, dst_off)) {
+		if (dm_icomp_update_io_read_range(io)) {
 			req->result = -EIO;
 			return;
 		}
diff --git a/drivers/md/dm-inplace-compress.h b/drivers/md/dm-inplace-compress.h
index e144e96..775ccbf 100644
--- a/drivers/md/dm-inplace-compress.h
+++ b/drivers/md/dm-inplace-compress.h
@@ -120,6 +120,7 @@ struct dm_icomp_io_range {
 	void *decomp_real_data; /* holds the actual start of the buffer */
 	unsigned int decomp_req_len;/* originally requested length */
 	unsigned int decomp_len; /* actual allocated/mapped length */
+	int comp_kmap;          /* Is the comp_data kmapped'? */
 	void *comp_data;
 	unsigned int comp_len; /* For write, this is estimated */
 	struct list_head next;
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463026 — [RFC PATCH 13/16] DM: macros to set and get the state of the request.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 13/16] DM: macros to set and get the state of the request.
Message-ID<s6u1I-59-41@gated-at.bofh.it>
In reply to#1463017
Consolidate code to set and get the state of a request.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |   31 +++++++++++++++++--------------
 1 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index b1c3e5f..55a515b 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -44,6 +44,9 @@ static struct kernel_param_ops dm_icomp_compressor_param_ops = {
 module_param_cb(compress_algorithm, &dm_icomp_compressor_param_ops,
 		&dm_icomp_compressor_kparam, 0644);
 
+#define SET_REQ_STAGE(req, value) (req->stage = value)
+#define GET_REQ_STAGE(req) req->stage
+
 static int dm_icomp_get_compressor(const char *s)
 {
 	int r, val_len;
@@ -835,15 +838,15 @@ static void dm_icomp_put_req(struct dm_icomp_req *req)
 	if (atomic_dec_return(&req->io_pending))
 		return;
 
-	if (req->stage == STAGE_INIT) /* waiting for locking */
+	if (GET_REQ_STAGE(req) == STAGE_INIT) /* waiting for locking */
 		return;
 
-	if (req->stage == STAGE_READ_DECOMP ||
-	    req->stage == STAGE_WRITE_COMP ||
+	if (GET_REQ_STAGE(req) == STAGE_READ_DECOMP ||
+	    GET_REQ_STAGE(req) == STAGE_WRITE_COMP ||
 	    req->result)
-		req->stage = STAGE_DONE;
+		SET_REQ_STAGE(req, STAGE_DONE);
 
-	if (req->stage != STAGE_DONE) {
+	if (GET_REQ_STAGE(req) != STAGE_DONE) {
 		dm_icomp_queue_req(req->info, req);
 		return;
 	}
@@ -1153,7 +1156,7 @@ static void dm_icomp_handle_read_decomp(struct dm_icomp_req *req)
 	off_t bio_off = 0;
 	int ret;
 
-	req->stage = STAGE_READ_DECOMP;
+	SET_REQ_STAGE(req, STAGE_READ_DECOMP);
 
 	if (req->result)
 		return;
@@ -1250,7 +1253,7 @@ static void dm_icomp_handle_read_read_existing(struct dm_icomp_req *req)
 	u64 block_index, first_block_index;
 	u16 logical_sectors, data_sectors;
 
-	req->stage = STAGE_READ_EXISTING;
+	SET_REQ_STAGE(req, STAGE_READ_EXISTING);
 
 	block_index = dm_icomp_sector_to_block(req->bio->bi_iter.bi_sector);
 again:
@@ -1279,14 +1282,14 @@ static void dm_icomp_handle_read_request(struct dm_icomp_req *req)
 {
 	dm_icomp_get_req(req);
 
-	if (req->stage == STAGE_INIT) {
+	if (GET_REQ_STAGE(req) == STAGE_INIT) {
 		if (!dm_icomp_lock_req_range(req)) {
 			dm_icomp_put_req(req);
 			return;
 		}
 
 		dm_icomp_handle_read_read_existing(req);
-	} else if (req->stage == STAGE_READ_EXISTING)
+	} else if (GET_REQ_STAGE(req) == STAGE_READ_EXISTING)
 		dm_icomp_handle_read_decomp(req);
 
 	dm_icomp_put_req(req);
@@ -1411,7 +1414,7 @@ static void dm_icomp_handle_write_comp(struct dm_icomp_req *req)
 	int ret;
 	bool handle_bio = true;
 
-	req->stage = STAGE_WRITE_COMP;
+	SET_REQ_STAGE(req, STAGE_WRITE_COMP);
 
 	if (req->result)
 		return;
@@ -1486,7 +1489,7 @@ static void dm_icomp_handle_write_read_existing(struct dm_icomp_req *req)
 	u64 block_index, first_block_index;
 	u16 logical_sectors, data_sectors;
 
-	req->stage = STAGE_READ_EXISTING;
+	SET_REQ_STAGE(req, STAGE_READ_EXISTING);
 
 	block_index = dm_icomp_sector_to_block(req->bio->bi_iter.bi_sector);
 	dm_icomp_get_extent(req->info, block_index, &first_block_index,
@@ -1524,14 +1527,14 @@ static void dm_icomp_handle_write_request(struct dm_icomp_req *req)
 {
 	dm_icomp_get_req(req);
 
-	if (req->stage == STAGE_INIT) {
+	if (GET_REQ_STAGE(req) == STAGE_INIT) {
 		if (!dm_icomp_lock_req_range(req)) {
 			dm_icomp_put_req(req);
 			return;
 		}
 
 		dm_icomp_handle_write_read_existing(req);
-	} else if (req->stage == STAGE_READ_EXISTING)
+	} else if (GET_REQ_STAGE(req) == STAGE_READ_EXISTING)
 		dm_icomp_handle_write_comp(req);
 
 	dm_icomp_put_req(req);
@@ -1611,7 +1614,7 @@ static int dm_icomp_map(struct dm_target *ti, struct bio *bio)
 	atomic_set(&req->io_pending, 0);
 	INIT_LIST_HEAD(&req->all_io);
 	req->result = 0;
-	req->stage = STAGE_INIT;
+	SET_REQ_STAGE(req, STAGE_INIT);
 	req->locked_locks = 0;
 
 	req->cpu = raw_smp_processor_id();
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463027 — [RFC PATCH 03/16] DM: Error if enough space is not available.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 03/16] DM: Error if enough space is not available.
Message-ID<s6u1I-59-49@gated-at.bofh.it>
In reply to#1463017
if enough space is not available to create a block of the specified size error
out.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index 70d6c0e..17221a1 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -453,6 +453,12 @@ static int dm_icomp_read_or_create_super(struct dm_icomp_info *info)
 	info->data_blocks = data_blocks;
 	info->data_start = (1 + meta_blocks) << DMCP_BLOCK_SECTOR_SHIFT;
 
+	if ((data_blocks << DMCP_BLOCK_SECTOR_SHIFT) < info->ti->len) {
+		info->ti->error =
+			"Insufficient sectors to satisfy requested size";
+		return -ENOMEM;
+	}
+
 	addr = kzalloc(DMCP_BLOCK_SIZE, GFP_KERNEL);
 	if (!addr) {
 		info->ti->error = "Cannot allocate super";
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463028 — [RFC PATCH 16/16] DM: add documentation for dm-inplace-compress.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 16/16] DM: add documentation for dm-inplace-compress.
Message-ID<s6u1I-59-43@gated-at.bofh.it>
In reply to#1463017
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 .../device-mapper/dm-inplace-compress.text         |  138 ++++++++++++++++++++
 1 files changed, 138 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/device-mapper/dm-inplace-compress.text

diff --git a/Documentation/device-mapper/dm-inplace-compress.text b/Documentation/device-mapper/dm-inplace-compress.text
new file mode 100644
index 0000000..c31e69e
--- /dev/null
+++ b/Documentation/device-mapper/dm-inplace-compress.text
@@ -0,0 +1,138 @@
+dm-inplace-compress
+====================
+
+Device-Mapper's "inplace-compress" target provides inplace compression of block
+devices using the kernel compression API.
+
+Parameters: <device path> \
+	[ <#opt_params writethough> ]
+	[ <#opt_params <writeback> <meta_commit_delay> ]
+	[ <#opt_params compressor> <type> ]
+
+
+<writethrough>
+    Write data and metadata together.
+
+<writeback> <meta_commit_delay>
+    Write metadata every 'meta_commit_delay' interval.
+
+<device path>
+    This is the device that is going to be used as backend and contains the
+    compressed data.  You can specify it as a path like /dev/xxx or a device
+    number <major>:<minor>.
+
+<compressor> <type>
+    Choose the compressor algorithm. 'lzo' and '842'
+    compressors are supported.
+
+Example scripts
+===============
+
+create a inplace-compress block device using lzo compression. Write metadata
+and data together.
+[[
+#!/bin/sh
+# Create a inplace-compress device using dmsetup
+dmsetup create comp1 --table "0 `blockdev --getsize $1` inplacecompress $1
+		writethrough compressor lzo"
+]]
+
+
+create a inplace-compress block device using nx-842 hardware compression. Write
+metadata periodially every 5sec.
+
+[[
+#!/bin/sh
+# Create a inplace-compress device using dmsetup
+dmsetup create comp1 --table "0 `blockdev --getsize $1` inplacecompress $1
+		writeback 5 compressor 842"
+]]
+
+Description
+===========
+    This is a simple DM target supporting inplace compression. Its best suited for
+    SSD. The underlying disk must support 512B sector size, the target only
+    supports 4k sector size.
+
+    Disk layout:
+    |super|...meta...|..data...|
+
+    Store unit is 4k (a block). Super is 1 block, which stores meta and data
+    size and compression algorithm. Meta is a bitmap. For each data block,
+    there are 5 bits meta.
+
+    Data:
+
+    Data of a block is compressed. Compressed data is round up to 512B, which
+    is the payload. In disk, payload is stored at the beginning of logical
+    sector of the block. Let's look at an example. Say we store data to block
+    A, which is in sector B(A*8), its orginal size is 4k, compressed size is
+    1500. Compressed data (CD) will use 3 sectors (512B). The 3 sectors are the
+    payload. Payload will be stored at sector B.
+
+    ---------------------------------------------------
+    ... | CD1 | CD2 | CD3 |   |   |   |   |    | ...
+    ---------------------------------------------------
+        ^B    ^B+1  ^B+2                  ^B+7 ^B+8
+
+    For this block, we will not use sector B+3 to B+7 (a hole). We use 4 meta
+    bits to present payload size. The compressed size (1500) isn't stored in
+    meta directly. Instead, we store it at the last 32bits of payload. In this
+    example, we store it at the end of sector B+2. If compressed size +
+    sizeof(32bits) crosses a sector, payload size will increase one sector. If
+    payload uses 8 sectors, we store uncompressed data directly.
+
+    If IO size is bigger than one block, we can store the data as an extent.
+    Data of the whole extent will compressed and stored in the similar way like
+    above.  The first block of the extent is the head, all others are the tail.
+    If extent is 1 block, the block is head. We have 1 bit of meta to present
+    if a block is head or tail. If 4 meta bits of head block can't store extent
+    payload size, we will borrow tail block meta bits to store payload size.
+    Max allowd extent size is 128k, so we don't compress/decompress too big
+    size data.
+
+    Meta:
+    Modifying data will modify meta too. Meta will be written(flush) to disk
+    depending on meta write policy. We support writeback and writethrough mode.
+    In writeback mode, meta will be written to disk in an interval or a FLUSH
+    request.  In writethrough mode, data and meta data will be written to disk
+    together.
+
+    Advantages:
+
+    1. Simple. Since we store compressed data in-place, we don't need complicated
+    disk data management.
+    2. Efficient. For each 4k, we only need 5 bits meta. 1T data will use less than
+    200M meta, so we can load all meta into memory. And actual compression size is
+    in payload. So if IO doesn't need RMW and we use writeback meta flush, we don't
+    need extra IO for meta.
+
+    Disadvantages:
+
+    1. hole. Since we store compressed data in-place, there are a lot of holes
+    (in above example, B+3 - B+7) Hole can impact IO, because we can't do IO
+    merge.
+
+    2. 1:1 size. Compression doesn't change disk size. If disk is 1T, we can
+    only store 1T data even we do compression.
+
+    But this is for SSD only. Generally SSD firmware has a FTL layer to map
+    disk sectors to flash nand. High end SSD firmware has filesystem-like FTL.
+
+    1. hole. Disk has a lot of holes, but SSD FTL can still store data continuous
+    in nand. Even if we can't do IO merge in OS layer, SSD firmware can do it.
+
+    2. 1:1 size. On one side, we write compressed data to SSD, which means less
+    data is written to SSD. This will be very helpful to improve SSD garbage
+    collection, and so write speed and life cycle. So even this is a problem, the
+    target is still helpful. On the other side, advanced SSD FTL can easily do thin
+    provision. For example, if nand is 1T and we let SSD report it as 2T, and use
+    the SSD as compressed target. In such SSD, we don't have the 1:1 size issue.
+
+    So even if SSD FTL cannot map non-continuous disk sectors to continuous nand,
+    the compression target can still function well.
+
+
+Author:
+    Shaohua Li <shli@fusionio.com>
+    Ram Pai <ram.n.pai@gmail.com>
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463029 — [RFC PATCH 09/16] DM: Delay allocation of decompression buffer during read.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:40 +0200
Subject[RFC PATCH 09/16] DM: Delay allocation of decompression buffer during read.
Message-ID<s6u1I-59-51@gated-at.bofh.it>
In reply to#1463017
The read path allocates a temporary buffer each to hold compressed data and
decompressed data. The buffer to hold the decompressed data is not needed till
the compressed data is read from the device and is uncompressed.

Hence delay the allocation of decompress buffer till it is really needed.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |   76 +++++++++++++++++++++++++++++++++-----
 drivers/md/dm-inplace-compress.h |    3 +-
 2 files changed, 68 insertions(+), 11 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index 04decdd..c56d9b7 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -863,7 +863,7 @@ static inline int dm_icomp_compressor_maxlen(struct dm_icomp_info *info,
  * comp_data
  */
 static struct dm_icomp_io_range *dm_icomp_create_io_range(
-	struct dm_icomp_req *req, int comp_len, int decomp_len)
+		struct dm_icomp_req *req, int comp_len)
 {
 	struct dm_icomp_io_range *io;
 
@@ -871,12 +871,8 @@ static struct dm_icomp_io_range *dm_icomp_create_io_range(
 	if (!io)
 		return NULL;
 
-	io->comp_data = dm_icomp_kmalloc(
-		dm_icomp_compressor_len(req->info, comp_len), GFP_NOIO);
-	io->decomp_data = dm_icomp_kmalloc(decomp_len, GFP_NOIO);
-	if (!io->decomp_data || !io->comp_data) {
-		dm_icomp_kfree(io->decomp_data, io->decomp_len);
-		dm_icomp_kfree(io->comp_data, io->comp_len);
+	io->comp_data = dm_icomp_kmalloc(comp_len, GFP_NOIO);
+	if (!io->comp_data) {
 		kmem_cache_free(dm_icomp_io_range_cachep, io);
 		return NULL;
 	}
@@ -890,12 +886,42 @@ static struct dm_icomp_io_range *dm_icomp_create_io_range(
 
 	io->io_region.bdev = req->info->dev->bdev;
 
-	io->decomp_len = decomp_len;
 	io->comp_len = comp_len;
 	io->req = req;
+
+	io->decomp_data = NULL;
+	io->decomp_len = 0;
+	io->decomp_req_len = 0;
 	return io;
 }
 
+static struct dm_icomp_io_range *dm_icomp_create_io_read_range(
+		struct dm_icomp_req *req, int comp_len, int decomp_len)
+{
+	struct dm_icomp_io_range *io = dm_icomp_create_io_range(req, comp_len);
+
+	if (io) {
+		/* note down the requested length for decompress buffer.
+		 * but dont allocate it yet.
+		 */
+		io->decomp_req_len = decomp_len;
+	}
+	return io;
+}
+
+static int dm_icomp_update_io_read_range(struct dm_icomp_io_range *io)
+{
+	if (io->decomp_len)
+		return 0;
+
+	io->decomp_data = dm_icomp_kmalloc(io->decomp_req_len, GFP_NOIO);
+	if (!io->decomp_data)
+		return 1;
+	io->decomp_len = io->decomp_req_len;
+
+	return 0;
+}
+
 static void dm_icomp_bio_copy(struct bio *bio, off_t bio_off, void *buf,
 		ssize_t len, bool to_buf)
 {
@@ -948,6 +974,31 @@ static int dm_icomp_mod_to_max_io_range(struct dm_icomp_info *info,
 	return 0;
 }
 
+static struct dm_icomp_io_range *dm_icomp_create_io_write_range(
+		struct dm_icomp_req *req)
+{
+	struct dm_icomp_io_range *io;
+	sector_t size  = bio_sectors(req->bio)<<9;
+	int comp_len = dm_icomp_compressor_len(req->info, size);
+	void *addr;
+
+	addr  = dm_icomp_kmalloc(size, GFP_NOIO);
+	if (!addr)
+		return NULL;
+
+	io = dm_icomp_create_io_range(req, comp_len);
+	if (!io) {
+		dm_icomp_kfree(addr, size);
+		return NULL;
+	}
+
+	io->decomp_data = addr;
+	io->decomp_len = size;
+
+	dm_icomp_bio_copy(req->bio, 0, io->decomp_data, size, true);
+	return io;
+}
+
 /*
  * return value:
  * < 0 : error
@@ -1054,6 +1105,11 @@ static void dm_icomp_handle_read_decomp(struct dm_icomp_req *req)
 
 		io->io_region.sector -= req->info->data_start;
 
+		if (dm_icomp_update_io_read_range(io)) {
+			req->result = -EIO;
+			return;
+		}
+
 		/* Do decomp here */
 		ret = dm_icomp_io_range_decompress(req->info, io->comp_data,
 			io->comp_len, io->decomp_data, io->decomp_len);
@@ -1110,7 +1166,7 @@ static void dm_icomp_read_one_extent(struct dm_icomp_req *req, u64 block,
 		return;
 	}
 
-	io = dm_icomp_create_io_range(req, data_sectors << 9,
+	io = dm_icomp_create_io_read_range(req, data_sectors << 9,
 		logical_sectors << 9);
 	if (!io) {
 		req->result = -EIO;
@@ -1313,7 +1369,7 @@ static void dm_icomp_handle_write_comp(struct dm_icomp_req *req)
 		goto update_meta;
 
 	count = bio_sectors(req->bio);
-	io = dm_icomp_create_io_range(req, count << 9, count << 9);
+	io = dm_icomp_create_io_write_range(req);
 	if (!io) {
 		req->result = -EIO;
 		return;
diff --git a/drivers/md/dm-inplace-compress.h b/drivers/md/dm-inplace-compress.h
index 1ce7a6e..d9cf05a 100644
--- a/drivers/md/dm-inplace-compress.h
+++ b/drivers/md/dm-inplace-compress.h
@@ -116,7 +116,8 @@ struct dm_icomp_io_range {
 	struct dm_io_request io_req;
 	struct dm_io_region io_region;
 	void *decomp_data;
-	unsigned int decomp_len;
+	unsigned int decomp_req_len;/* originally requested length */
+	unsigned int decomp_len; /* actual allocated/mapped length */
 	void *comp_data;
 	unsigned int comp_len; /* For write, this is estimated */
 	struct list_head next;
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463030 — [RFC PATCH 04/16] DM: Ensure that the read request is within the device range.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:50 +0200
Subject[RFC PATCH 04/16] DM: Ensure that the read request is within the device range.
Message-ID<s6ubn-9z-3@gated-at.bofh.it>
In reply to#1463017
If a read request is not within the device range return error.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index 17221a1..bf18028 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -1025,6 +1025,12 @@ static void dm_icomp_read_one_extent(struct dm_icomp_req *req, u64 block,
 {
 	struct dm_icomp_io_range *io;
 
+	if (block+(data_sectors>>DMCP_BLOCK_SECTOR_SHIFT) >=
+			req->info->data_blocks) {
+		req->result = -EIO;
+		return;
+	}
+
 	io = dm_icomp_create_io_range(req, data_sectors << 9,
 		logical_sectors << 9);
 	if (!io) {
@@ -1063,7 +1069,9 @@ again:
 
 	block_index = first_block_index + (logical_sectors >>
 				DMCP_BLOCK_SECTOR_SHIFT);
-	if ((block_index << DMCP_BLOCK_SECTOR_SHIFT) < bio_end_sector(req->bio))
+	if (((block_index << DMCP_BLOCK_SECTOR_SHIFT) <
+			 bio_end_sector(req->bio)) &&
+			((block_index) < req->info->data_blocks))
 		goto again;
 
 	/* A shortcut if all data is in already */
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463031 — [RFC PATCH 07/16] DM: Optimize memory allocated to hold compressed buffer.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:50 +0200
Subject[RFC PATCH 07/16] DM: Optimize memory allocated to hold compressed buffer.
Message-ID<s6ubn-9z-5@gated-at.bofh.it>
In reply to#1463017
On an average the compressed size is less than 50% of the original buffer.  Use
this knowledge to optimize the amount of space allocated to hold the compressed
buffer. If the allocated size is determined to be insufficient than reallocate
the required size.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |   39 ++++++++++++++++++++++++++++++++++++++
 drivers/md/dm-inplace-compress.h |   11 ++++++++++
 2 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index 5c39169..fe4a4c1 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -19,10 +19,12 @@ static struct dm_icomp_compressor_data compressors[] = {
 	[DMCP_COMP_ALG_LZO] = {
 		.name = "lzo",
 		.comp_len = lzo_comp_len,
+		.max_comp_len = lzo_max_comp_len,
 	},
 	[DMCP_COMP_ALG_842] = {
 		.name = "842",
 		.comp_len = nx842_comp_len,
+		.max_comp_len = nx842_max_comp_len,
 	},
 };
 static int default_compressor = -1;
@@ -848,6 +850,14 @@ static inline int dm_icomp_compressor_len(struct dm_icomp_info *info, int len)
 	return len;
 }
 
+static inline int dm_icomp_compressor_maxlen(struct dm_icomp_info *info,
+		int len)
+{
+	if (compressors[info->comp_alg].max_comp_len)
+		return compressors[info->comp_alg].max_comp_len(len);
+	return len;
+}
+
 /*
  * caller should set region.sector, region.count. bi_rw. IO always to/from
  * comp_data
@@ -919,6 +929,25 @@ static void dm_icomp_bio_copy(struct bio *bio, off_t bio_off, void *buf,
 	}
 }
 
+static int dm_icomp_mod_to_max_io_range(struct dm_icomp_info *info,
+			 struct dm_icomp_io_range *io)
+{
+	unsigned int maxlen = dm_icomp_compressor_maxlen(info, io->decomp_len);
+
+	if (maxlen <= io->comp_len)
+		return -ENOSPC;
+	io->io_req.mem.ptr.addr = io->comp_data =
+		dm_icomp_krealloc(io->comp_data, maxlen,
+			io->comp_len, GFP_NOIO);
+	if (!io->comp_data) {
+		DMWARN("UNFORTUNE allocation failure ");
+		io->comp_len = 0;
+		return -ENOSPC;
+	}
+	io->comp_len = maxlen;
+	return 0;
+}
+
 /*
  * return value:
  * < 0 : error
@@ -940,7 +969,17 @@ static int dm_icomp_io_range_compress(struct dm_icomp_info *info,
 	ret = crypto_comp_compress(tfm, decomp_data, decomp_len,
 		io->comp_data, &actual_comp_len);
 
+	if (ret || actual_comp_len > io->comp_len) {
+		ret = dm_icomp_mod_to_max_io_range(info, io);
+		if (!ret) {
+			actual_comp_len = io->comp_len;
+			ret = crypto_comp_compress(tfm, decomp_data, decomp_len,
+				io->comp_data, &actual_comp_len);
+		}
+	}
+
 	put_cpu();
+
 	if (ret < 0)
 		DMWARN("CO Error %d ", ret);
 
diff --git a/drivers/md/dm-inplace-compress.h b/drivers/md/dm-inplace-compress.h
index b61ff0d..86c0ce6 100644
--- a/drivers/md/dm-inplace-compress.h
+++ b/drivers/md/dm-inplace-compress.h
@@ -17,15 +17,26 @@ struct dm_icomp_super_block {
 struct dm_icomp_compressor_data {
 	char *name;
 	int (*comp_len)(int comp_len);
+	int (*max_comp_len)(int comp_len);
 };
 
 static inline int lzo_comp_len(int comp_len)
 {
+	return lzo1x_worst_compress(comp_len) >> 1;
+}
+
+static inline int lzo_max_comp_len(int comp_len)
+{
 	return lzo1x_worst_compress(comp_len);
 }
 
 static inline int nx842_comp_len(int comp_len)
 {
+	return (comp_len>>4)*7; /* less than half: 7/16 */
+}
+
+static inline int nx842_max_comp_len(int comp_len)
+{
 	return comp_len;
 }
 
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463035 — [RFC PATCH 10/16] DM: Try to use the bio buffer for decompression instead of allocating one.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:50 +0200
Subject[RFC PATCH 10/16] DM: Try to use the bio buffer for decompression instead of allocating one.
Message-ID<s6ubn-9z-17@gated-at.bofh.it>
In reply to#1463017
The read path allocates a temporary buffer to hold decompressed data, which is
than copied into the caller's bio buffer.

Instead of allocating a temporary buffer to hold the decompressed data,
decompress the data in the caller's bio buffer. This can be done only if the
destination in the bio-buffer is contigious within the same bio-segment.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |  143 ++++++++++++++++++++++++++-----------
 drivers/md/dm-inplace-compress.h |    2 +
 2 files changed, 102 insertions(+), 43 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index c56d9b7..f6b95e3 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -792,11 +792,34 @@ static void dm_icomp_kfree(void *addr, unsigned int size)
 	kfree(addr);
 }
 
+static void dm_icomp_release_decomp_buffer(struct dm_icomp_io_range *io)
+{
+	if (!io->decomp_data)
+		return;
 
-static void dm_icomp_free_io_range(struct dm_icomp_io_range *io)
+	if (io->decomp_kmap)
+		kunmap(io->decomp_real_data);
+	else
+		dm_icomp_kfree(io->decomp_real_data, io->decomp_req_len);
+	io->decomp_data = io->decomp_real_data = NULL;
+	io->decomp_len  = 0;
+	io->decomp_kmap = false;
+}
+
+static void dm_icomp_release_comp_buffer(struct dm_icomp_io_range *io)
 {
-	dm_icomp_kfree(io->decomp_data, io->decomp_len);
+	if (!io->comp_data)
+		return;
 	dm_icomp_kfree(io->comp_data, io->comp_len);
+
+	io->comp_data = NULL;
+	io->comp_len = 0;
+}
+
+static void dm_icomp_free_io_range(struct dm_icomp_io_range *io)
+{
+	dm_icomp_release_decomp_buffer(io);
+	dm_icomp_release_comp_buffer(io);
 	kmem_cache_free(dm_icomp_io_range_cachep, io);
 }
 
@@ -890,7 +913,9 @@ static struct dm_icomp_io_range *dm_icomp_create_io_range(
 	io->req = req;
 
 	io->decomp_data = NULL;
+	io->decomp_real_data = NULL;
 	io->decomp_len = 0;
+	io->decomp_kmap = false;
 	io->decomp_req_len = 0;
 	return io;
 }
@@ -909,15 +934,43 @@ static struct dm_icomp_io_range *dm_icomp_create_io_read_range(
 	return io;
 }
 
-static int dm_icomp_update_io_read_range(struct dm_icomp_io_range *io)
+static int dm_icomp_update_io_read_range(struct dm_icomp_io_range *io,
+		struct bio *bio, ssize_t bio_off)
 {
+	struct bvec_iter iter;
+	struct bio_vec bv;
+	bool just_use = false;
+
 	if (io->decomp_len)
 		return 0;
 
+	/* use a bio buffer long enough to hold the uncompressed data */
+	bio_for_each_segment(bv, bio, iter) {
+		int avail_len;
+		int length = bv.bv_len;
+
+		if (!just_use && bio_off >= length) {
+			bio_off -= length;
+			continue;
+		}
+		avail_len = just_use ? length : length-bio_off;
+		if (avail_len >= io->decomp_req_len) {
+			io->decomp_real_data = kmap(bv.bv_page);
+			io->decomp_data = io->decomp_real_data + bio_off;
+			io->decomp_len = io->decomp_req_len = avail_len;
+			io->decomp_kmap = true;
+			return 0;
+		}
+		just_use = true;
+	}
+
+	/* none available. :( Allocate one */
 	io->decomp_data = dm_icomp_kmalloc(io->decomp_req_len, GFP_NOIO);
 	if (!io->decomp_data)
 		return 1;
+	io->decomp_real_data = io->decomp_data;
 	io->decomp_len = io->decomp_req_len;
+	io->decomp_kmap = false;
 
 	return 0;
 }
@@ -978,24 +1031,34 @@ static struct dm_icomp_io_range *dm_icomp_create_io_write_range(
 		struct dm_icomp_req *req)
 {
 	struct dm_icomp_io_range *io;
+	struct bio *bio = req->bio;
 	sector_t size  = bio_sectors(req->bio)<<9;
+	int segments = bio_segments(bio);
 	int comp_len = dm_icomp_compressor_len(req->info, size);
 	void *addr;
 
-	addr  = dm_icomp_kmalloc(size, GFP_NOIO);
+	if (segments == 1) {
+		struct bio_vec bv = bio_iovec(bio);
+
+		addr = kmap(bv.bv_page);
+	} else
+		addr  = dm_icomp_kmalloc(size, GFP_NOIO);
+
 	if (!addr)
 		return NULL;
 
 	io = dm_icomp_create_io_range(req, comp_len);
 	if (!io) {
-		dm_icomp_kfree(addr, size);
+		(segments == 1) ?  kunmap(addr) : dm_icomp_kfree(addr, size);
 		return NULL;
 	}
 
-	io->decomp_data = addr;
+	io->decomp_data = io->decomp_real_data = addr;
 	io->decomp_len = size;
 
-	dm_icomp_bio_copy(req->bio, 0, io->decomp_data, size, true);
+	io->decomp_kmap = (segments == 1);
+	if (!io->decomp_kmap)
+		dm_icomp_bio_copy(req->bio, 0, io->decomp_data, size, true);
 	return io;
 }
 
@@ -1105,7 +1168,15 @@ static void dm_icomp_handle_read_decomp(struct dm_icomp_req *req)
 
 		io->io_region.sector -= req->info->data_start;
 
-		if (dm_icomp_update_io_read_range(io)) {
+		if (io->io_region.sector >=
+				req->bio->bi_iter.bi_sector)
+			dst_off = (io->io_region.sector -
+				req->bio->bi_iter.bi_sector) << 9;
+		else
+			src_off = (req->bio->bi_iter.bi_sector -
+				io->io_region.sector) << 9;
+
+		if (dm_icomp_update_io_read_range(io, req->bio, dst_off)) {
 			req->result = -EIO;
 			return;
 		}
@@ -1114,20 +1185,19 @@ static void dm_icomp_handle_read_decomp(struct dm_icomp_req *req)
 		ret = dm_icomp_io_range_decompress(req->info, io->comp_data,
 			io->comp_len, io->decomp_data, io->decomp_len);
 		if (ret < 0) {
+			dm_icomp_release_decomp_buffer(io);
+			dm_icomp_release_comp_buffer(io);
 			req->result = -EIO;
 			return;
 		}
 
-		if (io->io_region.sector >= req->bio->bi_iter.bi_sector)
-			dst_off = (io->io_region.sector -
-				 req->bio->bi_iter.bi_sector) << 9;
-		else
-			src_off = (req->bio->bi_iter.bi_sector -
-				 io->io_region.sector) << 9;
-
 		len = min_t(ssize_t, io->decomp_len - src_off,
 			(bio_sectors(req->bio) << 9) - dst_off);
 
+		dm_icomp_bio_copy(req->bio, dst_off,
+		  ((ret == 1) ? io->comp_data : io->decomp_data) + src_off,
+		  len, false);
+
 		/* io range in all_io list is ordered for read IO */
 		while (bio_off != dst_off) {
 			ssize_t size = min_t(ssize_t, PAGE_SIZE,
@@ -1137,13 +1207,9 @@ static void dm_icomp_handle_read_decomp(struct dm_icomp_req *req)
 			bio_off += size;
 		}
 
-		if (ret == 1)
-			dm_icomp_bio_copy(req->bio, dst_off,
-					io->comp_data + src_off, len, false);
-		else
-			dm_icomp_bio_copy(req->bio, dst_off,
-					io->decomp_data + src_off, len, false);
 		bio_off = dst_off + len;
+		dm_icomp_release_decomp_buffer(io);
+		dm_icomp_release_comp_buffer(io);
 	}
 
 	while (bio_off != (bio_sectors(req->bio) << 9)) {
@@ -1270,29 +1336,20 @@ static int dm_icomp_handle_write_modify(struct dm_icomp_io_range *io,
 	if (start < req->bio->bi_iter.bi_sector && start + count >
 					bio_end_sector(req->bio)) {
 		/* we don't split an extent */
-		if (ret == 1) {
-			memcpy(io->decomp_data, io->comp_data, io->decomp_len);
-			dm_icomp_bio_copy(req->bio, 0,
-			   io->decomp_data +
-			   ((req->bio->bi_iter.bi_sector - start) << 9),
-			   bio_sectors(req->bio) << 9, true);
-		} else {
-			dm_icomp_bio_copy(req->bio, 0,
-			   io->decomp_data +
-			   ((req->bio->bi_iter.bi_sector - start) << 9),
-			   bio_sectors(req->bio) << 9, true);
-
-			dm_icomp_kfree(io->comp_data, io->comp_len);
-			/* New compressed len might be bigger */
-			io->comp_data = dm_icomp_kmalloc(
-				dm_icomp_compressor_len(
-				req->info, io->decomp_len), GFP_NOIO);
-			io->comp_len = io->decomp_len;
-			if (!io->comp_data) {
-				req->result = -ENOMEM;
-				return -EIO;
+		if (!io->decomp_kmap) {
+			if (ret == 1) {
+				memcpy(io->decomp_data, io->comp_data,
+					io->decomp_len);
+				dm_icomp_bio_copy(req->bio, 0,
+				   io->decomp_data +
+				   ((req->bio->bi_iter.bi_sector - start) << 9),
+				   bio_sectors(req->bio) << 9, true);
+			} else {
+				dm_icomp_bio_copy(req->bio, 0,
+				   io->decomp_data +
+				   ((req->bio->bi_iter.bi_sector - start) << 9),
+				   bio_sectors(req->bio) << 9, true);
 			}
-			io->io_req.mem.ptr.addr = io->comp_data;
 		}
 		/* need compress data */
 		ret = 0;
diff --git a/drivers/md/dm-inplace-compress.h b/drivers/md/dm-inplace-compress.h
index d9cf05a..e144e96 100644
--- a/drivers/md/dm-inplace-compress.h
+++ b/drivers/md/dm-inplace-compress.h
@@ -115,7 +115,9 @@ struct dm_icomp_meta_io {
 struct dm_icomp_io_range {
 	struct dm_io_request io_req;
 	struct dm_io_region io_region;
+	int decomp_kmap;	/* Is the decomp_data kmapped'? */
 	void *decomp_data;
+	void *decomp_real_data; /* holds the actual start of the buffer */
 	unsigned int decomp_req_len;/* originally requested length */
 	unsigned int decomp_len; /* actual allocated/mapped length */
 	void *comp_data;
-- 
1.7.1

[toc] | [prev] | [next] | [standalone]


#1463038 — [RFC PATCH 05/16] DM: allocation/free helper routines.

FromRam Pai <linuxram@us.ibm.com>
Date2016-08-15 19:50 +0200
Subject[RFC PATCH 05/16] DM: allocation/free helper routines.
Message-ID<s6ubo-9z-25@gated-at.bofh.it>
In reply to#1463017
Helper functions to allocate/reallocate and free memory.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
 drivers/md/dm-inplace-compress.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/drivers/md/dm-inplace-compress.c b/drivers/md/dm-inplace-compress.c
index bf18028..c11567c 100644
--- a/drivers/md/dm-inplace-compress.c
+++ b/drivers/md/dm-inplace-compress.c
@@ -774,6 +774,23 @@ static void dm_icomp_get_req(struct dm_icomp_req *req)
 	atomic_inc(&req->io_pending);
 }
 
+static void *dm_icomp_kmalloc(size_t size, gfp_t flags)
+{
+	return  kmalloc(size, flags);
+}
+
+static void *dm_icomp_krealloc(void *addr, size_t size,
+		 size_t orig_size, gfp_t flags)
+{
+	return krealloc(addr, size, flags);
+}
+
+static void dm_icomp_kfree(void *addr, unsigned int size)
+{
+	kfree(addr);
+}
+
+
 static void dm_icomp_free_io_range(struct dm_icomp_io_range *io)
 {
 	kfree(io->decomp_data);
-- 
1.7.1

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web