[RHEL7,COMMIT] ploop: Stop fast path reqs living their own lives

Submitted by Konstantin Khorenko on March 6, 2020, 9:55 a.m.

Details

Message ID 202003060955.0269tlf4031613@finist-ce7.sw.ru
State New
Series "Series without cover letter"
Headers show

Commit Message

Konstantin Khorenko March 6, 2020, 9:55 a.m.
The commit is pushed to "branch-rh7-3.10.0-1062.12.1.vz7.145.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1062.12.1.vz7.131.8
------>
commit 025bc88fce89605ab2cda49d70495d16bcf161a9
Author: Kirill Tkhai <ktkhai@virtuozzo.com>
Date:   Tue Mar 3 18:13:48 2020 +0300

    ploop: Stop fast path reqs living their own lives
    
    Doing ploop_quiesce() we want any IO becomes stopped.
    But fast path requests live their own lives, and this
    completelly ignores quiesce state. This may be a reason
    of unpredictable behaviour.
    
    This patch fixes the problem.
    
    Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
    
    khorenko@:
    - spin_lock in fast_path_reqs_count() is needed because
      plo->fastpath_reqs may be updated on any processor, so for visibility
      syncronisation
    
    - at the moment in fast_path_reqs_count() spin_lock_irq() is enough,
      but we use spin_lock_irqsave() just in order to avoid possible
      mistakes in the future if one day fast_path_reqs_count() is called
      with irqs disabled
---
 drivers/block/ploop/dev.c   | 31 +++++++++++++++++++++++++++++--
 include/linux/ploop/ploop.h |  2 ++
 2 files changed, 31 insertions(+), 2 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index 21f6197671d04..7410e2e5dc4e0 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -164,6 +164,23 @@  static void ploop_uncongest(struct ploop_device *plo)
 	}
 }
 
+static int fast_path_reqs_count(struct ploop_device *plo)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&plo->locki, flags);
+	ret = plo->fastpath_reqs;
+	spin_unlock_irqrestore(&plo->lock, flags);
+
+	return ret;
+}
+
+static void wait_fast_path_reqs(struct ploop_device *plo)
+{
+	wait_event(plo->fast_path_waitq, fast_path_reqs_count(plo) == 0);
+}
+
 static void ploop_init_request(struct ploop_request *preq)
 {
 	preq->eng_state = PLOOP_E_ENTRY;
@@ -656,6 +673,8 @@  DEFINE_BIO_CB(ploop_fast_end_io)
 	    (test_bit(PLOOP_S_EXITING, &plo->state) ||
 	     !list_empty(&plo->entry_queue)))
 		wake_up_interruptible(&plo->waitq);
+	if (plo->fast_path_disabled_count && !plo->fastpath_reqs)
+		wake_up(&plo->fast_path_waitq);
 	spin_unlock_irqrestore(&plo->lock, flags);
 
 	BIO_ENDIO(plo->queue, orig, err);
@@ -969,7 +988,8 @@  static void ploop_make_request(struct request_queue *q, struct bio *bio)
 
 	/* No fast path, when maintenance is in progress.
 	 * (PLOOP_S_TRACK was checked immediately above) */
-	if (FAST_PATH_DISABLED(plo->maintenance_type))
+	if (FAST_PATH_DISABLED(plo->maintenance_type) ||
+	    plo->fast_path_disabled_count)
 		goto queue;
 
 	/* Attention state, always queue */
@@ -3444,7 +3464,6 @@  static int ploop_replace_delta(struct ploop_device * plo, unsigned long arg)
 	return err;
 }
 
-
 void ploop_quiesce(struct ploop_device * plo)
 {
 	struct completion qcomp;
@@ -3454,6 +3473,8 @@  void ploop_quiesce(struct ploop_device * plo)
 		return;
 
 	spin_lock_irq(&plo->lock);
+	plo->fast_path_disabled_count++;
+
 	preq = ploop_alloc_request(plo, true);
 	preq->req_rw = 0;
 	preq->state = (1 << PLOOP_REQ_SYNC) | (1 << PLOOP_REQ_BARRIER);
@@ -3471,6 +3492,7 @@  void ploop_quiesce(struct ploop_device * plo)
 		wake_up_interruptible(&plo->waitq);
 	spin_unlock_irq(&plo->lock);
 
+	wait_fast_path_reqs(plo);
 	wait_for_completion(&qcomp);
 	plo->quiesce_comp = NULL;
 }
@@ -3478,6 +3500,10 @@  EXPORT_SYMBOL(ploop_quiesce);
 
 void ploop_relax(struct ploop_device * plo)
 {
+	spin_lock_irq(&plo->lock);
+	plo->fast_path_disabled_count--;
+	spin_unlock_irq(&plo->lock);
+
 	if (!test_bit(PLOOP_S_RUNNING, &plo->state))
 		return;
 
@@ -5458,6 +5484,7 @@  static struct ploop_device *__ploop_dev_alloc(int index)
 	init_waitqueue_head(&plo->req_waitq);
 	init_waitqueue_head(&plo->freeze_waitq);
 	init_waitqueue_head(&plo->event_waitq);
+	init_waitqueue_head(&plo->fast_path_waitq);
 	plo->tune = DEFAULT_PLOOP_TUNE;
 	map_init(plo, &plo->map);
 	track_init(plo);
diff --git a/include/linux/ploop/ploop.h b/include/linux/ploop/ploop.h
index 66591623f79d0..8495ca2145fd4 100644
--- a/include/linux/ploop/ploop.h
+++ b/include/linux/ploop/ploop.h
@@ -407,6 +407,7 @@  struct ploop_device
 	wait_queue_head_t	req_waitq;
 	wait_queue_head_t	freeze_waitq;
 	wait_queue_head_t	event_waitq;
+	wait_queue_head_t	fast_path_waitq;
 
 	struct ploop_map	map;
 	struct ploop_map	*trans_map;
@@ -473,6 +474,7 @@  struct ploop_device
 	struct block_device *dm_crypt_bdev;
 
 	unsigned long		locking_state; /* plo locked by userspace */
+	unsigned int		fast_path_disabled_count;
 };
 
 enum