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 <[email protected]>
---
 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;

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to