===================================================================
@@ -106,11 +106,10 @@ struct dm_snapshot {
int merge_failed;
/* Merge operation is in progress */
- int merge_running;
+ atomic_t merge_running;
- /* It is requested to shut down merging */
- /* Cleared back to 0 when the merging is stopped */
- int merge_shutdown;
+ /* Merge completion that is triggered when using stop_merge() */
+ struct completion *merge_completion;
/* Merging this area --- block any writes */
chunk_t merge_write_interlock;
@@ -776,9 +775,17 @@ static void snapshot_merge_process(struc
struct dm_io_region src, dest;
sector_t io_size;
- BUG_ON(!s->merge_running);
- if (s->merge_shutdown)
+ BUG_ON(!atomic_read(&s->merge_running));
+ if (s->merge_completion) {
+ /* stop_merge() has requested that merging be shutdown */
+ down_write(&s->lock);
+ if (s->merge_completion) {
+ complete(s->merge_completion);
+ s->merge_completion = NULL;
+ }
+ up_write(&s->lock);
goto shut;
+ }
if (!s->valid) {
DMERR("snapshot is invalid, can't merge");
@@ -849,7 +856,7 @@ test_again:
return;
shut:
- s->merge_running = 0;
+ atomic_set(&s->merge_running, 0);
}
/* This function drops s->lock */
@@ -932,13 +939,13 @@ static void merge_callback(int read_err,
shut:
down_write(&s->lock);
release_write_interlock(s, 1);
- s->merge_running = 0;
+ atomic_set(&s->merge_running, 0);
}
static void start_merge(struct dm_snapshot *s)
{
- if (!s->merge_running && !s->merge_shutdown) {
- s->merge_running = 1;
+ if (!atomic_read(&s->merge_running)) {
+ atomic_set(&s->merge_running, 1);
snapshot_merge_process(s);
}
}
@@ -948,11 +955,13 @@ static void start_merge(struct dm_snapsh
*/
static void stop_merge(struct dm_snapshot *s)
{
- while (s->merge_running) {
- s->merge_shutdown = 1;
- msleep(1);
+ DECLARE_COMPLETION_ONSTACK(merge_stopped);
+ if (atomic_read(&s->merge_running)) {
+ down_write(&s->lock);
+ s->merge_completion = &merge_stopped;
+ up_write(&s->lock);
+ wait_for_completion(&merge_stopped);
}
- s->merge_shutdown = 0;
}
/*
@@ -1020,8 +1029,8 @@ static int snapshot_ctr(struct dm_target
INIT_LIST_HEAD(&s->list);
spin_lock_init(&s->pe_lock);
s->merge_failed = 0;
- s->merge_running = 0;
- s->merge_shutdown = 0;
+ atomic_set(&s->merge_running, 0);
+ s->merge_completion = NULL;
s->merge_write_interlock = 0;
s->merge_write_interlock_n = 0;
bio_list_init(&s->merge_write_list);