ia64/xen-unstable

view tools/blktap2/lvm/lvm-util.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
line source
1 /*
2 * Copyright (c) 2008, XenSource Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of XenSource Inc. nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 #include <stdio.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
33 #include "lvm-util.h"
35 #define _NAME "%255s"
36 static char line[1024];
38 static inline int
39 lvm_read_line(FILE *scan)
40 {
41 memset(line, 0, sizeof(line));
42 return (fscanf(scan, "%1023[^\n]", line) != 1);
43 }
45 static inline int
46 lvm_next_line(FILE *scan)
47 {
48 return (fscanf(scan, "%1023[\n]", line) != 1);
49 }
51 static int
52 lvm_copy_name(char *dst, const char *src, size_t size)
53 {
54 if (strnlen(src, size) == size)
55 return -ENAMETOOLONG;
57 strcpy(dst, src);
58 return 0;
59 }
61 static int
62 lvm_parse_pv(struct vg *vg, const char *name, int pvs, uint64_t start)
63 {
64 int i, err;
65 struct pv *pv;
67 pv = NULL;
69 if (!vg->pvs) {
70 vg->pvs = calloc(pvs, sizeof(struct pv));
71 if (!vg->pvs)
72 return -ENOMEM;
73 }
75 for (i = 0; i < pvs; i++) {
76 pv = vg->pvs + i;
78 if (!pv->name[0])
79 break;
81 if (!strcmp(pv->name, name))
82 return -EEXIST;
83 }
85 if (!pv)
86 return -ENOENT;
88 if (i == pvs)
89 return -ENOMEM;
91 err = lvm_copy_name(pv->name, name, sizeof(pv->name) - 1);
92 if (err)
93 return err;
95 pv->start = start;
96 return 0;
97 }
99 static int
100 lvm_open_vg(const char *vgname, struct vg *vg)
101 {
102 FILE *scan;
103 int i, err, pvs, lvs;
104 char *cmd, pvname[256];
105 uint64_t size, pv_start;
107 memset(vg, 0, sizeof(*vg));
109 err = asprintf(&cmd, "/usr/sbin/vgs %s --noheadings --nosuffix --units=b "
110 "--options=vg_name,vg_extent_size,lv_count,pv_count,"
111 "pv_name,pe_start --unbuffered 2> /dev/null", vgname);
112 if (err == -1)
113 return -ENOMEM;
115 errno = 0;
116 scan = popen(cmd, "r");
117 if (!scan) {
118 err = (errno ? -errno : ENOMEM);
119 goto out;
120 }
122 for (;;) {
123 if (lvm_read_line(scan))
124 break;
126 err = -EINVAL;
127 if (sscanf(line, _NAME" %"SCNu64" %d %d "_NAME" %"SCNu64,
128 vg->name, &size, &lvs, &pvs, pvname, &pv_start) != 6)
129 goto out;
131 if (strcmp(vg->name, vgname))
132 goto out;
134 err = lvm_parse_pv(vg, pvname, pvs, pv_start);
135 if (err)
136 goto out;
138 if (lvm_next_line(scan))
139 break;
140 }
142 err = -EINVAL;
143 if (strcmp(vg->name, vgname))
144 goto out;
146 for (i = 0; i < pvs; i++)
147 if (!vg->pvs[i].name[0])
148 goto out;
150 err = -ENOMEM;
151 vg->lvs = calloc(lvs, sizeof(struct lv));
152 if (!vg->lvs)
153 goto out;
155 err = 0;
156 vg->lv_cnt = lvs;
157 vg->pv_cnt = pvs;
158 vg->extent_size = size;
160 out:
161 if (scan)
162 pclose(scan);
163 if (err)
164 lvm_free_vg(vg);
165 free(cmd);
166 return err;
167 }
169 static int
170 lvm_parse_lv_devices(struct vg *vg, struct lv_segment *seg, char *devices)
171 {
172 int i;
173 uint64_t start, pe_start;
175 for (i = 0; i < strlen(devices); i++)
176 if (strchr(",()", devices[i]))
177 devices[i] = ' ';
179 if (sscanf(devices, _NAME" %"SCNu64, seg->device, &start) != 2)
180 return -EINVAL;
182 pe_start = -1;
183 for (i = 0; i < vg->pv_cnt; i++)
184 if (!strcmp(vg->pvs[i].name, seg->device)) {
185 pe_start = vg->pvs[i].start;
186 break;
187 }
189 if (pe_start == -1)
190 return -EINVAL;
192 seg->pe_start = (start * vg->extent_size) + pe_start;
193 return 0;
194 }
196 static int
197 lvm_scan_lvs(struct vg *vg)
198 {
199 char *cmd;
200 FILE *scan;
201 int i, err;
203 err = asprintf(&cmd, "/usr/sbin/lvs %s --noheadings --nosuffix --units=b "
204 "--options=lv_name,lv_size,segtype,seg_count,seg_start,"
205 "seg_size,devices --unbuffered 2> /dev/null", vg->name);
206 if (err == -1)
207 return -ENOMEM;
209 errno = 0;
210 scan = popen(cmd, "r");
211 if (!scan) {
212 err = (errno ? -errno : -ENOMEM);
213 goto out;
214 }
216 for (i = 0;;) {
217 int segs;
218 struct lv *lv;
219 struct lv_segment seg;
220 uint64_t size, seg_start;
221 char type[32], name[256], dev[256], devices[1024];
223 if (i >= vg->lv_cnt)
224 break;
226 if (lvm_read_line(scan)) {
227 vg->lv_cnt = i;
228 break;
229 }
231 err = -EINVAL;
232 lv = vg->lvs + i;
234 if (sscanf(line, _NAME" %"SCNu64" %31s %u %"SCNu64" %"SCNu64" %1023s",
235 name, &size, type, &segs, &seg_start,
236 &seg.pe_size, devices) != 7)
237 goto out;
239 if (seg_start)
240 goto next;
242 if (!strcmp(type, "linear"))
243 seg.type = LVM_SEG_TYPE_LINEAR;
244 else
245 seg.type = LVM_SEG_TYPE_UNKNOWN;
247 if (lvm_parse_lv_devices(vg, &seg, devices))
248 goto out;
250 i++;
251 lv->size = size;
252 lv->segments = segs;
253 lv->first_segment = seg;
255 err = lvm_copy_name(lv->name, name, sizeof(lv->name) - 1);
256 if (err)
257 goto out;
258 err = -EINVAL;
260 next:
261 if (lvm_next_line(scan))
262 goto out;
263 }
265 err = 0;
267 out:
268 if (scan)
269 pclose(scan);
270 free(cmd);
271 return err;
272 }
274 void
275 lvm_free_vg(struct vg *vg)
276 {
277 free(vg->lvs);
278 free(vg->pvs);
279 memset(vg, 0, sizeof(*vg));
280 }
282 int
283 lvm_scan_vg(const char *vg_name, struct vg *vg)
284 {
285 int err;
287 memset(vg, 0, sizeof(*vg));
289 err = lvm_open_vg(vg_name, vg);
290 if (err)
291 return err;
293 err = lvm_scan_lvs(vg);
294 if (err) {
295 lvm_free_vg(vg);
296 return err;
297 }
299 return 0;
300 }
302 #ifdef LVM_UTIL
303 static int
304 usage(void)
305 {
306 printf("usage: lvm-util <vgname>\n");
307 exit(EINVAL);
308 }
310 int
311 main(int argc, char **argv)
312 {
313 int i, err;
314 struct vg vg;
315 struct pv *pv;
316 struct lv *lv;
317 struct lv_segment *seg;
319 if (argc != 2)
320 usage();
322 err = lvm_scan_vg(argv[1], &vg);
323 if (err) {
324 printf("scan failed: %d\n", err);
325 return (err >= 0 ? err : -err);
326 }
329 printf("vg %s: extent_size: %"PRIu64", pvs: %d, lvs: %d\n",
330 vg.name, vg.extent_size, vg.pv_cnt, vg.lv_cnt);
332 for (i = 0; i < vg.pv_cnt; i++) {
333 pv = vg.pvs + i;
334 printf("pv %s: start %"PRIu64"\n", pv->name, pv->start);
335 }
337 for (i = 0; i < vg.lv_cnt; i++) {
338 lv = vg.lvs + i;
339 seg = &lv->first_segment;
340 printf("lv %s: size: %"PRIu64", segments: %u, type: %u, "
341 "dev: %s, pe_start: %"PRIu64", pe_size: %"PRIu64"\n",
342 lv->name, lv->size, lv->segments, seg->type,
343 seg->device, seg->pe_start, seg->pe_size);
344 }
346 lvm_free_vg(&vg);
347 return 0;
348 }
349 #endif