ia64/xen-unstable

view tools/blktap/drivers/qcow2raw.c @ 15783:c93e2a822d6f

[xen, xencomm] xencomm multiple page support
Current implementation doesn't allow struct xencomm_desc::address
array to be more than single page. On IA64 it causes 64GB+ domain
creation failure. This patch generalizes xencomm to allow multipage

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author kfraser@localhost.localdomain
date Tue Aug 28 15:32:27 2007 +0100 (2007-08-28)
parents 6898d8ae7ae4
children b6cc74f275fd
line source
1 /* qcow2raw.c
2 *
3 * Generates raw image data from an existing qcow image
4 *
5 * (c) 2006 Julian Chesterfield and Andrew Warfield
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation; or, when distributed
10 * separately from the Linux kernel or incorporated into other
11 * software packages, subject to the following license:
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this source file (the "Software"), to deal in the Software without
15 * restriction, including without limitation the rights to use, copy, modify,
16 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
17 * and to permit persons to whom the Software is furnished to do so, subject to
18 * the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29 * IN THE SOFTWARE.
30 */
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <sys/statvfs.h>
38 #include <sys/stat.h>
39 #include <sys/ioctl.h>
40 #include <linux/fs.h>
41 #include <string.h>
42 #include "tapdisk.h"
44 #if 1
45 #define DFPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a )
46 #else
47 #define DFPRINTF(_f, _a...) ((void)0)
48 #endif
50 #define TAPDISK 1
51 #define BLOCK_PROCESSSZ 4096
53 static int maxfds, *qcowio_fd, *aio_fd, running = 1, complete = 0;
54 static int returned_read_events = 0, returned_write_events = 0;
55 static int submit_events = 0;
56 static uint32_t read_idx = 0, write_idx = 0;
57 struct disk_driver ddqcow, ddaio;
58 static uint64_t prev = 0, written = 0;
59 static char output[25];
61 void print_bytes(void *ptr, int length) {
63 int i,k;
64 unsigned char *p = ptr;
66 DFPRINTF("Buf dump, length %d:\n",length);
67 for (k = 0; k < length; k++) {
68 DFPRINTF("%x",*p);
69 *p++;
70 if (k % 16 == 0) DFPRINTF("\n");
71 else if (k % 2 == 0) DFPRINTF(" ");
72 }
73 DFPRINTF("\n");
74 return;
75 }
77 void debug_output(uint64_t progress, uint64_t size)
78 {
79 /*Output progress every 5% */
80 uint64_t blocks = size/20;
82 if (progress/blocks > prev) {
83 memcpy(output+prev+1,"=>",2);
84 prev++;
85 DFPRINTF("\r%s %llu%%",
86 output, (long long)((prev-1)*5));
87 }
88 return;
89 }
91 static inline void LOCAL_FD_SET(fd_set *readfds)
92 {
93 FD_SET(qcowio_fd[0], readfds);
94 FD_SET(aio_fd[0], readfds);
96 maxfds = (qcowio_fd[0] > aio_fd[0] ? qcowio_fd[0] : aio_fd[0]) + 1;
98 return;
99 }
101 static int send_write_responses(struct disk_driver *dd, int res, uint64_t sec,
102 int nr_secs, int idx, void *private)
103 {
104 if (res < 0) {
105 DFPRINTF("AIO FAILURE: res [%d]!\n",res);
106 return 0;
107 }
108 written += BLOCK_PROCESSSZ;
109 returned_write_events++;
110 write_idx = idx;
112 debug_output(written, dd->td_state->size << 9);
113 free(private);
114 return 0;
115 }
117 static int send_read_responses(struct disk_driver *dd, int res, uint64_t sec,
118 int nr_secs, int idx, void *private)
119 {
120 int ret;
122 if (res < 0) DFPRINTF("AIO FAILURE: res [%d]!\n",res);
124 returned_read_events++;
125 read_idx = idx;
127 ret = ddaio.drv->td_queue_write(&ddaio, idx, BLOCK_PROCESSSZ>>9, private,
128 send_write_responses, idx, private);
129 if (ret != 0) {
130 DFPRINTF("ERROR in submitting queue write!\n");
131 return 0;
132 }
134 if ( (returned_read_events == submit_events) ||
135 (returned_read_events % 10 == 0) ) {
136 ddaio.drv->td_submit(&ddaio);
137 }
139 return 0;
140 }
142 int main(int argc, char *argv[])
143 {
144 int ret = -1, fd, len,input;
145 long int size;
146 fd_set readfds;
147 struct timeval timeout;
148 uint64_t i;
149 char *buf;
150 struct stat finfo;
152 if (argc != 3) {
153 fprintf(stderr, "Qcow-utils: v1.0.0\n");
154 fprintf(stderr, "usage: %s <Dest File descriptor> "
155 "<Qcow SRC IMAGE>\n",
156 argv[0]);
157 exit(-1);
158 }
160 ddqcow.td_state = malloc(sizeof(struct td_state));
161 ddaio.td_state = malloc(sizeof(struct td_state));
163 /*Open qcow source file*/
164 ddqcow.drv = &tapdisk_qcow;
165 ddqcow.private = malloc(ddqcow.drv->private_data_size);
167 if (ddqcow.drv->td_open(&ddqcow, argv[2], TD_RDONLY)!=0) {
168 DFPRINTF("Unable to open Qcow file [%s]\n",argv[2]);
169 exit(-1);
170 } else DFPRINTF("QCOW file opened, size %llu\n",
171 (long long unsigned)ddqcow.td_state->size);
173 qcowio_fd = ddqcow.io_fd;
175 /*Setup aio destination file*/
176 ret = stat(argv[1],&finfo);
177 if (ret == -1) {
178 /*Check errno*/
179 switch(errno) {
180 case ENOENT:
181 /*File doesn't exist, create*/
182 fd = open(argv[1],
183 O_RDWR | O_LARGEFILE | O_CREAT, 0644);
184 if (fd < 0) {
185 DFPRINTF("ERROR creating file [%s] "
186 "(errno %d)\n",
187 argv[1], 0 - errno);
188 exit(-1);
189 }
190 if (ftruncate(fd, (off_t)ddqcow.td_state->size<<9) < 0) {
191 DFPRINTF("Unable to create file "
192 "[%s] of size %llu (errno %d). "
193 "Exiting...\n",
194 argv[1],
195 (long long unsigned)ddqcow.td_state->size<<9,
196 0 - errno);
197 close(fd);
198 exit(-1);
199 }
200 close(fd);
201 break;
202 case ENXIO:
203 DFPRINTF("ERROR Device [%s] does not exist\n",argv[1]);
204 exit(-1);
205 default:
206 DFPRINTF("An error occurred opening Device [%s] "
207 "(errno %d)\n",
208 argv[1], 0 - errno);
209 exit(-1);
210 }
211 } else {
212 fprintf(stderr, "WARNING: All existing data in "
213 "%s will be overwritten.\nDo you wish to continue? "
214 "(y or n) ",
215 argv[1]);
216 if (getchar() != 'y') {
217 DFPRINTF("Exiting...\n");
218 exit(-1);
219 }
221 /*TODO - Test the existing file or device for adequate space*/
222 fd = open(argv[1], O_RDWR | O_LARGEFILE);
223 if (fd < 0) {
224 DFPRINTF("ERROR: opening file [%s] (errno %d)\n",
225 argv[1], 0 - errno);
226 exit(-1);
227 }
229 if (S_ISBLK(finfo.st_mode)) {
230 if(ioctl(fd,BLKGETSIZE,&size)!=0) {
231 DFPRINTF("ERROR: BLKGETSIZE failed, "
232 "couldn't stat image [%s]\n",
233 argv[1]);
234 close(fd);
235 exit(-1);
236 }
237 if (size < ddqcow.td_state->size<<9) {
238 DFPRINTF("ERROR: Not enough space on device "
239 "%s (%lu bytes available, %llu bytes required\n",
240 argv[1], size,
241 (long long unsigned)ddqcow.td_state->size<<9);
242 close(fd);
243 exit(-1);
244 }
245 } else {
246 if (ftruncate(fd, (off_t)ddqcow.td_state->size<<9) < 0) {
247 DFPRINTF("Unable to create file "
248 "[%s] of size %llu (errno %d). "
249 "Exiting...\n",
250 argv[1],
251 (long long unsigned)ddqcow.td_state->size<<9,
252 0 - errno);
253 close(fd);
254 exit(-1);
255 } else DFPRINTF("File [%s] truncated to length %llu "
256 "(%llu)\n",
257 argv[1],
258 (long long unsigned)ddqcow.td_state->size<<9,
259 (long long unsigned)ddqcow.td_state->size);
260 }
261 close(fd);
262 }
264 /*Open aio destination file*/
265 ddaio.drv = &tapdisk_aio;
266 ddaio.private = malloc(ddaio.drv->private_data_size);
268 if (ddaio.drv->td_open(&ddaio, argv[1], 0)!=0) {
269 DFPRINTF("Unable to open Qcow file [%s]\n", argv[1]);
270 exit(-1);
271 }
273 aio_fd = ddaio.io_fd;
275 /*Initialise the output string*/
276 memset(output,0x20,25);
277 output[0] = '[';
278 output[22] = ']';
279 output[23] = '\0';
280 DFPRINTF("%s",output);
282 i = 0;
283 while (running) {
284 timeout.tv_sec = 0;
286 if (!complete) {
287 /*Read Pages from qcow image*/
288 if ( (ret = posix_memalign((void **)&buf,
289 BLOCK_PROCESSSZ,
290 BLOCK_PROCESSSZ))
291 != 0) {
292 DFPRINTF("Unable to alloc memory (%d)\n",ret);
293 exit(-1);
294 }
296 /*Attempt to read 4k sized blocks*/
297 submit_events++;
298 ret = ddqcow.drv->td_queue_read(&ddqcow, i>>9,
299 BLOCK_PROCESSSZ>>9, buf,
300 send_read_responses, i>>9, buf);
302 if (ret < 0) {
303 DFPRINTF("UNABLE TO READ block [%llu]\n",
304 (long long unsigned)i);
305 exit(-1);
306 } else {
307 i += BLOCK_PROCESSSZ;
308 }
310 if (i >= ddqcow.td_state->size<<9) {
311 complete = 1;
312 }
314 if ((submit_events % 10 == 0) || complete)
315 ddqcow.drv->td_submit(&ddqcow);
316 timeout.tv_usec = 0;
318 } else {
319 timeout.tv_usec = 1000;
320 if (!submit_events) running = 0;
321 }
324 /*Check AIO FD*/
325 LOCAL_FD_SET(&readfds);
326 ret = select(maxfds + 1, &readfds, (fd_set *) 0,
327 (fd_set *) 0, &timeout);
329 if (ret > 0) {
330 if (FD_ISSET(qcowio_fd[0], &readfds))
331 ddqcow.drv->td_do_callbacks(&ddqcow, 0);
332 if (FD_ISSET(aio_fd[0], &readfds))
333 ddaio.drv->td_do_callbacks(&ddaio, 0);
334 }
335 if (complete && (returned_write_events == submit_events))
336 running = 0;
337 }
338 memcpy(output+prev+1,"=",1);
339 DFPRINTF("\r%s 100%%\nTRANSFER COMPLETE\n\n", output);
341 return 0;
342 }