aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/device-mapper/snapshot.txt16
-rw-r--r--drivers/md/dm-snap.c186
2 files changed, 181 insertions, 21 deletions
diff --git a/Documentation/device-mapper/snapshot.txt b/Documentation/device-mapper/snapshot.txt
index b8bbb516f989..1810833f6dc6 100644
--- a/Documentation/device-mapper/snapshot.txt
+++ b/Documentation/device-mapper/snapshot.txt
@@ -31,6 +31,7 @@ its visible content unchanged, at least until the <COW device> fills up.
31 31
32 32
33*) snapshot <origin> <COW device> <persistent?> <chunksize> 33*) snapshot <origin> <COW device> <persistent?> <chunksize>
34 [<# feature args> [<arg>]*]
34 35
35A snapshot of the <origin> block device is created. Changed chunks of 36A snapshot of the <origin> block device is created. Changed chunks of
36<chunksize> sectors will be stored on the <COW device>. Writes will 37<chunksize> sectors will be stored on the <COW device>. Writes will
@@ -53,8 +54,23 @@ When loading or unloading the snapshot target, the corresponding
53snapshot-origin or snapshot-merge target must be suspended. A failure to 54snapshot-origin or snapshot-merge target must be suspended. A failure to
54suspend the origin target could result in data corruption. 55suspend the origin target could result in data corruption.
55 56
57Optional features:
58
59 discard_zeroes_cow - a discard issued to the snapshot device that
60 maps to entire chunks to will zero the corresponding exception(s) in
61 the snapshot's exception store.
62
63 discard_passdown_origin - a discard to the snapshot device is passed
64 down to the snapshot-origin's underlying device. This doesn't cause
65 copy-out to the snapshot exception store because the snapshot-origin
66 target is bypassed.
67
68 The discard_passdown_origin feature depends on the discard_zeroes_cow
69 feature being enabled.
70
56 71
57* snapshot-merge <origin> <COW device> <persistent> <chunksize> 72* snapshot-merge <origin> <COW device> <persistent> <chunksize>
73 [<# feature args> [<arg>]*]
58 74
59takes the same table arguments as the snapshot target except it only 75takes the same table arguments as the snapshot target except it only
60works with persistent snapshots. This target assumes the role of the 76works with persistent snapshots. This target assumes the role of the
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 3107f2b1988b..63916e1dc569 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -1,6 +1,4 @@
1/* 1/*
2 * dm-snapshot.c
3 *
4 * Copyright (C) 2001-2002 Sistina Software (UK) Limited. 2 * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
5 * 3 *
6 * This file is released under the GPL. 4 * This file is released under the GPL.
@@ -134,7 +132,10 @@ struct dm_snapshot {
134 * - I/O error while merging 132 * - I/O error while merging
135 * => stop merging; set merge_failed; process I/O normally. 133 * => stop merging; set merge_failed; process I/O normally.
136 */ 134 */
137 int merge_failed; 135 bool merge_failed:1;
136
137 bool discard_zeroes_cow:1;
138 bool discard_passdown_origin:1;
138 139
139 /* 140 /*
140 * Incoming bios that overlap with chunks being merged must wait 141 * Incoming bios that overlap with chunks being merged must wait
@@ -1173,12 +1174,64 @@ static void stop_merge(struct dm_snapshot *s)
1173 clear_bit(SHUTDOWN_MERGE, &s->state_bits); 1174 clear_bit(SHUTDOWN_MERGE, &s->state_bits);
1174} 1175}
1175 1176
1177static int parse_snapshot_features(struct dm_arg_set *as, struct dm_snapshot *s,
1178 struct dm_target *ti)
1179{
1180 int r;
1181 unsigned argc;
1182 const char *arg_name;
1183
1184 static const struct dm_arg _args[] = {
1185 {0, 2, "Invalid number of feature arguments"},
1186 };
1187
1188 /*
1189 * No feature arguments supplied.
1190 */
1191 if (!as->argc)
1192 return 0;
1193
1194 r = dm_read_arg_group(_args, as, &argc, &ti->error);
1195 if (r)
1196 return -EINVAL;
1197
1198 while (argc && !r) {
1199 arg_name = dm_shift_arg(as);
1200 argc--;
1201
1202 if (!strcasecmp(arg_name, "discard_zeroes_cow"))
1203 s->discard_zeroes_cow = true;
1204
1205 else if (!strcasecmp(arg_name, "discard_passdown_origin"))
1206 s->discard_passdown_origin = true;
1207
1208 else {
1209 ti->error = "Unrecognised feature requested";
1210 r = -EINVAL;
1211 break;
1212 }
1213 }
1214
1215 if (!s->discard_zeroes_cow && s->discard_passdown_origin) {
1216 /*
1217 * TODO: really these are disjoint.. but ti->num_discard_bios
1218 * and dm_bio_get_target_bio_nr() require rigid constraints.
1219 */
1220 ti->error = "discard_passdown_origin feature depends on discard_zeroes_cow";
1221 r = -EINVAL;
1222 }
1223
1224 return r;
1225}
1226
1176/* 1227/*
1177 * Construct a snapshot mapping: <origin_dev> <COW-dev> <p|po|n> <chunk-size> 1228 * Construct a snapshot mapping:
1229 * <origin_dev> <COW-dev> <p|po|n> <chunk-size> [<# feature args> [<arg>]*]
1178 */ 1230 */
1179static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) 1231static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1180{ 1232{
1181 struct dm_snapshot *s; 1233 struct dm_snapshot *s;
1234 struct dm_arg_set as;
1182 int i; 1235 int i;
1183 int r = -EINVAL; 1236 int r = -EINVAL;
1184 char *origin_path, *cow_path; 1237 char *origin_path, *cow_path;
@@ -1186,8 +1239,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1186 unsigned args_used, num_flush_bios = 1; 1239 unsigned args_used, num_flush_bios = 1;
1187 fmode_t origin_mode = FMODE_READ; 1240 fmode_t origin_mode = FMODE_READ;
1188 1241
1189 if (argc != 4) { 1242 if (argc < 4) {
1190 ti->error = "requires exactly 4 arguments"; 1243 ti->error = "requires 4 or more arguments";
1191 r = -EINVAL; 1244 r = -EINVAL;
1192 goto bad; 1245 goto bad;
1193 } 1246 }
@@ -1204,6 +1257,13 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1204 goto bad; 1257 goto bad;
1205 } 1258 }
1206 1259
1260 as.argc = argc;
1261 as.argv = argv;
1262 dm_consume_args(&as, 4);
1263 r = parse_snapshot_features(&as, s, ti);
1264 if (r)
1265 goto bad_features;
1266
1207 origin_path = argv[0]; 1267 origin_path = argv[0];
1208 argv++; 1268 argv++;
1209 argc--; 1269 argc--;
@@ -1289,6 +1349,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1289 1349
1290 ti->private = s; 1350 ti->private = s;
1291 ti->num_flush_bios = num_flush_bios; 1351 ti->num_flush_bios = num_flush_bios;
1352 if (s->discard_zeroes_cow)
1353 ti->num_discard_bios = (s->discard_passdown_origin ? 2 : 1);
1292 ti->per_io_data_size = sizeof(struct dm_snap_tracked_chunk); 1354 ti->per_io_data_size = sizeof(struct dm_snap_tracked_chunk);
1293 1355
1294 /* Add snapshot to the list of snapshots for this origin */ 1356 /* Add snapshot to the list of snapshots for this origin */
@@ -1336,29 +1398,22 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1336 1398
1337bad_read_metadata: 1399bad_read_metadata:
1338 unregister_snapshot(s); 1400 unregister_snapshot(s);
1339
1340bad_load_and_register: 1401bad_load_and_register:
1341 mempool_exit(&s->pending_pool); 1402 mempool_exit(&s->pending_pool);
1342
1343bad_pending_pool: 1403bad_pending_pool:
1344 dm_kcopyd_client_destroy(s->kcopyd_client); 1404 dm_kcopyd_client_destroy(s->kcopyd_client);
1345
1346bad_kcopyd: 1405bad_kcopyd:
1347 dm_exception_table_exit(&s->pending, pending_cache); 1406 dm_exception_table_exit(&s->pending, pending_cache);
1348 dm_exception_table_exit(&s->complete, exception_cache); 1407 dm_exception_table_exit(&s->complete, exception_cache);
1349
1350bad_hash_tables: 1408bad_hash_tables:
1351 dm_exception_store_destroy(s->store); 1409 dm_exception_store_destroy(s->store);
1352
1353bad_store: 1410bad_store:
1354 dm_put_device(ti, s->cow); 1411 dm_put_device(ti, s->cow);
1355
1356bad_cow: 1412bad_cow:
1357 dm_put_device(ti, s->origin); 1413 dm_put_device(ti, s->origin);
1358
1359bad_origin: 1414bad_origin:
1415bad_features:
1360 kfree(s); 1416 kfree(s);
1361
1362bad: 1417bad:
1363 return r; 1418 return r;
1364} 1419}
@@ -1806,6 +1861,37 @@ static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
1806 (bio->bi_iter.bi_sector & s->store->chunk_mask); 1861 (bio->bi_iter.bi_sector & s->store->chunk_mask);
1807} 1862}
1808 1863
1864static void zero_callback(int read_err, unsigned long write_err, void *context)
1865{
1866 struct bio *bio = context;
1867 struct dm_snapshot *s = bio->bi_private;
1868
1869 up(&s->cow_count);
1870 bio->bi_status = write_err ? BLK_STS_IOERR : 0;
1871 bio_endio(bio);
1872}
1873
1874static void zero_exception(struct dm_snapshot *s, struct dm_exception *e,
1875 struct bio *bio, chunk_t chunk)
1876{
1877 struct dm_io_region dest;
1878
1879 dest.bdev = s->cow->bdev;
1880 dest.sector = bio->bi_iter.bi_sector;
1881 dest.count = s->store->chunk_size;
1882
1883 down(&s->cow_count);
1884 WARN_ON_ONCE(bio->bi_private);
1885 bio->bi_private = s;
1886 dm_kcopyd_zero(s->kcopyd_client, 1, &dest, 0, zero_callback, bio);
1887}
1888
1889static bool io_overlaps_chunk(struct dm_snapshot *s, struct bio *bio)
1890{
1891 return bio->bi_iter.bi_size ==
1892 (s->store->chunk_size << SECTOR_SHIFT);
1893}
1894
1809static int snapshot_map(struct dm_target *ti, struct bio *bio) 1895static int snapshot_map(struct dm_target *ti, struct bio *bio)
1810{ 1896{
1811 struct dm_exception *e; 1897 struct dm_exception *e;
@@ -1839,10 +1925,43 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
1839 goto out_unlock; 1925 goto out_unlock;
1840 } 1926 }
1841 1927
1928 if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
1929 if (s->discard_passdown_origin && dm_bio_get_target_bio_nr(bio)) {
1930 /*
1931 * passdown discard to origin (without triggering
1932 * snapshot exceptions via do_origin; doing so would
1933 * defeat the goal of freeing space in origin that is
1934 * implied by the "discard_passdown_origin" feature)
1935 */
1936 bio_set_dev(bio, s->origin->bdev);
1937 track_chunk(s, bio, chunk);
1938 goto out_unlock;
1939 }
1940 /* discard to snapshot (target_bio_nr == 0) zeroes exceptions */
1941 }
1942
1842 /* If the block is already remapped - use that, else remap it */ 1943 /* If the block is already remapped - use that, else remap it */
1843 e = dm_lookup_exception(&s->complete, chunk); 1944 e = dm_lookup_exception(&s->complete, chunk);
1844 if (e) { 1945 if (e) {
1845 remap_exception(s, e, bio, chunk); 1946 remap_exception(s, e, bio, chunk);
1947 if (unlikely(bio_op(bio) == REQ_OP_DISCARD) &&
1948 io_overlaps_chunk(s, bio)) {
1949 dm_exception_table_unlock(&lock);
1950 up_read(&s->lock);
1951 zero_exception(s, e, bio, chunk);
1952 r = DM_MAPIO_SUBMITTED; /* discard is not issued */
1953 goto out;
1954 }
1955 goto out_unlock;
1956 }
1957
1958 if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
1959 /*
1960 * If no exception exists, complete discard immediately
1961 * otherwise it'll trigger copy-out.
1962 */
1963 bio_endio(bio);
1964 r = DM_MAPIO_SUBMITTED;
1846 goto out_unlock; 1965 goto out_unlock;
1847 } 1966 }
1848 1967
@@ -1890,9 +2009,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
1890 2009
1891 r = DM_MAPIO_SUBMITTED; 2010 r = DM_MAPIO_SUBMITTED;
1892 2011
1893 if (!pe->started && 2012 if (!pe->started && io_overlaps_chunk(s, bio)) {
1894 bio->bi_iter.bi_size ==
1895 (s->store->chunk_size << SECTOR_SHIFT)) {
1896 pe->started = 1; 2013 pe->started = 1;
1897 2014
1898 dm_exception_table_unlock(&lock); 2015 dm_exception_table_unlock(&lock);
@@ -2138,6 +2255,7 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
2138{ 2255{
2139 unsigned sz = 0; 2256 unsigned sz = 0;
2140 struct dm_snapshot *snap = ti->private; 2257 struct dm_snapshot *snap = ti->private;
2258 unsigned num_features;
2141 2259
2142 switch (type) { 2260 switch (type) {
2143 case STATUSTYPE_INFO: 2261 case STATUSTYPE_INFO:
@@ -2178,8 +2296,16 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
2178 * make sense. 2296 * make sense.
2179 */ 2297 */
2180 DMEMIT("%s %s", snap->origin->name, snap->cow->name); 2298 DMEMIT("%s %s", snap->origin->name, snap->cow->name);
2181 snap->store->type->status(snap->store, type, result + sz, 2299 sz += snap->store->type->status(snap->store, type, result + sz,
2182 maxlen - sz); 2300 maxlen - sz);
2301 num_features = snap->discard_zeroes_cow + snap->discard_passdown_origin;
2302 if (num_features) {
2303 DMEMIT(" %u", num_features);
2304 if (snap->discard_zeroes_cow)
2305 DMEMIT(" discard_zeroes_cow");
2306 if (snap->discard_passdown_origin)
2307 DMEMIT(" discard_passdown_origin");
2308 }
2183 break; 2309 break;
2184 } 2310 }
2185} 2311}
@@ -2198,6 +2324,22 @@ static int snapshot_iterate_devices(struct dm_target *ti,
2198 return r; 2324 return r;
2199} 2325}
2200 2326
2327static void snapshot_io_hints(struct dm_target *ti, struct queue_limits *limits)
2328{
2329 struct dm_snapshot *snap = ti->private;
2330
2331 if (snap->discard_zeroes_cow) {
2332 struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
2333
2334 (void) __find_snapshots_sharing_cow(snap, &snap_src, &snap_dest, NULL);
2335 if (snap_src && snap_dest)
2336 snap = snap_src;
2337
2338 /* All discards are split on chunk_size boundary */
2339 limits->discard_granularity = snap->store->chunk_size;
2340 limits->max_discard_sectors = snap->store->chunk_size;
2341 }
2342}
2201 2343
2202/*----------------------------------------------------------------- 2344/*-----------------------------------------------------------------
2203 * Origin methods 2345 * Origin methods
@@ -2522,7 +2664,7 @@ static struct target_type origin_target = {
2522 2664
2523static struct target_type snapshot_target = { 2665static struct target_type snapshot_target = {
2524 .name = "snapshot", 2666 .name = "snapshot",
2525 .version = {1, 15, 0}, 2667 .version = {1, 16, 0},
2526 .module = THIS_MODULE, 2668 .module = THIS_MODULE,
2527 .ctr = snapshot_ctr, 2669 .ctr = snapshot_ctr,
2528 .dtr = snapshot_dtr, 2670 .dtr = snapshot_dtr,
@@ -2532,11 +2674,12 @@ static struct target_type snapshot_target = {
2532 .resume = snapshot_resume, 2674 .resume = snapshot_resume,
2533 .status = snapshot_status, 2675 .status = snapshot_status,
2534 .iterate_devices = snapshot_iterate_devices, 2676 .iterate_devices = snapshot_iterate_devices,
2677 .io_hints = snapshot_io_hints,
2535}; 2678};
2536 2679
2537static struct target_type merge_target = { 2680static struct target_type merge_target = {
2538 .name = dm_snapshot_merge_target_name, 2681 .name = dm_snapshot_merge_target_name,
2539 .version = {1, 4, 0}, 2682 .version = {1, 5, 0},
2540 .module = THIS_MODULE, 2683 .module = THIS_MODULE,
2541 .ctr = snapshot_ctr, 2684 .ctr = snapshot_ctr,
2542 .dtr = snapshot_dtr, 2685 .dtr = snapshot_dtr,
@@ -2547,6 +2690,7 @@ static struct target_type merge_target = {
2547 .resume = snapshot_merge_resume, 2690 .resume = snapshot_merge_resume,
2548 .status = snapshot_status, 2691 .status = snapshot_status,
2549 .iterate_devices = snapshot_iterate_devices, 2692 .iterate_devices = snapshot_iterate_devices,
2693 .io_hints = snapshot_io_hints,
2550}; 2694};
2551 2695
2552static int __init dm_snapshot_init(void) 2696static int __init dm_snapshot_init(void)