Loading drivers/md/dm-snap.c +48 −35 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ struct pending_exception { /* * The primary pending_exception is the one that holds * the sibling_count and the list of origin_bios for a * the ref_count and the list of origin_bios for a * group of pending_exceptions. It is always last to get freed. * These fields get set up when writing to the origin. */ Loading @@ -72,7 +72,7 @@ struct pending_exception { * the sibling concerned and not pe->primary_pe->snap->lock unless * they are the same. */ atomic_t sibling_count; atomic_t ref_count; /* Pointer back to snapshot context */ struct dm_snapshot *snap; Loading Loading @@ -653,10 +653,46 @@ static void __invalidate_snapshot(struct dm_snapshot *s, dm_table_event(s->table); } static void get_pending_exception(struct pending_exception *pe) { atomic_inc(&pe->ref_count); } static struct bio *put_pending_exception(struct pending_exception *pe) { struct pending_exception *primary_pe; struct bio *origin_bios = NULL; primary_pe = pe->primary_pe; /* * If this pe is involved in a write to the origin and * it is the last sibling to complete then release * the bios for the original write to the origin. */ if (primary_pe && atomic_dec_and_test(&primary_pe->ref_count)) origin_bios = bio_list_get(&primary_pe->origin_bios); /* * Free the pe if it's not linked to an origin write or if * it's not itself a primary pe. */ if (!primary_pe || primary_pe != pe) free_pending_exception(pe); /* * Free the primary pe if nothing references it. */ if (primary_pe && !atomic_read(&primary_pe->ref_count)) free_pending_exception(primary_pe); return origin_bios; } static void pending_complete(struct pending_exception *pe, int success) { struct exception *e; struct pending_exception *primary_pe; struct dm_snapshot *s = pe->snap; struct bio *origin_bios = NULL; struct bio *snapshot_bios = NULL; Loading Loading @@ -695,30 +731,7 @@ static void pending_complete(struct pending_exception *pe, int success) out: snapshot_bios = bio_list_get(&pe->snapshot_bios); primary_pe = pe->primary_pe; /* * If this pe is involved in a write to the origin and * it is the last sibling to complete then release * the bios for the original write to the origin. */ if (primary_pe && atomic_dec_and_test(&primary_pe->sibling_count)) origin_bios = bio_list_get(&primary_pe->origin_bios); /* * Free the pe if it's not linked to an origin write or if * it's not itself a primary pe. */ if (!primary_pe || primary_pe != pe) free_pending_exception(pe); /* * Free the primary pe if nothing references it. */ if (primary_pe && !atomic_read(&primary_pe->sibling_count)) free_pending_exception(primary_pe); origin_bios = put_pending_exception(pe); up_write(&s->lock); Loading Loading @@ -829,7 +842,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) bio_list_init(&pe->origin_bios); bio_list_init(&pe->snapshot_bios); pe->primary_pe = NULL; atomic_set(&pe->sibling_count, 1); atomic_set(&pe->ref_count, 0); pe->snap = s; pe->started = 0; Loading @@ -838,6 +851,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) return NULL; } get_pending_exception(pe); insert_exception(&s->pending, &pe->e); out: Loading Loading @@ -1012,7 +1026,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) * is already remapped in this snapshot * and trigger an exception if not. * * sibling_count is initialised to 1 so pending_complete() * ref_count is initialised to 1 so pending_complete() * won't destroy the primary_pe while we're inside this loop. */ e = lookup_exception(&snap->complete, chunk); Loading Loading @@ -1043,8 +1057,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) } if (!pe->primary_pe) { atomic_inc(&primary_pe->sibling_count); pe->primary_pe = primary_pe; get_pending_exception(primary_pe); } if (!pe->started) { Loading @@ -1057,20 +1071,20 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) } if (!primary_pe) goto out; return r; /* * If this is the first time we're processing this chunk and * sibling_count is now 1 it means all the pending exceptions * ref_count is now 1 it means all the pending exceptions * got completed while we were in the loop above, so it falls to * us here to remove the primary_pe and submit any origin_bios. */ if (first && atomic_dec_and_test(&primary_pe->sibling_count)) { if (first && atomic_dec_and_test(&primary_pe->ref_count)) { flush_bios(bio_list_get(&primary_pe->origin_bios)); free_pending_exception(primary_pe); /* If we got here, pe_queue is necessarily empty. */ goto out; return r; } /* Loading @@ -1079,7 +1093,6 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) list_for_each_entry_safe(pe, next_pe, &pe_queue, list) start_copy(pe); out: return r; } Loading Loading
drivers/md/dm-snap.c +48 −35 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ struct pending_exception { /* * The primary pending_exception is the one that holds * the sibling_count and the list of origin_bios for a * the ref_count and the list of origin_bios for a * group of pending_exceptions. It is always last to get freed. * These fields get set up when writing to the origin. */ Loading @@ -72,7 +72,7 @@ struct pending_exception { * the sibling concerned and not pe->primary_pe->snap->lock unless * they are the same. */ atomic_t sibling_count; atomic_t ref_count; /* Pointer back to snapshot context */ struct dm_snapshot *snap; Loading Loading @@ -653,10 +653,46 @@ static void __invalidate_snapshot(struct dm_snapshot *s, dm_table_event(s->table); } static void get_pending_exception(struct pending_exception *pe) { atomic_inc(&pe->ref_count); } static struct bio *put_pending_exception(struct pending_exception *pe) { struct pending_exception *primary_pe; struct bio *origin_bios = NULL; primary_pe = pe->primary_pe; /* * If this pe is involved in a write to the origin and * it is the last sibling to complete then release * the bios for the original write to the origin. */ if (primary_pe && atomic_dec_and_test(&primary_pe->ref_count)) origin_bios = bio_list_get(&primary_pe->origin_bios); /* * Free the pe if it's not linked to an origin write or if * it's not itself a primary pe. */ if (!primary_pe || primary_pe != pe) free_pending_exception(pe); /* * Free the primary pe if nothing references it. */ if (primary_pe && !atomic_read(&primary_pe->ref_count)) free_pending_exception(primary_pe); return origin_bios; } static void pending_complete(struct pending_exception *pe, int success) { struct exception *e; struct pending_exception *primary_pe; struct dm_snapshot *s = pe->snap; struct bio *origin_bios = NULL; struct bio *snapshot_bios = NULL; Loading Loading @@ -695,30 +731,7 @@ static void pending_complete(struct pending_exception *pe, int success) out: snapshot_bios = bio_list_get(&pe->snapshot_bios); primary_pe = pe->primary_pe; /* * If this pe is involved in a write to the origin and * it is the last sibling to complete then release * the bios for the original write to the origin. */ if (primary_pe && atomic_dec_and_test(&primary_pe->sibling_count)) origin_bios = bio_list_get(&primary_pe->origin_bios); /* * Free the pe if it's not linked to an origin write or if * it's not itself a primary pe. */ if (!primary_pe || primary_pe != pe) free_pending_exception(pe); /* * Free the primary pe if nothing references it. */ if (primary_pe && !atomic_read(&primary_pe->sibling_count)) free_pending_exception(primary_pe); origin_bios = put_pending_exception(pe); up_write(&s->lock); Loading Loading @@ -829,7 +842,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) bio_list_init(&pe->origin_bios); bio_list_init(&pe->snapshot_bios); pe->primary_pe = NULL; atomic_set(&pe->sibling_count, 1); atomic_set(&pe->ref_count, 0); pe->snap = s; pe->started = 0; Loading @@ -838,6 +851,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) return NULL; } get_pending_exception(pe); insert_exception(&s->pending, &pe->e); out: Loading Loading @@ -1012,7 +1026,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) * is already remapped in this snapshot * and trigger an exception if not. * * sibling_count is initialised to 1 so pending_complete() * ref_count is initialised to 1 so pending_complete() * won't destroy the primary_pe while we're inside this loop. */ e = lookup_exception(&snap->complete, chunk); Loading Loading @@ -1043,8 +1057,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) } if (!pe->primary_pe) { atomic_inc(&primary_pe->sibling_count); pe->primary_pe = primary_pe; get_pending_exception(primary_pe); } if (!pe->started) { Loading @@ -1057,20 +1071,20 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) } if (!primary_pe) goto out; return r; /* * If this is the first time we're processing this chunk and * sibling_count is now 1 it means all the pending exceptions * ref_count is now 1 it means all the pending exceptions * got completed while we were in the loop above, so it falls to * us here to remove the primary_pe and submit any origin_bios. */ if (first && atomic_dec_and_test(&primary_pe->sibling_count)) { if (first && atomic_dec_and_test(&primary_pe->ref_count)) { flush_bios(bio_list_get(&primary_pe->origin_bios)); free_pending_exception(primary_pe); /* If we got here, pe_queue is necessarily empty. */ goto out; return r; } /* Loading @@ -1079,7 +1093,6 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) list_for_each_entry_safe(pe, next_pe, &pe_queue, list) start_copy(pe); out: return r; } Loading