aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/device-mapper/snapshot.txt60
-rw-r--r--drivers/md/dm-snap.c53
2 files changed, 96 insertions, 17 deletions
diff --git a/Documentation/device-mapper/snapshot.txt b/Documentation/device-mapper/snapshot.txt
index a5009c8300f3..e3a77b215135 100644
--- a/Documentation/device-mapper/snapshot.txt
+++ b/Documentation/device-mapper/snapshot.txt
@@ -8,13 +8,19 @@ the block device which are also writable without interfering with the
8original content; 8original content;
9*) To create device "forks", i.e. multiple different versions of the 9*) To create device "forks", i.e. multiple different versions of the
10same data stream. 10same data stream.
11*) To merge a snapshot of a block device back into the snapshot's origin
12device.
11 13
14In the first two cases, dm copies only the chunks of data that get
15changed and uses a separate copy-on-write (COW) block device for
16storage.
12 17
13In both cases, dm copies only the chunks of data that get changed and 18For snapshot merge the contents of the COW storage are merged back into
14uses a separate copy-on-write (COW) block device for storage. 19the origin device.
15 20
16 21
17There are two dm targets available: snapshot and snapshot-origin. 22There are three dm targets available:
23snapshot, snapshot-origin, and snapshot-merge.
18 24
19*) snapshot-origin <origin> 25*) snapshot-origin <origin>
20 26
@@ -40,8 +46,25 @@ The difference is that for transient snapshots less metadata must be
40saved on disk - they can be kept in memory by the kernel. 46saved on disk - they can be kept in memory by the kernel.
41 47
42 48
43How this is used by LVM2 49* snapshot-merge <origin> <COW device> <persistent> <chunksize>
44======================== 50
51takes the same table arguments as the snapshot target except it only
52works with persistent snapshots. This target assumes the role of the
53"snapshot-origin" target and must not be loaded if the "snapshot-origin"
54is still present for <origin>.
55
56Creates a merging snapshot that takes control of the changed chunks
57stored in the <COW device> of an existing snapshot, through a handover
58procedure, and merges these chunks back into the <origin>. Once merging
59has started (in the background) the <origin> may be opened and the merge
60will continue while I/O is flowing to it. Changes to the <origin> are
61deferred until the merging snapshot's corresponding chunk(s) have been
62merged. Once merging has started the snapshot device, associated with
63the "snapshot" target, will return -EIO when accessed.
64
65
66How snapshot is used by LVM2
67============================
45When you create the first LVM2 snapshot of a volume, four dm devices are used: 68When you create the first LVM2 snapshot of a volume, four dm devices are used:
46 69
471) a device containing the original mapping table of the source volume; 701) a device containing the original mapping table of the source volume;
@@ -72,3 +95,30 @@ brw------- 1 root root 254, 12 29 ago 18:15 /dev/mapper/volumeGroup-snap-cow
72brw------- 1 root root 254, 13 29 ago 18:15 /dev/mapper/volumeGroup-snap 95brw------- 1 root root 254, 13 29 ago 18:15 /dev/mapper/volumeGroup-snap
73brw------- 1 root root 254, 10 29 ago 18:14 /dev/mapper/volumeGroup-base 96brw------- 1 root root 254, 10 29 ago 18:14 /dev/mapper/volumeGroup-base
74 97
98
99How snapshot-merge is used by LVM2
100==================================
101A merging snapshot assumes the role of the "snapshot-origin" while
102merging. As such the "snapshot-origin" is replaced with
103"snapshot-merge". The "-real" device is not changed and the "-cow"
104device is renamed to <origin name>-cow to aid LVM2's cleanup of the
105merging snapshot after it completes. The "snapshot" that hands over its
106COW device to the "snapshot-merge" is deactivated (unless using lvchange
107--refresh); but if it is left active it will simply return I/O errors.
108
109A snapshot will merge into its origin with the following command:
110
111lvconvert --merge volumeGroup/snap
112
113we'll now have this situation:
114
115# dmsetup table|grep volumeGroup
116
117volumeGroup-base-real: 0 2097152 linear 8:19 384
118volumeGroup-base-cow: 0 204800 linear 8:19 2097536
119volumeGroup-base: 0 2097152 snapshot-merge 254:11 254:12 P 16
120
121# ls -lL /dev/mapper/volumeGroup-*
122brw------- 1 root root 254, 11 29 ago 18:15 /dev/mapper/volumeGroup-base-real
123brw------- 1 root root 254, 12 29 ago 18:16 /dev/mapper/volumeGroup-base-cow
124brw------- 1 root root 254, 10 29 ago 18:16 /dev/mapper/volumeGroup-base
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 288994ee7142..446827f98236 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -25,6 +25,11 @@
25 25
26#define DM_MSG_PREFIX "snapshots" 26#define DM_MSG_PREFIX "snapshots"
27 27
28static const char dm_snapshot_merge_target_name[] = "snapshot-merge";
29
30#define dm_target_is_snapshot_merge(ti) \
31 ((ti)->type->name == dm_snapshot_merge_target_name)
32
28/* 33/*
29 * The percentage increment we will wake up users at 34 * The percentage increment we will wake up users at
30 */ 35 */
@@ -1743,6 +1748,21 @@ static struct target_type snapshot_target = {
1743 .iterate_devices = snapshot_iterate_devices, 1748 .iterate_devices = snapshot_iterate_devices,
1744}; 1749};
1745 1750
1751static struct target_type merge_target = {
1752 .name = dm_snapshot_merge_target_name,
1753 .version = {1, 0, 0},
1754 .module = THIS_MODULE,
1755 .ctr = snapshot_ctr,
1756 .dtr = snapshot_dtr,
1757 .map = snapshot_map,
1758 .end_io = snapshot_end_io,
1759 .postsuspend = snapshot_postsuspend,
1760 .preresume = snapshot_preresume,
1761 .resume = snapshot_resume,
1762 .status = snapshot_status,
1763 .iterate_devices = snapshot_iterate_devices,
1764};
1765
1746static int __init dm_snapshot_init(void) 1766static int __init dm_snapshot_init(void)
1747{ 1767{
1748 int r; 1768 int r;
@@ -1754,7 +1774,7 @@ static int __init dm_snapshot_init(void)
1754 } 1774 }
1755 1775
1756 r = dm_register_target(&snapshot_target); 1776 r = dm_register_target(&snapshot_target);
1757 if (r) { 1777 if (r < 0) {
1758 DMERR("snapshot target register failed %d", r); 1778 DMERR("snapshot target register failed %d", r);
1759 goto bad_register_snapshot_target; 1779 goto bad_register_snapshot_target;
1760 } 1780 }
@@ -1762,34 +1782,40 @@ static int __init dm_snapshot_init(void)
1762 r = dm_register_target(&origin_target); 1782 r = dm_register_target(&origin_target);
1763 if (r < 0) { 1783 if (r < 0) {
1764 DMERR("Origin target register failed %d", r); 1784 DMERR("Origin target register failed %d", r);
1765 goto bad1; 1785 goto bad_register_origin_target;
1786 }
1787
1788 r = dm_register_target(&merge_target);
1789 if (r < 0) {
1790 DMERR("Merge target register failed %d", r);
1791 goto bad_register_merge_target;
1766 } 1792 }
1767 1793
1768 r = init_origin_hash(); 1794 r = init_origin_hash();
1769 if (r) { 1795 if (r) {
1770 DMERR("init_origin_hash failed."); 1796 DMERR("init_origin_hash failed.");
1771 goto bad2; 1797 goto bad_origin_hash;
1772 } 1798 }
1773 1799
1774 exception_cache = KMEM_CACHE(dm_exception, 0); 1800 exception_cache = KMEM_CACHE(dm_exception, 0);
1775 if (!exception_cache) { 1801 if (!exception_cache) {
1776 DMERR("Couldn't create exception cache."); 1802 DMERR("Couldn't create exception cache.");
1777 r = -ENOMEM; 1803 r = -ENOMEM;
1778 goto bad3; 1804 goto bad_exception_cache;
1779 } 1805 }
1780 1806
1781 pending_cache = KMEM_CACHE(dm_snap_pending_exception, 0); 1807 pending_cache = KMEM_CACHE(dm_snap_pending_exception, 0);
1782 if (!pending_cache) { 1808 if (!pending_cache) {
1783 DMERR("Couldn't create pending cache."); 1809 DMERR("Couldn't create pending cache.");
1784 r = -ENOMEM; 1810 r = -ENOMEM;
1785 goto bad4; 1811 goto bad_pending_cache;
1786 } 1812 }
1787 1813
1788 tracked_chunk_cache = KMEM_CACHE(dm_snap_tracked_chunk, 0); 1814 tracked_chunk_cache = KMEM_CACHE(dm_snap_tracked_chunk, 0);
1789 if (!tracked_chunk_cache) { 1815 if (!tracked_chunk_cache) {
1790 DMERR("Couldn't create cache to track chunks in use."); 1816 DMERR("Couldn't create cache to track chunks in use.");
1791 r = -ENOMEM; 1817 r = -ENOMEM;
1792 goto bad5; 1818 goto bad_tracked_chunk_cache;
1793 } 1819 }
1794 1820
1795 ksnapd = create_singlethread_workqueue("ksnapd"); 1821 ksnapd = create_singlethread_workqueue("ksnapd");
@@ -1803,19 +1829,21 @@ static int __init dm_snapshot_init(void)
1803 1829
1804bad_pending_pool: 1830bad_pending_pool:
1805 kmem_cache_destroy(tracked_chunk_cache); 1831 kmem_cache_destroy(tracked_chunk_cache);
1806bad5: 1832bad_tracked_chunk_cache:
1807 kmem_cache_destroy(pending_cache); 1833 kmem_cache_destroy(pending_cache);
1808bad4: 1834bad_pending_cache:
1809 kmem_cache_destroy(exception_cache); 1835 kmem_cache_destroy(exception_cache);
1810bad3: 1836bad_exception_cache:
1811 exit_origin_hash(); 1837 exit_origin_hash();
1812bad2: 1838bad_origin_hash:
1839 dm_unregister_target(&merge_target);
1840bad_register_merge_target:
1813 dm_unregister_target(&origin_target); 1841 dm_unregister_target(&origin_target);
1814bad1: 1842bad_register_origin_target:
1815 dm_unregister_target(&snapshot_target); 1843 dm_unregister_target(&snapshot_target);
1816
1817bad_register_snapshot_target: 1844bad_register_snapshot_target:
1818 dm_exception_store_exit(); 1845 dm_exception_store_exit();
1846
1819 return r; 1847 return r;
1820} 1848}
1821 1849
@@ -1825,6 +1853,7 @@ static void __exit dm_snapshot_exit(void)
1825 1853
1826 dm_unregister_target(&snapshot_target); 1854 dm_unregister_target(&snapshot_target);
1827 dm_unregister_target(&origin_target); 1855 dm_unregister_target(&origin_target);
1856 dm_unregister_target(&merge_target);
1828 1857
1829 exit_origin_hash(); 1858 exit_origin_hash();
1830 kmem_cache_destroy(pending_cache); 1859 kmem_cache_destroy(pending_cache);