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
