diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2009-12-10 18:52:34 -0500 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2009-12-10 18:52:34 -0500 |
commit | 73dfd078cf8bfee4018fb22f1e2a24f2e05b69dc (patch) | |
tree | e5cc81262315df5c44d13d5a2eb731cfe7f8ea86 /drivers/md/dm-snap.c | |
parent | 17aa03326d40614db94bc51fbbc92df628a5c97c (diff) |
dm snapshot: trigger exceptions in remaining snapshots during merge
When there is one merging snapshot and other non-merging snapshots,
snapshot_merge_process() must make exceptions in the non-merging
snapshots.
Use a sequence count to resolve the race between I/O to chunks that are
about to be merged. The count increases each time an exception
reallocation finishes. Use wait_event() to wait until the count
changes.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r-- | drivers/md/dm-snap.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index bc52776c69cc..1498704467a7 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -270,6 +270,10 @@ struct origin { | |||
270 | static struct list_head *_origins; | 270 | static struct list_head *_origins; |
271 | static struct rw_semaphore _origins_lock; | 271 | static struct rw_semaphore _origins_lock; |
272 | 272 | ||
273 | static DECLARE_WAIT_QUEUE_HEAD(_pending_exceptions_done); | ||
274 | static DEFINE_SPINLOCK(_pending_exceptions_done_spinlock); | ||
275 | static uint64_t _pending_exceptions_done_count; | ||
276 | |||
273 | static int init_origin_hash(void) | 277 | static int init_origin_hash(void) |
274 | { | 278 | { |
275 | int i; | 279 | int i; |
@@ -847,14 +851,38 @@ out: | |||
847 | return r; | 851 | return r; |
848 | } | 852 | } |
849 | 853 | ||
854 | static int origin_write_extent(struct dm_snapshot *merging_snap, | ||
855 | sector_t sector, unsigned chunk_size); | ||
856 | |||
850 | static void merge_callback(int read_err, unsigned long write_err, | 857 | static void merge_callback(int read_err, unsigned long write_err, |
851 | void *context); | 858 | void *context); |
852 | 859 | ||
860 | static uint64_t read_pending_exceptions_done_count(void) | ||
861 | { | ||
862 | uint64_t pending_exceptions_done; | ||
863 | |||
864 | spin_lock(&_pending_exceptions_done_spinlock); | ||
865 | pending_exceptions_done = _pending_exceptions_done_count; | ||
866 | spin_unlock(&_pending_exceptions_done_spinlock); | ||
867 | |||
868 | return pending_exceptions_done; | ||
869 | } | ||
870 | |||
871 | static void increment_pending_exceptions_done_count(void) | ||
872 | { | ||
873 | spin_lock(&_pending_exceptions_done_spinlock); | ||
874 | _pending_exceptions_done_count++; | ||
875 | spin_unlock(&_pending_exceptions_done_spinlock); | ||
876 | |||
877 | wake_up_all(&_pending_exceptions_done); | ||
878 | } | ||
879 | |||
853 | static void snapshot_merge_next_chunks(struct dm_snapshot *s) | 880 | static void snapshot_merge_next_chunks(struct dm_snapshot *s) |
854 | { | 881 | { |
855 | int r; | 882 | int r; |
856 | chunk_t old_chunk, new_chunk; | 883 | chunk_t old_chunk, new_chunk; |
857 | struct dm_io_region src, dest; | 884 | struct dm_io_region src, dest; |
885 | uint64_t previous_count; | ||
858 | 886 | ||
859 | BUG_ON(!test_bit(RUNNING_MERGE, &s->state_bits)); | 887 | BUG_ON(!test_bit(RUNNING_MERGE, &s->state_bits)); |
860 | if (unlikely(test_bit(SHUTDOWN_MERGE, &s->state_bits))) | 888 | if (unlikely(test_bit(SHUTDOWN_MERGE, &s->state_bits))) |
@@ -887,6 +915,24 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s) | |||
887 | src.sector = chunk_to_sector(s->store, new_chunk); | 915 | src.sector = chunk_to_sector(s->store, new_chunk); |
888 | src.count = dest.count; | 916 | src.count = dest.count; |
889 | 917 | ||
918 | /* | ||
919 | * Reallocate any exceptions needed in other snapshots then | ||
920 | * wait for the pending exceptions to complete. | ||
921 | * Each time any pending exception (globally on the system) | ||
922 | * completes we are woken and repeat the process to find out | ||
923 | * if we can proceed. While this may not seem a particularly | ||
924 | * efficient algorithm, it is not expected to have any | ||
925 | * significant impact on performance. | ||
926 | */ | ||
927 | previous_count = read_pending_exceptions_done_count(); | ||
928 | while (origin_write_extent(s, dest.sector, s->store->chunk_size)) { | ||
929 | wait_event(_pending_exceptions_done, | ||
930 | (read_pending_exceptions_done_count() != | ||
931 | previous_count)); | ||
932 | /* Retry after the wait, until all exceptions are done. */ | ||
933 | previous_count = read_pending_exceptions_done_count(); | ||
934 | } | ||
935 | |||
890 | down_write(&s->lock); | 936 | down_write(&s->lock); |
891 | s->first_merging_chunk = old_chunk; | 937 | s->first_merging_chunk = old_chunk; |
892 | s->num_merging_chunks = 1; | 938 | s->num_merging_chunks = 1; |
@@ -1372,6 +1418,8 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) | |||
1372 | origin_bios = bio_list_get(&pe->origin_bios); | 1418 | origin_bios = bio_list_get(&pe->origin_bios); |
1373 | free_pending_exception(pe); | 1419 | free_pending_exception(pe); |
1374 | 1420 | ||
1421 | increment_pending_exceptions_done_count(); | ||
1422 | |||
1375 | up_write(&s->lock); | 1423 | up_write(&s->lock); |
1376 | 1424 | ||
1377 | /* Submit any pending write bios */ | 1425 | /* Submit any pending write bios */ |
@@ -1963,6 +2011,41 @@ static int do_origin(struct dm_dev *origin, struct bio *bio) | |||
1963 | } | 2011 | } |
1964 | 2012 | ||
1965 | /* | 2013 | /* |
2014 | * Trigger exceptions in all non-merging snapshots. | ||
2015 | * | ||
2016 | * The chunk size of the merging snapshot may be larger than the chunk | ||
2017 | * size of some other snapshot so we may need to reallocate multiple | ||
2018 | * chunks in other snapshots. | ||
2019 | * | ||
2020 | * We scan all the overlapping exceptions in the other snapshots. | ||
2021 | * Returns 1 if anything was reallocated and must be waited for, | ||
2022 | * otherwise returns 0. | ||
2023 | * | ||
2024 | * size must be a multiple of merging_snap's chunk_size. | ||
2025 | */ | ||
2026 | static int origin_write_extent(struct dm_snapshot *merging_snap, | ||
2027 | sector_t sector, unsigned size) | ||
2028 | { | ||
2029 | int must_wait = 0; | ||
2030 | sector_t n; | ||
2031 | struct origin *o; | ||
2032 | |||
2033 | /* | ||
2034 | * The origin's __minimum_chunk_size() got stored in split_io | ||
2035 | * by snapshot_merge_resume(). | ||
2036 | */ | ||
2037 | down_read(&_origins_lock); | ||
2038 | o = __lookup_origin(merging_snap->origin->bdev); | ||
2039 | for (n = 0; n < size; n += merging_snap->ti->split_io) | ||
2040 | if (__origin_write(&o->snapshots, sector + n, NULL) == | ||
2041 | DM_MAPIO_SUBMITTED) | ||
2042 | must_wait = 1; | ||
2043 | up_read(&_origins_lock); | ||
2044 | |||
2045 | return must_wait; | ||
2046 | } | ||
2047 | |||
2048 | /* | ||
1966 | * Origin: maps a linear range of a device, with hooks for snapshotting. | 2049 | * Origin: maps a linear range of a device, with hooks for snapshotting. |
1967 | */ | 2050 | */ |
1968 | 2051 | ||