[Devel] [PATCH RHEL7 COMMIT] ploop: io_kaio: Introduce 4K discard_granuality with 1M clearing indexes when possible
Vasily Averin
vvs at virtuozzo.com
Fri Aug 21 11:06:11 MSK 2020
The commit is pushed to "branch-rh7-3.10.0-1127.18.2.vz7.163.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1127.18.2.vz7.163.3
------>
commit b93800202805f72314dda1298beba8110bf07252
Author: Kirill Tkhai <ktkhai at virtuozzo.com>
Date: Fri Aug 21 11:06:11 2020 +0300
ploop: io_kaio: Introduce 4K discard_granuality with 1M clearing indexes when possible
1)In case of discard size is less then 1 cluster,
a small hole is punched.
2)In case of discard request covers the whole cluster,
index in BAT is also cleared.
Since small 4K holes require 4K discard_granuality,
this makes impossible to use block level to make
discard requests 1 cluster aligned. This requires
us to split the requests manually, so force_split_discard_reqs
parameter was introduced.
See comments in kaio_queue_settings() for details.
https://jira.sw.ru/browse/PSBM-105347
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
drivers/block/ploop/dev.c | 12 ++++++++----
drivers/block/ploop/io_kaio.c | 36 +++++++++++++++++++++++++++++++++++-
include/linux/ploop/ploop.h | 1 +
3 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index 5f1a0c2..25b516c 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -979,7 +979,8 @@ static void ploop_make_request(struct request_queue *q, struct bio *bio)
* bio layer assumes that it can prepare single-page bio
* not depending on any alignment constraints. So be it.
*/
- if (!(bio->bi_rw & REQ_DISCARD) && bio->bi_size &&
+ if ((!(bio->bi_rw & REQ_DISCARD) || plo->force_split_discard_reqs) &&
+ bio->bi_size &&
(bio->bi_sector >> cluster_log) !=
((bio->bi_sector + (bio->bi_size >> 9) - 1) >> cluster_log)) {
struct bio_pair *bp;
@@ -988,7 +989,8 @@ static void ploop_make_request(struct request_queue *q, struct bio *bio)
plo->st.bio_splits++;
- BUG_ON(bio->bi_vcnt != 1 || bio->bi_idx != 0);
+ if (!(bio->bi_rw & REQ_DISCARD))
+ BUG_ON(bio->bi_vcnt != 1 || bio->bi_idx != 0);
bp = bio_split(bio, first_sectors);
ploop_make_request(q, &bp->bio1);
@@ -2298,7 +2300,7 @@ static bool ploop_can_issue_discard(struct ploop_device *plo,
if (!list_is_singular(&plo->map.delta_list))
return false;
- return whole_block(plo, preq);
+ return whole_block(plo, preq) || plo->force_split_discard_reqs;
}
static void
@@ -2568,7 +2570,8 @@ delta_io:
}
preq->iblock = iblk;
if (!(preq->req_rw & REQ_DISCARD) ||
- (delta->ops->capability & PLOOP_FMT_CAP_IDENTICAL))
+ (delta->ops->capability & PLOOP_FMT_CAP_IDENTICAL) ||
+ !whole_block(plo, preq))
preq->eng_state = PLOOP_E_COMPLETE;
else
preq->eng_state = PLOOP_E_DATA_WBI;
@@ -4205,6 +4208,7 @@ static int ploop_start(struct ploop_device * plo, struct block_device *bdev)
blk_queue_merge_bvec(q, ploop_merge_bvec);
blk_queue_flush(q, REQ_FLUSH);
+ plo->force_split_discard_reqs = false;
top_delta->io.ops->queue_settings(&top_delta->io, q);
/* REQ_WRITE_SAME is not supported */
blk_queue_max_write_same_sectors(q, 0);
diff --git a/drivers/block/ploop/io_kaio.c b/drivers/block/ploop/io_kaio.c
index 1151b86..020e79f 100644
--- a/drivers/block/ploop/io_kaio.c
+++ b/drivers/block/ploop/io_kaio.c
@@ -1130,7 +1130,41 @@ static void kaio_queue_settings(struct ploop_io * io, struct request_queue * q)
if (inode->i_sb->s_magic == EXT4_SUPER_MAGIC) {
WARN_ON(!kaio_backed_ext4);
blk_queue_stack_limits(q, bdev_get_queue(io->files.bdev));
- ploop_set_discard_limits(io->plo);
+ /*
+ * There is no a way to force block engine to split a request
+ * to fit a single cluster, when discard granuality is 4K
+ * (inherited from fs block size in blk_queue_stack_limits()).
+ * So, ploop_make_request() splits them.
+ */
+ io->plo->force_split_discard_reqs = true;
+ /*
+ * Why not (1 << io->plo->cluster_log)?
+ * Someone may want to clear indexes in case of a request
+ * is big enough to fit the whole cluster.
+ * In case of max_discard_sectors is 1 cluster, a request
+ * for [cluster_start - 4K, cluster_start + cluster_size)
+ * at block level will be splitted in two requests:
+ *
+ * [cluster_start - 4K, cluster_start + cluster_size - 4K)
+ * [cluster_start + cluster_size - 4K, cluster_start + cluster_size)
+ *
+ * Then, ploop_make_request() splits the first of them in two
+ * to fit a single cluster, so all three requests will be smaller
+ * then 1 cluster, and no index will be cleared.
+ *
+ * Note, this does not solve a problem, when a request covers
+ * 3 clusters: [cluster_start - 4K, cluster_start + 2 * cluster_size],
+ * so the third cluster's index will remain. This will require
+ * unlimited max_discard_sectors and splitting every request
+ * in ploop_make_request(). We don't want that in that context.
+ *
+ * But even in current view, this makes indexes to be cleared
+ * more frequently, and index-clearing code will be tested better.
+ *
+ * Anyway, in general this may be an excess functionality.
+ * If it's so, it will be dropped later.
+ */
+ q->limits.max_discard_sectors = (1 << io->plo->cluster_log) * 2 - 1;
return;
}
diff --git a/include/linux/ploop/ploop.h b/include/linux/ploop/ploop.h
index 3e1b59e..fe6f94e 100644
--- a/include/linux/ploop/ploop.h
+++ b/include/linux/ploop/ploop.h
@@ -404,6 +404,7 @@ struct ploop_device
int cluster_log;
int fmt_version;
+ bool force_split_discard_reqs;
int active_reqs;
int fastpath_reqs;
More information about the Devel
mailing list