[Devel] [PATCH RH8 08/14] push_backup: Do not split bios by cluster size
Kirill Tkhai
ktkhai at virtuozzo.com
Mon Sep 6 18:34:51 MSK 2021
Splitting leads to allocation more dm bios.
Also, it won't be possible after switch
to request-based dev.
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
drivers/md/dm-push-backup.c | 130 ++++++++++++++++++++++++++++++-------------
1 file changed, 91 insertions(+), 39 deletions(-)
diff --git a/drivers/md/dm-push-backup.c b/drivers/md/dm-push-backup.c
index 66c55e5aa07f..77c41680730b 100644
--- a/drivers/md/dm-push-backup.c
+++ b/drivers/md/dm-push-backup.c
@@ -26,7 +26,9 @@ static inline struct hlist_head *pb_htable_slot(struct hlist_head head[], u32 cl
struct pb_bio {
struct hlist_node hlist_node;
- u64 clu;
+ u64 start_clu;
+ u64 end_clu;
+ u64 key_clu; /* Cluster, we are waiting at the moment */
struct list_head list;
};
@@ -75,29 +77,66 @@ static inline void remap_to_origin(struct push_backup *pb, struct bio *bio)
bio_set_dev(bio, pb->origin_dev->bdev);
}
-static int pb_bio_cluster(struct push_backup *pb, struct bio *bio, u64 *clu)
+static u64 pbio_first_required_for_backup_clu(struct push_backup *pb, struct pb_bio *pbio)
+{
+ u64 clu;
+
+ for (clu = pbio->start_clu; clu <= pbio->end_clu; clu++)
+ if (test_bit(clu, pb->map))
+ return clu;
+ return U64_MAX;
+}
+static u64 pbio_last_required_for_backup_clu(struct push_backup *pb, struct pb_bio *pbio)
+{
+ u64 clu;
+
+ for (clu = pbio->end_clu; clu >= pbio->start_clu; clu--) {
+ if (test_bit(clu, pb->map))
+ return clu;
+ if (clu == 0)
+ break;
+ }
+ return U64_MAX;
+}
+
+static void calc_bio_clusters(struct push_backup *pb, struct pb_bio *pbio)
{
+ struct bio *bio = pbio_to_bio(pbio);
loff_t off = to_bytes(bio->bi_iter.bi_sector);
- u64 start_clu, end_clu;
- start_clu = off / pb->clu_size;
- end_clu = (off + bio->bi_iter.bi_size - 1) / pb->clu_size;
+ pbio->start_clu = off / pb->clu_size;
+ pbio->end_clu = (off + bio->bi_iter.bi_size - 1) / pb->clu_size;
+}
- if (unlikely(start_clu != end_clu))
- return -EIO;
+static bool setup_if_required_for_backup(struct push_backup *pb, struct pb_bio *pbio)
+{
+ u64 key;
- *clu = start_clu;
- return 0;
+ calc_bio_clusters(pb, pbio);
+
+ key = pbio_last_required_for_backup_clu(pb, pbio);
+ if (key != U64_MAX) {
+ pbio->key_clu = key;
+ return true;
+ }
+ return false;
}
-static void link_pending_pbio(struct push_backup *pb, struct pb_bio *pbio, u64 clu)
+static void update_pending_map(struct push_backup *pb, struct pb_bio *pbio)
{
- struct hlist_head *slot = pb_htable_slot(pb->pending_htable, clu);
+ u64 clu;
+
+ for (clu = pbio->start_clu; clu <= pbio->end_clu; clu++)
+ if (test_bit(clu, pb->map))
+ set_bit(clu, pb->pending_map);
+}
+
+static void link_pending_pbio(struct push_backup *pb, struct pb_bio *pbio)
+{
+ struct hlist_head *slot = pb_htable_slot(pb->pending_htable, pbio->key_clu);
hlist_add_head(&pbio->hlist_node, slot);
list_add_tail(&pbio->list, &pb->pending);
-
- pbio->clu = clu;
}
static void unlink_pending_pbio(struct push_backup *pb, struct pb_bio *pbio)
@@ -106,13 +145,22 @@ static void unlink_pending_pbio(struct push_backup *pb, struct pb_bio *pbio)
list_del_init(&pbio->list);
}
+static void relink_pending_pbio(struct push_backup *pb, struct pb_bio *pbio, u64 key)
+{
+ struct hlist_head *slot = pb_htable_slot(pb->pending_htable, key);
+
+ hlist_del_init(&pbio->hlist_node);
+ pbio->key_clu = key;
+ hlist_add_head(&pbio->hlist_node, slot);
+}
+
static struct pb_bio *find_pending_pbio(struct push_backup *pb, u64 clu)
{
struct hlist_head *slot = pb_htable_slot(pb->pending_htable, clu);
struct pb_bio *pbio;
hlist_for_each_entry(pbio, slot, hlist_node)
- if (pbio->clu == clu)
+ if (pbio->key_clu == clu)
return pbio;
return NULL;
@@ -191,28 +239,26 @@ static void pb_timer_func(struct timer_list *timer)
}
static bool postpone_if_required_for_backup(struct push_backup *pb,
- struct bio *bio, u64 clu)
+ struct bio *bio)
{
bool queue_timer = false, postpone = false;
- struct pb_bio *pbio;
+ struct pb_bio *pbio = bio_to_pbio(bio);
unsigned long flags;
rcu_read_lock(); /* See push_backup_stop() */
spin_lock_irqsave(&pb->lock, flags);
- if (likely(!pb->alive) || !test_bit(clu, pb->map))
+ if (!pb->alive || !setup_if_required_for_backup(pb, pbio))
goto unlock;
+ update_pending_map(pb, pbio);
+ link_pending_pbio(pb, pbio);
+
postpone = true;
pb->nr_delayed += 1;
if (pb->nr_delayed == 1) {
pb->deadline_jiffies = get_jiffies_64() + pb->timeout_in_jiffies;
queue_timer = true;
}
-
- pbio = bio_to_pbio(bio);
-
- link_pending_pbio(pb, pbio, clu);
- set_bit(clu, pb->pending_map);
unlock:
spin_unlock_irqrestore(&pb->lock, flags);
@@ -231,22 +277,17 @@ static void init_pb_bio(struct bio *bio)
struct pb_bio *pbio = bio_to_pbio(bio);
INIT_HLIST_NODE(&pbio->hlist_node);
- pbio->clu = UINT_MAX;
INIT_LIST_HEAD(&pbio->list);
}
static int pb_map(struct dm_target *ti, struct bio *bio)
{
struct push_backup *pb = ti->private;
- u64 clu;
init_pb_bio(bio);
if (bio_sectors(bio) && op_is_write(bio->bi_opf)) {
- if (pb_bio_cluster(pb, bio, &clu))
- return DM_MAPIO_KILL;
-
- if (postpone_if_required_for_backup(pb, bio, clu))
+ if (postpone_if_required_for_backup(pb, bio))
return DM_MAPIO_SUBMITTED;
}
@@ -378,7 +419,11 @@ static int push_backup_read(struct push_backup *pb,
goto again;
}
- left = pbio->clu;
+ ret = -EBADMSG;
+ left = pbio_first_required_for_backup_clu(pb, pbio);
+ if (WARN_ON_ONCE(left == U64_MAX))
+ goto unlock;
+
right = find_next_zero_bit(pb->pending_map, pb->nr_clus, left + 1);
if (right < pb->nr_clus)
right -= 1;
@@ -396,8 +441,8 @@ static int push_backup_write(struct push_backup *pb,
unsigned int clu, unsigned int nr)
{
struct bio_list bio_list = BIO_EMPTY_LIST;
+ u64 i, key, nr_clus = pb->nr_clus;
bool finished, has_more = false;
- u64 i, nr_clus = pb->nr_clus;
struct pb_bio *pbio;
if (!pb)
@@ -428,6 +473,22 @@ static int push_backup_write(struct push_backup *pb,
pbio = find_pending_pbio(pb, i);
if (!pbio)
break;
+ key = pbio_last_required_for_backup_clu(pb, pbio);
+ if (key != U64_MAX) {
+ /*
+ * There is one or more clusters-to-backup
+ * required for this bio. Wait for them.
+ * Userspace possible backups clusters
+ * from smallest to biggest, so we use
+ * last clu as key.
+ */
+ relink_pending_pbio(pb, pbio, key);
+ continue;
+ }
+ /*
+ * All clusters of this bios were backuped or
+ * they are not needed for backup.
+ */
unlink_postponed_backup_pbio(pb, &bio_list, pbio);
}
}
@@ -586,15 +647,6 @@ static int pb_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
pb->clu_size = to_bytes(sectors);
pb->nr_clus = DIV_ROUND_UP(ti->len, sectors);
- /*
- * TODO: we may avoid splitting bio by cluster size.
- * Tree search, read, write, etc should be changed.
- */
- ret = dm_set_target_max_io_len(ti, sectors);
- if (ret) {
- ti->error = "could not set max_io_len";
- goto err;
- }
/*
* We do not add FMODE_EXCL, because further open_table_device()
More information about the Devel
mailing list