source: trunk/packages/xen-3.1/xen-3.1/tools/blktap/drivers/qcow2raw.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 8.7 KB
Line 
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 */
31
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"
43
44#if 1
45#define DFPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a )
46#else
47#define DFPRINTF(_f, _a...) ((void)0)
48#endif
49
50#define TAPDISK 1
51#define BLOCK_PROCESSSZ 4096
52
53static int maxfds, *qcowio_fd, *aio_fd, running = 1, complete = 0; 
54static int returned_read_events = 0, returned_write_events = 0;
55static int submit_events = 0;
56static uint32_t read_idx = 0, write_idx = 0;
57struct disk_driver ddqcow, ddaio;
58static uint64_t prev = 0, written = 0;
59static char output[25];
60
61void print_bytes(void *ptr, int length) {
62
63  int i,k;
64  unsigned char *p = ptr;
65
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}
76
77void debug_output(uint64_t progress, uint64_t size)
78{
79        /*Output progress every 5% */   
80        uint64_t blocks = size/20;
81
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}
90
91static inline void LOCAL_FD_SET(fd_set *readfds) 
92{
93        FD_SET(qcowio_fd[0], readfds);
94        FD_SET(aio_fd[0], readfds);
95       
96        maxfds = (qcowio_fd[0] > aio_fd[0] ? qcowio_fd[0] : aio_fd[0]) + 1;
97       
98        return;
99}
100
101static 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;
111
112        debug_output(written, dd->td_state->size << 9);
113        free(private);
114        return 0;
115}
116
117static 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;
121
122        if (res < 0) DFPRINTF("AIO FAILURE: res [%d]!\n",res);
123       
124        returned_read_events++;
125        read_idx = idx;
126       
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        }
133
134        if ( (returned_read_events == submit_events) || 
135             (returned_read_events % 10 == 0) ) {
136                ddaio.drv->td_submit(&ddaio);
137        }
138
139        return 0;
140}
141
142int 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;
151
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        }
159
160        ddqcow.td_state = malloc(sizeof(struct td_state));
161        ddaio.td_state  = malloc(sizeof(struct td_state));
162       
163        /*Open qcow source file*/       
164        ddqcow.drv = &tapdisk_qcow;
165        ddqcow.private = malloc(ddqcow.drv->private_data_size);
166
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);
172
173        qcowio_fd = ddqcow.io_fd;
174
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                }
220               
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                }
228
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        }
263
264        /*Open aio destination file*/   
265        ddaio.drv = &tapdisk_aio;
266        ddaio.private = malloc(ddaio.drv->private_data_size);
267
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        }
272
273        aio_fd = ddaio.io_fd;
274
275        /*Initialise the output string*/
276        memset(output,0x20,25);
277        output[0] = '[';
278        output[22] = ']';
279        output[23] = '\0';
280        DFPRINTF("%s",output);
281
282        i = 0;
283        while (running) {
284                timeout.tv_sec = 0;
285               
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                        }
295               
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);
301
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                        }
309
310                        if (i >= ddqcow.td_state->size<<9) {
311                                complete = 1;
312                        }
313                       
314                        if ((submit_events % 10 == 0) || complete) 
315                                ddqcow.drv->td_submit(&ddqcow);
316                        timeout.tv_usec = 0;
317                       
318                } else {
319                        timeout.tv_usec = 1000;
320                        if (!submit_events) running = 0;
321                }
322               
323
324                /*Check AIO FD*/
325                LOCAL_FD_SET(&readfds);
326                ret = select(maxfds + 1, &readfds, (fd_set *) 0,
327                             (fd_set *) 0, &timeout);
328                             
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);
340               
341        return 0;
342}
Note: See TracBrowser for help on using the repository browser.