@@ -102,6 +102,9 @@ struct dm_snapshot {
spinlock_t tracked_chunk_lock;
struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];
+ /* Merge operation failed if this is set */
+ int merge_failed;
+
/* Merge operation is in progress */
int merge_running;
@@ -775,9 +778,13 @@ static void snapshot_merge_process(struct dm_snapshot *s)
linear_chunks = s->store->type->prepare_merge(s->store,
&old_chunk, &new_chunk);
if (linear_chunks <= 0) {
- if (linear_chunks < 0)
+ if (linear_chunks < 0) {
DMERR("Read error in exception store, "
"shutting down merge");
+ down_write(&s->lock);
+ s->merge_failed = 1;
+ up_write(&s->lock);
+ }
goto shut;
}
/* Adjust old_chunk and new_chunk to reflect start of linear region */
@@ -883,6 +890,7 @@ static void merge_callback(int read_err, unsigned long write_err, void *context)
DMERR("corruption detected: exception for block %llu "
"is on disk but not in memory",
(unsigned long long)old_chunk);
+ s->merge_failed = 1;
up_write(&s->lock);
goto shut;
}
@@ -898,6 +906,7 @@ static void merge_callback(int read_err, unsigned long write_err, void *context)
(unsigned long long)e->old_chunk,
(unsigned long long)e->old_chunk +
dm_consecutive_chunk_count(e));
+ s->merge_failed = 1;
up_write(&s->lock);
goto shut;
}
@@ -1002,6 +1011,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
init_rwsem(&s->lock);
INIT_LIST_HEAD(&s->list);
spin_lock_init(&s->pe_lock);
+ s->merge_failed = 0;
s->merge_running = 0;
s->merge_shutdown = 0;
s->merge_write_interlock = 0;
@@ -1741,6 +1751,8 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
if (!snap->valid)
DMEMIT("Invalid");
+ else if (snap->merge_failed)
+ DMEMIT("Merge failed");
else {
if (snap->store->type->usage) {
sector_t total_sectors, sectors_allocated,