diff options
-rw-r--r-- | drivers/md/dm-exception-store.h | 3 | ||||
-rw-r--r-- | drivers/md/dm-snap.c | 137 |
2 files changed, 116 insertions, 24 deletions
diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index 12b5216c2cfe..5a3c696c057f 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #define _LINUX_DM_EXCEPTION_STORE | 11 | #define _LINUX_DM_EXCEPTION_STORE |
12 | 12 | ||
13 | #include <linux/blkdev.h> | 13 | #include <linux/blkdev.h> |
14 | #include <linux/list_bl.h> | ||
14 | #include <linux/device-mapper.h> | 15 | #include <linux/device-mapper.h> |
15 | 16 | ||
16 | /* | 17 | /* |
@@ -27,7 +28,7 @@ typedef sector_t chunk_t; | |||
27 | * chunk within the device. | 28 | * chunk within the device. |
28 | */ | 29 | */ |
29 | struct dm_exception { | 30 | struct dm_exception { |
30 | struct list_head hash_list; | 31 | struct hlist_bl_node hash_list; |
31 | 32 | ||
32 | chunk_t old_chunk; | 33 | chunk_t old_chunk; |
33 | chunk_t new_chunk; | 34 | chunk_t new_chunk; |
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 5a67f408876e..10bb37e27ecf 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/kdev_t.h> | 14 | #include <linux/kdev_t.h> |
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/list_bl.h> | ||
16 | #include <linux/mempool.h> | 17 | #include <linux/mempool.h> |
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
@@ -44,7 +45,7 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge"; | |||
44 | struct dm_exception_table { | 45 | struct dm_exception_table { |
45 | uint32_t hash_mask; | 46 | uint32_t hash_mask; |
46 | unsigned hash_shift; | 47 | unsigned hash_shift; |
47 | struct list_head *table; | 48 | struct hlist_bl_head *table; |
48 | }; | 49 | }; |
49 | 50 | ||
50 | struct dm_snapshot { | 51 | struct dm_snapshot { |
@@ -618,6 +619,36 @@ static void unregister_snapshot(struct dm_snapshot *s) | |||
618 | * The lowest hash_shift bits of the chunk number are ignored, allowing | 619 | * The lowest hash_shift bits of the chunk number are ignored, allowing |
619 | * some consecutive chunks to be grouped together. | 620 | * some consecutive chunks to be grouped together. |
620 | */ | 621 | */ |
622 | static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk); | ||
623 | |||
624 | /* Lock to protect access to the completed and pending exception hash tables. */ | ||
625 | struct dm_exception_table_lock { | ||
626 | struct hlist_bl_head *complete_slot; | ||
627 | struct hlist_bl_head *pending_slot; | ||
628 | }; | ||
629 | |||
630 | static void dm_exception_table_lock_init(struct dm_snapshot *s, chunk_t chunk, | ||
631 | struct dm_exception_table_lock *lock) | ||
632 | { | ||
633 | struct dm_exception_table *complete = &s->complete; | ||
634 | struct dm_exception_table *pending = &s->pending; | ||
635 | |||
636 | lock->complete_slot = &complete->table[exception_hash(complete, chunk)]; | ||
637 | lock->pending_slot = &pending->table[exception_hash(pending, chunk)]; | ||
638 | } | ||
639 | |||
640 | static void dm_exception_table_lock(struct dm_exception_table_lock *lock) | ||
641 | { | ||
642 | hlist_bl_lock(lock->complete_slot); | ||
643 | hlist_bl_lock(lock->pending_slot); | ||
644 | } | ||
645 | |||
646 | static void dm_exception_table_unlock(struct dm_exception_table_lock *lock) | ||
647 | { | ||
648 | hlist_bl_unlock(lock->pending_slot); | ||
649 | hlist_bl_unlock(lock->complete_slot); | ||
650 | } | ||
651 | |||
621 | static int dm_exception_table_init(struct dm_exception_table *et, | 652 | static int dm_exception_table_init(struct dm_exception_table *et, |
622 | uint32_t size, unsigned hash_shift) | 653 | uint32_t size, unsigned hash_shift) |
623 | { | 654 | { |
@@ -625,12 +656,12 @@ static int dm_exception_table_init(struct dm_exception_table *et, | |||
625 | 656 | ||
626 | et->hash_shift = hash_shift; | 657 | et->hash_shift = hash_shift; |
627 | et->hash_mask = size - 1; | 658 | et->hash_mask = size - 1; |
628 | et->table = dm_vcalloc(size, sizeof(struct list_head)); | 659 | et->table = dm_vcalloc(size, sizeof(struct hlist_bl_head)); |
629 | if (!et->table) | 660 | if (!et->table) |
630 | return -ENOMEM; | 661 | return -ENOMEM; |
631 | 662 | ||
632 | for (i = 0; i < size; i++) | 663 | for (i = 0; i < size; i++) |
633 | INIT_LIST_HEAD(et->table + i); | 664 | INIT_HLIST_BL_HEAD(et->table + i); |
634 | 665 | ||
635 | return 0; | 666 | return 0; |
636 | } | 667 | } |
@@ -638,15 +669,16 @@ static int dm_exception_table_init(struct dm_exception_table *et, | |||
638 | static void dm_exception_table_exit(struct dm_exception_table *et, | 669 | static void dm_exception_table_exit(struct dm_exception_table *et, |
639 | struct kmem_cache *mem) | 670 | struct kmem_cache *mem) |
640 | { | 671 | { |
641 | struct list_head *slot; | 672 | struct hlist_bl_head *slot; |
642 | struct dm_exception *ex, *next; | 673 | struct dm_exception *ex; |
674 | struct hlist_bl_node *pos, *n; | ||
643 | int i, size; | 675 | int i, size; |
644 | 676 | ||
645 | size = et->hash_mask + 1; | 677 | size = et->hash_mask + 1; |
646 | for (i = 0; i < size; i++) { | 678 | for (i = 0; i < size; i++) { |
647 | slot = et->table + i; | 679 | slot = et->table + i; |
648 | 680 | ||
649 | list_for_each_entry_safe (ex, next, slot, hash_list) | 681 | hlist_bl_for_each_entry_safe(ex, pos, n, slot, hash_list) |
650 | kmem_cache_free(mem, ex); | 682 | kmem_cache_free(mem, ex); |
651 | } | 683 | } |
652 | 684 | ||
@@ -660,7 +692,7 @@ static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk) | |||
660 | 692 | ||
661 | static void dm_remove_exception(struct dm_exception *e) | 693 | static void dm_remove_exception(struct dm_exception *e) |
662 | { | 694 | { |
663 | list_del(&e->hash_list); | 695 | hlist_bl_del(&e->hash_list); |
664 | } | 696 | } |
665 | 697 | ||
666 | /* | 698 | /* |
@@ -670,11 +702,12 @@ static void dm_remove_exception(struct dm_exception *e) | |||
670 | static struct dm_exception *dm_lookup_exception(struct dm_exception_table *et, | 702 | static struct dm_exception *dm_lookup_exception(struct dm_exception_table *et, |
671 | chunk_t chunk) | 703 | chunk_t chunk) |
672 | { | 704 | { |
673 | struct list_head *slot; | 705 | struct hlist_bl_head *slot; |
706 | struct hlist_bl_node *pos; | ||
674 | struct dm_exception *e; | 707 | struct dm_exception *e; |
675 | 708 | ||
676 | slot = &et->table[exception_hash(et, chunk)]; | 709 | slot = &et->table[exception_hash(et, chunk)]; |
677 | list_for_each_entry (e, slot, hash_list) | 710 | hlist_bl_for_each_entry(e, pos, slot, hash_list) |
678 | if (chunk >= e->old_chunk && | 711 | if (chunk >= e->old_chunk && |
679 | chunk <= e->old_chunk + dm_consecutive_chunk_count(e)) | 712 | chunk <= e->old_chunk + dm_consecutive_chunk_count(e)) |
680 | return e; | 713 | return e; |
@@ -721,7 +754,8 @@ static void free_pending_exception(struct dm_snap_pending_exception *pe) | |||
721 | static void dm_insert_exception(struct dm_exception_table *eh, | 754 | static void dm_insert_exception(struct dm_exception_table *eh, |
722 | struct dm_exception *new_e) | 755 | struct dm_exception *new_e) |
723 | { | 756 | { |
724 | struct list_head *l; | 757 | struct hlist_bl_head *l; |
758 | struct hlist_bl_node *pos; | ||
725 | struct dm_exception *e = NULL; | 759 | struct dm_exception *e = NULL; |
726 | 760 | ||
727 | l = &eh->table[exception_hash(eh, new_e->old_chunk)]; | 761 | l = &eh->table[exception_hash(eh, new_e->old_chunk)]; |
@@ -731,7 +765,7 @@ static void dm_insert_exception(struct dm_exception_table *eh, | |||
731 | goto out; | 765 | goto out; |
732 | 766 | ||
733 | /* List is ordered by old_chunk */ | 767 | /* List is ordered by old_chunk */ |
734 | list_for_each_entry_reverse(e, l, hash_list) { | 768 | hlist_bl_for_each_entry(e, pos, l, hash_list) { |
735 | /* Insert after an existing chunk? */ | 769 | /* Insert after an existing chunk? */ |
736 | if (new_e->old_chunk == (e->old_chunk + | 770 | if (new_e->old_chunk == (e->old_chunk + |
737 | dm_consecutive_chunk_count(e) + 1) && | 771 | dm_consecutive_chunk_count(e) + 1) && |
@@ -752,12 +786,24 @@ static void dm_insert_exception(struct dm_exception_table *eh, | |||
752 | return; | 786 | return; |
753 | } | 787 | } |
754 | 788 | ||
755 | if (new_e->old_chunk > e->old_chunk) | 789 | if (new_e->old_chunk < e->old_chunk) |
756 | break; | 790 | break; |
757 | } | 791 | } |
758 | 792 | ||
759 | out: | 793 | out: |
760 | list_add(&new_e->hash_list, e ? &e->hash_list : l); | 794 | if (!e) { |
795 | /* | ||
796 | * Either the table doesn't support consecutive chunks or slot | ||
797 | * l is empty. | ||
798 | */ | ||
799 | hlist_bl_add_head(&new_e->hash_list, l); | ||
800 | } else if (new_e->old_chunk < e->old_chunk) { | ||
801 | /* Add before an existing exception */ | ||
802 | hlist_bl_add_before(&new_e->hash_list, &e->hash_list); | ||
803 | } else { | ||
804 | /* Add to l's tail: e is the last exception in this slot */ | ||
805 | hlist_bl_add_behind(&new_e->hash_list, &e->hash_list); | ||
806 | } | ||
761 | } | 807 | } |
762 | 808 | ||
763 | /* | 809 | /* |
@@ -766,6 +812,7 @@ out: | |||
766 | */ | 812 | */ |
767 | static int dm_add_exception(void *context, chunk_t old, chunk_t new) | 813 | static int dm_add_exception(void *context, chunk_t old, chunk_t new) |
768 | { | 814 | { |
815 | struct dm_exception_table_lock lock; | ||
769 | struct dm_snapshot *s = context; | 816 | struct dm_snapshot *s = context; |
770 | struct dm_exception *e; | 817 | struct dm_exception *e; |
771 | 818 | ||
@@ -778,7 +825,17 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new) | |||
778 | /* Consecutive_count is implicitly initialised to zero */ | 825 | /* Consecutive_count is implicitly initialised to zero */ |
779 | e->new_chunk = new; | 826 | e->new_chunk = new; |
780 | 827 | ||
828 | /* | ||
829 | * Although there is no need to lock access to the exception tables | ||
830 | * here, if we don't then hlist_bl_add_head(), called by | ||
831 | * dm_insert_exception(), will complain about accessing the | ||
832 | * corresponding list without locking it first. | ||
833 | */ | ||
834 | dm_exception_table_lock_init(s, old, &lock); | ||
835 | |||
836 | dm_exception_table_lock(&lock); | ||
781 | dm_insert_exception(&s->complete, e); | 837 | dm_insert_exception(&s->complete, e); |
838 | dm_exception_table_unlock(&lock); | ||
782 | 839 | ||
783 | return 0; | 840 | return 0; |
784 | } | 841 | } |
@@ -807,7 +864,7 @@ static int calc_max_buckets(void) | |||
807 | { | 864 | { |
808 | /* use a fixed size of 2MB */ | 865 | /* use a fixed size of 2MB */ |
809 | unsigned long mem = 2 * 1024 * 1024; | 866 | unsigned long mem = 2 * 1024 * 1024; |
810 | mem /= sizeof(struct list_head); | 867 | mem /= sizeof(struct hlist_bl_head); |
811 | 868 | ||
812 | return mem; | 869 | return mem; |
813 | } | 870 | } |
@@ -1473,13 +1530,18 @@ static void pending_complete(void *context, int success) | |||
1473 | struct bio *origin_bios = NULL; | 1530 | struct bio *origin_bios = NULL; |
1474 | struct bio *snapshot_bios = NULL; | 1531 | struct bio *snapshot_bios = NULL; |
1475 | struct bio *full_bio = NULL; | 1532 | struct bio *full_bio = NULL; |
1533 | struct dm_exception_table_lock lock; | ||
1476 | int error = 0; | 1534 | int error = 0; |
1477 | 1535 | ||
1536 | dm_exception_table_lock_init(s, pe->e.old_chunk, &lock); | ||
1537 | |||
1478 | if (!success) { | 1538 | if (!success) { |
1479 | /* Read/write error - snapshot is unusable */ | 1539 | /* Read/write error - snapshot is unusable */ |
1480 | down_write(&s->lock); | 1540 | down_write(&s->lock); |
1481 | __invalidate_snapshot(s, -EIO); | 1541 | __invalidate_snapshot(s, -EIO); |
1482 | error = 1; | 1542 | error = 1; |
1543 | |||
1544 | dm_exception_table_lock(&lock); | ||
1483 | goto out; | 1545 | goto out; |
1484 | } | 1546 | } |
1485 | 1547 | ||
@@ -1488,11 +1550,14 @@ static void pending_complete(void *context, int success) | |||
1488 | down_write(&s->lock); | 1550 | down_write(&s->lock); |
1489 | __invalidate_snapshot(s, -ENOMEM); | 1551 | __invalidate_snapshot(s, -ENOMEM); |
1490 | error = 1; | 1552 | error = 1; |
1553 | |||
1554 | dm_exception_table_lock(&lock); | ||
1491 | goto out; | 1555 | goto out; |
1492 | } | 1556 | } |
1493 | *e = pe->e; | 1557 | *e = pe->e; |
1494 | 1558 | ||
1495 | down_write(&s->lock); | 1559 | down_write(&s->lock); |
1560 | dm_exception_table_lock(&lock); | ||
1496 | if (!s->valid) { | 1561 | if (!s->valid) { |
1497 | free_completed_exception(e); | 1562 | free_completed_exception(e); |
1498 | error = 1; | 1563 | error = 1; |
@@ -1510,14 +1575,19 @@ static void pending_complete(void *context, int success) | |||
1510 | 1575 | ||
1511 | /* Wait for conflicting reads to drain */ | 1576 | /* Wait for conflicting reads to drain */ |
1512 | if (__chunk_is_tracked(s, pe->e.old_chunk)) { | 1577 | if (__chunk_is_tracked(s, pe->e.old_chunk)) { |
1578 | dm_exception_table_unlock(&lock); | ||
1513 | up_write(&s->lock); | 1579 | up_write(&s->lock); |
1514 | __check_for_conflicting_io(s, pe->e.old_chunk); | 1580 | __check_for_conflicting_io(s, pe->e.old_chunk); |
1515 | down_write(&s->lock); | 1581 | down_write(&s->lock); |
1582 | dm_exception_table_lock(&lock); | ||
1516 | } | 1583 | } |
1517 | 1584 | ||
1518 | out: | 1585 | out: |
1519 | /* Remove the in-flight exception from the list */ | 1586 | /* Remove the in-flight exception from the list */ |
1520 | dm_remove_exception(&pe->e); | 1587 | dm_remove_exception(&pe->e); |
1588 | |||
1589 | dm_exception_table_unlock(&lock); | ||
1590 | |||
1521 | snapshot_bios = bio_list_get(&pe->snapshot_bios); | 1591 | snapshot_bios = bio_list_get(&pe->snapshot_bios); |
1522 | origin_bios = bio_list_get(&pe->origin_bios); | 1592 | origin_bios = bio_list_get(&pe->origin_bios); |
1523 | full_bio = pe->full_bio; | 1593 | full_bio = pe->full_bio; |
@@ -1733,6 +1803,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) | |||
1733 | int r = DM_MAPIO_REMAPPED; | 1803 | int r = DM_MAPIO_REMAPPED; |
1734 | chunk_t chunk; | 1804 | chunk_t chunk; |
1735 | struct dm_snap_pending_exception *pe = NULL; | 1805 | struct dm_snap_pending_exception *pe = NULL; |
1806 | struct dm_exception_table_lock lock; | ||
1736 | 1807 | ||
1737 | init_tracked_chunk(bio); | 1808 | init_tracked_chunk(bio); |
1738 | 1809 | ||
@@ -1742,6 +1813,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) | |||
1742 | } | 1813 | } |
1743 | 1814 | ||
1744 | chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector); | 1815 | chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector); |
1816 | dm_exception_table_lock_init(s, chunk, &lock); | ||
1745 | 1817 | ||
1746 | /* Full snapshots are not usable */ | 1818 | /* Full snapshots are not usable */ |
1747 | /* To get here the table must be live so s->active is always set. */ | 1819 | /* To get here the table must be live so s->active is always set. */ |
@@ -1749,6 +1821,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) | |||
1749 | return DM_MAPIO_KILL; | 1821 | return DM_MAPIO_KILL; |
1750 | 1822 | ||
1751 | down_write(&s->lock); | 1823 | down_write(&s->lock); |
1824 | dm_exception_table_lock(&lock); | ||
1752 | 1825 | ||
1753 | if (!s->valid || (unlikely(s->snapshot_overflowed) && | 1826 | if (!s->valid || (unlikely(s->snapshot_overflowed) && |
1754 | bio_data_dir(bio) == WRITE)) { | 1827 | bio_data_dir(bio) == WRITE)) { |
@@ -1771,9 +1844,11 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) | |||
1771 | if (bio_data_dir(bio) == WRITE) { | 1844 | if (bio_data_dir(bio) == WRITE) { |
1772 | pe = __lookup_pending_exception(s, chunk); | 1845 | pe = __lookup_pending_exception(s, chunk); |
1773 | if (!pe) { | 1846 | if (!pe) { |
1847 | dm_exception_table_unlock(&lock); | ||
1774 | up_write(&s->lock); | 1848 | up_write(&s->lock); |
1775 | pe = alloc_pending_exception(s); | 1849 | pe = alloc_pending_exception(s); |
1776 | down_write(&s->lock); | 1850 | down_write(&s->lock); |
1851 | dm_exception_table_lock(&lock); | ||
1777 | 1852 | ||
1778 | if (!s->valid || s->snapshot_overflowed) { | 1853 | if (!s->valid || s->snapshot_overflowed) { |
1779 | free_pending_exception(pe); | 1854 | free_pending_exception(pe); |
@@ -1790,13 +1865,17 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) | |||
1790 | 1865 | ||
1791 | pe = __find_pending_exception(s, pe, chunk); | 1866 | pe = __find_pending_exception(s, pe, chunk); |
1792 | if (!pe) { | 1867 | if (!pe) { |
1868 | dm_exception_table_unlock(&lock); | ||
1869 | |||
1793 | if (s->store->userspace_supports_overflow) { | 1870 | if (s->store->userspace_supports_overflow) { |
1794 | s->snapshot_overflowed = 1; | 1871 | s->snapshot_overflowed = 1; |
1795 | DMERR("Snapshot overflowed: Unable to allocate exception."); | 1872 | DMERR("Snapshot overflowed: Unable to allocate exception."); |
1796 | } else | 1873 | } else |
1797 | __invalidate_snapshot(s, -ENOMEM); | 1874 | __invalidate_snapshot(s, -ENOMEM); |
1875 | up_write(&s->lock); | ||
1876 | |||
1798 | r = DM_MAPIO_KILL; | 1877 | r = DM_MAPIO_KILL; |
1799 | goto out_unlock; | 1878 | goto out; |
1800 | } | 1879 | } |
1801 | } | 1880 | } |
1802 | 1881 | ||
@@ -1808,6 +1887,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) | |||
1808 | bio->bi_iter.bi_size == | 1887 | bio->bi_iter.bi_size == |
1809 | (s->store->chunk_size << SECTOR_SHIFT)) { | 1888 | (s->store->chunk_size << SECTOR_SHIFT)) { |
1810 | pe->started = 1; | 1889 | pe->started = 1; |
1890 | dm_exception_table_unlock(&lock); | ||
1811 | up_write(&s->lock); | 1891 | up_write(&s->lock); |
1812 | start_full_bio(pe, bio); | 1892 | start_full_bio(pe, bio); |
1813 | goto out; | 1893 | goto out; |
@@ -1818,6 +1898,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) | |||
1818 | if (!pe->started) { | 1898 | if (!pe->started) { |
1819 | /* this is protected by snap->lock */ | 1899 | /* this is protected by snap->lock */ |
1820 | pe->started = 1; | 1900 | pe->started = 1; |
1901 | dm_exception_table_unlock(&lock); | ||
1821 | up_write(&s->lock); | 1902 | up_write(&s->lock); |
1822 | start_copy(pe); | 1903 | start_copy(pe); |
1823 | goto out; | 1904 | goto out; |
@@ -1828,6 +1909,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) | |||
1828 | } | 1909 | } |
1829 | 1910 | ||
1830 | out_unlock: | 1911 | out_unlock: |
1912 | dm_exception_table_unlock(&lock); | ||
1831 | up_write(&s->lock); | 1913 | up_write(&s->lock); |
1832 | out: | 1914 | out: |
1833 | return r; | 1915 | return r; |
@@ -2129,6 +2211,7 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, | |||
2129 | struct dm_snap_pending_exception *pe, *pe2; | 2211 | struct dm_snap_pending_exception *pe, *pe2; |
2130 | struct dm_snap_pending_exception *pe_to_start_now = NULL; | 2212 | struct dm_snap_pending_exception *pe_to_start_now = NULL; |
2131 | struct dm_snap_pending_exception *pe_to_start_last = NULL; | 2213 | struct dm_snap_pending_exception *pe_to_start_last = NULL; |
2214 | struct dm_exception_table_lock lock; | ||
2132 | chunk_t chunk; | 2215 | chunk_t chunk; |
2133 | 2216 | ||
2134 | /* Do all the snapshots on this origin */ | 2217 | /* Do all the snapshots on this origin */ |
@@ -2140,21 +2223,23 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, | |||
2140 | if (dm_target_is_snapshot_merge(snap->ti)) | 2223 | if (dm_target_is_snapshot_merge(snap->ti)) |
2141 | continue; | 2224 | continue; |
2142 | 2225 | ||
2143 | down_write(&snap->lock); | ||
2144 | |||
2145 | /* Only deal with valid and active snapshots */ | ||
2146 | if (!snap->valid || !snap->active) | ||
2147 | goto next_snapshot; | ||
2148 | |||
2149 | /* Nothing to do if writing beyond end of snapshot */ | 2226 | /* Nothing to do if writing beyond end of snapshot */ |
2150 | if (sector >= dm_table_get_size(snap->ti->table)) | 2227 | if (sector >= dm_table_get_size(snap->ti->table)) |
2151 | goto next_snapshot; | 2228 | continue; |
2152 | 2229 | ||
2153 | /* | 2230 | /* |
2154 | * Remember, different snapshots can have | 2231 | * Remember, different snapshots can have |
2155 | * different chunk sizes. | 2232 | * different chunk sizes. |
2156 | */ | 2233 | */ |
2157 | chunk = sector_to_chunk(snap->store, sector); | 2234 | chunk = sector_to_chunk(snap->store, sector); |
2235 | dm_exception_table_lock_init(snap, chunk, &lock); | ||
2236 | |||
2237 | down_write(&snap->lock); | ||
2238 | dm_exception_table_lock(&lock); | ||
2239 | |||
2240 | /* Only deal with valid and active snapshots */ | ||
2241 | if (!snap->valid || !snap->active) | ||
2242 | goto next_snapshot; | ||
2158 | 2243 | ||
2159 | pe = __lookup_pending_exception(snap, chunk); | 2244 | pe = __lookup_pending_exception(snap, chunk); |
2160 | if (!pe) { | 2245 | if (!pe) { |
@@ -2167,9 +2252,11 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, | |||
2167 | if (e) | 2252 | if (e) |
2168 | goto next_snapshot; | 2253 | goto next_snapshot; |
2169 | 2254 | ||
2255 | dm_exception_table_unlock(&lock); | ||
2170 | up_write(&snap->lock); | 2256 | up_write(&snap->lock); |
2171 | pe = alloc_pending_exception(snap); | 2257 | pe = alloc_pending_exception(snap); |
2172 | down_write(&snap->lock); | 2258 | down_write(&snap->lock); |
2259 | dm_exception_table_lock(&lock); | ||
2173 | 2260 | ||
2174 | if (!snap->valid) { | 2261 | if (!snap->valid) { |
2175 | free_pending_exception(pe); | 2262 | free_pending_exception(pe); |
@@ -2187,8 +2274,11 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, | |||
2187 | 2274 | ||
2188 | pe = __insert_pending_exception(snap, pe, chunk); | 2275 | pe = __insert_pending_exception(snap, pe, chunk); |
2189 | if (!pe) { | 2276 | if (!pe) { |
2277 | dm_exception_table_unlock(&lock); | ||
2190 | __invalidate_snapshot(snap, -ENOMEM); | 2278 | __invalidate_snapshot(snap, -ENOMEM); |
2191 | goto next_snapshot; | 2279 | up_write(&snap->lock); |
2280 | |||
2281 | continue; | ||
2192 | } | 2282 | } |
2193 | } else { | 2283 | } else { |
2194 | free_pending_exception(pe); | 2284 | free_pending_exception(pe); |
@@ -2219,6 +2309,7 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, | |||
2219 | } | 2309 | } |
2220 | 2310 | ||
2221 | next_snapshot: | 2311 | next_snapshot: |
2312 | dm_exception_table_unlock(&lock); | ||
2222 | up_write(&snap->lock); | 2313 | up_write(&snap->lock); |
2223 | 2314 | ||
2224 | if (pe_to_start_now) { | 2315 | if (pe_to_start_now) { |