{"id":127,"date":"2020-04-13T19:26:59","date_gmt":"2020-04-13T17:26:59","guid":{"rendered":"https:\/\/www.theta-soft.de\/blog\/?p=127"},"modified":"2020-04-13T19:28:25","modified_gmt":"2020-04-13T17:28:25","slug":"lvm-snapshots-2","status":"publish","type":"post","link":"https:\/\/www.theta-soft.de\/blog\/2020\/lvm-snapshots-2\/","title":{"rendered":"LVM Snapshots"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>LVM, the Linux Logical Volume Manager, allows taking so-called <em>snapshots<\/em> of logical volumes (LVs). A snapshot has the same behavior as an independent copy of the original volume; however, the snapshot only stores the changes compared to the original volume, so it typically needs considerably less disk space. Actually, the size of the snapshot volume can be arbitrarily chosen (independent of the size of the original volume). However, when the disk space of the snapshot is not sufficient to store all changes, the snapshot becomes invalid. To be on the safe side, the snapshot should have the same size as the original volume.<\/p>\n<p>Technically, the snapshot is a&nbsp;<em>copy-on-write <\/em>(COW) table. A change to the snapshot is stored in this table, and the original volume remains unchanged. On the other hand, when the original volume is changed, the previous data is copied into the copy-on-write table, so that the change to the original volume is not visible in the snapshot. If the same data in the snapshot has already been changed earlier (i.e. there is already an entry in the COW table), then this change is obviously not overwritten.<\/p>\n<h2>The device mapper<\/h2>\n<p>The LVM functionality is mostly handled by the&nbsp;<em>device mapper<\/em>. It can provide virtual block devices and redirects any access to these virtual devices to another low-level device. The device mapper has different <em>targets<\/em> (i.e. kernel modules) that are responsible for the actual mapping.<\/p>\n<p>A simple LV is typically implemented by the target&nbsp;<em>linear<\/em>. This maps a continuous section of the virtual device to a likewise continuous section of the low-level device. Example:<\/p>\n<pre>test:~ # lvcreate -l 2 -n base vg0\n Logical volume \"base\" created\ntest:~ # dir \/dev\/vg0\ntotal 0\nlrwxrwxrwx 1 root root 7 Jul 4 09:33 base -&gt; ..\/dm-0\ntest:~ # dir \/dev\/mapper\ntotal 0\ncrw------- 1 root root 10, 236 Jul 4 09:28 control\nlrwxrwxrwx 1 root root 7 Jul 4 09:33 vg0-base -&gt; ..\/dm-0\ntest:~ # dmsetup table vg0-base\n0 16384 linear 202:4 2048<\/pre>\n<p>The device 202,4 is the physical volume <code>\/dev\/xvda4<\/code>&nbsp;that was used to create the volume group vg0:<\/p>\n<pre>test:~ # dir \/dev\/xvda*\nbrw-rw---- 1 root disk 202, 0 Jul 7 16:16 \/dev\/xvda\nbrw-rw---- 1 root disk 202, 1 Jul 7 16:16 \/dev\/xvda1\nbrw-rw---- 1 root disk 202, 2 Jul 7 16:16 \/dev\/xvda2\nbrw-rw---- 1 root disk 202, 3 Jul 7 16:16 \/dev\/xvda3\nbrw-rw---- 1 root disk 202, 4 Jul 7 16:16 \/dev\/xvda4<\/pre>\n<h2>Preparation of the original volume<\/h2>\n<p>For the following tests, the LV is filled with well-defined content, e.g. with the text &#8222;base&#8220;. Since the volume group has a <em>physical extent size<\/em> of 4 MB and the LV was created with a size of 2 extents, the size is 8 MB:<\/p>\n<pre>test:~ # lvdisplay \/dev\/vg0\/base | grep 'LV Size'\n LV Size 8.00 MiB<\/pre>\n<p>To fill the logical volume, the command <code>dd<\/code> is used:<\/p>\n<pre>test:~ # for i in $(seq 1 2097152); do \n&gt; echo -n base\n&gt; done | dd of=\/dev\/vg0\/base bs=4\n 2097152+0 records in\n 2097152+0 records out\n 8388608 bytes (8.4 MB) copied, 56.5065 s, 148 kB\/s<\/pre>\n<p>In order to check that the data has been correctly written, <code>dd<\/code> can be used again:<\/p>\n<pre>test:~ # dd if=\/dev\/vg0\/base bs=1 count=32\n basebasebasebasebasebasebasebase<\/pre>\n<h2>Creating the snapshot<\/h2>\n<p>We now create the snapshot with a size of 1 extent (4 MB):<\/p>\n<pre>test:~ # lvcreate -s \/dev\/vg0\/base -n snap -l 1\nLogical volume \"snap\" created<\/pre>\n<p>The directory&nbsp;<code>\/dev\/vg0<\/code> now contains the snapshot as a separate LV. Of course, the original volume is still there, too:<\/p>\n<pre>test:~ # dir \/dev\/vg0\n total 0\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 base -&gt; ..\/dm-0\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 snap -&gt; ..\/dm-1<\/pre>\n<p>It is much more interesting to look at the directory <code>\/dev\/mapper<\/code>. Besides the two externally visible devices (which are also present in<code>\/dev\/vg0<\/code>), it contains two more devices, namely <code>vg0-base-real<\/code> and <code>vg0-snap-cow<\/code>:<\/p>\n<pre>test:~ # dir \/dev\/mapper\n total 0\n crw------- 1 root root 10, 236 Jul 4 09:28 control\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 vg0-base -&gt; ..\/dm-0\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 vg0-snap -&gt; ..\/dm-1\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 vg0-snap-cow -&gt; ..\/dm-3\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 vg0-base-real -&gt; ..\/dm-2<\/pre>\n<p>It is also interesting to look at the output of <em>dmsetup<\/em> for these devices:<\/p>\n<pre>test:~ # dmsetup table vg0-base\n0 16384 snapshot-origin 253:2\ntest:~ # dmsetup table vg0-base-real\n0 16384 linear 202:4 2048\ntest:~ # dmsetup table vg0-snap\n0 16384 snapshot 253:2 253:3 P 8\ntest:~ # dmsetup table vg0-snap-cow\n0 8192 linear 202:4 18432<\/pre>\n<p>It becomes visible that the snapshot created another layer of mapping. The existing device for the original LV (<code>vg0-base<\/code>) is no longer of type&nbsp;<em>linear<\/em>, but instead of type&nbsp;<em>snapshot-origin<\/em>. It refers to the device <code>vg0-base-real<\/code>. The new device&nbsp;<code>vg0-snap<\/code> is of type <em>snapshot<\/em>. It refers to the device <code>vg0-base-real<\/code>, too, and also to <code>vg0-snap-cow<\/code>. These two devices behave like &#8222;normal&#8220; LVs, i.e. they refer to areas of the physical volume.<\/p>\n<p><a href=\"http:\/\/www.theta-soft.de\/blog\/wp-content\/uploads\/2013\/07\/lvm-snapshots.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-46\" src=\"http:\/\/www.theta-soft.de\/blog\/wp-content\/uploads\/2013\/07\/lvm-snapshots-300x214.png\" alt=\"lvm-snapshots\" width=\"300\" height=\"214\" srcset=\"https:\/\/www.theta-soft.de\/blog\/wp-content\/uploads\/2013\/07\/lvm-snapshots-300x214.png 300w, https:\/\/www.theta-soft.de\/blog\/wp-content\/uploads\/2013\/07\/lvm-snapshots.png 451w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>When we look at the sizes of the 4 block devices, we find that the two devices <code>vg0-base<\/code> and <code>vg0-base-real<\/code> both have a size of 8 MB each. <code>vg0-base-real<\/code> is the original volume that was initially created, and <code>vg0-base<\/code> is just a mapping overlay. The device&nbsp;<code>vg0-snap<\/code> also has a (virtual) size of 8 MB because a snapshot always has the same size as the original volume. On the other hand, the COW table <code>vg0-snap-cow<\/code> has only a size of 4 MB, which is exactly the size that was specified when the snapshot was created.<\/p>\n<pre>test:~ # blockdev --getsize64 \/dev\/mapper\/vg0-base \/dev\/mapper\/vg0-snap \/dev\/mapper\/vg0-snap-cow \/dev\/mapper\/vg0-base-real\n 8388608\n 8388608\n 4194304\n 8388608<\/pre>\n<h2>Changes to the snapshot<\/h2>\n<p>What happens when data is written to the snapshot?<\/p>\n<pre>test:~ # echo -n snapshot | dd of=\/dev\/vg0\/snap bs=1\n8+0 records in\n8+0 records out\n8 bytes (8 B) copied, 0.0341143 s, 0.2 kB\/s\n\ntest:~ # dd if=\/dev\/mapper\/vg0-snap bs=1 count=32\n<strong><span style=\"color: #ff0000;\">snapshot<\/span><\/strong>basebasebasebasebasebase\n\ntest:~ # dd if=\/dev\/mapper\/vg0-base bs=1 count=32\nbasebasebasebasebasebasebasebase<\/pre>\n<p>As expected, the data in the snapshot changed while the original volume remained unchanged. It is interesting to take a closer look at the underlying devices:<\/p>\n<pre>test:~ # dd if=\/dev\/mapper\/vg0-base-real bs=1 count=32\nbasebasebasebasebasebasebasebase\ntest:~ # dd if=\/dev\/mapper\/vg0-snap-cow | hexdump -C\n00000000  53 6e 41 70 01 00 00 00  01 00 00 00 08 00 00 00  |SnAp............|\n00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|\n*\n00001000  00 00 00 00 00 00 00 00  02 00 00 00 00 00 00 00  |................|\n00001010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|\n*\n00002000  73 6e 61 70 73 68 6f 74  62 61 73 65 62 61 73 65  |snapshotbasebase|\n00002010  62 61 73 65 62 61 73 65  62 61 73 65 62 61 73 65  |basebasebasebase|\n*\n00003000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|\n*\n00400000<\/pre>\n<p>The changed data has been written to the COW table, while the original LV remained unchanged. It should be noted that, even though only 4 bytes have been changed, the block that has been written to the COW table is 4096 bytes large. The size of the blocks that are written for each change is the&nbsp;<em>snapshot chunk size<\/em> that can be specified when the snapshot is created. Because the COW table is filled in chunks, it can be filled up with changes scattered over the snapshot, so that the snapshot becomes invalid although the total amount of changed data is much smaller than the snapshot size.<\/p>\n<h2>Changes to the original volume<\/h2>\n<p>What happens when the original volume is changed?<\/p>\n<pre>test:~ # echo -n test | dd of=\/dev\/vg0\/base bs=1 seek=4096\n4+0 records in\n4+0 records out\n4 bytes (4 B) copied, 0.0174384 s, 0.2 kB\/s\n\ntest:~ # dd if=\/dev\/mapper\/vg0-base bs=1 count=32 skip=4096\n<strong><span style=\"color: #ff0000;\">test<\/span><\/strong>basebasebasebasebasebasebase\n\ntest:~ # dd if=\/dev\/mapper\/vg0-base-real bs=1 count=32 skip=4096\n<strong><span style=\"color: #ff0000;\">test<\/span><\/strong>basebasebasebasebasebasebase\n\ntest:~ # dd if=\/dev\/mapper\/vg0-snap-cow | hexdump -C\n00000000 53 6e 41 70 01 00 00 00 01 00 00 00 08 00 00 00 |SnAp............|\n00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|\n*\n00001000 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|\n00001010 01 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 |................|\n00001020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|\n*\n00002000 73 6e 61 70 73 68 6f 74 62 61 73 65 62 61 73 65 |snapshotbasebase|\n00002010 62 61 73 65 62 61 73 65 62 61 73 65 62 61 73 65 |basebasebasebase|\n*\n<strong><span style=\"color: #ff0000;\">00004000<\/span><\/strong> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|\n*\n00400000<\/pre>\n<p>It does not surprise that the devices <code>vg0-base<\/code> and <code>vg0-base-real<\/code> show changes. More interesting is the COW table: At a first glance, it looks as if it had not changed at all. In fact, another 4k block has been added, into which the original data (&#8222;&#8230;basebasebasebase&#8230;&#8220;) has been copied. Hence, the change is not visible in the snapshot.<\/p>\n<h2>Sources \/ Links<\/h2>\n<ul>\n<li><a href=\"http:\/\/www.tldp.org\/HOWTO\/LVM-HOWTO\/snapshotintro.html\">http:\/\/www.tldp.org\/HOWTO\/LVM-HOWTO\/snapshotintro.html<\/a><\/li>\n<li><a style=\"line-height: 1.714285714; font-size: 1rem;\" href=\"http:\/\/rwmj.wordpress.com\/2010\/09\/28\/how-lvm-does-snapshots\/\">http:\/\/rwmj.wordpress.com\/2010\/09\/28\/how-lvm-does-snapshots\/<\/a><\/li>\n<li><a href=\"http:\/\/www.centos.org\/docs\/5\/html\/5.2\/Cluster_Logical_Volume_Manager\/snapshot-map.html\">http:\/\/www.centos.org\/docs\/5\/html\/5.2\/Cluster_Logical_Volume_Manager\/snapshot-map.html<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Introduction LVM, the Linux Logical Volume Manager, allows taking so-called snapshots of logical volumes (LVs). A snapshot has the same behavior as an independent copy of the original volume; however, the snapshot only stores the changes compared to the original volume, so it typically needs considerably less disk space. Actually, the size of the snapshot [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_members_access_role":[],"_members_access_error":""},"categories":[1],"tags":[4,2,3],"class_list":["post-127","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-linux","tag-lvm","tag-snapshot"],"_links":{"self":[{"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/posts\/127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/comments?post=127"}],"version-history":[{"count":2,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/posts\/127\/revisions"}],"predecessor-version":[{"id":129,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/posts\/127\/revisions\/129"}],"wp:attachment":[{"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/media?parent=127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/categories?post=127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/tags?post=127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}