diff mbox series

[-next] dm snapshot: record cause of invalidating snapshot

Message ID 20230810064406.1672148-1-lilingfeng3@huawei.com (mailing list archive)
State New, archived
Headers show
Series [-next] dm snapshot: record cause of invalidating snapshot | expand

Commit Message

Li Lingfeng Aug. 10, 2023, 6:44 a.m. UTC
The cause of invalidating snapshot will be print in log. However, if we
lost the log, we will never get the cause. What we can get by "dmsetup
status" is the state of "Invalid" without the cause.

Record cause of invalidating snapshot in snapshot->valid, so that we can
query the cause by "dmsetup status".

Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
---
 drivers/md/dm-snap.c | 60 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 45 insertions(+), 15 deletions(-)

Comments

Li Lingfeng Sept. 9, 2023, 11:09 a.m. UTC | #1
Friendly ping ...

Thanks

在 2023/8/10 14:44, Li Lingfeng 写道:
> The cause of invalidating snapshot will be print in log. However, if we
> lost the log, we will never get the cause. What we can get by "dmsetup
> status" is the state of "Invalid" without the cause.
>
> Record cause of invalidating snapshot in snapshot->valid, so that we can
> query the cause by "dmsetup status".
>
> Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
> ---
>   drivers/md/dm-snap.c | 60 +++++++++++++++++++++++++++++++++-----------
>   1 file changed, 45 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
> index 41735a25d50a..48788431e7bf 100644
> --- a/drivers/md/dm-snap.c
> +++ b/drivers/md/dm-snap.c
> @@ -39,6 +39,28 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge";
>   #define DM_TRACKED_CHUNK_HASH(x)	((unsigned long)(x) & \
>   					 (DM_TRACKED_CHUNK_HASH_SIZE - 1))
>   
> +#define INVALID_CAUSE_BIT		16
> +#define DM_SNAPSHOT_VALID(s)		(s->valid & \
> +					((1 << INVALID_CAUSE_BIT) - 1))
> +#define DM_SNAPSHOT_INVALID_CAUSE(s)	(s->valid >> INVALID_CAUSE_BIT)
> +#define SET_INVALID_CAUSE(s, cause)	(s->valid = \
> +					(DM_SNAPSHOT_VALID(s) | \
> +					(cause << INVALID_CAUSE_BIT)))
> +
> +enum invalid_cause {
> +	INVALID_BY_METADATA = 1,
> +	INVALID_BY_HANDOVER = 2,
> +	INVALID_BY_CACELLING_HANDOVER = 3,
> +	INVALID_BY_EIO = 4,
> +	INVALID_BY_ENOMEM = 5
> +};
> +
> +char *display_invalid_cause[] = {"by METADATA",
> +				 "by HANDOVER",
> +				 "by CANCELLING HANDOVER",
> +				 "by EIO",
> +				 "by ENOMEM"};
> +
>   struct dm_exception_table {
>   	uint32_t hash_mask;
>   	unsigned hash_shift;
> @@ -1054,7 +1076,7 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s)
>   	/*
>   	 * valid flag never changes during merge, so no lock required.
>   	 */
> -	if (!s->valid) {
> +	if (!DM_SNAPSHOT_VALID(s)) {
>   		DMERR("Snapshot is invalid: can't merge");
>   		goto shut;
>   	}
> @@ -1403,6 +1425,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
>   		goto bad_read_metadata;
>   	} else if (r > 0) {
>   		s->valid = 0;
> +		SET_INVALID_CAUSE(s, INVALID_BY_METADATA);
>   		DMWARN("Snapshot is marked invalid.");
>   	}
>   
> @@ -1480,6 +1503,7 @@ static void __handover_exceptions(struct dm_snapshot *snap_src,
>   	 * Set source invalid to ensure it receives no further I/O.
>   	 */
>   	snap_src->valid = 0;
> +	SET_INVALID_CAUSE(snap_src, INVALID_BY_HANDOVER);
>   }
>   
>   static void snapshot_dtr(struct dm_target *ti)
> @@ -1496,6 +1520,7 @@ static void snapshot_dtr(struct dm_target *ti)
>   	if (snap_src && snap_dest && (s == snap_src)) {
>   		down_write(&snap_dest->lock);
>   		snap_dest->valid = 0;
> +		SET_INVALID_CAUSE(snap_dest, INVALID_BY_HANDOVER);
>   		up_write(&snap_dest->lock);
>   		DMERR("Cancelling snapshot handover.");
>   	}
> @@ -1635,18 +1660,21 @@ static void error_bios(struct bio *bio)
>   
>   static void __invalidate_snapshot(struct dm_snapshot *s, int err)
>   {
> -	if (!s->valid)
> +	if (!DM_SNAPSHOT_VALID(s))
>   		return;
>   
> -	if (err == -EIO)
> -		DMERR("Invalidating snapshot: Error reading/writing.");
> -	else if (err == -ENOMEM)
> -		DMERR("Invalidating snapshot: Unable to allocate exception.");
> -
>   	if (s->store->type->drop_snapshot)
>   		s->store->type->drop_snapshot(s->store);
>   
>   	s->valid = 0;
> +	if (err == -EIO) {
> +		SET_INVALID_CAUSE(s, INVALID_BY_EIO);
> +		DMERR("Invalidating snapshot: Error reading/writing.");
> +	} else if (err == -ENOMEM) {
> +		SET_INVALID_CAUSE(s, INVALID_BY_ENOMEM);
> +		DMERR("Invalidating snapshot: Unable to allocate exception.");
> +	}
> +
>   
>   	dm_table_event(s->ti->table);
>   }
> @@ -1692,7 +1720,7 @@ static void pending_complete(void *context, int success)
>   
>   	down_read(&s->lock);
>   	dm_exception_table_lock(&lock);
> -	if (!s->valid) {
> +	if (!DM_SNAPSHOT_VALID(s)) {
>   		up_read(&s->lock);
>   		free_completed_exception(e);
>   		error = 1;
> @@ -1984,7 +2012,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
>   
>   	/* Full snapshots are not usable */
>   	/* To get here the table must be live so s->active is always set. */
> -	if (!s->valid)
> +	if (!DM_SNAPSHOT_VALID(s))
>   		return DM_MAPIO_KILL;
>   
>   	if (bio_data_dir(bio) == WRITE) {
> @@ -1995,7 +2023,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
>   	down_read(&s->lock);
>   	dm_exception_table_lock(&lock);
>   
> -	if (!s->valid || (unlikely(s->snapshot_overflowed) &&
> +	if (!DM_SNAPSHOT_VALID(s) || (unlikely(s->snapshot_overflowed) &&
>   	    bio_data_dir(bio) == WRITE)) {
>   		r = DM_MAPIO_KILL;
>   		goto out_unlock;
> @@ -2068,7 +2096,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
>   				down_write(&s->lock);
>   
>   				if (s->store->userspace_supports_overflow) {
> -					if (s->valid && !s->snapshot_overflowed) {
> +					if (DM_SNAPSHOT_VALID(s) && !s->snapshot_overflowed) {
>   						s->snapshot_overflowed = 1;
>   						DMERR("Snapshot overflowed: Unable to allocate exception.");
>   					}
> @@ -2159,7 +2187,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio)
>   	down_write(&s->lock);
>   
>   	/* Full merging snapshots are redirected to the origin */
> -	if (!s->valid)
> +	if (!DM_SNAPSHOT_VALID(s))
>   		goto redirect_to_origin;
>   
>   	/* If the block is already remapped - use that */
> @@ -2344,8 +2372,10 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
>   
>   		down_write(&snap->lock);
>   
> -		if (!snap->valid)
> -			DMEMIT("Invalid");
> +		if (!DM_SNAPSHOT_VALID(snap))
> +			DMEMIT("Invalid %s", DM_SNAPSHOT_INVALID_CAUSE(snap) ?
> +					display_invalid_cause[DM_SNAPSHOT_INVALID_CAUSE(snap) - 1] :
> +					"");
>   		else if (snap->merge_failed)
>   			DMEMIT("Merge failed");
>   		else if (snap->snapshot_overflowed)
> @@ -2477,7 +2507,7 @@ static int __origin_write(struct list_head *snapshots, sector_t sector,
>   		dm_exception_table_lock(&lock);
>   
>   		/* Only deal with valid and active snapshots */
> -		if (!snap->valid || !snap->active)
> +		if (!DM_SNAPSHOT_VALID(snap) || !snap->active)
>   			goto next_snapshot;
>   
>   		pe = __lookup_pending_exception(snap, chunk);

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel
Li Lingfeng Oct. 11, 2023, 2:36 a.m. UTC | #2
Ping again.

Thanks

在 2023/9/9 19:09, Li Lingfeng 写道:
> Friendly ping ...
>
> Thanks
>
> 在 2023/8/10 14:44, Li Lingfeng 写道:
>> The cause of invalidating snapshot will be print in log. However, if we
>> lost the log, we will never get the cause. What we can get by "dmsetup
>> status" is the state of "Invalid" without the cause.
>>
>> Record cause of invalidating snapshot in snapshot->valid, so that we can
>> query the cause by "dmsetup status".
>>
>> Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
>> ---
>>   drivers/md/dm-snap.c | 60 +++++++++++++++++++++++++++++++++-----------
>>   1 file changed, 45 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
>> index 41735a25d50a..48788431e7bf 100644
>> --- a/drivers/md/dm-snap.c
>> +++ b/drivers/md/dm-snap.c
>> @@ -39,6 +39,28 @@ static const char dm_snapshot_merge_target_name[] 
>> = "snapshot-merge";
>>   #define DM_TRACKED_CHUNK_HASH(x)    ((unsigned long)(x) & \
>>                        (DM_TRACKED_CHUNK_HASH_SIZE - 1))
>>   +#define INVALID_CAUSE_BIT        16
>> +#define DM_SNAPSHOT_VALID(s)        (s->valid & \
>> +                    ((1 << INVALID_CAUSE_BIT) - 1))
>> +#define DM_SNAPSHOT_INVALID_CAUSE(s)    (s->valid >> INVALID_CAUSE_BIT)
>> +#define SET_INVALID_CAUSE(s, cause)    (s->valid = \
>> +                    (DM_SNAPSHOT_VALID(s) | \
>> +                    (cause << INVALID_CAUSE_BIT)))
>> +
>> +enum invalid_cause {
>> +    INVALID_BY_METADATA = 1,
>> +    INVALID_BY_HANDOVER = 2,
>> +    INVALID_BY_CACELLING_HANDOVER = 3,
>> +    INVALID_BY_EIO = 4,
>> +    INVALID_BY_ENOMEM = 5
>> +};
>> +
>> +char *display_invalid_cause[] = {"by METADATA",
>> +                 "by HANDOVER",
>> +                 "by CANCELLING HANDOVER",
>> +                 "by EIO",
>> +                 "by ENOMEM"};
>> +
>>   struct dm_exception_table {
>>       uint32_t hash_mask;
>>       unsigned hash_shift;
>> @@ -1054,7 +1076,7 @@ static void snapshot_merge_next_chunks(struct 
>> dm_snapshot *s)
>>       /*
>>        * valid flag never changes during merge, so no lock required.
>>        */
>> -    if (!s->valid) {
>> +    if (!DM_SNAPSHOT_VALID(s)) {
>>           DMERR("Snapshot is invalid: can't merge");
>>           goto shut;
>>       }
>> @@ -1403,6 +1425,7 @@ static int snapshot_ctr(struct dm_target *ti, 
>> unsigned int argc, char **argv)
>>           goto bad_read_metadata;
>>       } else if (r > 0) {
>>           s->valid = 0;
>> +        SET_INVALID_CAUSE(s, INVALID_BY_METADATA);
>>           DMWARN("Snapshot is marked invalid.");
>>       }
>>   @@ -1480,6 +1503,7 @@ static void __handover_exceptions(struct 
>> dm_snapshot *snap_src,
>>        * Set source invalid to ensure it receives no further I/O.
>>        */
>>       snap_src->valid = 0;
>> +    SET_INVALID_CAUSE(snap_src, INVALID_BY_HANDOVER);
>>   }
>>     static void snapshot_dtr(struct dm_target *ti)
>> @@ -1496,6 +1520,7 @@ static void snapshot_dtr(struct dm_target *ti)
>>       if (snap_src && snap_dest && (s == snap_src)) {
>>           down_write(&snap_dest->lock);
>>           snap_dest->valid = 0;
>> +        SET_INVALID_CAUSE(snap_dest, INVALID_BY_HANDOVER);
>>           up_write(&snap_dest->lock);
>>           DMERR("Cancelling snapshot handover.");
>>       }
>> @@ -1635,18 +1660,21 @@ static void error_bios(struct bio *bio)
>>     static void __invalidate_snapshot(struct dm_snapshot *s, int err)
>>   {
>> -    if (!s->valid)
>> +    if (!DM_SNAPSHOT_VALID(s))
>>           return;
>>   -    if (err == -EIO)
>> -        DMERR("Invalidating snapshot: Error reading/writing.");
>> -    else if (err == -ENOMEM)
>> -        DMERR("Invalidating snapshot: Unable to allocate exception.");
>> -
>>       if (s->store->type->drop_snapshot)
>>           s->store->type->drop_snapshot(s->store);
>>         s->valid = 0;
>> +    if (err == -EIO) {
>> +        SET_INVALID_CAUSE(s, INVALID_BY_EIO);
>> +        DMERR("Invalidating snapshot: Error reading/writing.");
>> +    } else if (err == -ENOMEM) {
>> +        SET_INVALID_CAUSE(s, INVALID_BY_ENOMEM);
>> +        DMERR("Invalidating snapshot: Unable to allocate exception.");
>> +    }
>> +
>>         dm_table_event(s->ti->table);
>>   }
>> @@ -1692,7 +1720,7 @@ static void pending_complete(void *context, int 
>> success)
>>         down_read(&s->lock);
>>       dm_exception_table_lock(&lock);
>> -    if (!s->valid) {
>> +    if (!DM_SNAPSHOT_VALID(s)) {
>>           up_read(&s->lock);
>>           free_completed_exception(e);
>>           error = 1;
>> @@ -1984,7 +2012,7 @@ static int snapshot_map(struct dm_target *ti, 
>> struct bio *bio)
>>         /* Full snapshots are not usable */
>>       /* To get here the table must be live so s->active is always 
>> set. */
>> -    if (!s->valid)
>> +    if (!DM_SNAPSHOT_VALID(s))
>>           return DM_MAPIO_KILL;
>>         if (bio_data_dir(bio) == WRITE) {
>> @@ -1995,7 +2023,7 @@ static int snapshot_map(struct dm_target *ti, 
>> struct bio *bio)
>>       down_read(&s->lock);
>>       dm_exception_table_lock(&lock);
>>   -    if (!s->valid || (unlikely(s->snapshot_overflowed) &&
>> +    if (!DM_SNAPSHOT_VALID(s) || (unlikely(s->snapshot_overflowed) &&
>>           bio_data_dir(bio) == WRITE)) {
>>           r = DM_MAPIO_KILL;
>>           goto out_unlock;
>> @@ -2068,7 +2096,7 @@ static int snapshot_map(struct dm_target *ti, 
>> struct bio *bio)
>>                   down_write(&s->lock);
>>                     if (s->store->userspace_supports_overflow) {
>> -                    if (s->valid && !s->snapshot_overflowed) {
>> +                    if (DM_SNAPSHOT_VALID(s) && 
>> !s->snapshot_overflowed) {
>>                           s->snapshot_overflowed = 1;
>>                           DMERR("Snapshot overflowed: Unable to 
>> allocate exception.");
>>                       }
>> @@ -2159,7 +2187,7 @@ static int snapshot_merge_map(struct dm_target 
>> *ti, struct bio *bio)
>>       down_write(&s->lock);
>>         /* Full merging snapshots are redirected to the origin */
>> -    if (!s->valid)
>> +    if (!DM_SNAPSHOT_VALID(s))
>>           goto redirect_to_origin;
>>         /* If the block is already remapped - use that */
>> @@ -2344,8 +2372,10 @@ static void snapshot_status(struct dm_target 
>> *ti, status_type_t type,
>>             down_write(&snap->lock);
>>   -        if (!snap->valid)
>> -            DMEMIT("Invalid");
>> +        if (!DM_SNAPSHOT_VALID(snap))
>> +            DMEMIT("Invalid %s", DM_SNAPSHOT_INVALID_CAUSE(snap) ?
>> + display_invalid_cause[DM_SNAPSHOT_INVALID_CAUSE(snap) - 1] :
>> +                    "");
>>           else if (snap->merge_failed)
>>               DMEMIT("Merge failed");
>>           else if (snap->snapshot_overflowed)
>> @@ -2477,7 +2507,7 @@ static int __origin_write(struct list_head 
>> *snapshots, sector_t sector,
>>           dm_exception_table_lock(&lock);
>>             /* Only deal with valid and active snapshots */
>> -        if (!snap->valid || !snap->active)
>> +        if (!DM_SNAPSHOT_VALID(snap) || !snap->active)
>>               goto next_snapshot;
>>             pe = __lookup_pending_exception(snap, chunk);

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel
diff mbox series

Patch

diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 41735a25d50a..48788431e7bf 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -39,6 +39,28 @@  static const char dm_snapshot_merge_target_name[] = "snapshot-merge";
 #define DM_TRACKED_CHUNK_HASH(x)	((unsigned long)(x) & \
 					 (DM_TRACKED_CHUNK_HASH_SIZE - 1))
 
+#define INVALID_CAUSE_BIT		16
+#define DM_SNAPSHOT_VALID(s)		(s->valid & \
+					((1 << INVALID_CAUSE_BIT) - 1))
+#define DM_SNAPSHOT_INVALID_CAUSE(s)	(s->valid >> INVALID_CAUSE_BIT)
+#define SET_INVALID_CAUSE(s, cause)	(s->valid = \
+					(DM_SNAPSHOT_VALID(s) | \
+					(cause << INVALID_CAUSE_BIT)))
+
+enum invalid_cause {
+	INVALID_BY_METADATA = 1,
+	INVALID_BY_HANDOVER = 2,
+	INVALID_BY_CACELLING_HANDOVER = 3,
+	INVALID_BY_EIO = 4,
+	INVALID_BY_ENOMEM = 5
+};
+
+char *display_invalid_cause[] = {"by METADATA",
+				 "by HANDOVER",
+				 "by CANCELLING HANDOVER",
+				 "by EIO",
+				 "by ENOMEM"};
+
 struct dm_exception_table {
 	uint32_t hash_mask;
 	unsigned hash_shift;
@@ -1054,7 +1076,7 @@  static void snapshot_merge_next_chunks(struct dm_snapshot *s)
 	/*
 	 * valid flag never changes during merge, so no lock required.
 	 */
-	if (!s->valid) {
+	if (!DM_SNAPSHOT_VALID(s)) {
 		DMERR("Snapshot is invalid: can't merge");
 		goto shut;
 	}
@@ -1403,6 +1425,7 @@  static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 		goto bad_read_metadata;
 	} else if (r > 0) {
 		s->valid = 0;
+		SET_INVALID_CAUSE(s, INVALID_BY_METADATA);
 		DMWARN("Snapshot is marked invalid.");
 	}
 
@@ -1480,6 +1503,7 @@  static void __handover_exceptions(struct dm_snapshot *snap_src,
 	 * Set source invalid to ensure it receives no further I/O.
 	 */
 	snap_src->valid = 0;
+	SET_INVALID_CAUSE(snap_src, INVALID_BY_HANDOVER);
 }
 
 static void snapshot_dtr(struct dm_target *ti)
@@ -1496,6 +1520,7 @@  static void snapshot_dtr(struct dm_target *ti)
 	if (snap_src && snap_dest && (s == snap_src)) {
 		down_write(&snap_dest->lock);
 		snap_dest->valid = 0;
+		SET_INVALID_CAUSE(snap_dest, INVALID_BY_HANDOVER);
 		up_write(&snap_dest->lock);
 		DMERR("Cancelling snapshot handover.");
 	}
@@ -1635,18 +1660,21 @@  static void error_bios(struct bio *bio)
 
 static void __invalidate_snapshot(struct dm_snapshot *s, int err)
 {
-	if (!s->valid)
+	if (!DM_SNAPSHOT_VALID(s))
 		return;
 
-	if (err == -EIO)
-		DMERR("Invalidating snapshot: Error reading/writing.");
-	else if (err == -ENOMEM)
-		DMERR("Invalidating snapshot: Unable to allocate exception.");
-
 	if (s->store->type->drop_snapshot)
 		s->store->type->drop_snapshot(s->store);
 
 	s->valid = 0;
+	if (err == -EIO) {
+		SET_INVALID_CAUSE(s, INVALID_BY_EIO);
+		DMERR("Invalidating snapshot: Error reading/writing.");
+	} else if (err == -ENOMEM) {
+		SET_INVALID_CAUSE(s, INVALID_BY_ENOMEM);
+		DMERR("Invalidating snapshot: Unable to allocate exception.");
+	}
+
 
 	dm_table_event(s->ti->table);
 }
@@ -1692,7 +1720,7 @@  static void pending_complete(void *context, int success)
 
 	down_read(&s->lock);
 	dm_exception_table_lock(&lock);
-	if (!s->valid) {
+	if (!DM_SNAPSHOT_VALID(s)) {
 		up_read(&s->lock);
 		free_completed_exception(e);
 		error = 1;
@@ -1984,7 +2012,7 @@  static int snapshot_map(struct dm_target *ti, struct bio *bio)
 
 	/* Full snapshots are not usable */
 	/* To get here the table must be live so s->active is always set. */
-	if (!s->valid)
+	if (!DM_SNAPSHOT_VALID(s))
 		return DM_MAPIO_KILL;
 
 	if (bio_data_dir(bio) == WRITE) {
@@ -1995,7 +2023,7 @@  static int snapshot_map(struct dm_target *ti, struct bio *bio)
 	down_read(&s->lock);
 	dm_exception_table_lock(&lock);
 
-	if (!s->valid || (unlikely(s->snapshot_overflowed) &&
+	if (!DM_SNAPSHOT_VALID(s) || (unlikely(s->snapshot_overflowed) &&
 	    bio_data_dir(bio) == WRITE)) {
 		r = DM_MAPIO_KILL;
 		goto out_unlock;
@@ -2068,7 +2096,7 @@  static int snapshot_map(struct dm_target *ti, struct bio *bio)
 				down_write(&s->lock);
 
 				if (s->store->userspace_supports_overflow) {
-					if (s->valid && !s->snapshot_overflowed) {
+					if (DM_SNAPSHOT_VALID(s) && !s->snapshot_overflowed) {
 						s->snapshot_overflowed = 1;
 						DMERR("Snapshot overflowed: Unable to allocate exception.");
 					}
@@ -2159,7 +2187,7 @@  static int snapshot_merge_map(struct dm_target *ti, struct bio *bio)
 	down_write(&s->lock);
 
 	/* Full merging snapshots are redirected to the origin */
-	if (!s->valid)
+	if (!DM_SNAPSHOT_VALID(s))
 		goto redirect_to_origin;
 
 	/* If the block is already remapped - use that */
@@ -2344,8 +2372,10 @@  static void snapshot_status(struct dm_target *ti, status_type_t type,
 
 		down_write(&snap->lock);
 
-		if (!snap->valid)
-			DMEMIT("Invalid");
+		if (!DM_SNAPSHOT_VALID(snap))
+			DMEMIT("Invalid %s", DM_SNAPSHOT_INVALID_CAUSE(snap) ?
+					display_invalid_cause[DM_SNAPSHOT_INVALID_CAUSE(snap) - 1] :
+					"");
 		else if (snap->merge_failed)
 			DMEMIT("Merge failed");
 		else if (snap->snapshot_overflowed)
@@ -2477,7 +2507,7 @@  static int __origin_write(struct list_head *snapshots, sector_t sector,
 		dm_exception_table_lock(&lock);
 
 		/* Only deal with valid and active snapshots */
-		if (!snap->valid || !snap->active)
+		if (!DM_SNAPSHOT_VALID(snap) || !snap->active)
 			goto next_snapshot;
 
 		pe = __lookup_pending_exception(snap, chunk);