[RHEL7,COMMIT] ploop: Be overprotective on discard

Submitted by Konstantin Khorenko on March 6, 2020, 11:03 a.m.

Details

Message ID 202003061103.026B3b9I015055@finist-ce7.sw.ru
State New
Series "ploop: Be over protectable on discard"
Headers show

Commit Message

Konstantin Khorenko March 6, 2020, 11:03 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 db4ee42022c3c49a58b128b9a9aafa633a828ecc
Author: Kirill Tkhai <ktkhai@virtuozzo.com>
Date:   Thu Mar 5 15:46:46 2020 +0300

    ploop: Be overprotective on discard
    
    Forced wait all discard requests before snapshot and grow.
    
    Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
    
    khorenko@:
    v2: make disable_and_wait_discard() be prepared to be run in parallel so
        plo->discard_disabled_count could be > 1.
        It's not the case for now (ploop_snapshot() and ploop_grow() cann't
        run in parallel), but might become a case in the future.
    
    =====================
    Patchset description:
    
    ploop: Be over protectable on discard
    
    Forcedly wait and disable discard on snapshot and grow.
    
    Kirill Tkhai (4):
          ploop: Simplify check in ploop_fast_end_io()
          ploop: Rename fast_path_waitq into pending_waitq
          ploop: Rename bio_discard_inflight_reqs into discard_inflight_reqs
          ploop: Be overprotective on discard
---
 drivers/block/ploop/dev.c   | 69 ++++++++++++++++++++++++++++++++++++++++++---
 include/linux/ploop/ploop.h |  1 +
 2 files changed, 66 insertions(+), 4 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index 7836731223852..55ca57de61dbf 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -181,6 +181,41 @@  static void wait_fast_path_reqs(struct ploop_device *plo)
 	wait_event(plo->pending_waitq, fast_path_reqs_count(plo) == 0);
 }
 
+static int discard_reqs_count(struct ploop_device *plo)
+{
+	int ret;
+
+	spin_lock_irq(&plo->lock);
+	ret = plo->discard_inflight_reqs;
+	spin_unlock_irq(&plo->lock);
+
+	return ret;
+}
+
+/* Returns 0 or -EINTR */
+static int disable_and_wait_discard(struct ploop_device *plo)
+{
+	int ret;
+
+	spin_lock_irq(&plo->lock);
+	plo->discard_disabled_count++;
+	spin_unlock_irq(&plo->lock);
+
+	ret = wait_event_interruptible(plo->pending_waitq,
+				       discard_reqs_count(plo) == 0);
+	if (ret)
+		enable_discard(plo);
+
+	return ret;
+}
+
+static void enable_discard(struct ploop_device *plo)
+{
+	spin_lock_irq(&plo->lock);
+	WARN_ON_ONCE(plo->discard_disabled_count-- == 0);
+	spin_unlock_irq(&plo->lock);
+}
+
 static void ploop_init_request(struct ploop_request *preq)
 {
 	preq->eng_state = PLOOP_E_ENTRY;
@@ -2233,6 +2268,12 @@  static bool ploop_can_issue_discard(struct ploop_device *plo,
 	if (test_bit(PLOOP_S_NO_FALLOC_DISCARD, &plo->state))
 		return false;
 
+	if (plo->discard_disabled_count)
+		return false;
+
+	if (plo->maintenance_type != PLOOP_MNTN_OFF)
+		return false;
+
 	if (!list_is_singular(&plo->map.delta_list))
 		return false;
 
@@ -3591,13 +3632,17 @@  static int ploop_snapshot(struct ploop_device * plo, unsigned long arg,
 	if (IS_ERR(delta))
 		return PTR_ERR(delta);
 
-	err = delta->ops->compose(delta, 1, &chunk);
+	err = disable_and_wait_discard(plo);
 	if (err)
 		goto out_destroy;
 
+	err = delta->ops->compose(delta, 1, &chunk);
+	if (err)
+		goto out_enable;
+
 	err = delta->ops->open(delta);
 	if (err)
-		goto out_destroy;
+		goto out_enable;
 
 	err = KOBJECT_ADD(&delta->kobj, kobject_get(&plo->kobj),
 			  "%d", delta->level);
@@ -3650,6 +3695,7 @@  static int ploop_snapshot(struct ploop_device * plo, unsigned long arg,
 	if (err)
 		goto out_close2;
 
+	enable_discard(plo);
 	return 0;
 
 out_close2:
@@ -3657,6 +3703,8 @@  static int ploop_snapshot(struct ploop_device * plo, unsigned long arg,
 out_close:
 	kobject_put(&plo->kobj);
 	delta->ops->stop(delta);
+out_enable:
+	enable_discard(plo);
 out_destroy:
 	delta->ops->destroy(delta);
 	kobject_put(&delta->kobj);
@@ -4507,16 +4555,28 @@  static int ploop_grow(struct ploop_device *plo, struct block_device *bdev,
 	if (!delta->ops->prepare_grow)
 		return -EINVAL;
 
+	err = disable_and_wait_discard(plo);
+	if (err)
+		return -EINTR;
+
 	ploop_quiesce(plo);
 	err = delta->ops->prepare_grow(delta, &new_size, &reloc);
-	if (err)
+	if (err) {
+		enable_discard(plo);
 		goto grow_failed;
+	}
 
 	plo->grow_new_size = new_size;
 
 	/* prepare_grow() succeeded, but more actions needed */
 	if (reloc) {
 		plo->maintenance_type = PLOOP_MNTN_GROW;
+		/*
+		 * maintenance_type is changed, so now it prohibits
+		 * discard bios. Below we may leave this function,
+		 * and let's return discard counter back.
+		 */
+		enable_discard(plo);
 		ploop_relax(plo);
 		for (; grow_stage < PLOOP_GROW_MAX; grow_stage++) {
 			ploop_relocate(plo, grow_stage);
@@ -4541,7 +4601,8 @@  static int ploop_grow(struct ploop_device *plo, struct block_device *bdev,
 		new_size = plo->grow_new_size;
 		clear_bit(PLOOP_S_NULLIFY, &plo->state);
 		plo->maintenance_type = PLOOP_MNTN_OFF;
-	}
+	} else
+		enable_discard(plo);
 
 	/* Update bdev size and friends */
 	if (delta->ops->complete_grow) {
diff --git a/include/linux/ploop/ploop.h b/include/linux/ploop/ploop.h
index 688de1185d2b7..a22696e9c42e8 100644
--- a/include/linux/ploop/ploop.h
+++ b/include/linux/ploop/ploop.h
@@ -476,6 +476,7 @@  struct ploop_device
 
 	unsigned long		locking_state; /* plo locked by userspace */
 	unsigned int		fast_path_disabled_count;
+	unsigned int		discard_disabled_count;
 };
 
 enum