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>
This commit is contained in:
parent
10b8106a70
commit
9d3b15c4c7
@ -300,8 +300,10 @@ static void __insert_origin(struct origin *o)
|
|||||||
* Returns number of snapshots registered using the supplied cow device, plus:
|
* Returns number of snapshots registered using the supplied cow device, plus:
|
||||||
* snap_src - a snapshot suitable for use as a source of exception handover
|
* snap_src - a snapshot suitable for use as a source of exception handover
|
||||||
* snap_dest - a snapshot capable of receiving exception handover.
|
* snap_dest - a snapshot capable of receiving exception handover.
|
||||||
|
* snap_merge - an existing snapshot-merge target linked to the same origin.
|
||||||
|
* There can be at most one snapshot-merge target. The parameter is optional.
|
||||||
*
|
*
|
||||||
* Possible return values and states:
|
* Possible return values and states of snap_src and snap_dest.
|
||||||
* 0: NULL, NULL - first new snapshot
|
* 0: NULL, NULL - first new snapshot
|
||||||
* 1: snap_src, NULL - normal snapshot
|
* 1: snap_src, NULL - normal snapshot
|
||||||
* 2: snap_src, snap_dest - waiting for handover
|
* 2: snap_src, snap_dest - waiting for handover
|
||||||
@ -310,7 +312,8 @@ static void __insert_origin(struct origin *o)
|
|||||||
*/
|
*/
|
||||||
static int __find_snapshots_sharing_cow(struct dm_snapshot *snap,
|
static int __find_snapshots_sharing_cow(struct dm_snapshot *snap,
|
||||||
struct dm_snapshot **snap_src,
|
struct dm_snapshot **snap_src,
|
||||||
struct dm_snapshot **snap_dest)
|
struct dm_snapshot **snap_dest,
|
||||||
|
struct dm_snapshot **snap_merge)
|
||||||
{
|
{
|
||||||
struct dm_snapshot *s;
|
struct dm_snapshot *s;
|
||||||
struct origin *o;
|
struct origin *o;
|
||||||
@ -322,6 +325,8 @@ static int __find_snapshots_sharing_cow(struct dm_snapshot *snap,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
list_for_each_entry(s, &o->snapshots, list) {
|
list_for_each_entry(s, &o->snapshots, list) {
|
||||||
|
if (dm_target_is_snapshot_merge(s->ti) && snap_merge)
|
||||||
|
*snap_merge = s;
|
||||||
if (!bdev_equal(s->cow->bdev, snap->cow->bdev))
|
if (!bdev_equal(s->cow->bdev, snap->cow->bdev))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -349,9 +354,11 @@ static int __find_snapshots_sharing_cow(struct dm_snapshot *snap,
|
|||||||
static int __validate_exception_handover(struct dm_snapshot *snap)
|
static int __validate_exception_handover(struct dm_snapshot *snap)
|
||||||
{
|
{
|
||||||
struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
|
struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
|
||||||
|
struct dm_snapshot *snap_merge = NULL;
|
||||||
|
|
||||||
/* Does snapshot need exceptions handed over to it? */
|
/* Does snapshot need exceptions handed over to it? */
|
||||||
if ((__find_snapshots_sharing_cow(snap, &snap_src, &snap_dest) == 2) ||
|
if ((__find_snapshots_sharing_cow(snap, &snap_src, &snap_dest,
|
||||||
|
&snap_merge) == 2) ||
|
||||||
snap_dest) {
|
snap_dest) {
|
||||||
snap->ti->error = "Snapshot cow pairing for exception "
|
snap->ti->error = "Snapshot cow pairing for exception "
|
||||||
"table handover failed";
|
"table handover failed";
|
||||||
@ -365,6 +372,20 @@ static int __validate_exception_handover(struct dm_snapshot *snap)
|
|||||||
if (!snap_src)
|
if (!snap_src)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Non-snapshot-merge handover?
|
||||||
|
*/
|
||||||
|
if (!dm_target_is_snapshot_merge(snap->ti))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not allow more than one merging snapshot.
|
||||||
|
*/
|
||||||
|
if (snap_merge) {
|
||||||
|
snap->ti->error = "A snapshot is already merging.";
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -933,7 +954,7 @@ static void snapshot_dtr(struct dm_target *ti)
|
|||||||
|
|
||||||
down_read(&_origins_lock);
|
down_read(&_origins_lock);
|
||||||
/* Check whether exception handover must be cancelled */
|
/* Check whether exception handover must be cancelled */
|
||||||
(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest);
|
(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
|
||||||
if (snap_src && snap_dest && (s == snap_src)) {
|
if (snap_src && snap_dest && (s == snap_src)) {
|
||||||
down_write(&snap_dest->lock);
|
down_write(&snap_dest->lock);
|
||||||
snap_dest->valid = 0;
|
snap_dest->valid = 0;
|
||||||
@ -1399,7 +1420,7 @@ static int snapshot_preresume(struct dm_target *ti)
|
|||||||
struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
|
struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
|
||||||
|
|
||||||
down_read(&_origins_lock);
|
down_read(&_origins_lock);
|
||||||
(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest);
|
(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
|
||||||
if (snap_src && snap_dest) {
|
if (snap_src && snap_dest) {
|
||||||
down_read(&snap_src->lock);
|
down_read(&snap_src->lock);
|
||||||
if (s == snap_src) {
|
if (s == snap_src) {
|
||||||
@ -1424,7 +1445,7 @@ static void snapshot_resume(struct dm_target *ti)
|
|||||||
struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
|
struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
|
||||||
|
|
||||||
down_read(&_origins_lock);
|
down_read(&_origins_lock);
|
||||||
(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest);
|
(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
|
||||||
if (snap_src && snap_dest) {
|
if (snap_src && snap_dest) {
|
||||||
down_write(&snap_src->lock);
|
down_write(&snap_src->lock);
|
||||||
down_write_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING);
|
down_write_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING);
|
||||||
|
Loading…
Reference in New Issue
Block a user