aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2009-12-10 18:52:32 -0500
committerAlasdair G Kergon <agk@redhat.com>2009-12-10 18:52:32 -0500
commit9d3b15c4c776b041f9ee81810cbd375275411829 (patch)
tree8298b50b4d9cf11355e622e6b7c314628e5c6256 /drivers
parent10b8106a70433e14153469ebbdd189776500e238 (diff)
dm snapshot: permit only one merge at once
Merging more than one snapshot is not supported, so prevent this happening. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm-snap.c33
1 files changed, 27 insertions, 6 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 23e3396e43b9..7ddee7c0c518 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -300,8 +300,10 @@ static void __insert_origin(struct origin *o)
300 * Returns number of snapshots registered using the supplied cow device, plus: 300 * Returns number of snapshots registered using the supplied cow device, plus:
301 * snap_src - a snapshot suitable for use as a source of exception handover 301 * snap_src - a snapshot suitable for use as a source of exception handover
302 * snap_dest - a snapshot capable of receiving exception handover. 302 * snap_dest - a snapshot capable of receiving exception handover.
303 * snap_merge - an existing snapshot-merge target linked to the same origin.
304 * There can be at most one snapshot-merge target. The parameter is optional.
303 * 305 *
304 * Possible return values and states: 306 * Possible return values and states of snap_src and snap_dest.
305 * 0: NULL, NULL - first new snapshot 307 * 0: NULL, NULL - first new snapshot
306 * 1: snap_src, NULL - normal snapshot 308 * 1: snap_src, NULL - normal snapshot
307 * 2: snap_src, snap_dest - waiting for handover 309 * 2: snap_src, snap_dest - waiting for handover
@@ -310,7 +312,8 @@ static void __insert_origin(struct origin *o)
310 */ 312 */
311static int __find_snapshots_sharing_cow(struct dm_snapshot *snap, 313static int __find_snapshots_sharing_cow(struct dm_snapshot *snap,
312 struct dm_snapshot **snap_src, 314 struct dm_snapshot **snap_src,
313 struct dm_snapshot **snap_dest) 315 struct dm_snapshot **snap_dest,
316 struct dm_snapshot **snap_merge)
314{ 317{
315 struct dm_snapshot *s; 318 struct dm_snapshot *s;
316 struct origin *o; 319 struct origin *o;
@@ -322,6 +325,8 @@ static int __find_snapshots_sharing_cow(struct dm_snapshot *snap,
322 goto out; 325 goto out;
323 326
324 list_for_each_entry(s, &o->snapshots, list) { 327 list_for_each_entry(s, &o->snapshots, list) {
328 if (dm_target_is_snapshot_merge(s->ti) && snap_merge)
329 *snap_merge = s;
325 if (!bdev_equal(s->cow->bdev, snap->cow->bdev)) 330 if (!bdev_equal(s->cow->bdev, snap->cow->bdev))
326 continue; 331 continue;
327 332
@@ -349,9 +354,11 @@ out:
349static int __validate_exception_handover(struct dm_snapshot *snap) 354static int __validate_exception_handover(struct dm_snapshot *snap)
350{ 355{
351 struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; 356 struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
357 struct dm_snapshot *snap_merge = NULL;
352 358
353 /* Does snapshot need exceptions handed over to it? */ 359 /* Does snapshot need exceptions handed over to it? */
354 if ((__find_snapshots_sharing_cow(snap, &snap_src, &snap_dest) == 2) || 360 if ((__find_snapshots_sharing_cow(snap, &snap_src, &snap_dest,
361 &snap_merge) == 2) ||
355 snap_dest) { 362 snap_dest) {
356 snap->ti->error = "Snapshot cow pairing for exception " 363 snap->ti->error = "Snapshot cow pairing for exception "
357 "table handover failed"; 364 "table handover failed";
@@ -365,6 +372,20 @@ static int __validate_exception_handover(struct dm_snapshot *snap)
365 if (!snap_src) 372 if (!snap_src)
366 return 0; 373 return 0;
367 374
375 /*
376 * Non-snapshot-merge handover?
377 */
378 if (!dm_target_is_snapshot_merge(snap->ti))
379 return 1;
380
381 /*
382 * Do not allow more than one merging snapshot.
383 */
384 if (snap_merge) {
385 snap->ti->error = "A snapshot is already merging.";
386 return -EINVAL;
387 }
388
368 return 1; 389 return 1;
369} 390}
370 391
@@ -933,7 +954,7 @@ static void snapshot_dtr(struct dm_target *ti)
933 954
934 down_read(&_origins_lock); 955 down_read(&_origins_lock);
935 /* Check whether exception handover must be cancelled */ 956 /* Check whether exception handover must be cancelled */
936 (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest); 957 (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
937 if (snap_src && snap_dest && (s == snap_src)) { 958 if (snap_src && snap_dest && (s == snap_src)) {
938 down_write(&snap_dest->lock); 959 down_write(&snap_dest->lock);
939 snap_dest->valid = 0; 960 snap_dest->valid = 0;
@@ -1399,7 +1420,7 @@ static int snapshot_preresume(struct dm_target *ti)
1399 struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; 1420 struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
1400 1421
1401 down_read(&_origins_lock); 1422 down_read(&_origins_lock);
1402 (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest); 1423 (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
1403 if (snap_src && snap_dest) { 1424 if (snap_src && snap_dest) {
1404 down_read(&snap_src->lock); 1425 down_read(&snap_src->lock);
1405 if (s == snap_src) { 1426 if (s == snap_src) {
@@ -1424,7 +1445,7 @@ static void snapshot_resume(struct dm_target *ti)
1424 struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; 1445 struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
1425 1446
1426 down_read(&_origins_lock); 1447 down_read(&_origins_lock);
1427 (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest); 1448 (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
1428 if (snap_src && snap_dest) { 1449 if (snap_src && snap_dest) {
1429 down_write(&snap_src->lock); 1450 down_write(&snap_src->lock);
1430 down_write_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING); 1451 down_write_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING);