[rh7,4/4] ploop: Be overprotective on discard

Submitted by Kirill Tkhai on March 5, 2020, 12:46 p.m.

Details

Message ID 158341240658.293365.3704988024000907403.stgit@localhost.localdomain
State New
Series "ploop: Be over protectable on discard"
Headers show

Commit Message

Kirill Tkhai March 5, 2020, 12:46 p.m.
Forced wait all discard requests before snapshot and grow.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 drivers/block/ploop/dev.c   |   67 ++++++++++++++++++++++++++++++++++++++++---
 include/linux/ploop/ploop.h |    1 +
 2 files changed, 64 insertions(+), 4 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index 59aabe4a9386..64e6bd1f2cb3 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -180,6 +180,39 @@  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);
+	ret = !(plo->discard_disabled_count++);
+	spin_unlock_irq(&plo->lock);
+
+	if (ret)
+		ret = wait_event_interruptible(plo->pending_waitq,
+					       discard_reqs_count(plo) == 0);
+	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;
@@ -2232,6 +2265,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;
 
@@ -3590,13 +3629,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);
@@ -3649,6 +3692,7 @@  static int ploop_snapshot(struct ploop_device * plo, unsigned long arg,
 	if (err)
 		goto out_close2;
 
+	enable_discard(plo);
 	return 0;
 
 out_close2:
@@ -3656,6 +3700,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);
@@ -4506,16 +4552,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);
@@ -4540,7 +4598,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 688de1185d2b..a22696e9c42e 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