| @@ -229,19 +229,21 @@ static void __insert_origin(struct origin *o) · 228 unmodified lines |
| 229 | 229 | */ |
| 230 | 230 | static int register_snapshot(struct dm_snapshot *snap) |
| 231 | 231 | { |
| 232 | | − struct origin *o; |
| 232 | + struct origin *o, *new_o; |
| 233 | 233 | struct block_device *bdev = snap->origin->bdev; |
| 234 | 234 | |
| 235 | + new_o = kmalloc(sizeof(*new_o), GFP_KERNEL); |
| 236 | + if (!new_o) |
| 237 | + return -ENOMEM; |
| 238 | + |
| 235 | 239 | down_write(&_origins_lock); |
| 236 | 240 | o = __lookup_origin(bdev); |
| 237 | 241 | |
| 238 | | − if (!o) { |
| 242 | + if (o) |
| 243 | + kfree(new_o); |
| 244 | + else { |
| 239 | 245 | /* New origin */ |
| 240 | | − o = kmalloc(sizeof(*o), GFP_KERNEL); |
| 241 | | − if (!o) { |
| 242 | | − up_write(&_origins_lock); |
| 243 | | − return -ENOMEM; |
| 244 | | − } |
| 246 | + o = new_o; |
| 245 | 247 | |
| 246 | 248 | /* Initialise the struct */ |
| 247 | 249 | INIT_LIST_HEAD(&o->snapshots); |
| @@ -368,6 +370,7 @@ static struct dm_snap_pending_exception *alloc_pending_exception(struct dm_snaps · 120 unmodified lines |
| 368 | 370 | struct dm_snap_pending_exception *pe = mempool_alloc(s->pending_pool, |
| 369 | 371 | GFP_NOIO); |
| 370 | 372 | |
| 373 | + atomic_inc(&s->pending_exceptions_count); |
| 371 | 374 | pe->snap = s; |
| 372 | 375 | |
| 373 | 376 | return pe; |
| @@ -375,7 +378,11 @@ static struct dm_snap_pending_exception *alloc_pending_exception(struct dm_snaps · 1 unmodified line |
| 375 | 378 | |
| 376 | 379 | static void free_pending_exception(struct dm_snap_pending_exception *pe) |
| 377 | 380 | { |
| 378 | | − mempool_free(pe, pe->snap->pending_pool); |
| 381 | + struct dm_snapshot *s = pe->snap; |
| 382 | + |
| 383 | + mempool_free(pe, s->pending_pool); |
| 384 | + smp_mb__before_atomic_dec(); |
| 385 | + atomic_dec(&s->pending_exceptions_count); |
| 379 | 386 | } |
| 380 | 387 | |
| 381 | 388 | static void insert_completed_exception(struct dm_snapshot *s, |
| @@ -600,6 +607,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) · 218 unmodified lines |
| 600 | 607 | |
| 601 | 608 | s->valid = 1; |
| 602 | 609 | s->active = 0; |
| 610 | + atomic_set(&s->pending_exceptions_count, 0); |
| 603 | 611 | init_rwsem(&s->lock); |
| 604 | 612 | spin_lock_init(&s->pe_lock); |
| 605 | 613 | s->ti = ti; |
| @@ -726,6 +734,14 @@ static void snapshot_dtr(struct dm_target *ti) · 120 unmodified lines |
| 726 | 734 | /* After this returns there can be no new kcopyd jobs. */ |
| 727 | 735 | unregister_snapshot(s); |
| 728 | 736 | |
| 737 | + while (atomic_read(&s->pending_exceptions_count)) |
| 738 | + yield(); |
| 739 | + /* |
| 740 | + * Ensure instructions in mempool_destroy aren't reordered |
| 741 | + * before atomic_read. |
| 742 | + */ |
| 743 | + smp_mb(); |
| 744 | + |
| 729 | 745 | #ifdef CONFIG_DM_DEBUG |
| 730 | 746 | for (i = 0; i < DM_TRACKED_CHUNK_HASH_SIZE; i++) |
| 731 | 747 | BUG_ON(!hlist_empty(&s->tracked_chunk_hash[i])); |