diff options
-rw-r--r-- | drivers/md/dm-table.c | 35 | ||||
-rw-r--r-- | drivers/md/dm.c | 15 | ||||
-rw-r--r-- | drivers/md/dm.h | 1 |
3 files changed, 50 insertions, 1 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 77b90ae66991..100368eb7991 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -1212,6 +1212,41 @@ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector) | |||
1212 | return &t->targets[(KEYS_PER_NODE * n) + k]; | 1212 | return &t->targets[(KEYS_PER_NODE * n) + k]; |
1213 | } | 1213 | } |
1214 | 1214 | ||
1215 | static int count_device(struct dm_target *ti, struct dm_dev *dev, | ||
1216 | sector_t start, sector_t len, void *data) | ||
1217 | { | ||
1218 | unsigned *num_devices = data; | ||
1219 | |||
1220 | (*num_devices)++; | ||
1221 | |||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | /* | ||
1226 | * Check whether a table has no data devices attached using each | ||
1227 | * target's iterate_devices method. | ||
1228 | * Returns false if the result is unknown because a target doesn't | ||
1229 | * support iterate_devices. | ||
1230 | */ | ||
1231 | bool dm_table_has_no_data_devices(struct dm_table *table) | ||
1232 | { | ||
1233 | struct dm_target *uninitialized_var(ti); | ||
1234 | unsigned i = 0, num_devices = 0; | ||
1235 | |||
1236 | while (i < dm_table_get_num_targets(table)) { | ||
1237 | ti = dm_table_get_target(table, i++); | ||
1238 | |||
1239 | if (!ti->type->iterate_devices) | ||
1240 | return false; | ||
1241 | |||
1242 | ti->type->iterate_devices(ti, count_device, &num_devices); | ||
1243 | if (num_devices) | ||
1244 | return false; | ||
1245 | } | ||
1246 | |||
1247 | return true; | ||
1248 | } | ||
1249 | |||
1215 | /* | 1250 | /* |
1216 | * Establish the new table's queue_limits and validate them. | 1251 | * Establish the new table's queue_limits and validate them. |
1217 | */ | 1252 | */ |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 6748e0c4df1f..67ffa391edcf 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -2429,7 +2429,7 @@ static void dm_queue_flush(struct mapped_device *md) | |||
2429 | */ | 2429 | */ |
2430 | struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) | 2430 | struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) |
2431 | { | 2431 | { |
2432 | struct dm_table *map = ERR_PTR(-EINVAL); | 2432 | struct dm_table *live_map, *map = ERR_PTR(-EINVAL); |
2433 | struct queue_limits limits; | 2433 | struct queue_limits limits; |
2434 | int r; | 2434 | int r; |
2435 | 2435 | ||
@@ -2439,6 +2439,19 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) | |||
2439 | if (!dm_suspended_md(md)) | 2439 | if (!dm_suspended_md(md)) |
2440 | goto out; | 2440 | goto out; |
2441 | 2441 | ||
2442 | /* | ||
2443 | * If the new table has no data devices, retain the existing limits. | ||
2444 | * This helps multipath with queue_if_no_path if all paths disappear, | ||
2445 | * then new I/O is queued based on these limits, and then some paths | ||
2446 | * reappear. | ||
2447 | */ | ||
2448 | if (dm_table_has_no_data_devices(table)) { | ||
2449 | live_map = dm_get_live_table(md); | ||
2450 | if (live_map) | ||
2451 | limits = md->queue->limits; | ||
2452 | dm_table_put(live_map); | ||
2453 | } | ||
2454 | |||
2442 | r = dm_calculate_queue_limits(table, &limits); | 2455 | r = dm_calculate_queue_limits(table, &limits); |
2443 | if (r) { | 2456 | if (r) { |
2444 | map = ERR_PTR(r); | 2457 | map = ERR_PTR(r); |
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 52eef493d266..6a99fefaa743 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
@@ -54,6 +54,7 @@ void dm_table_event_callback(struct dm_table *t, | |||
54 | void (*fn)(void *), void *context); | 54 | void (*fn)(void *), void *context); |
55 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); | 55 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); |
56 | struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); | 56 | struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); |
57 | bool dm_table_has_no_data_devices(struct dm_table *table); | ||
57 | int dm_calculate_queue_limits(struct dm_table *table, | 58 | int dm_calculate_queue_limits(struct dm_table *table, |
58 | struct queue_limits *limits); | 59 | struct queue_limits *limits); |
59 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, | 60 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, |