(Comment some code to use it to optimize delta BAT parse)

Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com>
---
 drivers/md/dm-ploop-bat.c    |   91 ++++++++++++++++++++++--------------------
 drivers/md/dm-ploop-cmd.c    |   23 ++++++-----
 drivers/md/dm-ploop-map.c    |    8 ++--
 drivers/md/dm-ploop-target.c |   88 +++++++++++++++++++++++++----------------
 drivers/md/dm-ploop.h        |    5 +-
 5 files changed, 123 insertions(+), 92 deletions(-)

diff --git a/drivers/md/dm-ploop-bat.c b/drivers/md/dm-ploop-bat.c
index 04698d99a67a..632077ad781e 100644
--- a/drivers/md/dm-ploop-bat.c
+++ b/drivers/md/dm-ploop-bat.c
@@ -138,6 +138,7 @@ bool try_update_bat_entry(struct ploop *ploop, unsigned int 
cluster,
        return false;
 }
 
+#if 0
 /*
  * Clear all clusters, which are referred to in BAT, from holes_bitmap.
  * Set bat_levels[] to top delta's level. Mark unmapped clusters as
@@ -156,7 +157,7 @@ static int parse_bat_entries(struct ploop *ploop, 
map_index_t *bat_entries,
                if (bat_entries[i] == BAT_ENTRY_NONE)
                        return -EINVAL;
                if (bat_entries[i]) {
-                       bat_levels[i] = nr_deltas; /* See top_level() */
+                       bat_levels[i] = nr_deltas - 1; /* See top_level() */
                        /* Cluster may refer out holes_bitmap after shrinking */
                        if (bat_entries[i] < ploop->hb_nr)
                                ploop_hole_clear_bit(bat_entries[i], ploop);
@@ -172,7 +173,7 @@ static int parse_bat_entries(struct ploop *ploop, 
map_index_t *bat_entries,
  * Read from disk and fill bat_entries. Note, that on enter here, cluster #0
  * is already read from disk (with header) -- just parse bio pages content.
  */
-static int ploop_read_bat(struct ploop *ploop, struct bio *bio, u8 nr_deltas)
+int ploop_read_bat(struct ploop *ploop, struct bio *bio, u8 nr_deltas)
 {
        unsigned int id, entries_per_page, nr_copy, nr_all, page, i = 0;
        map_index_t *from, *to, cluster = 0;
@@ -224,6 +225,7 @@ static int ploop_read_bat(struct ploop *ploop, struct bio 
*bio, u8 nr_deltas)
 out:
        return ret;
 }
+#endif
 
 /* Alloc holes_bitmap and set bits of free clusters */
 static int ploop_setup_holes_bitmap(struct ploop *ploop,
@@ -254,30 +256,14 @@ static int ploop_setup_holes_bitmap(struct ploop *ploop,
        return 0;
 }
 
-/*
- * Allocate memory for bat_entries, bat_levels and holes_bitmap,
- * and read their content from disk.
- */
-int ploop_read_metadata(struct dm_target *ti, struct ploop *ploop, u8 
nr_deltas)
+int ploop_setup_metadata(struct ploop *ploop, struct page *page)
 {
        unsigned int bat_clusters, offset_clusters, cluster_log;
        struct ploop_pvd_header *m_hdr = NULL;
        unsigned long size;
-       struct page *page;
-       struct bio *bio;
        int ret;
 
        cluster_log = ploop->cluster_log;
-
-       bio = alloc_bio_with_pages(ploop);
-       if (!bio)
-               return -ENOMEM;
-
-       ret = ploop_read_cluster_sync(ploop, bio, 0);
-       if (ret < 0)
-               goto out;
-
-       page = bio->bi_io_vec[0].bv_page;
        m_hdr = kmap(page);
 
        ret = -ENOTSUPP;
@@ -309,18 +295,9 @@ int ploop_read_metadata(struct dm_target *ti, struct ploop 
*ploop, u8 nr_deltas)
        m_hdr = NULL;
 
        ret = ploop_setup_holes_bitmap(ploop, bat_clusters);
-       if (ret)
-               goto out;
-
-       ret = prealloc_md_pages(&ploop->bat_entries, 0, ploop->nr_bat_entries);
-       if (ret)
-               goto out;
-
-       ret = ploop_read_bat(ploop, bio, nr_deltas);
 out:
        if (m_hdr)
                kunmap(page);
-       free_bio_with_pages(ploop, bio);
        return ret;
 }
 
@@ -367,6 +344,20 @@ static int ploop_delta_check_header(struct ploop *ploop, 
struct page *page,
        return ret;
 }
 
+int convert_bat_entries(u32 *bat_entries, u32 count)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               if (bat_entries[i] == BAT_ENTRY_NONE)
+                       return -EPROTO;
+               if (!bat_entries[i])
+                       bat_entries[i] = BAT_ENTRY_NONE;
+       }
+
+       return 0;
+}
+
 int ploop_read_delta_metadata(struct ploop *ploop, struct file *file,
                              void **d_hdr)
 {
@@ -424,14 +415,7 @@ int ploop_read_delta_metadata(struct ploop *ploop, struct 
file *file,
        }
 
        delta_bat_entries = *d_hdr + PLOOP_MAP_OFFSET * sizeof(map_index_t);
-       for (i = 0; i < ploop->nr_bat_entries; i++) {
-               if (delta_bat_entries[i] == BAT_ENTRY_NONE) {
-                       ret = -EPROTO;
-                       goto out_vfree;
-               }
-               if (!delta_bat_entries[i])
-                       delta_bat_entries[i] = BAT_ENTRY_NONE;
-       }
+       ret = convert_bat_entries(delta_bat_entries, ploop->nr_bat_entries);
 
 out_vfree:
        if (ret) {
@@ -443,6 +427,13 @@ int ploop_read_delta_metadata(struct ploop *ploop, struct 
file *file,
        return ret;
 }
 
+static void ploop_set_not_hole(struct ploop *ploop, u32 dst_cluster)
+{
+       /* Cluster may refer out holes_bitmap after shrinking */
+       if (dst_cluster < ploop->hb_nr)
+               ploop_hole_clear_bit(dst_cluster, ploop);
+}
+
 /*
  * Prefer first added delta, since the order is:
  * 1)add top device
@@ -454,14 +445,15 @@ static void apply_delta_mappings(struct ploop *ploop, 
struct ploop_delta *deltas
                                 u32 level, void *hdr, u64 size_in_clus)
 {
        map_index_t *bat_entries, *delta_bat_entries;
+       bool is_top_level, is_raw, stop = false;
        unsigned int i, end, dst_cluster, clu;
        struct rb_node *node;
        struct md_page *md;
-       bool is_raw;
 
        /* 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));
 
        write_lock_irq(&ploop->bat_rwlock);
        ploop_for_each_md_page(ploop, md, node) {
@@ -469,10 +461,17 @@ static void apply_delta_mappings(struct ploop *ploop, 
struct ploop_delta *deltas
                bat_entries = kmap_atomic(md->page);
                for (; i <= end; i++) {
                        clu = page_clu_idx_to_bat_clu(md->id, i);
-                       if (clu >= size_in_clus)
-                               goto unlock;
-                       if (bat_entries[i] != BAT_ENTRY_NONE)
-                               continue;
+                       if (clu >= size_in_clus) {
+                               WARN_ON_ONCE(is_top_level);
+                               stop = true;
+                               goto unmap;
+                       }
+
+                       if (bat_entries[i] != BAT_ENTRY_NONE) {
+                               /* md0 is already populated */
+                               WARN_ON_ONCE(md->id && is_top_level);
+                               goto set_not_hole;
+                       }
 
                        if (!is_raw)
                                dst_cluster = delta_bat_entries[i];
@@ -485,12 +484,16 @@ static void apply_delta_mappings(struct ploop *ploop, 
struct ploop_delta *deltas
                                continue;
                        md->bat_levels[i] = level;
                        bat_entries[i] = dst_cluster;
-
+set_not_hole:
+                       if (is_top_level)
+                               ploop_set_not_hole(ploop, bat_entries[i]);
                }
+unmap:
                kunmap_atomic(bat_entries);
+               if (stop)
+                       break;
                delta_bat_entries += PAGE_SIZE / sizeof(map_index_t);
        }
-unlock:
        write_unlock_irq(&ploop->bat_rwlock);
 }
 
@@ -529,7 +532,7 @@ int ploop_add_delta(struct ploop *ploop, u32 level, struct 
file *file, bool is_r
        }
 
        ret = -EBADSLT;
-       if (level != ploop->nr_deltas - 1 &&
+       if (level != top_level(ploop) &&
            size_in_clus > deltas[level + 1].size_in_clus)
                goto out;
 
diff --git a/drivers/md/dm-ploop-cmd.c b/drivers/md/dm-ploop-cmd.c
index 7060e88675ed..9fd2b8664edc 100644
--- a/drivers/md/dm-ploop-cmd.c
+++ b/drivers/md/dm-ploop-cmd.c
@@ -581,7 +581,7 @@ static bool iter_delta_clusters(struct ploop *ploop, struct 
ploop_cmd *cmd)
                /* FIXME: Optimize this. ploop_bat_entries() is overkill */
                dst_cluster = ploop_bat_entries(ploop, *cluster, &level);
                if (dst_cluster == BAT_ENTRY_NONE ||
-                   level != ploop->nr_deltas - 1)
+                   level != ploop->nr_deltas - 2)
                        continue;
 
                spin_lock_irq(&ploop->deferred_lock);
@@ -653,7 +653,10 @@ static void process_merge_latest_snapshot_cmd(struct ploop 
*ploop,
                        goto complete;
                }
                write_lock_irq(&ploop->bat_rwlock);
-               file = ploop->deltas[--ploop->nr_deltas].file;
+               level = ploop->nr_deltas - 2;
+               file = ploop->deltas[level].file;
+               ploop->deltas[level] = ploop->deltas[level + 1];
+               ploop->nr_deltas--;
                write_unlock_irq(&ploop->bat_rwlock);
                fput(file);
        }
@@ -670,7 +673,7 @@ static int ploop_merge_latest_snapshot(struct ploop *ploop)
                return -EBUSY;
        if (ploop_is_ro(ploop))
                return -EROFS;
-       if (!ploop->nr_deltas)
+       if (ploop->nr_deltas < 2)
                return -ENOENT;
 again:
        memset(&cmd, 0, sizeof(cmd));
@@ -831,11 +834,13 @@ static int ploop_notify_merged(struct ploop *ploop, u8 
level, bool forward)
 {
        if (ploop->maintaince)
                return -EBUSY;
-       if (level >= ploop->nr_deltas)
+       if (level >= top_level(ploop))
                return -ENOENT;
        if (level == 0 && !forward)
                return -EINVAL;
-       if (level == ploop->nr_deltas - 1 && forward)
+       if (level == top_level(ploop) - 1 && forward)
+               return -EINVAL;
+       if (ploop->nr_deltas < 3)
                return -EINVAL;
        /*
         * Userspace notifies us, it has copied clusters of
@@ -896,7 +901,7 @@ static int ploop_update_delta_index(struct ploop *ploop, 
unsigned int level,
 
        if (ploop->maintaince)
                return -EBUSY;
-       if (level >= ploop->nr_deltas)
+       if (level >= top_level(ploop))
                return -ENOENT;
 
        cmd.update_delta_index.level = level;
@@ -914,7 +919,7 @@ static void process_flip_upper_deltas(struct ploop *ploop, 
struct ploop_cmd *cmd
 {
        unsigned int i, size, end, bat_clusters, hb_nr, *bat_entries;
        void *holes_bitmap = ploop->holes_bitmap;
-       u8 level = ploop->nr_deltas - 1;
+       u8 level = top_level(ploop) - 1;
        struct rb_node *node;
        struct md_page *md;
 
@@ -1165,9 +1170,9 @@ static int ploop_flip_upper_deltas(struct ploop *ploop, 
char *new_dev,
                return -EBUSY;
        if (ploop_is_ro(ploop))
                return -EROFS;
-       if (!ploop->nr_deltas)
+       if (ploop->nr_deltas < 2)
                return -ENOENT;
-       if (ploop->deltas[ploop->nr_deltas - 1].is_raw)
+       if (ploop->deltas[ploop->nr_deltas - 2].is_raw)
                return -EBADSLT;
        if (kstrtou32(new_ro_fd, 10, &new_fd) < 0 ||
            !(cmd.flip_upper_deltas.file = fget(new_fd)))
diff --git a/drivers/md/dm-ploop-map.c b/drivers/md/dm-ploop-map.c
index 9fe77addcb63..b1fd15d5516d 100644
--- a/drivers/md/dm-ploop-map.c
+++ b/drivers/md/dm-ploop-map.c
@@ -175,7 +175,7 @@ static int ploop_map_discard(struct ploop *ploop, struct 
bio *bio)
                read_lock_irqsave(&ploop->bat_rwlock, flags);
                /* Early checks to not wake up work for nought. */
                if (cluster_is_in_top_delta(ploop, cluster) &&
-                   !ploop->nr_deltas)
+                   ploop->nr_deltas == 1)
                        supported = true;
                read_unlock_irqrestore(&ploop->bat_rwlock, flags);
        }
@@ -418,7 +418,7 @@ static void handle_discard_bio(struct ploop *ploop, struct 
bio *bio,
        unsigned long flags;
        int ret;
 
-       if (!cluster_is_in_top_delta(ploop, cluster) || ploop->nr_deltas) {
+       if (!cluster_is_in_top_delta(ploop, cluster) || ploop->nr_deltas != 1) {
 enotsupp:
                bio->bi_status = BLK_STS_NOTSUPP;
                bio_endio(bio);
@@ -550,7 +550,7 @@ static void piwb_discard_completed(struct ploop *ploop, 
bool success,
                return;
 
        if (cluster_is_in_top_delta(ploop, cluster)) {
-               WARN_ON_ONCE(ploop->nr_deltas);
+               WARN_ON_ONCE(ploop->nr_deltas != 1);
                if (success)
                        ploop_release_cluster(ploop, cluster);
        }
@@ -1387,7 +1387,7 @@ static int process_one_discard_bio(struct ploop *ploop, 
struct bio *bio,
        map_index_t *to;
        struct pio *h;
 
-       WARN_ON(ploop->nr_deltas);
+       WARN_ON(ploop->nr_deltas != 1);
 
        h = bio_to_endio_hook(bio);
        cluster = h->cluster;
diff --git a/drivers/md/dm-ploop-target.c b/drivers/md/dm-ploop-target.c
index e3955819f341..5797ff2660cd 100644
--- a/drivers/md/dm-ploop-target.c
+++ b/drivers/md/dm-ploop-target.c
@@ -173,25 +173,6 @@ static void ploop_destroy(struct ploop *ploop)
        kfree(ploop);
 }
 
-static int ploop_check_origin_dev(struct dm_target *ti, struct ploop *ploop, 
u8 nr_deltas)
-{
-       struct block_device *bdev = ploop->origin_dev->bdev;
-       int r;
-
-       if (bdev->bd_block_size < PAGE_SIZE) {
-               ti->error = "Origin dev has too small block size";
-               return -EINVAL;
-       }
-
-       r = ploop_read_metadata(ti, ploop, nr_deltas);
-       if (r) {
-               ti->error = "Can't read ploop header";
-               return r;
-       }
-
-       return 0;
-}
-
 static struct file * get_delta_file(int fd)
 {
        struct file *file;
@@ -207,17 +188,57 @@ static struct file * get_delta_file(int fd)
        return file;
 }
 
+static int check_top_delta(struct ploop *ploop, struct file *file)
+{
+       u32 nr, *bat_entries;
+       struct md_page *md0;
+       int ret;
+
+       /* Prealloc a page to read hdr */
+       ret = prealloc_md_pages(&ploop->bat_entries, 0, 1);
+       if (ret)
+               goto out;
+
+       ret = -ENXIO;
+       md0 = md_page_find(ploop, 0);
+       if (!md0)
+               goto out;
+
+       ret = rw_page_sync(READ, file, 0, md0->page);
+       if (ret < 0)
+               goto out;
+
+       bat_entries = kmap(md0->page);
+       nr = PAGE_SIZE / sizeof(u32) - PLOOP_MAP_OFFSET;
+       ret = convert_bat_entries(bat_entries + PLOOP_MAP_OFFSET, nr);
+       kunmap(md0->page);
+       if (ret) {
+               pr_err("Can't read BAT\n");
+               goto out;
+       }
+
+       ret = ploop_setup_metadata(ploop, md0->page);
+       if (ret)
+               goto out;
+       /* Alloc rest of pages */
+       ret = prealloc_md_pages(&ploop->bat_entries, 1, ploop->nr_bat_entries);
+       if (ret)
+               goto out;
+out:
+       return ret;
+}
+
 static int ploop_add_deltas_stack(struct ploop *ploop, char **argv, int argc)
 {
        struct ploop_delta *deltas;
-       int i, delta_fd, ret = 0;
+       int i, delta_fd, ret;
        struct file *file;
        const char *arg;
        bool is_raw;
 
-       if (!argc)
-               goto out;
        ret = -EINVAL;
+       if (argc < 1)
+               goto out;
        if (argc > BAT_LEVEL_MAX - 1)
                goto out;
 
@@ -247,16 +268,23 @@ static int ploop_add_deltas_stack(struct ploop *ploop, 
char **argv, int argc)
                        goto out;
                }
 
-               ret = ploop_add_delta(ploop, i, file, is_raw);
-               if (ret < 0) {
-                       fput(file);
-                       goto out;
+               if (i == argc - 1) { /* Top delta */
+                       ret = check_top_delta(ploop, file);
+                       if (ret)
+                               goto err_fput;
                }
+
+               ret = ploop_add_delta(ploop, i, file, is_raw);
+               if (ret < 0)
+                       goto err_fput;
        }
 
        ret = 0;
 out:
        return ret;
+err_fput:
+       fput(file);
+       goto out;
 }
 /*
  * <data dev>
@@ -337,12 +365,6 @@ static int ploop_ctr(struct dm_target *ti, unsigned int 
argc, char **argv)
                goto err;
        }
 
-       ret = ploop_check_origin_dev(ti, ploop, argc - 2);
-       if (ret) {
-               /* ploop_check_origin_dev() assigns ti->error */
-               goto err;
-       }
-
        ret = ploop_add_deltas_stack(ploop, &argv[2], argc - 2);
        if (ret)
                goto err;
@@ -422,7 +444,7 @@ static void ploop_status(struct dm_target *ti, 
status_type_t type,
        if (p == stat)
                p += sprintf(p, "o");
        BUG_ON(p - stat >= sizeof(stat));
-       DMEMIT("%s %u v2 %u %s", ploop->origin_dev->name, ploop->nr_deltas,
+       DMEMIT("%u v2 %u %s", ploop->nr_deltas,
                1 << ploop->cluster_log, stat);
        read_unlock_irq(&ploop->bat_rwlock);
 }
diff --git a/drivers/md/dm-ploop.h b/drivers/md/dm-ploop.h
index 290924dc9b54..f8194e3869d7 100644
--- a/drivers/md/dm-ploop.h
+++ b/drivers/md/dm-ploop.h
@@ -319,7 +319,7 @@ static inline bool whole_cluster(struct ploop *ploop, 
struct bio *bio)
 #define BAT_LEVEL_MAX          (U8_MAX - 1)
 static inline u8 top_level(struct ploop *ploop)
 {
-       return ploop->nr_deltas;
+       return ploop->nr_deltas - 1;
 }
 
 static inline void ploop_hole_set_bit(unsigned long nr, struct ploop *ploop)
@@ -484,6 +484,7 @@ extern void 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, unsigned int cluster,
                                 u8 level, unsigned int dst_cluster);
+extern int convert_bat_entries(u32 *bat_entries, u32 count);
 
 extern int ploop_add_delta(struct ploop *ploop, u32 level, struct file *file, 
bool is_raw);
 extern void defer_bios(struct ploop *ploop, struct bio *bio, struct bio_list 
*bio_list);
@@ -517,7 +518,7 @@ extern void cleanup_backup(struct ploop *ploop);
 
 extern int ploop_read_cluster_sync(struct ploop *, struct bio *, unsigned int);
 
-extern int ploop_read_metadata(struct dm_target *ti, struct ploop *ploop, u8 
nr_deltas);
+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);
 extern void call_rw_iter(struct file *file, loff_t pos, unsigned rw,


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

Reply via email to