aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-table.c')
-rw-r--r--drivers/md/dm-table.c44
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
1295static 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
1303bool 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
1284EXPORT_SYMBOL(dm_vcalloc); 1328EXPORT_SYMBOL(dm_vcalloc);
1285EXPORT_SYMBOL(dm_get_device); 1329EXPORT_SYMBOL(dm_get_device);
1286EXPORT_SYMBOL(dm_put_device); 1330EXPORT_SYMBOL(dm_put_device);