[Devel] [PATCH rh7] ploop: push_backup: optimize ploop_pb_put_reported()

Maxim Patlasov mpatlasov at virtuozzo.com
Fri May 13 18:07:28 PDT 2016


To process an extent [clu, clu + len) coming from userspace, let's firstly
find the leftmost preq in the tree matching this interval.

Then, we can iterate to the right by rb_next() until we meet a preq that
doesn't match.

That's it because any preq to the right would have any higher req_cluster,
and hence doesn't match too.

https://jira.sw.ru/browse/PSBM-45000

Signed-off-by: Maxim Patlasov <mpatlasov at virtuozzo.com>
---
 drivers/block/ploop/dev.c         |    9 +--
 drivers/block/ploop/push_backup.c |  107 +++++++++++++++++++++++++------------
 2 files changed, 73 insertions(+), 43 deletions(-)

diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index c103b79..e2c5d9e 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -4627,13 +4627,8 @@ static int ploop_push_backup_io_write(struct ploop_device *plo, unsigned long ar
 		goto io_write_done;
 
 	rc = 0;
-	for (i = 0; i < ctl->n_extents; i++) {
-		cluster_t j;
-		for (j = e[i].clu; j < e[i].clu + e[i].len; j++)
-			ploop_pb_put_reported(plo->pbd, j, 1);
-                /* OPTIMIZE ME LATER: like this:
-		 * ploop_pb_put_reported(plo->pbd, e[i].clu, e[i].len); */
-	}
+	for (i = 0; i < ctl->n_extents; i++)
+		ploop_pb_put_reported(plo->pbd, e[i].clu, e[i].len);
 
 io_write_done:
 	kfree(e);
diff --git a/drivers/block/ploop/push_backup.c b/drivers/block/ploop/push_backup.c
index 3a46339..98e2f1e 100644
--- a/drivers/block/ploop/push_backup.c
+++ b/drivers/block/ploop/push_backup.c
@@ -329,11 +329,23 @@ static void ploop_pb_add_req_to_reported(struct ploop_pushbackup_desc *pbd,
 	ploop_pb_add_req_to_tree(preq, &pbd->reported_tree);
 }
 
+static inline bool preq_match(struct ploop_request *preq, cluster_t clu,
+			      cluster_t len)
+{
+	return preq &&
+		clu <= preq->req_cluster &&
+		preq->req_cluster < clu + len;
+}
+
+/* returns leftmost preq which req_cluster >= clu */
 static struct ploop_request *ploop_pb_get_req_from_tree(struct rb_root *tree,
-							cluster_t clu)
+						cluster_t clu, cluster_t len,
+						struct ploop_request **npreq)
 {
 	struct rb_node *n = tree->rb_node;
-	struct ploop_request *p;
+	struct ploop_request *p = NULL;
+
+	*npreq = NULL;
 
 	while (n) {
 		p = rb_entry(n, struct ploop_request, reloc_link);
@@ -342,11 +354,31 @@ static struct ploop_request *ploop_pb_get_req_from_tree(struct rb_root *tree,
 			n = n->rb_left;
 		else if (clu > p->req_cluster)
 			n = n->rb_right;
-		else {
+		else { /* perfect match */
+			n = rb_next(n);
+			if (n)
+				*npreq = rb_entry(n, struct ploop_request,
+						  reloc_link);
 			rb_erase(&p->reloc_link, tree);
 			return p;
 		}
 	}
+	/* here p is not perfect, but it's closest */
+
+	if (p && p->req_cluster < clu) {
+		n = rb_next(&p->reloc_link);
+		if (n)
+			p = rb_entry(n, struct ploop_request, reloc_link);
+	}
+
+	if (preq_match(p, clu, len)) {
+		n = rb_next(&p->reloc_link);
+		if (n)
+			*npreq = rb_entry(n, struct ploop_request, reloc_link);
+		rb_erase(&p->reloc_link, tree);
+		return p;
+	}
+
 	return NULL;
 }
 
@@ -393,20 +425,6 @@ ploop_pb_get_first_req_from_reported(struct ploop_pushbackup_desc *pbd)
 	return ploop_pb_get_first_req_from_tree(&pbd->reported_tree, NULL);
 }
 
-static struct ploop_request *
-ploop_pb_get_req_from_pending(struct ploop_pushbackup_desc *pbd,
-			      cluster_t clu)
-{
-	return ploop_pb_get_req_from_tree(&pbd->pending_tree, clu);
-}
-
-static struct ploop_request *
-ploop_pb_get_req_from_reported(struct ploop_pushbackup_desc *pbd,
-			       cluster_t clu)
-{
-	return ploop_pb_get_req_from_tree(&pbd->reported_tree, clu);
-}
-
 int ploop_pb_preq_add_pending(struct ploop_pushbackup_desc *pbd,
 			       struct ploop_request *preq)
 {
@@ -552,27 +570,46 @@ get_pending_unlock:
 	return err;
 }
 
+static void ploop_pb_process_extent(struct rb_root *tree, cluster_t clu,
+				    cluster_t len, struct list_head *ready_list,
+				    int *n_found)
+{
+	struct ploop_request *preq, *npreq;
+
+	preq = ploop_pb_get_req_from_tree(tree, clu, len, &npreq);
+
+	while (preq) {
+		struct rb_node *n;
+
+		__set_bit(PLOOP_REQ_PUSH_BACKUP, &preq->state);
+		list_add(&preq->list, ready_list);
+
+		if (n_found)
+			(*n_found)++;
+
+		if (!preq_match(npreq, clu, len))
+			break;
+
+		preq = npreq;
+		n = rb_next(&preq->reloc_link);
+		if (n)
+			npreq = rb_entry(n, struct ploop_request, reloc_link);
+		else
+			npreq = NULL;
+		rb_erase(&preq->reloc_link, tree);
+	}
+}
+
 void ploop_pb_put_reported(struct ploop_pushbackup_desc *pbd,
 			   cluster_t clu, cluster_t len)
 {
-	struct ploop_request *preq;
 	int n_found = 0;
-
-	/* OPTIMIZE ME LATER: find leftmost item for [clu, clu+len),
-	 * then rb_next() while req_cluster < clu+len.
-	 * Do this firstly for reported, then for pending */
-	BUG_ON(len != 1);
+	LIST_HEAD(ready_list);
 
 	spin_lock(&pbd->ppb_lock);
 
-	preq = ploop_pb_get_req_from_reported(pbd, clu);
-	if (!preq)
-		preq = ploop_pb_get_req_from_pending(pbd, clu);
-	else
-		n_found++;
-
-	if (preq)
-		__set_bit(PLOOP_REQ_PUSH_BACKUP, &preq->state);
+	ploop_pb_process_extent(&pbd->reported_tree, clu, len, &ready_list, &n_found);
+	ploop_pb_process_extent(&pbd->pending_tree, clu, len, &ready_list, NULL);
 
 	/*
 	 * If preq not found above, it's unsolicited report. Then it's
@@ -600,13 +637,11 @@ void ploop_pb_put_reported(struct ploop_pushbackup_desc *pbd,
 
 	spin_unlock(&pbd->ppb_lock);
 
-	if (preq) {
-		struct ploop_device *plo = preq->plo;
-		BUG_ON(preq->req_cluster != clu);
-		BUG_ON(plo != pbd->plo);
+	if (!list_empty(&ready_list)) {
+		struct ploop_device *plo = pbd->plo;
 
 		spin_lock_irq(&plo->lock);
-		list_add_tail(&preq->list, &plo->ready_queue);
+		list_splice(&ready_list, plo->ready_queue.prev);
 		if (test_bit(PLOOP_S_WAIT_PROCESS, &plo->state))
 			wake_up_interruptible(&plo->waitq);
 		spin_unlock_irq(&plo->lock);



More information about the Devel mailing list