parse_metadata() is called not only from the main kwork:
qcow2_llseek_hole() calls it in process context, in parallel with
the kwork. When both miss the same md page, both drop md_pages_lock
in submit_read_md_page() and try to insert a new md page. The one
that loses the insert gets -EEXIST from qcow2_alloc_and_insert_md_page()
and returns it as is: a guest I/O on the kwork side ends with EIO,
or lseek(SEEK_DATA/SEEK_HOLE) fails with -EEXIST.

Teach __handle_md_page() to handle -EEXIST by repeating the lookup:
the page inserted in parallel is found then, and the qio is either
served from it or postponed until its read completes.

https://virtuozzo.atlassian.net/browse/VSTOR-95494

Fixes: 412d5a4f7bf1 ("dm/dm-qcow2: add llseek_hole")
Feature: dm-qcow2: block device over QCOW2 files driver
Signed-off-by: Andrey Zhadchenko <[email protected]>
---
v2: say in the message what fails without the patch: the race of
    qcow2_llseek_hole() with main kwork; added Fixes: tag

 drivers/md/dm-qcow2-map.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index 34d9d9810f601..21d1c8975af99 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -1594,20 +1594,23 @@ static int submit_read_md_page(struct qcow2 *qcow2, 
struct qio **qio,
 /*
  * This may be called with @qio == NULL, in case of we are
  * interesting in searching cached in memory md only.
- * This is aimed to be called not only from main kwork
- * for L1/L2 pages, so all callers looking for L1/L2
- * must care about submit_read_md_page() may return EEXIST.
  */
 static int __handle_md_page(struct qcow2 *qcow2, u64 page_id,
                            struct qio **qio, struct md_page **ret_md)
 {
        struct md_page *md;
+       int ret;
 
        lockdep_assert_held(&qcow2->md_pages_lock);
+again:
        md = qcow2_md_page_find_or_postpone(qcow2, page_id, qio);
        if (!md) {
-               if (qio && *qio)
-                       return submit_read_md_page(qcow2, qio, page_id);
+               if (qio && *qio) {
+                       ret = submit_read_md_page(qcow2, qio, page_id);
+                       if (unlikely(ret == -EEXIST))
+                               goto again;
+                       return ret;
+               }
                return 0;
        }
 
-- 
2.43.5

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

Reply via email to