[Devel] [PATCH RH8 07/61] ploop: Setup device from file
Kirill Tkhai
ktkhai at virtuozzo.com
Fri May 14 18:55:13 MSK 2021
(Comment some code to use it to optimize delta BAT parse)
Signed-off-by: Kirill Tkhai <ktkhai at 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,
More information about the Devel
mailing list