[Devel,RHEL7,COMMIT] ploop: introduce plo->blockable_reqs counter

Submitted by Konstantin Khorenko on July 19, 2016, 9:43 a.m.

Details

Message ID 201607190943.u6J9hbTW016478@finist_cl7.x64_64.work.ct
State New
Series "ploop: introduce plo->blockable_reqs counter"
Headers show

Commit Message

Konstantin Khorenko July 19, 2016, 9:43 a.m.
The commit is pushed to "branch-rh7-3.10.0-327.18.2.vz7.15.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.18.2.vz7.14.27
------>
commit 293456e443367f049c070d5bcc412841cbf0d9d2
Author: Maxim Patlasov <mpatlasov@virtuozzo.com>
Date:   Tue Jul 19 13:43:37 2016 +0400

    ploop: introduce plo->blockable_reqs counter
    
    The counter represents the number of ploop requests that
    potentially can be blocked due to push_backup: let's call
    them "blockable" requersts. In the other words they are
    those who is going to be dependent on userspace backup tool.
    
    We claim a preq as "blockable" if, at the time of converting
    incoming bio to the preq, we observe corresponding bit in
    pbd->ppb_map set, and corresponding bit in pbd->reported_map
    is clear.
    
    In case of in-flight conversion (ploop_make_request calling
    process_bio_queue) the decision is posponed until ploop_thread
    process preq by ploop_req_state_process(). This is done
    intentionally, to avoid locking scheme complication.
    
    The counter will be used by next patch of this patch-set.
    
    https://jira.sw.ru/browse/PSBM-49454
    
    Signed-off-by: Maxim Patlasov <mpatlasov@virtuozzo.com>
---
 drivers/block/ploop/dev.c         | 36 ++++++++++++++++++++++++++++++------
 drivers/block/ploop/push_backup.c | 22 ++++++++++++++++++++++
 drivers/block/ploop/push_backup.h |  1 +
 drivers/block/ploop/sysfs.c       |  6 ++++++
 include/linux/ploop/ploop.h       |  2 ++
 5 files changed, 61 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index 2ff3ac1..174b3c6 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -227,6 +227,20 @@  static inline void preq_unlink(struct ploop_request * preq,
 	list_add(&preq->list, drop_list);
 }
 
+static void ploop_set_blockable(struct ploop_device *plo,
+				struct ploop_request *preq)
+{
+	if (!test_and_set_bit(PLOOP_REQ_BLOCKABLE, &preq->state))
+		plo->blockable_reqs++;
+}
+
+static void ploop_test_and_clear_blockable(struct ploop_device *plo,
+					   struct ploop_request *preq)
+{
+	if (test_and_clear_bit(PLOOP_REQ_BLOCKABLE, &preq->state))
+		plo->blockable_reqs--;
+}
+
 /* always called with plo->lock released */
 void ploop_preq_drop(struct ploop_device * plo, struct list_head *drop_list,
 		      int keep_locked)
@@ -242,6 +256,7 @@  void ploop_preq_drop(struct ploop_device * plo, struct list_head *drop_list,
 		}
 
 		BUG_ON (test_bit(PLOOP_REQ_ZERO, &preq->state));
+		ploop_test_and_clear_blockable(plo, preq);
 		drop_qlen++;
 	}
 
@@ -489,7 +504,7 @@  insert_entry_tree(struct ploop_device * plo, struct ploop_request * preq0,
 
 static void
 ploop_bio_queue(struct ploop_device * plo, struct bio * bio,
-		struct list_head *drop_list)
+		struct list_head *drop_list, int account_blockable)
 {
 	struct ploop_request * preq;
 
@@ -511,6 +526,10 @@  ploop_bio_queue(struct ploop_device * plo, struct bio * bio,
 	preq->iblock = 0;
 	preq->prealloc_size = 0;
 
+	if (account_blockable && (bio->bi_rw & REQ_WRITE) && bio->bi_size &&
+	    ploop_pb_check_and_clear_bit(plo->pbd, preq->req_cluster))
+		ploop_set_blockable(plo, preq);
+
 	if (unlikely(bio->bi_rw & REQ_DISCARD)) {
 		int clu_size = 1 << plo->cluster_log;
 		int i = (clu_size - 1) & bio->bi_sector;
@@ -734,7 +753,9 @@  preallocate_bio(struct bio * orig_bio, struct ploop_device * plo)
 	return nbio;
 }
 
-static void process_bio_queue(struct ploop_device * plo, struct list_head *drop_list)
+static void process_bio_queue(struct ploop_device * plo,
+			      struct list_head *drop_list,
+			      int account_blockable)
 {
 	while (plo->bio_head && !list_empty(&plo->free_list)) {
 		struct bio *tmp = plo->bio_head;
@@ -744,7 +765,7 @@  static void process_bio_queue(struct ploop_device * plo, struct list_head *drop_
 		if (!plo->bio_head)
 			plo->bio_tail = NULL;
 
-		ploop_bio_queue(plo, tmp, drop_list);
+		ploop_bio_queue(plo, tmp, drop_list, account_blockable);
 	}
 }
 
@@ -796,7 +817,7 @@  process_discard_bio_queue(struct ploop_device * plo, struct list_head *drop_list
 		/* If PLOOP_S_DISCARD isn't set, ploop_bio_queue
 		 * will complete it with a proper error.
 		 */
-		ploop_bio_queue(plo, tmp, drop_list);
+		ploop_bio_queue(plo, tmp, drop_list, 0);
 	}
 }
 
@@ -1001,7 +1022,7 @@  queue:
 	ploop_congest(plo);
 
 	/* second chance to merge requests */
-	process_bio_queue(plo, &drop_list);
+	process_bio_queue(plo, &drop_list, 0);
 
 queued:
 	/* If main thread is waiting for requests, wake it up.
@@ -1371,6 +1392,7 @@  static void ploop_complete_request(struct ploop_request * preq)
 
 	del_lockout(preq);
 	del_pb_lockout(preq); /* preq may die via ploop_fail_immediate() */
+	ploop_test_and_clear_blockable(plo, preq);
 
 	if (!list_empty(&preq->delay_list))
 		list_splice_init(&preq->delay_list, plo->ready_queue.prev);
@@ -2139,6 +2161,7 @@  restart:
 		} else {
 			/* needn't lock because only ploop_thread accesses */
 			ploop_add_pb_lockout(preq);
+			ploop_set_blockable(plo, preq);
 			/*
 			 * preq IN: preq is in ppb_pending tree waiting for
 			 * out-of-band push_backup processing by userspace ...
@@ -2152,6 +2175,7 @@  restart:
 		 * userspace done; preq was re-scheduled
 		 */
 		ploop_pb_clear_bit(plo->pbd, preq->req_cluster);
+		ploop_test_and_clear_blockable(plo, preq);
 
 		del_pb_lockout(preq);
 		spin_lock_irq(&plo->lock);
@@ -2855,7 +2879,7 @@  static int ploop_thread(void * data)
 	again:
 		BUG_ON (!list_empty(&drop_list));
 
-		process_bio_queue(plo, &drop_list);
+		process_bio_queue(plo, &drop_list, 1);
 		process_discard_bio_queue(plo, &drop_list);
 
 		if (!list_empty(&drop_list)) {
diff --git a/drivers/block/ploop/push_backup.c b/drivers/block/ploop/push_backup.c
index 4e2404c..c58aadf 100644
--- a/drivers/block/ploop/push_backup.c
+++ b/drivers/block/ploop/push_backup.c
@@ -657,6 +657,28 @@  int ploop_pb_preq_add_pending(struct ploop_pushbackup_desc *pbd,
 	return 0;
 }
 
+bool ploop_pb_check_and_clear_bit(struct ploop_pushbackup_desc *pbd,
+				  cluster_t clu)
+{
+	if (!pbd)
+		return false;
+
+	if (!check_bit_in_map(pbd->ppb_map, pbd->ppb_block_max, clu))
+		return false;
+
+	spin_lock(&pbd->ppb_lock);
+
+	if (pbd->ppb_state != PLOOP_PB_ALIVE ||
+	    check_bit_in_map(pbd->reported_map, pbd->ppb_block_max, clu)) {
+		spin_unlock(&pbd->ppb_lock);
+		ploop_pb_clear_bit(pbd, clu);
+		return false;
+	}
+
+	spin_unlock(&pbd->ppb_lock);
+	return true;
+}
+
 /* Always serialized by plo->ctl_mutex */
 unsigned long ploop_pb_stop(struct ploop_pushbackup_desc *pbd, bool do_merge)
 {
diff --git a/drivers/block/ploop/push_backup.h b/drivers/block/ploop/push_backup.h
index 5333537..0d479e0 100644
--- a/drivers/block/ploop/push_backup.h
+++ b/drivers/block/ploop/push_backup.h
@@ -24,6 +24,7 @@  void ploop_pb_put_reported(struct ploop_pushbackup_desc *pbd,
 
 void ploop_pb_clear_bit(struct ploop_pushbackup_desc *pbd, cluster_t clu);
 bool ploop_pb_check_bit(struct ploop_pushbackup_desc *pbd, cluster_t clu);
+bool ploop_pb_check_and_clear_bit(struct ploop_pushbackup_desc *pbd, cluster_t clu);
 
 int ploop_pb_preq_add_pending(struct ploop_pushbackup_desc *pbd,
 			       struct ploop_request *preq);
diff --git a/drivers/block/ploop/sysfs.c b/drivers/block/ploop/sysfs.c
index c062c1e..2160fb31 100644
--- a/drivers/block/ploop/sysfs.c
+++ b/drivers/block/ploop/sysfs.c
@@ -435,6 +435,11 @@  static u32 show_free_qmax(struct ploop_device * plo)
 	return plo->free_qmax;
 }
 
+static u32 show_blockable_reqs(struct ploop_device * plo)
+{
+	return plo->blockable_reqs;
+}
+
 #define _TUNE_U32(_name)				\
 static u32 show_##_name(struct ploop_device * plo)	\
 {							\
@@ -519,6 +524,7 @@  static struct attribute *state_attributes[] = {
 	_A(open_count),
 	_A(free_reqs),
 	_A(free_qmax),
+	_A(blockable_reqs),
 	NULL
 };
 
diff --git a/include/linux/ploop/ploop.h b/include/linux/ploop/ploop.h
index d2d3165..5d81b1c 100644
--- a/include/linux/ploop/ploop.h
+++ b/include/linux/ploop/ploop.h
@@ -366,6 +366,7 @@  struct ploop_device
 	int			read_sync_reqs;
 	int			free_qlen; /* len of free_list */
 	int			free_qmax; /* max len of free_list */
+	int			blockable_reqs; /* depends on userspace tool */
 
 	struct bio		*bio_head;
 	struct bio		*bio_tail;
@@ -485,6 +486,7 @@  enum
 	PLOOP_REQ_PUSH_BACKUP, /* preq was ACKed by userspace push_backup */
 	PLOOP_REQ_FSYNC_DONE,  /* fsync_thread() performed f_op->fsync() */
 	PLOOP_REQ_ISSUE_FLUSH, /* preq needs ->issue_flush before completing */
+	PLOOP_REQ_BLOCKABLE,  /* preq was accounted in plo->blockable_reqs */
 };
 
 #define PLOOP_REQ_MERGE_FL (1 << PLOOP_REQ_MERGE)