[Devel] [PATCH RHEL7 COMMIT] ploop: restrict the standby mode flag to work only on devices supporting it

Konstantin Khorenko khorenko at virtuozzo.com
Mon Oct 31 21:12:50 MSK 2022


The commit is pushed to "branch-rh7-3.10.0-1160.76.1.vz7.189.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1160.76.1.vz7.189.6
------>
commit bd6c64a17908562772b99311e3f9b42ab1938e19
Author: Alexander Atanasov <alexander.atanasov at virtuozzo.com>
Date:   Mon Oct 31 12:25:06 2022 +0200

    ploop: restrict the standby mode flag to work only on devices supporting it
    
    In commit 80da9c2abac9 ("ploop: add a standby mode") a flag
    on the block device's request queue was added to put the queue
    into standby mode on EBUSY. Later on, the list with errors was extended
    in commit e868f1e0b1a3 ("ploop: move to standby after -ENOTCONN too") and
    in commit 4b1eb3f667eb ("ploop: kaio: Enter standby mode on EIO as well").
    
    These were introduced to solve a problem on a specific device,
    that will clear the standby flag at some point.
    But the problem is that the clear counterpart is missing
    for the rest of the devices, so once ploop gets one of the errors
    it stops processing requests indefinitely.
    
    The flag is cleared at ploop_start(...) and ploop_replace_delta(...),
    while it is obvious that ploop_start would not clear the flag on error,
    ploop_replace_delta(...) is an user initiated operation and it can not
    be used when ploop is in maintenace mode.
    
    To solve this introduce a static key to enable the flag handling only
    when key is enabled - checks are at the start and at the end of
    every request and we want to avoid performance impact from these checks.
    
    Currently the only example of a configuration which support ploop
    standby mode is the following:
     - vStorage is mounted on the Host
     - ploop device which image is stored on the vStorage
     - vStorage provides an iSCSI target which is built on that ploop
       device, the target is handled by the SCST kernel module
    
    On systems where we are in mixed mode, meaning we have both devices that
    support the standby flag and devices that do not, a QUEUE_FLAG_STANDBY_EN
    is introduced to indicate the standby support from the device.
    Setting the QUEUE_FLAG_STANDBY_EN means the device promises to clear
    QUEUE_FLAG_STANDBY flag when it recovers, so ploop can continue processing
    requests.
    
    The state of the flags is exported via /sys/block/*/queue/standby,
    or at /sys/devices/virtual/block/*/queue/standby depending on the device.
     * not supported - no enabled on the queue
     * on  - queue is in standby mode, not processing requests
     * off - queue is processing requests
    
    https://jira.sw.ru/browse/PSBM-142759
    
    Signed-off-by: Alexander Atanasov <alexander.atanasov at virtuozzo.com>
    Cc: Kui Liu <Kui.Liu at acronis.com>
    Cc: Alexey Kuznetsov <kuznet at acronis.com>
---
 block/blk-sysfs.c             | 15 +++++++++++++++
 drivers/block/ploop/dev.c     | 10 +++++++---
 drivers/block/ploop/io_kaio.c | 11 ++++++++---
 include/linux/blkdev.h        |  2 ++
 kernel/ve/ve.c                |  8 ++++++++
 5 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 7aebab0ced19..7606de009f99 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -357,6 +357,15 @@ static ssize_t queue_wb_lat_store(struct request_queue *q, const char *page,
 	wbt_update_limits(q->rq_wb);
 	return count;
 }
+
+static ssize_t queue_standby_show(struct request_queue *q, char *page)
+{
+	if (!blk_queue_standby_en(q))
+		return sprintf(page, "not supported\n");
+	return sprintf(page, "%s\n",
+		blk_queue_standby(q) ? "on" : "off");
+}
+
 static struct queue_sysfs_entry queue_requests_entry = {
 	.attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR },
 	.show = queue_requests_show,
@@ -488,6 +497,11 @@ static struct queue_sysfs_entry queue_wb_lat_entry = {
 	.store = queue_wb_lat_store,
 };
 
+static struct queue_sysfs_entry queue_standby_entry = {
+	.attr = {.name = "standby", .mode = S_IRUGO },
+	.show = queue_standby_show,
+};
+
 static struct attribute *default_attrs[] = {
 	&queue_requests_entry.attr,
 	&queue_ra_entry.attr,
@@ -513,6 +527,7 @@ static struct attribute *default_attrs[] = {
 	&queue_iostats_entry.attr,
 	&queue_random_entry.attr,
 	&queue_wb_lat_entry.attr,
+	&queue_standby_entry.attr,
 	NULL,
 };
 
diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index 06b72542633b..32f4a394e4b8 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -76,6 +76,8 @@ static DEFINE_MUTEX(ploop_devices_mutex);
 static LIST_HEAD(ploop_formats);
 static DEFINE_MUTEX(ploop_formats_mutex);
 
+extern struct static_key ploop_standby_check;
+
 int ploop_register_format(struct ploop_delta_ops * ops)
 {
 	mutex_lock(&ploop_formats_mutex);
@@ -985,9 +987,11 @@ static void ploop_make_request(struct request_queue *q, struct bio *bio)
 	hd_struct_put(part);
 	part_stat_unlock();
 
-	if (blk_queue_standby(plo->queue)) {
-		BIO_ENDIO(q, bio, -EIO);
-		return;
+	if (static_key_false(&ploop_standby_check)) {
+		if (blk_queue_standby(plo->queue)) {
+			BIO_ENDIO(q, bio, -EIO);
+			return;
+		}
 	}
 
 	if (unlikely(bio->bi_size == 0)) {
diff --git a/drivers/block/ploop/io_kaio.c b/drivers/block/ploop/io_kaio.c
index e24952703549..a0c28379eb7d 100644
--- a/drivers/block/ploop/io_kaio.c
+++ b/drivers/block/ploop/io_kaio.c
@@ -23,6 +23,7 @@
 
 #define KAIO_MAX_PAGES_PER_REQ 32	  /* 128 KB */
 
+extern struct static_key ploop_standby_check;
 /* This will be used as flag "ploop_kaio_open() succeeded" */
 static struct extent_map_tree
 {
@@ -116,6 +117,9 @@ static void check_standby_mode(long res, struct ploop_device *plo) {
 	struct request_queue *q = plo->queue;
 	int prev;
 
+	if (!blk_queue_standby_en(q))
+		return;
+
 	/* move to standby if delta lease was stolen or mount is gone */
 	if (res != -EBUSY && res != -ENOTCONN && res != -EIO) {
 		return;
@@ -146,8 +150,8 @@ static void kaio_rw_aio_complete(u64 data, long res)
 		bio_list_for_each(b, &preq->bl)
 			printk(" bio=%p: bi_sector=%ld bi_size=%d\n",
 			       b, b->bi_sector, b->bi_size);
-
-		check_standby_mode(res, preq->plo);
+		if (static_key_false(&ploop_standby_check))
+			check_standby_mode(res, preq->plo);
 		PLOOP_REQ_SET_ERROR(preq, res);
 	}
 
@@ -560,7 +564,8 @@ static int kaio_fsync_thread(void * data)
 				       "on ploop%d)\n",
 				       err, io->files.inode->i_ino,
 				       io2level(io), plo->index);
-				check_standby_mode(err, plo);
+				if (static_key_false(&ploop_standby_check))
+					check_standby_mode(err, plo);
 				PLOOP_REQ_SET_ERROR(preq, -EIO);
 			} else if (preq->req_rw & REQ_FLUSH) {
 				BUG_ON(!preq->req_size);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 4e2970ff97b2..fb6daf0eef7a 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -643,6 +643,7 @@ struct request_queue {
 #define QUEUE_FLAG_SCSI_PASSTHROUGH 30	/* queue supports SCSI commands */
 
 #define QUEUE_FLAG_STANDBY     31	/* unable to handle read/write requests */
+#define QUEUE_FLAG_STANDBY_EN  32	/* enable standby queue flag */
 
 #define QUEUE_FLAG_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
 				 (1 << QUEUE_FLAG_STACKABLE)	|	\
@@ -739,6 +740,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
 #define blk_queue_scsi_passthrough(q)	\
 	test_bit(QUEUE_FLAG_SCSI_PASSTHROUGH, &(q)->queue_flags)
 #define blk_queue_standby(q)	test_bit(QUEUE_FLAG_STANDBY, &(q)->queue_flags)
+#define blk_queue_standby_en(q)	test_bit(QUEUE_FLAG_STANDBY_EN, &(q)->queue_flags)
 
 extern int blk_set_preempt_only(struct request_queue *q);
 extern void blk_clear_preempt_only(struct request_queue *q);
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 68c3e91d60c1..c0535d7836d6 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -76,6 +76,14 @@ MODULE_PARM_DESC(ve_allow_ioctl_fitrim,
 		 "Allow ioctl(FITRIM) from inside VE. Only ext4 is supported now");
 EXPORT_SYMBOL(ve_allow_ioctl_fitrim);
 
+/*
+ * This static key is used to enable queue standby flags checks in ploop code.
+ * These checks used by drivers that support managing the queue flags.
+ * But to avoid creating inter module dependencies leave key here.
+ */
+struct static_key ploop_standby_check = STATIC_KEY_INIT_FALSE;
+EXPORT_SYMBOL(ploop_standby_check);
+
 static DEFINE_PER_CPU(struct kstat_lat_pcpu_snap_struct, ve0_lat_stats);
 
 struct ve_struct ve0 = {


More information about the Devel mailing list