(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