diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/dm-snap.c | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index c01e0dafec3c..59d9ef6f5051 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -1308,6 +1308,54 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, | |||
1308 | return r; | 1308 | return r; |
1309 | } | 1309 | } |
1310 | 1310 | ||
1311 | /* | ||
1312 | * A snapshot-merge target behaves like a combination of a snapshot | ||
1313 | * target and a snapshot-origin target. It only generates new | ||
1314 | * exceptions in other snapshots and not in the one that is being | ||
1315 | * merged. | ||
1316 | * | ||
1317 | * For each chunk, if there is an existing exception, it is used to | ||
1318 | * redirect I/O to the cow device. Otherwise I/O is sent to the origin, | ||
1319 | * which in turn might generate exceptions in other snapshots. | ||
1320 | */ | ||
1321 | static int snapshot_merge_map(struct dm_target *ti, struct bio *bio, | ||
1322 | union map_info *map_context) | ||
1323 | { | ||
1324 | struct dm_exception *e; | ||
1325 | struct dm_snapshot *s = ti->private; | ||
1326 | int r = DM_MAPIO_REMAPPED; | ||
1327 | chunk_t chunk; | ||
1328 | |||
1329 | chunk = sector_to_chunk(s->store, bio->bi_sector); | ||
1330 | |||
1331 | down_read(&s->lock); | ||
1332 | |||
1333 | /* Full snapshots are not usable */ | ||
1334 | if (!s->valid) { | ||
1335 | r = -EIO; | ||
1336 | goto out_unlock; | ||
1337 | } | ||
1338 | |||
1339 | /* If the block is already remapped - use that */ | ||
1340 | e = dm_lookup_exception(&s->complete, chunk); | ||
1341 | if (e) { | ||
1342 | remap_exception(s, e, bio, chunk); | ||
1343 | goto out_unlock; | ||
1344 | } | ||
1345 | |||
1346 | bio->bi_bdev = s->origin->bdev; | ||
1347 | |||
1348 | if (bio_rw(bio) == WRITE) { | ||
1349 | up_read(&s->lock); | ||
1350 | return do_origin(s->origin, bio); | ||
1351 | } | ||
1352 | |||
1353 | out_unlock: | ||
1354 | up_read(&s->lock); | ||
1355 | |||
1356 | return r; | ||
1357 | } | ||
1358 | |||
1311 | static int snapshot_end_io(struct dm_target *ti, struct bio *bio, | 1359 | static int snapshot_end_io(struct dm_target *ti, struct bio *bio, |
1312 | int error, union map_info *map_context) | 1360 | int error, union map_info *map_context) |
1313 | { | 1361 | { |
@@ -1465,6 +1513,13 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, | |||
1465 | 1513 | ||
1466 | /* Do all the snapshots on this origin */ | 1514 | /* Do all the snapshots on this origin */ |
1467 | list_for_each_entry (snap, snapshots, list) { | 1515 | list_for_each_entry (snap, snapshots, list) { |
1516 | /* | ||
1517 | * Don't make new exceptions in a merging snapshot | ||
1518 | * because it has effectively been deleted | ||
1519 | */ | ||
1520 | if (dm_target_is_snapshot_merge(snap->ti)) | ||
1521 | continue; | ||
1522 | |||
1468 | down_write(&snap->lock); | 1523 | down_write(&snap->lock); |
1469 | 1524 | ||
1470 | /* Only deal with valid and active snapshots */ | 1525 | /* Only deal with valid and active snapshots */ |
@@ -1697,7 +1752,7 @@ static struct target_type merge_target = { | |||
1697 | .module = THIS_MODULE, | 1752 | .module = THIS_MODULE, |
1698 | .ctr = snapshot_ctr, | 1753 | .ctr = snapshot_ctr, |
1699 | .dtr = snapshot_dtr, | 1754 | .dtr = snapshot_dtr, |
1700 | .map = snapshot_map, | 1755 | .map = snapshot_merge_map, |
1701 | .end_io = snapshot_end_io, | 1756 | .end_io = snapshot_end_io, |
1702 | .postsuspend = snapshot_postsuspend, | 1757 | .postsuspend = snapshot_postsuspend, |
1703 | .preresume = snapshot_preresume, | 1758 | .preresume = snapshot_preresume, |