Our files are open with O_DIRECT. In this case,
kvec is not possible, since iov_iter_get_pages()
can't work with it. So, every read results
in EFAULT.

Signed-off-by: Kirill Tkhai <[email protected]>
---
 drivers/md/dm-ploop-bat.c |  130 ++++++++++++++++++++++++++++-----------------
 drivers/md/dm-ploop-cmd.c |   28 +++++-----
 drivers/md/dm-ploop.h     |    3 -
 3 files changed, 97 insertions(+), 64 deletions(-)

diff --git a/drivers/md/dm-ploop-bat.c b/drivers/md/dm-ploop-bat.c
index a3abf1f509ef..036edc317de3 100644
--- a/drivers/md/dm-ploop-bat.c
+++ b/drivers/md/dm-ploop-bat.c
@@ -313,12 +313,18 @@ int ploop_setup_metadata(struct ploop *ploop, struct page 
*page)
 }
 
 static int ploop_delta_check_header(struct ploop *ploop,
-                                   struct ploop_pvd_header *d_hdr,
+                                   struct rb_root *md_root,
                                    u32 *delta_nr_be_ret)
 {
        u32 bytes, delta_nr_be, offset_clusters, bat_clusters;
+       struct rb_node *node = rb_first(md_root);
+       struct md_page *md0 = rb_entry(node, struct md_page, node);
+       struct ploop_pvd_header *d_hdr;
        int ret = -EPROTO;
 
+       WARN_ON_ONCE(md0->id != 0);
+
+       d_hdr = kmap(md0->page);
        if (memcmp(d_hdr->m_Sig, ploop->m_Sig, sizeof(d_hdr->m_Sig)) ||
            d_hdr->m_Sectors != ploop->m_Sectors ||
            d_hdr->m_Type != ploop->m_Type)
@@ -336,72 +342,96 @@ static int ploop_delta_check_header(struct ploop *ploop,
        *delta_nr_be_ret = delta_nr_be;
        ret = 0;
 out:
+       kunmap(md0->page);
        return ret;
 }
 
-int convert_bat_entries(struct ploop *ploop, u32 *bat_entries, u32 nr_be)
+static int convert_bat_entries(struct ploop *ploop, struct rb_root *md_root, 
u32 nr_be)
 {
-       u32 i, bytes, bat_clusters;
+       u32 i, end, bytes, bat_clusters, *bat_entries;
+       struct rb_node *node;
+       struct md_page *md;
+       int ret = 0;
 
        bytes = (PLOOP_MAP_OFFSET + nr_be) * sizeof(map_index_t);
        bat_clusters = DIV_ROUND_UP(bytes, CLU_SIZE(ploop));
 
-       for (i = 0; i < nr_be; i++) {
-               if (bat_entries[i] == BAT_ENTRY_NONE)
-                       return -EPROTO;
-               if (!bat_entries[i])
-                       bat_entries[i] = BAT_ENTRY_NONE;
-               if (bat_entries[i] < bat_clusters)
-                       return -EXDEV;
+       rb_root_for_each_md_page(md_root, md, node) {
+               bat_entries = kmap(md->page);
+               init_be_iter(nr_be, md->id, &i, &end);
+
+               for (; i <= end; i++) {
+                       if (bat_entries[i] == BAT_ENTRY_NONE)
+                               ret = -EPROTO;
+                       if (!bat_entries[i])
+                               bat_entries[i] = BAT_ENTRY_NONE;
+                       if (bat_entries[i] < bat_clusters)
+                               ret = -EXDEV;
+               }
+               kunmap(md->page);
+
+               if (ret)
+                       break;
        }
 
-       return 0;
+       return ret;
 }
 
 int ploop_read_delta_metadata(struct ploop *ploop, struct file *file,
-                             void **d_hdr, u32 *delta_nr_be_ret)
+                             struct rb_root *md_root, u32 *delta_nr_be_ret)
 {
-       u32 size, delta_nr_be, *delta_bat_entries;
+       u32 i, size, delta_nr_be, nr_segs;
+       struct bio_vec *bvec = NULL;
        struct iov_iter iter;
-       struct kvec kvec;
+       struct rb_node *node;
+       struct md_page *md;
        ssize_t len;
        loff_t pos;
        int ret;
 
+       ret = -ENOMEM;
+       if (prealloc_md_pages(md_root, 0, ploop->nr_bat_entries))
+               goto out;
+
        size = (PLOOP_MAP_OFFSET + ploop->nr_bat_entries) * sizeof(map_index_t);
        size = ALIGN(size, PAGE_SIZE); /* file may be open as direct */
-       *d_hdr = vzalloc(size);
-       if (!*d_hdr) {
-               ret = -ENOMEM;
+       nr_segs = size / PAGE_SIZE;
+
+       bvec = kvmalloc(sizeof(*bvec) * nr_segs, GFP_KERNEL);
+       if (!bvec)
                goto out;
-       }
 
-       kvec.iov_base = *d_hdr;
-       kvec.iov_len = size;
+       ret = -EMLINK;
+       i = 0;
+       rb_root_for_each_md_page(md_root, md, node) {
+               if (WARN_ON_ONCE(md->id != i))
+                       goto out;
+               bvec[i].bv_page = md->page;
+               bvec[i].bv_len = PAGE_SIZE;
+               bvec[i].bv_offset = 0;
+               i++;
+       }
 
-       iov_iter_kvec(&iter, READ, &kvec, 1, kvec.iov_len);
+       iov_iter_bvec(&iter, READ, bvec, nr_segs, size);
        pos = 0;
 
        len = vfs_iter_read(file, &iter, &pos, 0);
        if (len != size) {
                ret = len < 0 ? (int)len : -ENODATA;
-               goto out_vfree;
+               goto out;
        }
 
-       ret = ploop_delta_check_header(ploop, *d_hdr, &delta_nr_be);
+       ret = ploop_delta_check_header(ploop, md_root, &delta_nr_be);
        if (ret)
-               goto out_vfree;
+               goto out;
 
-       delta_bat_entries = *d_hdr + PLOOP_MAP_OFFSET * sizeof(map_index_t);
-       ret = convert_bat_entries(ploop, delta_bat_entries, delta_nr_be);
+       ret = convert_bat_entries(ploop, md_root, delta_nr_be);
 
        *delta_nr_be_ret = delta_nr_be;
-out_vfree:
-       if (ret) {
-               vfree(*d_hdr);
-               *d_hdr = NULL;
-       }
 out:
+       if (ret)
+               free_md_pages_tree(md_root);
+       kvfree(bvec);
        return ret;
 }
 
@@ -420,37 +450,38 @@ static void ploop_set_not_hole(struct ploop *ploop, u32 
dst_clu)
  * n)add oldest delta
  */
 static void apply_delta_mappings(struct ploop *ploop, struct ploop_delta 
*deltas,
-                                u32 level, void *hdr, u64 size_in_clus)
+                                u32 level, struct rb_root *md_root, u64 
size_in_clus)
 {
-       map_index_t *bat_entries, *delta_bat_entries;
+       map_index_t *bat_entries, *delta_bat_entries = NULL;
        bool is_top_level, is_raw, stop = false;
+       struct md_page *md, *d_md = NULL;
        u32 i, end, dst_clu, clu;
        struct rb_node *node;
-       struct md_page *md;
 
-       /* Points to hdr since md_page[0] also contains hdr. */
-       delta_bat_entries = (map_index_t *)hdr;
        is_raw = deltas[level].is_raw;
        is_top_level = (level == top_level(ploop));
 
+       if (!is_raw)
+               d_md = md_first_entry(md_root);
+
        write_lock_irq(&ploop->bat_rwlock);
        ploop_for_each_md_page(ploop, md, node) {
                bat_entries = kmap_atomic(md->page);
+               if (!is_raw)
+                       delta_bat_entries = kmap_atomic(d_md->page);
 
                if (is_top_level && md->id == 0 && !is_raw) {
                        /* bat_entries before PLOOP_MAP_OFFSET is hdr */
-                       memcpy(bat_entries, hdr, sizeof(struct 
ploop_pvd_header));
+                       memcpy(bat_entries, delta_bat_entries,
+                              sizeof(struct ploop_pvd_header));
                }
 
-               ploop_init_be_iter(ploop, md->id, &i, &end);
+               init_be_iter(size_in_clus, md->id, &i, &end);
 
                for (; i <= end; i++) {
                        clu = page_clu_idx_to_bat_clu(md->id, i);
-                       if (clu >= size_in_clus) {
-                               WARN_ON_ONCE(is_top_level);
+                       if (clu == size_in_clus - 1)
                                stop = true;
-                               goto unmap;
-                       }
 
                        if (bat_entries[i] != BAT_ENTRY_NONE) {
                                /* md0 is already populated */
@@ -473,11 +504,14 @@ static void apply_delta_mappings(struct ploop *ploop, 
struct ploop_delta *deltas
                        if (is_top_level)
                                ploop_set_not_hole(ploop, bat_entries[i]);
                }
-unmap:
+
                kunmap_atomic(bat_entries);
+               if (!is_raw)
+                       kunmap_atomic(delta_bat_entries);
                if (stop)
                        break;
-               delta_bat_entries += PAGE_SIZE / sizeof(map_index_t);
+               if (!is_raw)
+                       d_md = md_next_entry(d_md);
        }
        write_unlock_irq(&ploop->bat_rwlock);
 }
@@ -499,7 +533,7 @@ int ploop_check_delta_length(struct ploop *ploop, struct 
file *file, loff_t *fil
 int ploop_add_delta(struct ploop *ploop, u32 level, struct file *file, bool 
is_raw)
 {
        struct ploop_delta *deltas = ploop->deltas;
-       struct ploop_pvd_header *hdr = NULL;
+       struct rb_root md_root = RB_ROOT;
        loff_t file_size;
        u32 size_in_clus;
        int ret;
@@ -509,7 +543,7 @@ int ploop_add_delta(struct ploop *ploop, u32 level, struct 
file *file, bool is_r
                goto out;
 
        if (!is_raw) {
-               ret = ploop_read_delta_metadata(ploop, file, (void *)&hdr,
+               ret = ploop_read_delta_metadata(ploop, file, &md_root,
                                                &size_in_clus);
                if (ret)
                        goto out;
@@ -522,7 +556,7 @@ int ploop_add_delta(struct ploop *ploop, u32 level, struct 
file *file, bool is_r
            size_in_clus > deltas[level + 1].size_in_clus)
                goto out;
 
-       apply_delta_mappings(ploop, deltas, level, (void *)hdr, size_in_clus);
+       apply_delta_mappings(ploop, deltas, level, &md_root, size_in_clus);
 
        deltas[level].file = file;
        deltas[level].file_size = file_size;
@@ -531,6 +565,6 @@ int ploop_add_delta(struct ploop *ploop, u32 level, struct 
file *file, bool is_r
        deltas[level].is_raw = is_raw;
        ret = 0;
 out:
-       vfree(hdr);
+       free_md_pages_tree(&md_root);
        return ret;
 }
diff --git a/drivers/md/dm-ploop-cmd.c b/drivers/md/dm-ploop-cmd.c
index 9406a1d61000..005fa32aba3a 100644
--- a/drivers/md/dm-ploop-cmd.c
+++ b/drivers/md/dm-ploop-cmd.c
@@ -680,29 +680,28 @@ static int ploop_merge_latest_snapshot(struct ploop 
*ploop)
        return ret;
 }
 
-static void notify_delta_merged(struct ploop *ploop, u8 level, void *hdr,
+static void notify_delta_merged(struct ploop *ploop, u8 level,
+                               struct rb_root *md_root,
                                bool forward, u32 size_in_clus)
 {
        u32 i, end, *bat_entries, *delta_bat_entries;
+       struct md_page *md, *d_md;
        struct rb_node *node;
-       struct md_page *md;
        struct file *file;
        bool stop = false;
        u32 clu;
 
-       /* Points to hdr since md_page[0] also contains hdr. */
-       delta_bat_entries = (map_index_t *)hdr;
+       d_md = md_first_entry(md_root);
 
        write_lock_irq(&ploop->bat_rwlock);
        ploop_for_each_md_page(ploop, md, node) {
-               ploop_init_be_iter(ploop, md->id, &i, &end);
+               init_be_iter(size_in_clus, md->id, &i, &end);
                bat_entries = kmap_atomic(md->page);
+               delta_bat_entries = kmap_atomic(d_md->page);
                for (; i <= end; i++) {
                        clu = page_clu_idx_to_bat_clu(md->id, i);
-                       if (clu >= size_in_clus) {
+                       if (clu == size_in_clus - 1)
                                stop = true;
-                               goto unmap;
-                       }
 
                        if (md_page_cluster_is_in_top_delta(ploop, md, i) ||
                            delta_bat_entries[i] == BAT_ENTRY_NONE ||
@@ -725,11 +724,12 @@ static void notify_delta_merged(struct ploop *ploop, u8 
level, void *hdr,
                        if (!forward)
                                md->bat_levels[i]--;
                }
-unmap:
+
                kunmap_atomic(bat_entries);
+               kunmap_atomic(delta_bat_entries);
                if (stop)
                        break;
-               delta_bat_entries += PAGE_SIZE / sizeof(map_index_t);
+               d_md = md_next_entry(delta_md);
        }
 
        file = ploop->deltas[level].file;
@@ -774,7 +774,7 @@ static int process_update_delta_index(struct ploop *ploop, 
u8 level,
 static int ploop_delta_clusters_merged(struct ploop *ploop, u8 level,
                                       bool forward)
 {
-       struct ploop_pvd_header *d_hdr = NULL;
+       struct rb_root md_root = RB_ROOT;
        struct file *file;
        u32 size_in_clus;
        int ret;
@@ -782,7 +782,7 @@ static int ploop_delta_clusters_merged(struct ploop *ploop, 
u8 level,
        /* Reread BAT of deltas[@level + 1] (or [@level - 1]) */
        file = ploop->deltas[level + forward ? 1 : -1].file;
 
-       ret = ploop_read_delta_metadata(ploop, file, (void *)&d_hdr, 
&size_in_clus);
+       ret = ploop_read_delta_metadata(ploop, file, &md_root, &size_in_clus);
        if (ret)
                goto out;
 
@@ -790,12 +790,12 @@ static int ploop_delta_clusters_merged(struct ploop 
*ploop, u8 level,
        if (ret)
                goto out;
 
-       notify_delta_merged(ploop, level, d_hdr, forward, size_in_clus);
+       notify_delta_merged(ploop, level, &md_root, forward, size_in_clus);
 
        ploop_resume_submitting_pios(ploop);
        ret = 0;
 out:
-       vfree(d_hdr);
+       free_md_pages_tree(&md_root);
        return ret;
 }
 
diff --git a/drivers/md/dm-ploop.h b/drivers/md/dm-ploop.h
index c26641ce4e2b..9c4b77852c18 100644
--- a/drivers/md/dm-ploop.h
+++ b/drivers/md/dm-ploop.h
@@ -549,7 +549,6 @@ extern void ploop_free_md_page(struct md_page *md);
 extern void free_md_pages_tree(struct rb_root *root);
 extern bool try_update_bat_entry(struct ploop *ploop, u32 clu,
                                 u8 level, u32 dst_clu);
-extern int convert_bat_entries(struct ploop *ploop, u32 *bat_entries, u32 
count);
 
 extern int ploop_add_delta(struct ploop *ploop, u32 level, struct file *file, 
bool is_raw);
 extern int ploop_check_delta_length(struct ploop *ploop, struct file *file, 
loff_t *file_size);
@@ -577,7 +576,7 @@ extern void pio_prepare_offsets(struct ploop *, struct pio 
*, u32);
 
 extern int ploop_setup_metadata(struct ploop *ploop, struct page *page);
 extern int ploop_read_delta_metadata(struct ploop *ploop, struct file *file,
-                                    void **d_hdr, u32 *delta_nr_be);
+                                    struct rb_root *md_root, u32 *delta_nr_be);
 extern void ploop_index_wb_init(struct ploop_index_wb *piwb, struct ploop 
*ploop);
 extern void ploop_call_rw_iter(struct file *file, loff_t pos, unsigned rw,
                               struct iov_iter *iter, struct pio *pio);


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

Reply via email to