dm-devel.redhat.com archive mirror
 help / color / mirror / Atom feed
From: Mike Snitzer <snitzer@redhat.com>
To: Alasdair G Kergon <agk@redhat.com>
Cc: dm-devel@redhat.com, David Jeffery <djeffery@redhat.com>
Subject: [PATCH v3] dm: re-use live table's limits if next table has no data devices
Date: Fri, 21 Sep 2012 11:37:44 -0400	[thread overview]
Message-ID: <20120921153744.GA5967@redhat.com> (raw)
In-Reply-To: <20120918130226.GA8065@redhat.com>

DM recalculates queue limits based only on devices which currently exist
in the table.  This creates a problem in the event all devices are
temporarily removed such as all paths being lost in multipath.  DM will
reset the limits to the maximum permissible, which can then assemble
requests which exceed the limits of the paths when the paths are
restored.  The request will fail the blk_rq_check_limits() test when
sent to a path with lower limits, and will be retried without end by
multipath.  This became a much bigger issue after commit fe86cdcef
("block: do not artificially constrain max_sectors for stacking
drivers").

Add a safety net that will re-use the DM device's existing limits in the
event that DM device has a temporary table that doesn't have any
component devices.

Reported-by: David Jeffery <djeffery@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 drivers/md/dm-table.c |   30 ++++++++++++++++++++++++++++++
 drivers/md/dm.c       |    8 +++++++-
 drivers/md/dm.h       |    1 +
 3 files changed, 38 insertions(+), 1 deletion(-)

Index: linux/drivers/md/dm-table.c
===================================================================
--- linux.orig/drivers/md/dm-table.c
+++ linux/drivers/md/dm-table.c
@@ -1212,6 +1212,36 @@ struct dm_target *dm_table_find_target(s
 	return &t->targets[(KEYS_PER_NODE * n) + k];
 }
 
+static int count_device(struct dm_target *ti, struct dm_dev *dev,
+			sector_t start, sector_t len, void *data)
+{
+	unsigned *num_devices_p = data;
+	*num_devices_p += 1;
+	return 0;
+}
+
+bool dm_table_has_no_data_devices(struct dm_table *table)
+{
+	struct dm_target *uninitialized_var(ti);
+	unsigned i = 0, num_devices = 0;
+
+	while (i < dm_table_get_num_targets(table)) {
+		ti = dm_table_get_target(table, i++);
+
+		if (!ti->type->iterate_devices) {
+			/* unfortunately, must assume there are devices */
+			num_devices = 1;
+			break;
+		}
+
+		ti->type->iterate_devices(ti, count_device, &num_devices);
+		if (num_devices)
+			break;
+	}
+
+	return num_devices == 0;
+}
+
 /*
  * Establish the new table's queue_limits and validate them.
  */
Index: linux/drivers/md/dm.c
===================================================================
--- linux.orig/drivers/md/dm.c
+++ linux/drivers/md/dm.c
@@ -2422,7 +2422,7 @@ static void dm_queue_flush(struct mapped
  */
 struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
 {
-	struct dm_table *map = ERR_PTR(-EINVAL);
+	struct dm_table *live_map, *map = ERR_PTR(-EINVAL);
 	struct queue_limits limits;
 	int r;
 
@@ -2432,6 +2432,12 @@ struct dm_table *dm_swap_table(struct ma
 	if (!dm_suspended_md(md))
 		goto out;
 
+	/* re-use live table's limits if next table has no data devices */
+	live_map = dm_get_live_table(md);
+	if (live_map && dm_table_has_no_data_devices(table))
+		limits = md->queue->limits;
+	dm_table_put(live_map);
+
 	r = dm_calculate_queue_limits(table, &limits);
 	if (r) {
 		map = ERR_PTR(r);
Index: linux/drivers/md/dm.h
===================================================================
--- linux.orig/drivers/md/dm.h
+++ linux/drivers/md/dm.h
@@ -54,6 +54,7 @@ void dm_table_event_callback(struct dm_t
 			     void (*fn)(void *), void *context);
 struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);
 struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
+bool dm_table_has_no_data_devices(struct dm_table *table);
 int dm_calculate_queue_limits(struct dm_table *table,
 			      struct queue_limits *limits);
 void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,

  reply	other threads:[~2012-09-21 15:37 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-31 15:04 [PATCH] multipath queues build invalid requests when all paths are lost David Jeffery
2012-09-04 14:58 ` Mike Snitzer
2012-09-04 16:10   ` Mike Snitzer
2012-09-04 16:12     ` Mike Snitzer
2012-09-08 16:50       ` Mikulas Patocka
2012-09-12 15:37         ` [PATCH] dm mpath: only retry ioctl if queue_if_no_path was configured Mike Snitzer
2012-09-12 17:01           ` Mikulas Patocka
2012-09-12 19:37   ` [PATCH] dm table: do not allow queue limits that will exceed hardware limits Mike Snitzer
2012-09-14 20:41     ` [PATCH v2] " Mike Snitzer
2012-09-17 19:44       ` David Jeffery
2012-09-17 19:52         ` Alasdair G Kergon
2012-09-18 11:40         ` Alasdair G Kergon
2012-09-18 13:02           ` Mike Snitzer
2012-09-21 15:37             ` Mike Snitzer [this message]
2012-09-17 20:24       ` Alasdair G Kergon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120921153744.GA5967@redhat.com \
    --to=snitzer@redhat.com \
    --cc=agk@redhat.com \
    --cc=djeffery@redhat.com \
    --cc=dm-devel@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).