Skip to content

Commit

Permalink
dm snapshot: don't invalidate on-disk image on snapshot write overflow
Browse files Browse the repository at this point in the history
When the snapshot overflows because of a write to the origin, the on-disk
image has to be invalidated.  However, when the snapshot overflows because
of a write to the snapshot, the on-disk image doesn't have to be
invalidated.  Change the behavior so that the on-disk image is not
invalidated in this case.

When the snapshot overflows, the variable snapshot_overflowed is set.
All writes to the snapshot are disallowed to minimize filesystem
corruption - this condition is cleared when the snapshot is deactivated
and activated.

The user can extend the overflowed snapshot, deactivate and activate it
again, run fsck (if journaling filesystem is not used) mount it and
recover the data.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
  • Loading branch information
Mikulas Patocka authored and snitm committed Aug 12, 2015
1 parent fc0a446 commit 76c44f6
Showing 1 changed file with 16 additions and 4 deletions.
20 changes: 16 additions & 4 deletions drivers/md/dm-snap.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ struct dm_snapshot {
*/
int valid;

/*
* The snapshot overflowed because of a write to the snapshot device.
* We don't have to invalidate the snapshot in this case, but we need
* to prevent further writes.
*/
int snapshot_overflowed;

/* Origin writes don't trigger exceptions until this is set */
int active;

Expand Down Expand Up @@ -1152,6 +1159,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)

s->ti = ti;
s->valid = 1;
s->snapshot_overflowed = 0;
s->active = 0;
atomic_set(&s->pending_exceptions_count, 0);
s->exception_start_sequence = 0;
Expand Down Expand Up @@ -1301,6 +1309,7 @@ static void __handover_exceptions(struct dm_snapshot *snap_src,

snap_dest->ti->max_io_len = snap_dest->store->chunk_size;
snap_dest->valid = snap_src->valid;
snap_dest->snapshot_overflowed = snap_src->snapshot_overflowed;

/*
* Set source invalid to ensure it receives no further I/O.
Expand Down Expand Up @@ -1691,7 +1700,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
* to copy an exception */
down_write(&s->lock);

if (!s->valid) {
if (!s->valid || (unlikely(s->snapshot_overflowed) && bio_rw(bio) == WRITE)) {
r = -EIO;
goto out_unlock;
}
Expand All @@ -1715,7 +1724,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
pe = alloc_pending_exception(s);
down_write(&s->lock);

if (!s->valid) {
if (!s->valid || s->snapshot_overflowed) {
free_pending_exception(pe);
r = -EIO;
goto out_unlock;
Expand All @@ -1730,7 +1739,8 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)

pe = __find_pending_exception(s, pe, chunk);
if (!pe) {
__invalidate_snapshot(s, -ENOMEM);
s->snapshot_overflowed = 1;
DMERR("Snapshot overflowed: Unable to allocate exception.");
r = -EIO;
goto out_unlock;
}
Expand Down Expand Up @@ -1990,6 +2000,8 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
DMEMIT("Invalid");
else if (snap->merge_failed)
DMEMIT("Merge failed");
else if (snap->snapshot_overflowed)
DMEMIT("Overflow");
else {
if (snap->store->type->usage) {
sector_t total_sectors, sectors_allocated,
Expand Down Expand Up @@ -2368,7 +2380,7 @@ static struct target_type origin_target = {

static struct target_type snapshot_target = {
.name = "snapshot",
.version = {1, 13, 0},
.version = {1, 14, 0},
.module = THIS_MODULE,
.ctr = snapshot_ctr,
.dtr = snapshot_dtr,
Expand Down

0 comments on commit 76c44f6

Please sign in to comment.