Parallel handle_md_page() may fail because of a page has just been added.
Teach it to repeat the search.

Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com>
---
 drivers/md/dm-qcow2-map.c    |    5 ++---
 drivers/md/dm-qcow2-target.c |   14 ++++++++++----
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index 4e04505810fc..4edd63e47a3d 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -1526,10 +1526,8 @@ static int submit_read_md_page(struct qcow2 *qcow2, 
struct qio **qio,
        int ret;
 
        ret = alloc_and_insert_md_page(qcow2, page_id, &md);
-       if (ret < 0) {
-               pr_err("Can't alloc: ret=%d, page_id=%llu\n", ret, page_id);
+       if (ret < 0)
                return ret;
-       }
 
        spin_lock_irq(&qcow2->md_pages_lock);
        list_add_tail(&(*qio)->link, &md->wait_list);
@@ -1543,6 +1541,7 @@ 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.
  */
 static int handle_md_page(struct qcow2 *qcow2, u64 page_id,
                 struct qio **qio, struct md_page **ret_md)
diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c
index 6c550cbe2579..795d64516507 100644
--- a/drivers/md/dm-qcow2-target.c
+++ b/drivers/md/dm-qcow2-target.c
@@ -318,7 +318,7 @@ struct md_page *md_page_find_or_postpone(struct qcow2 
*qcow2, unsigned int id,
        return md;
 }
 
-static void md_page_insert(struct qcow2 *qcow2, struct md_page *new_md)
+static int md_page_try_insert(struct qcow2 *qcow2, struct md_page *new_md)
 {
        struct rb_root *root = &qcow2->md_pages;
        unsigned int new_id = new_md->id;
@@ -337,11 +337,12 @@ static void md_page_insert(struct qcow2 *qcow2, struct 
md_page *new_md)
                else if (new_id > md->id)
                        node = &parent->rb_right;
                else
-                       BUG();
+                       return -EEXIST;
        }
 
        rb_link_node(&new_md->node, parent, node);
        rb_insert_color(&new_md->node, root);
+       return 0;
 }
 
 void md_page_erase(struct qcow2 *qcow2, struct md_page *md)
@@ -361,7 +362,8 @@ struct md_page *md_page_renumber(struct qcow2 *qcow2, 
unsigned int id,
                WARN_ON_ONCE(!list_empty(&md->wait_list));
                md_page_erase(qcow2, md);
                md->id = new_id;
-               md_page_insert(qcow2, md);
+               if (WARN_ON(md_page_try_insert(qcow2, md) < 0))
+                       md = NULL;
        }
        return md;
 }
@@ -396,10 +398,14 @@ int alloc_and_insert_md_page(struct qcow2 *qcow2, u64 
index, struct md_page **md
        INIT_LIST_HEAD(&(*md)->wb_link);
 
        spin_lock_irq(&qcow2->md_pages_lock);
-       md_page_insert(qcow2, *md);
+       ret = md_page_try_insert(qcow2, *md);
        spin_unlock_irq(&qcow2->md_pages_lock);
+       if (ret)
+               goto err_putpage;
        return 0;
 
+err_putpage:
+       put_page((*md)->page);
 err_kfree:
        kfree(*md);
        return ret;


_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to