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, |
