[rh7,12/12] ploop: Online discard support for dio engine

Submitted by Kirill Tkhai on March 1, 2019, 3:14 p.m.

Details

Message ID 155145326626.8852.7931670353490707829.stgit@localhost.localdomain
State New
Series "ploop: Add online discard support for dio engine"
Headers show

Commit Message

Kirill Tkhai March 1, 2019, 3:14 p.m.
Send FALLOC_FL_PUNCH_HOLE on discard and 0 (i.e., alloc)
on reusing of freed block range. Use dio engine extents
tracking to differ allocated blocks from discarded.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 drivers/block/ploop/io_direct.c     |   41 ++++++++++++++++++---
 drivers/block/ploop/io_direct_map.c |   67 ++++++++++++++++++++++++++++++++---
 2 files changed, 96 insertions(+), 12 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/block/ploop/io_direct.c b/drivers/block/ploop/io_direct.c
index 18563eaa4f1a..21cfdeb7441b 100644
--- a/drivers/block/ploop/io_direct.c
+++ b/drivers/block/ploop/io_direct.c
@@ -84,6 +84,29 @@  static int cached_submit(struct ploop_io *io, iblock_t iblk,
 	      struct ploop_request * preq,
 	      struct bio_list * sbl, unsigned int size, bool use_prealloc);
 
+static int dio_discard(struct ploop_io *io, struct ploop_request *preq, sector_t sec)
+{
+	struct ploop_device *plo = io->plo;
+	struct file *file = io->files.file;
+	int err;
+
+	if (!dio_may_fallocate(io)) {
+		preq->eng_state = PLOOP_E_COMPLETE;
+		preq->error = -EOPNOTSUPP;
+		return 0;
+	}
+
+	if (io->files.em_tree)
+		trim_extent_mappings(plo, io->files.em_tree,
+				     sec, cluster_size_in_sec(plo));
+
+	err = file->f_op->fallocate(file,
+				    FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE,
+				    sec << 9,
+				    cluster_size_in_bytes(plo));
+	return err;
+}
+
 static void
 dio_submit(struct ploop_io *io, struct ploop_request *preq,
 	   unsigned long rw,
@@ -124,6 +147,17 @@  dio_submit(struct ploop_io *io, struct ploop_request *preq,
 	sec = sbl->head->bi_sector;
 	sec = ((sector_t)iblk << plo->cluster_log) | (sec & ((1<<plo->cluster_log) - 1));
 
+	ploop_prepare_io_request(preq);
+	if (rw & REQ_WRITE)
+		ploop_prepare_tracker(preq, sec);
+
+	if (rw & REQ_DISCARD) {
+		err = dio_discard(io, preq, sec);
+		if (err < 0)
+			goto out;
+		goto complete;
+	}
+
 	em = extent_lookup_create(io, sec, size);
 	if (IS_ERR(em))
 		goto out_em_err;
@@ -150,10 +184,6 @@  dio_submit(struct ploop_io *io, struct ploop_request *preq,
 		goto write_unint;
 	}
 
-	ploop_prepare_io_request(preq);
-	if (rw & REQ_WRITE)
-		ploop_prepare_tracker(preq, sec);
-
 	bw.cur = sbl->head;
 	bw.idx = 0;
 	bw.bv_off = 0;
@@ -240,7 +270,7 @@  dio_submit(struct ploop_io *io, struct ploop_request *preq,
 		ploop_acc_ff_out(plo, rw2 | b->bi_rw);
 		submit_bio(rw2, b);
 	}
-
+complete:
 	ploop_complete_io_request(preq);
 	return;
 
@@ -1000,7 +1030,6 @@  dio_init(struct ploop_io * io)
 	init_timer(&io->fsync_timer);
 	io->fsync_timer.function = fsync_timeout;
 	io->fsync_timer.data = (unsigned long)io;
-	set_bit(PLOOP_S_NO_FALLOC_DISCARD, &io->plo->state);
 
 	return 0;
 }
diff --git a/drivers/block/ploop/io_direct_map.c b/drivers/block/ploop/io_direct_map.c
index 9afd0610e708..bc65e60e72a3 100644
--- a/drivers/block/ploop/io_direct_map.c
+++ b/drivers/block/ploop/io_direct_map.c
@@ -13,6 +13,7 @@ 
 #include <linux/version.h>
 #include <linux/buffer_head.h>
 #include <linux/interrupt.h>
+#include <linux/falloc.h>
 #include <linux/slab.h>
 
 #include <linux/ploop/ploop_if.h>
@@ -570,6 +571,59 @@  static int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map
 	return ret;
 }
 
+static int fallocate_cluster(struct ploop_io *io, struct inode *inode,
+			     loff_t start_off, loff_t len, bool align)
+{
+	struct ploop_device *plo = io->plo;
+	struct file *file = io->files.file;
+	unsigned int clu_sz = cluster_size_in_bytes(plo);
+	struct fiemap_extent_info fieinfo;
+	struct fiemap_extent fi_extent;
+	loff_t start_clu = round_down(start_off, clu_sz);
+	int ret;
+
+	if (start_clu + clu_sz >= i_size_read(inode))
+		return -EINVAL;
+
+	if (test_bit(PLOOP_S_NO_FALLOC_DISCARD, &plo->state)) {
+		pr_err("a hole in image file detected (i_size=%llu off=%llu)",
+		       i_size_read(inode), start_off);
+		return -EINVAL;
+	}
+
+	fieinfo.fi_extents_start = &fi_extent;
+	fieinfo.fi_extents_max = 1;
+	fieinfo.fi_flags = 0;
+	fieinfo.fi_extents_mapped = 0;
+	fi_extent.fe_flags = 0;
+
+	if (!align)
+		goto not_align;
+
+	ret = inode->i_op->fiemap(inode, &fieinfo, start_clu, clu_sz);
+	if (ret)
+		goto out;
+
+	if (fieinfo.fi_extents_mapped == 0) {
+		start_off = start_clu;
+		len = clu_sz;
+	} else {
+not_align:
+		fi_extent.fe_flags = 0;
+		ret = inode->i_op->fiemap(inode, &fieinfo, start_off, len);
+		if (ret)
+			goto out;
+		if (fieinfo.fi_extents_mapped != 0) {
+			WARN_ON_ONCE(fi_extent.fe_logical <= start_off);
+			len = fi_extent.fe_logical - start_off;
+		}
+	}
+
+	ret = file->f_op->fallocate(file, FALLOC_FL_KEEP_SIZE, start_off, len);
+out:
+	return ret;
+}
+
 static struct extent_map *__map_extent_bmap(struct ploop_io *io,
 				       struct address_space *mapping,
 				       sector_t start, sector_t len, gfp_t gfp_mask)
@@ -581,9 +635,11 @@  static struct extent_map *__map_extent_bmap(struct ploop_io *io,
 	struct fiemap_extent_info fieinfo;
 	struct fiemap_extent fi_extent;
 	mm_segment_t old_fs;
+	bool align_to_clu;
 	int ret;
 
 again:
+	align_to_clu = true;
 	em = lookup_extent_mapping(tree, start, len);
 	if (em) {
 		/*
@@ -593,6 +649,7 @@  static struct extent_map *__map_extent_bmap(struct ploop_io *io,
 		 */
 		if (em->start > start) {
 			len = em->start - start;
+			align_to_clu = false;
 		} else {
 			return em;
 		}
@@ -644,13 +701,11 @@  static struct extent_map *__map_extent_bmap(struct ploop_io *io,
 	}
 
 	if (fieinfo.fi_extents_mapped != 1) {
-		if (start_off < i_size_read(inode))
-			ploop_msg_once(io->plo, "a hole in image file detected"
-				       " (mapped=%d i_size=%llu off=%llu)",
-				       fieinfo.fi_extents_mapped,
-				       i_size_read(inode), start_off);
 		ploop_extent_put(em);
-		return ERR_PTR(-EINVAL);
+		ret = fallocate_cluster(io, inode, start_off, len, align_to_clu);
+		if (!ret)
+			goto again;
+		return ERR_PTR(ret);
 	}
 
 	em->start = fi_extent.fe_logical >> 9;