[Devel] [PATCH RHEL7 COMMIT] ploop: push_backup: implement timeout functions

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jun 27 00:11:24 PDT 2016


The commit is pushed to "branch-rh7-3.10.0-327.18.2.vz7.14.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.18.2.vz7.14.20
------>
commit 352797f8af8bde875f03655319ebbf9e98696801
Author: Maxim Patlasov <mpatlasov at virtuozzo.com>
Date:   Mon Jun 27 11:11:24 2016 +0400

    ploop: push_backup: implement timeout functions
    
    If timeout fired, the function must scan the pending/reported lists
    searching for expired preq. If at least one expired preq found,
    the function must abort the whole push_backup operation merging
    initial CBT mask back to CBT.
    
    It is not nice to call heavy-weight ploop_pb_stop() directly from
    timeout handler, so we only change pbd->ppb_state in the handler,
    and wake up ploop_pb_health_monitor(). The latter will do the rest.
    
    The strategy of handling pending_set/reported_set timers consits of
    three cases (having in mind that the first preq in the set list is
    always the oldest):
    
    1) The first preq coming to the set arms the timer.
    2) If we delete the first preq from the list, we have to
    modify the timer according to the next preq timestamp.
    3) If timer fired, but no expired preq found, let's
    re-schedule timer according to the oldest preq timestamp.
    
    https://jira.sw.ru/browse/PSBM-48082
    
    Signed-off-by: Maxim Patlasov <mpatlasov at virtuozzo.com>
---
 drivers/block/ploop/push_backup.c | 78 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/drivers/block/ploop/push_backup.c b/drivers/block/ploop/push_backup.c
index 8fae402..4e2404c 100644
--- a/drivers/block/ploop/push_backup.c
+++ b/drivers/block/ploop/push_backup.c
@@ -470,6 +470,7 @@ static void ploop_pb_add_req_to_tree(struct ploop_request *preq,
 	struct rb_node ** p = &tree->rb_node;
 	struct rb_node *parent = NULL;
 	struct ploop_request * pr;
+	unsigned long timeout = preq->plo->tune.push_backup_timeout * HZ;
 
 	while (*p) {
 		parent = *p;
@@ -482,6 +483,11 @@ static void ploop_pb_add_req_to_tree(struct ploop_request *preq,
 			p = &(*p)->rb_right;
 	}
 
+	preq->tstamp = jiffies;
+	if (timeout && list_empty(&pbs->list) &&
+	    pbs->pbd->ppb_state == PLOOP_PB_ALIVE)
+		mod_timer(&pbs->timer, preq->tstamp + timeout + 1);
+
 	list_add_tail(&preq->list, &pbs->list);
 
 	rb_link_node(&preq->reloc_link, parent, p);
@@ -503,8 +509,21 @@ static void ploop_pb_add_req_to_reported(struct ploop_pushbackup_desc *pbd,
 static void remove_req_from_pbs(struct pb_set *pbs,
 					 struct ploop_request *preq)
 {
+	unsigned long timeout = preq->plo->tune.push_backup_timeout * HZ;
+	bool oldest_deleted = false;
+
+	if (preq == list_first_entry(&pbs->list, struct ploop_request, list))
+		oldest_deleted = true;
+
 	rb_erase(&preq->reloc_link, &pbs->tree);
 	list_del_init(&preq->list);
+
+	if (timeout && oldest_deleted && !list_empty(&pbs->list) &&
+	    pbs->pbd->ppb_state == PLOOP_PB_ALIVE) {
+		preq = list_first_entry(&pbs->list, struct ploop_request,
+					list);
+		mod_timer(&pbs->timer, preq->tstamp + timeout + 1);
+	}
 }
 
 
@@ -942,6 +961,65 @@ int ploop_pb_destroy(struct ploop_device *plo, __u32 *status)
 	return 0;
 }
 
+static bool ploop_pb_set_expired(struct pb_set *pbs)
+{
+	struct ploop_pushbackup_desc *pbd = pbs->pbd;
+	struct ploop_device          *plo = pbd->plo;
+	unsigned long timeout = plo->tune.push_backup_timeout * HZ;
+	unsigned long tstamp = 0;
+	cluster_t clu = 0;
+	bool ret = false;
+
+	if (!timeout)
+		return false;
+
+	spin_lock(&pbd->ppb_lock);
+
+	if (pbd->ppb_state != PLOOP_PB_ALIVE) {
+		spin_unlock(&pbd->ppb_lock);
+		return false;
+	}
+
+	/* No need to scan the whole list: the first preq is the oldest! */
+	if (!list_empty(&pbs->list)) {
+		struct ploop_request *preq = list_first_entry(&pbs->list,
+							      struct ploop_request, list);
+		if (time_before(preq->tstamp + timeout, jiffies)) {
+			tstamp = preq->tstamp;
+			clu = preq->req_cluster;
+			ret = true;
+		} else
+			mod_timer(&pbs->timer, preq->tstamp + timeout + 1);
+	}
+
+	spin_unlock(&pbd->ppb_lock);
+
+	if (ret)
+		printk(KERN_WARNING "Abort push_backup for ploop%d: found "
+		       "preq (clu=%d) in %s tree delayed for %u msecs\n",
+		       plo->index, clu, pbs->name,
+		       jiffies_to_msecs(jiffies - tstamp));
+
+	return ret;
+}
+
 static void ploop_pb_timeout_func(unsigned long data)
 {
+	struct pb_set                *pbs = (void*)data;
+	struct ploop_pushbackup_desc *pbd = pbs->pbd;
+	struct ploop_device          *plo = pbd->plo;
+
+	if (!plo->tune.push_backup_timeout ||
+	    !test_bit(PLOOP_S_RUNNING, &plo->state) ||
+	    !test_bit(PLOOP_S_PUSH_BACKUP, &plo->state) ||
+	    !ploop_pb_set_expired(pbs))
+		return;
+
+	spin_lock(&pbd->ppb_lock);
+	if (pbd->ppb_state == PLOOP_PB_ALIVE) {
+		pbd->ppb_state = PLOOP_PB_STOPPING;
+		if (waitqueue_active(&pbd->ppb_waitq))
+			wake_up_interruptible(&pbd->ppb_waitq);
+	}
+	spin_unlock(&pbd->ppb_lock);
 }


More information about the Devel mailing list