[Devel] [PATCH rh7 12/12] ploop: Online discard support for dio engine
Kirill Tkhai
ktkhai at virtuozzo.com
Fri Mar 1 18:14:26 MSK 2019
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 at virtuozzo.com>
---
drivers/block/ploop/io_direct.c | 41 ++++++++++++++++++---
drivers/block/ploop/io_direct_map.c | 67 ++++++++++++++++++++++++++++++++---
2 files changed, 96 insertions(+), 12 deletions(-)
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;
More information about the Devel
mailing list