ia64/xen-unstable

view tools/blktap2/vhd/vhd-update.c @ 19647:1c627434605e

blktap2: a completely rewritten blktap implementation

Benefits to blktap2 over the old version of blktap:

* Isolation from xenstore - Blktap devices are now created directly on
the linux dom0 command line, rather than being spawned in response
to XenStore events. This is handy for debugging, makes blktap
generally easier to work with, and is a step toward a generic
user-level block device implementation that is not Xen-specific.

* Improved tapdisk infrastructure: simpler request forwarding, new
request scheduler, request merging, more efficient use of AIO.

* Improved tapdisk error handling and memory management. No
allocations on the block data path, IO retry logic to protect
guests
transient block device failures. This has been tested and is known
to work on weird environments such as NFS soft mounts.

* Pause and snapshot of live virtual disks (see xmsnap script).

* VHD support. The VHD code in this release has been rigorously
tested, and represents a very mature implementation of the VHD
image
format.

* No more duplication of mechanism with blkback. The blktap kernel
module has changed dramatically from the original blktap. Blkback
is now always used to talk to Xen guests, blktap just presents a
Linux gendisk that blkback can export. This is done while
preserving the zero-copy data path from domU to physical device.

These patches deprecate the old blktap code, which can hopefully be
removed from the tree completely at some point in the future.

Signed-off-by: Jake Wires <jake.wires@citrix.com>
Signed-off-by: Dutch Meyer <dmeyer@cs.ubc.ca>
author Keir Fraser <keir.fraser@citrix.com>
date Tue May 26 11:52:31 2009 +0100 (2009-05-26)
parents
children b7f73a7f3078
line source
1 /* Copyright (c) 2008, XenSource Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of XenSource Inc. nor the names of its contributors
12 * may be used to endorse or promote products derived from this software
13 * without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Before updating a VHD file, we create a journal consisting of:
28 * - all data at the beginning of the file, up to and including the BAT
29 * - each allocated bitmap (existing at the same offset in the journal as
30 * its corresponding bitmap in the original file)
31 * Updates are performed in place by writing appropriately
32 * transformed versions of journaled bitmaps to the original file.
33 */
34 #include <stdio.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <endian.h>
40 #include <byteswap.h>
42 #include "atomicio.h"
43 #include "libvhd.h"
44 #include "libvhd-journal.h"
46 static void
47 usage(void)
48 {
49 printf("usage: vhd-update <-n name> [-j existing journal] [-h]\n");
50 exit(EINVAL);
51 }
53 /*
54 * update vhd creator version to reflect its new bitmap ordering
55 */
56 static inline int
57 update_creator_version(vhd_journal_t *journal)
58 {
59 journal->vhd.footer.crtr_ver = VHD_VERSION(1, 1);
60 return vhd_write_footer(&journal->vhd, &journal->vhd.footer);
61 }
63 static int
64 journal_bitmaps(vhd_journal_t *journal)
65 {
66 int i, err;
68 for (i = 0; i < journal->vhd.bat.entries; i++) {
69 err = vhd_journal_add_block(journal, i, VHD_JOURNAL_METADATA);
70 if (err)
71 return err;
72 }
74 return 0;
75 }
77 /*
78 * older VHD bitmaps were little endian
79 * and bits within a word were set from right to left
80 */
81 static inline int
82 old_test_bit(int nr, volatile void * addr)
83 {
84 return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >>
85 (nr % (sizeof(unsigned long)*8))) & 1;
86 }
88 /*
89 * new VHD bitmaps are big endian
90 * and bits within a word are set from left to right
91 */
92 #define BIT_MASK 0x80
93 static inline void
94 new_set_bit (int nr, volatile char *addr)
95 {
96 addr[nr >> 3] |= (BIT_MASK >> (nr & 7));
97 }
99 static void
100 convert_bitmap(char *in, char *out, int bytes)
101 {
102 int i;
104 memset(out, 0, bytes);
106 for (i = 0; i < bytes << 3; i++)
107 if (old_test_bit(i, (void *)in))
108 new_set_bit(i, out);
109 }
111 static int
112 update_vhd(vhd_journal_t *journal, int rollback)
113 {
114 int i, err;
115 size_t size;
116 char *buf, *converted;
118 buf = NULL;
119 converted = NULL;
121 size = vhd_bytes_padded(journal->vhd.spb / 8);
122 err = posix_memalign((void **)&converted, 512, size);
123 if (err) {
124 converted = NULL;
125 goto out;
126 }
128 for (i = 0; i < journal->vhd.bat.entries; i++) {
129 if (journal->vhd.bat.bat[i] == DD_BLK_UNUSED)
130 continue;
132 err = vhd_read_bitmap(&journal->vhd, i, &buf);
133 if (err)
134 goto out;
136 if (rollback)
137 memcpy(converted, buf, size);
138 else
139 convert_bitmap(buf, converted, size);
141 free(buf);
143 err = vhd_write_bitmap(&journal->vhd, i, converted);
144 if (err)
145 goto out;
146 }
148 err = 0;
149 out:
150 free(converted);
151 return err;
152 }
154 static int
155 open_journal(vhd_journal_t *journal, const char *file, const char *jfile)
156 {
157 int err;
159 err = vhd_journal_create(journal, file, jfile);
160 if (err) {
161 printf("error creating journal for %s: %d\n", file, err);
162 return err;
163 }
165 return 0;
166 }
168 static int
169 close_journal(vhd_journal_t *journal, int err)
170 {
171 if (err)
172 err = vhd_journal_revert(journal);
173 else
174 err = vhd_journal_commit(journal);
176 if (err)
177 return vhd_journal_close(journal);
178 else
179 return vhd_journal_remove(journal);
180 }
182 int
183 main(int argc, char **argv)
184 {
185 char *file, *jfile;
186 int c, err, rollback;
187 vhd_journal_t journal;
189 file = NULL;
190 jfile = NULL;
191 rollback = 0;
193 while ((c = getopt(argc, argv, "n:j:rh")) != -1) {
194 switch(c) {
195 case 'n':
196 file = optarg;
197 break;
198 case 'j':
199 jfile = optarg;
200 err = access(jfile, R_OK);
201 if (err == -1) {
202 printf("invalid journal arg %s\n", jfile);
203 return -errno;
204 }
205 break;
206 case 'r':
207 /* add a rollback option for debugging which
208 * pushes journalled bitmaps to original file
209 * without transforming them */
210 rollback = 1;
211 break;
212 default:
213 usage();
214 }
215 }
217 if (!file)
218 usage();
220 if (rollback && !jfile) {
221 printf("rollback requires a journal argument\n");
222 usage();
223 }
225 err = open_journal(&journal, file, jfile);
226 if (err)
227 return err;
229 if (!vhd_creator_tapdisk(&journal.vhd) ||
230 journal.vhd.footer.crtr_ver != VHD_VERSION(0, 1) ||
231 journal.vhd.footer.type == HD_TYPE_FIXED) {
232 err = 0;
233 goto out;
234 }
236 err = journal_bitmaps(&journal);
237 if (err) {
238 /* no changes to vhd file yet,
239 * so close the journal and bail */
240 vhd_journal_close(&journal);
241 return err;
242 }
244 err = update_vhd(&journal, rollback);
245 if (err) {
246 printf("update failed: %d; saving journal\n", err);
247 goto out;
248 }
250 err = update_creator_version(&journal);
251 if (err) {
252 printf("failed to udpate creator version: %d\n", err);
253 goto out;
254 }
256 err = 0;
258 out:
259 err = close_journal(&journal, err);
260 return err;
261 }