1
1
/*
2
- * dm-snapshot.c
3
- *
4
2
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
5
3
*
6
4
* This file is released under the GPL.
@@ -134,7 +132,10 @@ struct dm_snapshot {
134
132
* - I/O error while merging
135
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
141
* Incoming bios that overlap with chunks being merged must wait
@@ -1173,21 +1174,73 @@ static void stop_merge(struct dm_snapshot *s)
1173
1174
clear_bit (SHUTDOWN_MERGE , & s -> state_bits );
1174
1175
}
1175
1176
1177
+ static 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
*/
1179
1231
static int snapshot_ctr (struct dm_target * ti , unsigned int argc , char * * argv )
1180
1232
{
1181
1233
struct dm_snapshot * s ;
1234
+ struct dm_arg_set as ;
1182
1235
int i ;
1183
1236
int r = - EINVAL ;
1184
1237
char * origin_path , * cow_path ;
1185
1238
dev_t origin_dev , cow_dev ;
1186
1239
unsigned args_used , num_flush_bios = 1 ;
1187
1240
fmode_t origin_mode = FMODE_READ ;
1188
1241
1189
- if (argc != 4 ) {
1190
- ti -> error = "requires exactly 4 arguments" ;
1242
+ if (argc < 4 ) {
1243
+ ti -> error = "requires 4 or more arguments" ;
1191
1244
r = - EINVAL ;
1192
1245
goto bad ;
1193
1246
}
@@ -1204,6 +1257,13 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1204
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
1267
origin_path = argv [0 ];
1208
1268
argv ++ ;
1209
1269
argc -- ;
@@ -1289,6 +1349,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1289
1349
1290
1350
ti -> private = s ;
1291
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
1354
ti -> per_io_data_size = sizeof (struct dm_snap_tracked_chunk );
1293
1355
1294
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
1337
1399
bad_read_metadata :
1338
1400
unregister_snapshot (s );
1339
-
1340
1401
bad_load_and_register :
1341
1402
mempool_exit (& s -> pending_pool );
1342
-
1343
1403
bad_pending_pool :
1344
1404
dm_kcopyd_client_destroy (s -> kcopyd_client );
1345
-
1346
1405
bad_kcopyd :
1347
1406
dm_exception_table_exit (& s -> pending , pending_cache );
1348
1407
dm_exception_table_exit (& s -> complete , exception_cache );
1349
-
1350
1408
bad_hash_tables :
1351
1409
dm_exception_store_destroy (s -> store );
1352
-
1353
1410
bad_store :
1354
1411
dm_put_device (ti , s -> cow );
1355
-
1356
1412
bad_cow :
1357
1413
dm_put_device (ti , s -> origin );
1358
-
1359
1414
bad_origin :
1415
+ bad_features :
1360
1416
kfree (s );
1361
-
1362
1417
bad :
1363
1418
return r ;
1364
1419
}
@@ -1806,6 +1861,37 @@ static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
1806
1861
(bio -> bi_iter .bi_sector & s -> store -> chunk_mask );
1807
1862
}
1808
1863
1864
+ static 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
+
1874
+ static 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
+
1889
+ static 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
+
1809
1895
static int snapshot_map (struct dm_target * ti , struct bio * bio )
1810
1896
{
1811
1897
struct dm_exception * e ;
@@ -1839,10 +1925,43 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
1839
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
1943
/* If the block is already remapped - use that, else remap it */
1843
1944
e = dm_lookup_exception (& s -> complete , chunk );
1844
1945
if (e ) {
1845
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
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
2010
r = DM_MAPIO_SUBMITTED ;
1892
2011
1893
- if (!pe -> started &&
1894
- bio -> bi_iter .bi_size ==
1895
- (s -> store -> chunk_size << SECTOR_SHIFT )) {
2012
+ if (!pe -> started && io_overlaps_chunk (s , bio )) {
1896
2013
pe -> started = 1 ;
1897
2014
1898
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
2256
unsigned sz = 0 ;
2140
2257
struct dm_snapshot * snap = ti -> private ;
2258
+ unsigned num_features ;
2141
2259
2142
2260
switch (type ) {
2143
2261
case STATUSTYPE_INFO :
@@ -2178,8 +2296,16 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
2178
2296
* make sense.
2179
2297
*/
2180
2298
DMEMIT ("%s %s" , snap -> origin -> name , snap -> cow -> name );
2181
- snap -> store -> type -> status (snap -> store , type , result + sz ,
2182
- maxlen - sz );
2299
+ sz += snap -> store -> type -> status (snap -> store , type , result + 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
2309
break ;
2184
2310
}
2185
2311
}
@@ -2198,6 +2324,22 @@ static int snapshot_iterate_devices(struct dm_target *ti,
2198
2324
return r ;
2199
2325
}
2200
2326
2327
+ static 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
2345
* Origin methods
@@ -2522,7 +2664,7 @@ static struct target_type origin_target = {
2522
2664
2523
2665
static struct target_type snapshot_target = {
2524
2666
.name = "snapshot" ,
2525
- .version = {1 , 15 , 0 },
2667
+ .version = {1 , 16 , 0 },
2526
2668
.module = THIS_MODULE ,
2527
2669
.ctr = snapshot_ctr ,
2528
2670
.dtr = snapshot_dtr ,
@@ -2532,11 +2674,12 @@ static struct target_type snapshot_target = {
2532
2674
.resume = snapshot_resume ,
2533
2675
.status = snapshot_status ,
2534
2676
.iterate_devices = snapshot_iterate_devices ,
2677
+ .io_hints = snapshot_io_hints ,
2535
2678
};
2536
2679
2537
2680
static struct target_type merge_target = {
2538
2681
.name = dm_snapshot_merge_target_name ,
2539
- .version = {1 , 4 , 0 },
2682
+ .version = {1 , 5 , 0 },
2540
2683
.module = THIS_MODULE ,
2541
2684
.ctr = snapshot_ctr ,
2542
2685
.dtr = snapshot_dtr ,
@@ -2547,6 +2690,7 @@ static struct target_type merge_target = {
2547
2690
.resume = snapshot_merge_resume ,
2548
2691
.status = snapshot_status ,
2549
2692
.iterate_devices = snapshot_iterate_devices ,
2693
+ .io_hints = snapshot_io_hints ,
2550
2694
};
2551
2695
2552
2696
static int __init dm_snapshot_init (void )
0 commit comments