[Devel] [PATCH RH9 12/12] dm_qcow2: get next hole
Kirill Tkhai
ktkhai at virtuozzo.com
Wed Jan 19 19:20:12 MSK 2022
---
drivers/md/dm-qcow2-cmd.c | 46 ++++++++++++++++++++++++++++-------
drivers/md/dm-qcow2-map.c | 60 +++++++++++++++++++++++++++++++++++++++++++++
drivers/md/dm-qcow2.h | 2 ++
3 files changed, 99 insertions(+), 9 deletions(-)
diff --git a/drivers/md/dm-qcow2-cmd.c b/drivers/md/dm-qcow2-cmd.c
index e3c2de89d1bf..19b1f6c33265 100644
--- a/drivers/md/dm-qcow2-cmd.c
+++ b/drivers/md/dm-qcow2-cmd.c
@@ -317,24 +317,52 @@ static int qcow2_set_fault_injection(struct qcow2_target *tgt,
return 0;
}
-static int qcow2_seek_hole(struct qcow2_target *tgt, u64 pos)
+static int qcow2_seek_hole(struct qcow2_target *tgt, u64 old_pos,
+ char *result, unsigned int maxlen)
{
+ loff_t pos, hole_pos, search_pos, end_pos;
struct qcow2 *qcow2, *img;
+ unsigned int sz = 0;
u8 ref_index;
+ u32 clu_size;
u64 step;
int ret;
qcow2 = img = qcow2_ref_inc(tgt, &ref_index);
+ if (old_pos >= qcow2->hdr.size) {
+ ret = -EINVAL;
+ goto out;
+ }
+
/* This expects lower deltas have the same clu_size and ext_l2 */
- step = (u64)qcow2->l2_entries * qcow2->clu_size;
+ clu_size = qcow2->clu_size;
+ search_pos = round_down(old_pos, clu_size);
+ step = (u64)qcow2->l2_entries * clu_size;
+
+ hole_pos = OFFSET_MAX;
+ while (search_pos < qcow2->hdr.size) {
+ end_pos = round_up(search_pos + 1, step);
+ img = qcow2;
+ while (img && search_pos < img->hdr.size) {
+ ret = pos = qcow2_find_next_hole(tgt, img, search_pos, end_pos);
+ if (pos < 0)
+ goto out;
+ if (pos < hole_pos)
+ hole_pos = pos;
+ img = img->lower;
+ }
- while (img) { /* Cache metadata of all images */
- ret = qcow2_service_iter(tgt, img, img->hdr.size, step,
- REQ_OP_READ, QIO_IS_FAKEREAD_FL);
- if (ret)
- goto out;
- img = img->lower;
+ if (hole_pos != OFFSET_MAX)
+ break;
+ search_pos = end_pos;
}
+
+ if (hole_pos < old_pos) /* initial @search_pos is rounded down */
+ hole_pos = old_pos;
+ if (hole_pos == OFFSET_MAX)
+ hole_pos = qcow2->hdr.size;
+ ret = DMEMIT("hole_pos=%lld\n", hole_pos);
+ ret = ret ? 1 : 0;
out:
qcow2_ref_dec(tgt, ref_index);
return ret;
@@ -382,7 +410,7 @@ int qcow2_message(struct dm_target *ti, unsigned int argc, char **argv,
ret = -EINVAL;
goto out;
}
- ret = qcow2_seek_hole(tgt, val64);
+ ret = qcow2_seek_hole(tgt, val64, result, maxlen);
goto out;
}
diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index 4531d680fa63..bb7ecc3423f5 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -1996,6 +1996,66 @@ static int parse_metadata(struct qcow2 *qcow2, struct qio **qio,
return ret < 0 ? ret : 0;
}
+static void wake_wq_qio_endio(struct qcow2_target *tgt, struct qio *qio,
+ void *completed_ptr, blk_status_t bi_status)
+{
+ bool *completed = completed_ptr;
+
+ *completed = true;
+ wake_up(&tgt->service_wq);
+}
+
+/* Find a hole in diapason referred by L2 containing @pos (starting from @pos) */
+loff_t qcow2_find_next_hole(struct qcow2_target *tgt, struct qcow2 *qcow2,
+ u64 pos, u64 end_pos)
+{
+ u32 clu_size = qcow2->clu_size;
+ bool completed, found = false;
+ struct qio *qio, *qio_orig;
+ int ret;
+
+ qio = qio_orig = alloc_qio(tgt->qio_pool, true);
+ if (!qio)
+ return -ENOMEM;
+
+ while (pos < end_pos) {
+ struct qcow2_map map = { .qcow2 = qcow2, };
+
+ qio = qio_orig;
+ init_qio(qio, REQ_OP_READ, qcow2);
+ qio->flags = QIO_IS_FAKEREAD_FL;
+ qio->bi_iter.bi_sector = to_sector(pos);
+ qio->endio_cb = wake_wq_qio_endio;
+ qio->endio_cb_data = &completed;
+ completed = false;
+
+ ret = parse_metadata(qcow2, &qio, &map);
+ if (ret < 0)
+ goto out;
+ if (!qio) {
+ wait_event(tgt->service_wq, completed == true);
+ if (qio_orig->bi_status) {
+ ret = blk_status_to_errno(qio_orig->bi_status);
+ goto out;
+ }
+ continue;
+ }
+ if (!map.data_clu_alloced) {
+ found = true;
+ break; /* Found */
+ }
+ pos += clu_size;
+ }
+out:
+ free_qio(qio_orig, tgt->qio_pool);
+ if (ret < 0)
+ return ret;
+ if (!found)
+ return OFFSET_MAX;
+ return pos;
+}
+
+
/*
* This occupies cluster at @r2_pos for R2 cluster,
* and connects it to R1 table entry.
diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h
index 5c59cc4a7c25..34e0c271c9e8 100644
--- a/drivers/md/dm-qcow2.h
+++ b/drivers/md/dm-qcow2.h
@@ -304,6 +304,8 @@ void qcow2_ref_dec(struct qcow2_target *tgt, u8 ref_index);
int qcow2_inflight_ref_switch(struct qcow2_target *tgt);
void flush_deferred_activity(struct qcow2_target *tgt, struct qcow2 *qcow2);
int qcow2_truncate_safe(struct file *file, loff_t new_len);
+loff_t qcow2_find_next_hole(struct qcow2_target *tgt,
+ struct qcow2 *qcow2, u64 pos, u64 end_pos);
static inline struct qcow2_target *to_qcow2_target(struct dm_target *ti)
{
More information about the Devel
mailing list