Add a helper, which returns an up to date md page from md cache, or allocates a new one, inserts it and reads it synchronously. On read failure the page is erased from cache and freed.
Use it in qcow2_parse_header() instead of open-coded allocation and read of page 0. It will also be used by a later patch in the series. https://virtuozzo.atlassian.net/browse/VSTOR-148171 Feature: dm-qcow2: block device over QCOW2 files driver Signed-off-by: Alexander Ivanov <[email protected]> Reviewed-by: Denis V. Lunev <[email protected]> Reviewed-by: Andrey Zhadchenko <[email protected]> --- drivers/md/dm-qcow2-target.c | 48 ++++++++++++++++++++++++++++++++---- drivers/md/dm-qcow2.h | 2 ++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c index 7c572bd66e1c..0cbbd8e4f493 100644 --- a/drivers/md/dm-qcow2-target.c +++ b/drivers/md/dm-qcow2-target.c @@ -418,6 +418,48 @@ int qcow2_alloc_and_insert_md_page(struct qcow2 *qcow2, u64 index, struct md_pag } ALLOW_ERROR_INJECTION(qcow2_alloc_and_insert_md_page, ERRNO); +/* + * Returns up to date md page from cache, or allocates + * a new one and reads it synchronously. Sets *md to NULL on error. + * + * The caller must ensure nobody else looks this page up until this + * returns (e.g., the device is suspended). A lookup before MD_UPTODATE + * is set queues its qio on md->wait_list, which is never woken here, + * and the page is freed with the qio still queued on read error. + * A cached page that is not MD_UPTODATE yet makes the insert fail. + */ +int qcow2_md_page_read_sync(struct qcow2 *qcow2, u64 id, struct md_page **md) +{ + int ret; + + spin_lock_irq(&qcow2->md_pages_lock); + *md = qcow2_md_page_find_or_postpone(qcow2, id, NULL); + spin_unlock_irq(&qcow2->md_pages_lock); + if (*md) + return 0; + + ret = qcow2_alloc_and_insert_md_page(qcow2, id, md); + if (ret) + goto err; + + ret = qcow2_rw_page_sync(READ, qcow2, id, (*md)->page); + if (ret) { + spin_lock_irq(&qcow2->md_pages_lock); + qcow2_md_page_erase(qcow2, *md); + spin_unlock_irq(&qcow2->md_pages_lock); + qcow2_free_md_page(*md); + goto err; + } + + spin_lock_irq(&qcow2->md_pages_lock); + (*md)->status |= MD_UPTODATE; + spin_unlock_irq(&qcow2->md_pages_lock); + return 0; +err: + *md = NULL; + return ret; +} + static void inflight_ref_exit0(struct percpu_ref *ref) { struct qcow2_target *tgt = container_of(ref, struct qcow2_target, @@ -851,13 +893,9 @@ static int qcow2_parse_header(struct dm_target *ti, struct qcow2 *qcow2, } qcow2->file_preallocated_area_start = qcow2->file_size; - ret = qcow2_alloc_and_insert_md_page(qcow2, 0, &md); - if (ret) - return ret; - ret = qcow2_rw_page_sync(READ, qcow2, md->id, md->page); + ret = qcow2_md_page_read_sync(qcow2, 0, &md); if (ret) return ret; - md->status |= MD_UPTODATE; raw_hdr = kmap(md->page); min_len = to_bytes(ti->len); diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h index ad5286b16883..5abc7f5ad239 100644 --- a/drivers/md/dm-qcow2.h +++ b/drivers/md/dm-qcow2.h @@ -388,6 +388,8 @@ void do_qcow2_work(struct work_struct *ws); void do_qcow2_fsync_work(struct work_struct *ws); int qcow2_alloc_and_insert_md_page(struct qcow2 *qcow2, u64 index, struct md_page **md); +int qcow2_md_page_read_sync(struct qcow2 *qcow2, u64 id, + struct md_page **md); struct md_page *qcow2_md_page_find_or_postpone(struct qcow2 *qcow2, u64 id, struct qio **qio); struct md_page *qcow2_md_page_renumber(struct qcow2 *qcow2, u64 id, -- 2.53.0 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
