|
@@ -2429,7 +2429,7 @@ static void dm_queue_flush(struct mapped_device *md)
|
|
*/
|
|
*/
|
|
struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
|
|
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;
|
|
struct queue_limits limits;
|
|
int r;
|
|
int r;
|
|
|
|
|
|
@@ -2439,6 +2439,19 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
|
|
if (!dm_suspended_md(md))
|
|
if (!dm_suspended_md(md))
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If the new table has no data devices, retain the existing limits.
|
|
|
|
+ * This helps multipath with queue_if_no_path if all paths disappear,
|
|
|
|
+ * then new I/O is queued based on these limits, and then some paths
|
|
|
|
+ * reappear.
|
|
|
|
+ */
|
|
|
|
+ if (dm_table_has_no_data_devices(table)) {
|
|
|
|
+ live_map = dm_get_live_table(md);
|
|
|
|
+ if (live_map)
|
|
|
|
+ limits = md->queue->limits;
|
|
|
|
+ dm_table_put(live_map);
|
|
|
|
+ }
|
|
|
|
+
|
|
r = dm_calculate_queue_limits(table, &limits);
|
|
r = dm_calculate_queue_limits(table, &limits);
|
|
if (r) {
|
|
if (r) {
|
|
map = ERR_PTR(r);
|
|
map = ERR_PTR(r);
|