diff options
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r-- | drivers/md/dm-snap.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index bb4b733697b3..4c80e82f941c 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -71,7 +71,10 @@ struct dm_snapshot { | |||
71 | /* List of snapshots per Origin */ | 71 | /* List of snapshots per Origin */ |
72 | struct list_head list; | 72 | struct list_head list; |
73 | 73 | ||
74 | /* You can't use a snapshot if this is 0 (e.g. if full) */ | 74 | /* |
75 | * You can't use a snapshot if this is 0 (e.g. if full). | ||
76 | * A snapshot-merge target never clears this. | ||
77 | */ | ||
75 | int valid; | 78 | int valid; |
76 | 79 | ||
77 | /* Origin writes don't trigger exceptions until this is set */ | 80 | /* Origin writes don't trigger exceptions until this is set */ |
@@ -107,6 +110,21 @@ struct dm_snapshot { | |||
107 | spinlock_t tracked_chunk_lock; | 110 | spinlock_t tracked_chunk_lock; |
108 | struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE]; | 111 | struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE]; |
109 | 112 | ||
113 | /* | ||
114 | * The merge operation failed if this flag is set. | ||
115 | * Failure modes are handled as follows: | ||
116 | * - I/O error reading the header | ||
117 | * => don't load the target; abort. | ||
118 | * - Header does not have "valid" flag set | ||
119 | * => use the origin; forget about the snapshot. | ||
120 | * - I/O error when reading exceptions | ||
121 | * => don't load the target; abort. | ||
122 | * (We can't use the intermediate origin state.) | ||
123 | * - I/O error while merging | ||
124 | * => stop merging; set merge_failed; process I/O normally. | ||
125 | */ | ||
126 | int merge_failed; | ||
127 | |||
110 | /* Wait for events based on state_bits */ | 128 | /* Wait for events based on state_bits */ |
111 | unsigned long state_bits; | 129 | unsigned long state_bits; |
112 | 130 | ||
@@ -900,9 +918,13 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s) | |||
900 | linear_chunks = s->store->type->prepare_merge(s->store, &old_chunk, | 918 | linear_chunks = s->store->type->prepare_merge(s->store, &old_chunk, |
901 | &new_chunk); | 919 | &new_chunk); |
902 | if (linear_chunks <= 0) { | 920 | if (linear_chunks <= 0) { |
903 | if (linear_chunks < 0) | 921 | if (linear_chunks < 0) { |
904 | DMERR("Read error in exception store: " | 922 | DMERR("Read error in exception store: " |
905 | "shutting down merge"); | 923 | "shutting down merge"); |
924 | down_write(&s->lock); | ||
925 | s->merge_failed = 1; | ||
926 | up_write(&s->lock); | ||
927 | } | ||
906 | goto shut; | 928 | goto shut; |
907 | } | 929 | } |
908 | 930 | ||
@@ -988,6 +1010,7 @@ static void merge_callback(int read_err, unsigned long write_err, void *context) | |||
988 | 1010 | ||
989 | shut: | 1011 | shut: |
990 | down_write(&s->lock); | 1012 | down_write(&s->lock); |
1013 | s->merge_failed = 1; | ||
991 | b = __release_queued_bios_after_merge(s); | 1014 | b = __release_queued_bios_after_merge(s); |
992 | up_write(&s->lock); | 1015 | up_write(&s->lock); |
993 | error_bios(b); | 1016 | error_bios(b); |
@@ -1090,6 +1113,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1090 | INIT_LIST_HEAD(&s->list); | 1113 | INIT_LIST_HEAD(&s->list); |
1091 | spin_lock_init(&s->pe_lock); | 1114 | spin_lock_init(&s->pe_lock); |
1092 | s->state_bits = 0; | 1115 | s->state_bits = 0; |
1116 | s->merge_failed = 0; | ||
1093 | s->first_merging_chunk = 0; | 1117 | s->first_merging_chunk = 0; |
1094 | s->num_merging_chunks = 0; | 1118 | s->num_merging_chunks = 0; |
1095 | bio_list_init(&s->bios_queued_during_merge); | 1119 | bio_list_init(&s->bios_queued_during_merge); |
@@ -1835,6 +1859,8 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, | |||
1835 | 1859 | ||
1836 | if (!snap->valid) | 1860 | if (!snap->valid) |
1837 | DMEMIT("Invalid"); | 1861 | DMEMIT("Invalid"); |
1862 | else if (snap->merge_failed) | ||
1863 | DMEMIT("Merge failed"); | ||
1838 | else { | 1864 | else { |
1839 | if (snap->store->type->usage) { | 1865 | if (snap->store->type->usage) { |
1840 | sector_t total_sectors, sectors_allocated, | 1866 | sector_t total_sectors, sectors_allocated, |