diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 7401540086df..874f145431d8 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -48,6 +48,11 @@ struct pending_exception { struct bio_list origin_bios; struct bio_list snapshot_bios; + /* + * Short-term queue of pending exceptions prior to submission. + */ + struct list_head list; + /* * Other pending_exceptions that are processing this * chunk. When this list is empty, we know we can @@ -930,8 +935,9 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) int r = 1, first = 1; struct dm_snapshot *snap; struct exception *e; - struct pending_exception *pe, *last = NULL; + struct pending_exception *pe, *next_pe, *last = NULL; chunk_t chunk; + LIST_HEAD(pe_queue); /* Do all the snapshots on this origin */ list_for_each_entry (snap, snapshots, list) { @@ -965,12 +971,19 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) snap->valid = 0; } else { - if (last) + if (first) { + bio_list_add(&pe->origin_bios, bio); + r = 0; + first = 0; + } + if (last && list_empty(&pe->siblings)) list_merge(&pe->siblings, &last->siblings); - + if (!pe->started) { + pe->started = 1; + list_add_tail(&pe->list, &pe_queue); + } last = pe; - r = 0; } } @@ -980,24 +993,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) /* * Now that we have a complete pe list we can start the copying. */ - if (last) { - pe = last; - do { - down_write(&pe->snap->lock); - if (first) - bio_list_add(&pe->origin_bios, bio); - if (!pe->started) { - pe->started = 1; - up_write(&pe->snap->lock); - start_copy(pe); - } else - up_write(&pe->snap->lock); - first = 0; - pe = list_entry(pe->siblings.next, - struct pending_exception, siblings); - - } while (pe != last); - } + list_for_each_entry_safe(pe, next_pe, &pe_queue, list) + start_copy(pe); return r; }