Skip to content

Commit 67e2e2b

Browse files
jthornberkergon
authored andcommitted
dm thin: add pool target flags to control discard
Add dm thin target arguments to control discard support. ignore_discard: Disables discard support no_discard_passdown: Don't pass discards down to the underlying data device, but just remove the mapping within the thin provisioning target. Signed-off-by: Joe Thornber <[email protected]> Signed-off-by: Mike Snitzer <[email protected]> Signed-off-by: Alasdair G Kergon <[email protected]>
1 parent 104655f commit 67e2e2b

File tree

2 files changed

+115
-28
lines changed

2 files changed

+115
-28
lines changed

Documentation/device-mapper/thin-provisioning.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,13 @@ i) Constructor
223223
<low water mark (blocks)> [<number of feature args> [<arg>]*]
224224

225225
Optional feature arguments:
226-
- 'skip_block_zeroing': skips the zeroing of newly-provisioned blocks.
226+
227+
skip_block_zeroing: Skip the zeroing of newly-provisioned blocks.
228+
229+
ignore_discard: Disable discard support.
230+
231+
no_discard_passdown: Don't pass discards down to the underlying
232+
data device, but just remove the mapping.
227233

228234
Data block size must be between 64KB (128 sectors) and 1GB
229235
(2097152 sectors) inclusive.

drivers/md/dm-thin.c

Lines changed: 108 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,13 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
489489
* devices.
490490
*/
491491
struct new_mapping;
492+
493+
struct pool_features {
494+
unsigned zero_new_blocks:1;
495+
unsigned discard_enabled:1;
496+
unsigned discard_passdown:1;
497+
};
498+
492499
struct pool {
493500
struct list_head list;
494501
struct dm_target *ti; /* Only set if a pool target is bound */
@@ -502,7 +509,7 @@ struct pool {
502509
dm_block_t offset_mask;
503510
dm_block_t low_water_blocks;
504511

505-
unsigned zero_new_blocks:1;
512+
struct pool_features pf;
506513
unsigned low_water_triggered:1; /* A dm event has been sent */
507514
unsigned no_free_space:1; /* A -ENOSPC warning has been issued */
508515

@@ -543,7 +550,7 @@ struct pool_c {
543550
struct dm_target_callbacks callbacks;
544551

545552
dm_block_t low_water_blocks;
546-
unsigned zero_new_blocks:1;
553+
struct pool_features pf;
547554
};
548555

549556
/*
@@ -1051,7 +1058,7 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
10511058
* zeroing pre-existing data, we can issue the bio immediately.
10521059
* Otherwise we use kcopyd to zero the data first.
10531060
*/
1054-
if (!pool->zero_new_blocks)
1061+
if (!pool->pf.zero_new_blocks)
10551062
process_prepared_mapping(m);
10561063

10571064
else if (io_overwrites_block(pool, bio)) {
@@ -1202,7 +1209,7 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
12021209
*/
12031210
m = get_next_mapping(pool);
12041211
m->tc = tc;
1205-
m->pass_discard = !lookup_result.shared;
1212+
m->pass_discard = (!lookup_result.shared) & pool->pf.discard_passdown;
12061213
m->virt_block = block;
12071214
m->data_block = lookup_result.block;
12081215
m->cell = cell;
@@ -1617,7 +1624,7 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
16171624

16181625
pool->ti = ti;
16191626
pool->low_water_blocks = pt->low_water_blocks;
1620-
pool->zero_new_blocks = pt->zero_new_blocks;
1627+
pool->pf = pt->pf;
16211628

16221629
return 0;
16231630
}
@@ -1631,6 +1638,14 @@ static void unbind_control_target(struct pool *pool, struct dm_target *ti)
16311638
/*----------------------------------------------------------------
16321639
* Pool creation
16331640
*--------------------------------------------------------------*/
1641+
/* Initialize pool features. */
1642+
static void pool_features_init(struct pool_features *pf)
1643+
{
1644+
pf->zero_new_blocks = 1;
1645+
pf->discard_enabled = 1;
1646+
pf->discard_passdown = 1;
1647+
}
1648+
16341649
static void __pool_destroy(struct pool *pool)
16351650
{
16361651
__pool_table_remove(pool);
@@ -1678,7 +1693,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
16781693
pool->block_shift = ffs(block_size) - 1;
16791694
pool->offset_mask = block_size - 1;
16801695
pool->low_water_blocks = 0;
1681-
pool->zero_new_blocks = 1;
1696+
pool_features_init(&pool->pf);
16821697
pool->prison = prison_create(PRISON_CELLS);
16831698
if (!pool->prison) {
16841699
*error = "Error creating pool's bio prison";
@@ -1775,7 +1790,8 @@ static void __pool_dec(struct pool *pool)
17751790

17761791
static struct pool *__pool_find(struct mapped_device *pool_md,
17771792
struct block_device *metadata_dev,
1778-
unsigned long block_size, char **error)
1793+
unsigned long block_size, char **error,
1794+
int *created)
17791795
{
17801796
struct pool *pool = __pool_table_lookup_metadata_dev(metadata_dev);
17811797

@@ -1791,8 +1807,10 @@ static struct pool *__pool_find(struct mapped_device *pool_md,
17911807
return ERR_PTR(-EINVAL);
17921808
__pool_inc(pool);
17931809

1794-
} else
1810+
} else {
17951811
pool = pool_create(pool_md, metadata_dev, block_size, error);
1812+
*created = 1;
1813+
}
17961814
}
17971815

17981816
return pool;
@@ -1816,10 +1834,6 @@ static void pool_dtr(struct dm_target *ti)
18161834
mutex_unlock(&dm_thin_pool_table.mutex);
18171835
}
18181836

1819-
struct pool_features {
1820-
unsigned zero_new_blocks:1;
1821-
};
1822-
18231837
static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
18241838
struct dm_target *ti)
18251839
{
@@ -1828,7 +1842,7 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
18281842
const char *arg_name;
18291843

18301844
static struct dm_arg _args[] = {
1831-
{0, 1, "Invalid number of pool feature arguments"},
1845+
{0, 3, "Invalid number of pool feature arguments"},
18321846
};
18331847

18341848
/*
@@ -1848,6 +1862,12 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
18481862
if (!strcasecmp(arg_name, "skip_block_zeroing")) {
18491863
pf->zero_new_blocks = 0;
18501864
continue;
1865+
} else if (!strcasecmp(arg_name, "ignore_discard")) {
1866+
pf->discard_enabled = 0;
1867+
continue;
1868+
} else if (!strcasecmp(arg_name, "no_discard_passdown")) {
1869+
pf->discard_passdown = 0;
1870+
continue;
18511871
}
18521872

18531873
ti->error = "Unrecognised pool feature requested";
@@ -1865,10 +1885,12 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
18651885
*
18661886
* Optional feature arguments are:
18671887
* skip_block_zeroing: skips the zeroing of newly-provisioned blocks.
1888+
* ignore_discard: disable discard
1889+
* no_discard_passdown: don't pass discards down to the data device
18681890
*/
18691891
static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
18701892
{
1871-
int r;
1893+
int r, pool_created = 0;
18721894
struct pool_c *pt;
18731895
struct pool *pool;
18741896
struct pool_features pf;
@@ -1928,8 +1950,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
19281950
/*
19291951
* Set default pool features.
19301952
*/
1931-
memset(&pf, 0, sizeof(pf));
1932-
pf.zero_new_blocks = 1;
1953+
pool_features_init(&pf);
19331954

19341955
dm_consume_args(&as, 4);
19351956
r = parse_pool_features(&as, &pf, ti);
@@ -1943,21 +1964,58 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
19431964
}
19441965

19451966
pool = __pool_find(dm_table_get_md(ti->table), metadata_dev->bdev,
1946-
block_size, &ti->error);
1967+
block_size, &ti->error, &pool_created);
19471968
if (IS_ERR(pool)) {
19481969
r = PTR_ERR(pool);
19491970
goto out_free_pt;
19501971
}
19511972

1973+
/*
1974+
* 'pool_created' reflects whether this is the first table load.
1975+
* Top level discard support is not allowed to be changed after
1976+
* initial load. This would require a pool reload to trigger thin
1977+
* device changes.
1978+
*/
1979+
if (!pool_created && pf.discard_enabled != pool->pf.discard_enabled) {
1980+
ti->error = "Discard support cannot be disabled once enabled";
1981+
r = -EINVAL;
1982+
goto out_flags_changed;
1983+
}
1984+
1985+
/*
1986+
* If discard_passdown was enabled verify that the data device
1987+
* supports discards. Disable discard_passdown if not; otherwise
1988+
* -EOPNOTSUPP will be returned.
1989+
*/
1990+
if (pf.discard_passdown) {
1991+
struct request_queue *q = bdev_get_queue(data_dev->bdev);
1992+
if (!q || !blk_queue_discard(q)) {
1993+
DMWARN("Discard unsupported by data device: Disabling discard passdown.");
1994+
pf.discard_passdown = 0;
1995+
}
1996+
}
1997+
19521998
pt->pool = pool;
19531999
pt->ti = ti;
19542000
pt->metadata_dev = metadata_dev;
19552001
pt->data_dev = data_dev;
19562002
pt->low_water_blocks = low_water_blocks;
1957-
pt->zero_new_blocks = pf.zero_new_blocks;
2003+
pt->pf = pf;
19582004
ti->num_flush_requests = 1;
1959-
ti->num_discard_requests = 1;
1960-
ti->discards_supported = 1;
2005+
/*
2006+
* Only need to enable discards if the pool should pass
2007+
* them down to the data device. The thin device's discard
2008+
* processing will cause mappings to be removed from the btree.
2009+
*/
2010+
if (pf.discard_enabled && pf.discard_passdown) {
2011+
ti->num_discard_requests = 1;
2012+
/*
2013+
* Setting 'discards_supported' circumvents the normal
2014+
* stacking of discard limits (this keeps the pool and
2015+
* thin devices' discard limits consistent).
2016+
*/
2017+
ti->discards_supported = 1;
2018+
}
19612019
ti->private = pt;
19622020

19632021
pt->callbacks.congested_fn = pool_is_congested;
@@ -1967,6 +2025,8 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
19672025

19682026
return 0;
19692027

2028+
out_flags_changed:
2029+
__pool_dec(pool);
19702030
out_free_pt:
19712031
kfree(pt);
19722032
out:
@@ -2255,7 +2315,7 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv)
22552315
static int pool_status(struct dm_target *ti, status_type_t type,
22562316
char *result, unsigned maxlen)
22572317
{
2258-
int r;
2318+
int r, count;
22592319
unsigned sz = 0;
22602320
uint64_t transaction_id;
22612321
dm_block_t nr_free_blocks_data;
@@ -2318,10 +2378,19 @@ static int pool_status(struct dm_target *ti, status_type_t type,
23182378
(unsigned long)pool->sectors_per_block,
23192379
(unsigned long long)pt->low_water_blocks);
23202380

2321-
DMEMIT("%u ", !pool->zero_new_blocks);
2381+
count = !pool->pf.zero_new_blocks + !pool->pf.discard_enabled +
2382+
!pool->pf.discard_passdown;
2383+
DMEMIT("%u ", count);
23222384

2323-
if (!pool->zero_new_blocks)
2385+
if (!pool->pf.zero_new_blocks)
23242386
DMEMIT("skip_block_zeroing ");
2387+
2388+
if (!pool->pf.discard_enabled)
2389+
DMEMIT("ignore_discard ");
2390+
2391+
if (!pool->pf.discard_passdown)
2392+
DMEMIT("no_discard_passdown ");
2393+
23252394
break;
23262395
}
23272396

@@ -2352,13 +2421,17 @@ static int pool_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
23522421

23532422
static void set_discard_limits(struct pool *pool, struct queue_limits *limits)
23542423
{
2424+
/*
2425+
* FIXME: these limits may be incompatible with the pool's data device
2426+
*/
23552427
limits->max_discard_sectors = pool->sectors_per_block;
23562428

23572429
/*
23582430
* This is just a hint, and not enforced. We have to cope with
23592431
* bios that overlap 2 blocks.
23602432
*/
23612433
limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT;
2434+
limits->discard_zeroes_data = pool->pf.zero_new_blocks;
23622435
}
23632436

23642437
static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
@@ -2368,14 +2441,15 @@ static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
23682441

23692442
blk_limits_io_min(limits, 0);
23702443
blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
2371-
set_discard_limits(pool, limits);
2444+
if (pool->pf.discard_enabled)
2445+
set_discard_limits(pool, limits);
23722446
}
23732447

23742448
static struct target_type pool_target = {
23752449
.name = "thin-pool",
23762450
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
23772451
DM_TARGET_IMMUTABLE,
2378-
.version = {1, 0, 0},
2452+
.version = {1, 1, 0},
23792453
.module = THIS_MODULE,
23802454
.ctr = pool_ctr,
23812455
.dtr = pool_dtr,
@@ -2417,6 +2491,9 @@ static void thin_dtr(struct dm_target *ti)
24172491
* pool_dev: the path to the pool (eg, /dev/mapper/my_pool)
24182492
* dev_id: the internal device identifier
24192493
* origin_dev: a device external to the pool that should act as the origin
2494+
*
2495+
* If the pool device has discards disabled, they get disabled for the thin
2496+
* device as well.
24202497
*/
24212498
static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
24222499
{
@@ -2485,8 +2562,12 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
24852562

24862563
ti->split_io = tc->pool->sectors_per_block;
24872564
ti->num_flush_requests = 1;
2488-
ti->num_discard_requests = 1;
2489-
ti->discards_supported = 1;
2565+
2566+
/* In case the pool supports discards, pass them on. */
2567+
if (tc->pool->pf.discard_enabled) {
2568+
ti->discards_supported = 1;
2569+
ti->num_discard_requests = 1;
2570+
}
24902571

24912572
dm_put(pool_md);
24922573

0 commit comments

Comments
 (0)