diff options
| -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, |
