diff options
Diffstat (limited to 'drivers/md/dm-table.c')
-rw-r--r-- | drivers/md/dm-table.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index bc60ef77a0d8..f9fc07d7a4b9 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -54,6 +54,8 @@ struct dm_table { | |||
54 | sector_t *highs; | 54 | sector_t *highs; |
55 | struct dm_target *targets; | 55 | struct dm_target *targets; |
56 | 56 | ||
57 | unsigned discards_supported:1; | ||
58 | |||
57 | /* | 59 | /* |
58 | * Indicates the rw permissions for the new logical | 60 | * Indicates the rw permissions for the new logical |
59 | * device. This should be a combination of FMODE_READ | 61 | * device. This should be a combination of FMODE_READ |
@@ -203,6 +205,7 @@ int dm_table_create(struct dm_table **result, fmode_t mode, | |||
203 | 205 | ||
204 | INIT_LIST_HEAD(&t->devices); | 206 | INIT_LIST_HEAD(&t->devices); |
205 | atomic_set(&t->holders, 0); | 207 | atomic_set(&t->holders, 0); |
208 | t->discards_supported = 1; | ||
206 | 209 | ||
207 | if (!num_targets) | 210 | if (!num_targets) |
208 | num_targets = KEYS_PER_NODE; | 211 | num_targets = KEYS_PER_NODE; |
@@ -770,6 +773,9 @@ int dm_table_add_target(struct dm_table *t, const char *type, | |||
770 | 773 | ||
771 | t->highs[t->num_targets++] = tgt->begin + tgt->len - 1; | 774 | t->highs[t->num_targets++] = tgt->begin + tgt->len - 1; |
772 | 775 | ||
776 | if (!tgt->num_discard_requests) | ||
777 | t->discards_supported = 0; | ||
778 | |||
773 | return 0; | 779 | return 0; |
774 | 780 | ||
775 | bad: | 781 | bad: |
@@ -1135,6 +1141,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, | |||
1135 | else | 1141 | else |
1136 | queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q); | 1142 | queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q); |
1137 | 1143 | ||
1144 | if (!dm_table_supports_discards(t)) | ||
1145 | queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); | ||
1146 | else | ||
1147 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); | ||
1148 | |||
1138 | dm_table_set_integrity(t); | 1149 | dm_table_set_integrity(t); |
1139 | 1150 | ||
1140 | /* | 1151 | /* |
@@ -1281,6 +1292,39 @@ struct mapped_device *dm_table_get_md(struct dm_table *t) | |||
1281 | return t->md; | 1292 | return t->md; |
1282 | } | 1293 | } |
1283 | 1294 | ||
1295 | static int device_discard_capable(struct dm_target *ti, struct dm_dev *dev, | ||
1296 | sector_t start, sector_t len, void *data) | ||
1297 | { | ||
1298 | struct request_queue *q = bdev_get_queue(dev->bdev); | ||
1299 | |||
1300 | return q && blk_queue_discard(q); | ||
1301 | } | ||
1302 | |||
1303 | bool dm_table_supports_discards(struct dm_table *t) | ||
1304 | { | ||
1305 | struct dm_target *ti; | ||
1306 | unsigned i = 0; | ||
1307 | |||
1308 | if (!t->discards_supported) | ||
1309 | return 0; | ||
1310 | |||
1311 | /* | ||
1312 | * Ensure that at least one underlying device supports discards. | ||
1313 | * t->devices includes internal dm devices such as mirror logs | ||
1314 | * so we need to use iterate_devices here, which targets | ||
1315 | * supporting discard must provide. | ||
1316 | */ | ||
1317 | while (i < dm_table_get_num_targets(t)) { | ||
1318 | ti = dm_table_get_target(t, i++); | ||
1319 | |||
1320 | if (ti->type->iterate_devices && | ||
1321 | ti->type->iterate_devices(ti, device_discard_capable, NULL)) | ||
1322 | return 1; | ||
1323 | } | ||
1324 | |||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1284 | EXPORT_SYMBOL(dm_vcalloc); | 1328 | EXPORT_SYMBOL(dm_vcalloc); |
1285 | EXPORT_SYMBOL(dm_get_device); | 1329 | EXPORT_SYMBOL(dm_get_device); |
1286 | EXPORT_SYMBOL(dm_put_device); | 1330 | EXPORT_SYMBOL(dm_put_device); |