[Devel] [PATCH RHEL9 COMMIT] dm-qcow2: Add fault injection

Konstantin Khorenko khorenko at virtuozzo.com
Tue Dec 7 18:05:23 MSK 2021


The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh9-5.14.0-4.vz9.10.33
------>
commit 58bf3de88a6e59258842a66eed0b6b1025972d49
Author: Kirill Tkhai <ktkhai at virtuozzo.com>
Date:   Tue Dec 7 18:05:23 2021 +0300

    dm-qcow2: Add fault injection
    
    $dmsetup message dm_qcow2 0 set_fault_injection <delta_id> <ratio>
    
    This sets percent of failing IO for specific @delta_id.
    @ratio is in (1/1000)%.
    
    https://jira.sw.ru/browse/PSBM-132050
    Feature: dm-qcow2: block device over QCOW2 file driver
    
    Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 drivers/md/dm-qcow2-cmd.c    | 28 +++++++++++++++++++++++++++-
 drivers/md/dm-qcow2-target.c | 16 +++++++++++++++-
 drivers/md/dm-qcow2.h        |  3 +++
 3 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/drivers/md/dm-qcow2-cmd.c b/drivers/md/dm-qcow2-cmd.c
index bb541e4707cf..779c6618e598 100644
--- a/drivers/md/dm-qcow2-cmd.c
+++ b/drivers/md/dm-qcow2-cmd.c
@@ -301,12 +301,30 @@ static int qcow2_get_img_name(struct qcow2_target *tgt, u32 img_id,
 	return ret;
 }
 
+static int qcow2_set_fault_injection(struct qcow2_target *tgt,
+				     u32 img_id, u32 ratio)
+{
+	struct qcow2 *qcow2;
+	u8 ref_index;
+
+	if (ratio > 100 * QCOW2_FAULT_RATIO)
+		return -EINVAL;
+
+	qcow2 = qcow2_get_img(tgt, img_id, &ref_index);
+	if (!qcow2)
+		return -ENOENT;
+
+	qcow2->fault_injection = ratio; /* Unlocked */
+	qcow2_ref_dec(tgt, ref_index);
+	return 0;
+}
+
 int qcow2_message(struct dm_target *ti, unsigned int argc, char **argv,
 		  char *result, unsigned int maxlen)
 {
 	struct qcow2_target *tgt = to_qcow2_target(ti);
 	int ret = -EPERM;
-	u32 val;
+	u32 val, val2;
 
 	if (!capable(CAP_SYS_ADMIN))
 		goto out;
@@ -329,6 +347,14 @@ int qcow2_message(struct dm_target *ti, unsigned int argc, char **argv,
 		}
 		ret = qcow2_get_img_name(tgt, val, result, maxlen);
 		goto out;
+	} else if (!strcmp(argv[0], "set_fault_injection")) {
+		if (argc != 3 || kstrtou32(argv[1], 10, &val) ||
+				 kstrtou32(argv[2], 10, &val2)) {
+			ret = -EINVAL;
+			goto out;
+		}
+		ret = qcow2_set_fault_injection(tgt, val, val2);
+		goto out;
 	}
 
 	ret = mutex_lock_killable(&tgt->ctl_mutex);
diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c
index 646a0152fd7b..2a29bff42bfe 100644
--- a/drivers/md/dm-qcow2-target.c
+++ b/drivers/md/dm-qcow2-target.c
@@ -2,6 +2,7 @@
 /*
  *  Copyright (C) 2021 Virtuozzo International GmbH. All rights reserved.
  */
+#include <linux/prandom.h>
 #include <linux/uio.h>
 
 #include "dm.h"
@@ -79,6 +80,17 @@ int rw_page_sync(unsigned int rw, struct qcow2 *qcow2,
 	return rw_pages_sync(rw, qcow2, index, pages, 1);
 }
 
+static bool should_fail_rw(struct qcow2 *qcow2)
+{
+	u32 fault_injection = data_race(qcow2->fault_injection);
+
+	if (likely(!fault_injection))
+		return false;
+	if (fault_injection < prandom_u32() % (100 * QCOW2_FAULT_RATIO))
+		return false;
+	return true;
+}
+
 static void qcow2_aio_do_completion(struct qio *qio)
 {
 	if (!atomic_dec_and_test(&qio->aio_ref))
@@ -110,7 +122,9 @@ void call_rw_iter(struct qcow2 *qcow2, loff_t pos, unsigned int rw,
 
 	atomic_set(&qio->aio_ref, 2);
 
-	if (rw == WRITE)
+	if (unlikely(should_fail_rw(qcow2)))
+		ret = -EIO;
+	else if (rw == WRITE)
 		ret = call_write_iter(file, iocb, iter);
 	else
 		ret = call_read_iter(file, iocb, iter);
diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h
index b1ae1770ee14..962b767c84b1 100644
--- a/drivers/md/dm-qcow2.h
+++ b/drivers/md/dm-qcow2.h
@@ -175,6 +175,9 @@ struct qcow2 {
 	/* File size covered by single page of block entries */
 	loff_t r2_page_covered_file_size;
 
+#define QCOW2_FAULT_RATIO 1000
+	u32 fault_injection; /* In 1%/QCOW2_FAULT_RATIO */
+
 	spinlock_t deferred_lock ____cacheline_aligned;
 	spinlock_t md_pages_lock;
 


More information about the Devel mailing list