Annotation of qemu/block.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * QEMU System Emulator block driver
                      3:  * 
                      4:  * Copyright (c) 2003 Fabrice Bellard
                      5:  * 
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include "vl.h"
                     25: #include "block_int.h"
                     26: 
                     27: #ifdef _BSD
                     28: #include <sys/types.h>
                     29: #include <sys/stat.h>
                     30: #include <sys/ioctl.h>
                     31: #include <sys/queue.h>
                     32: #include <sys/disk.h>
                     33: #endif
                     34: 
                     35: static BlockDriverState *bdrv_first;
                     36: static BlockDriver *first_drv;
                     37: 
                     38: void bdrv_register(BlockDriver *bdrv)
                     39: {
                     40:     bdrv->next = first_drv;
                     41:     first_drv = bdrv;
                     42: }
                     43: 
                     44: /* create a new block device (by default it is empty) */
                     45: BlockDriverState *bdrv_new(const char *device_name)
                     46: {
                     47:     BlockDriverState **pbs, *bs;
                     48: 
                     49:     bs = qemu_mallocz(sizeof(BlockDriverState));
                     50:     if(!bs)
                     51:         return NULL;
                     52:     pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
                     53:     if (device_name[0] != '\0') {
                     54:         /* insert at the end */
                     55:         pbs = &bdrv_first;
                     56:         while (*pbs != NULL)
                     57:             pbs = &(*pbs)->next;
                     58:         *pbs = bs;
                     59:     }
                     60:     return bs;
                     61: }
                     62: 
                     63: BlockDriver *bdrv_find_format(const char *format_name)
                     64: {
                     65:     BlockDriver *drv1;
                     66:     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
                     67:         if (!strcmp(drv1->format_name, format_name))
                     68:             return drv1;
                     69:     }
                     70:     return NULL;
                     71: }
                     72: 
                     73: int bdrv_create(BlockDriver *drv, 
                     74:                 const char *filename, int64_t size_in_sectors,
                     75:                 const char *backing_file, int flags)
                     76: {
                     77:     if (!drv->bdrv_create)
                     78:         return -ENOTSUP;
                     79:     return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
                     80: }
                     81: 
                     82: #ifdef _WIN32
                     83: static void get_tmp_filename(char *filename, int size)
                     84: {
                     85:     /* XXX: find a better function */
                     86:     tmpnam(filename);
                     87: }
                     88: #else
                     89: static void get_tmp_filename(char *filename, int size)
                     90: {
                     91:     int fd;
                     92:     /* XXX: race condition possible */
                     93:     pstrcpy(filename, size, "/tmp/vl.XXXXXX");
                     94:     fd = mkstemp(filename);
                     95:     close(fd);
                     96: }
                     97: #endif
                     98: 
                     99: /* XXX: force raw format if block or character device ? It would
                    100:    simplify the BSD case */
                    101: static BlockDriver *find_image_format(const char *filename)
                    102: {
                    103:     int fd, ret, score, score_max;
                    104:     BlockDriver *drv1, *drv;
                    105:     uint8_t *buf;
                    106:     size_t bufsize = 1024;
                    107: 
                    108:     fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
                    109:     if (fd < 0) {
                    110:         buf = NULL;
                    111:         ret = 0;
                    112:     } else {
                    113: #ifdef DIOCGSECTORSIZE
                    114:         {
                    115:             unsigned int sectorsize = 512;
                    116:             if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
                    117:                 sectorsize > bufsize)
                    118:                 bufsize = sectorsize;
                    119:         }
                    120: #endif
                    121:         buf = qemu_malloc(bufsize);
                    122:         if (!buf)
                    123:             return NULL;
                    124:         ret = read(fd, buf, bufsize);
                    125:         if (ret < 0) {
                    126:             close(fd);
                    127:             qemu_free(buf);
                    128:             return NULL;
                    129:         }
                    130:         close(fd);
                    131:     }
                    132:     
                    133:     drv = NULL;
                    134:     score_max = 0;
                    135:     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
                    136:         score = drv1->bdrv_probe(buf, ret, filename);
                    137:         if (score > score_max) {
                    138:             score_max = score;
                    139:             drv = drv1;
                    140:         }
                    141:     }
                    142:     qemu_free(buf);
                    143:     return drv;
                    144: }
                    145: 
                    146: int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
                    147: {
                    148:     return bdrv_open2(bs, filename, snapshot, NULL);
                    149: }
                    150: 
                    151: int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
                    152:                BlockDriver *drv)
                    153: {
                    154:     int ret;
                    155:     char tmp_filename[1024];
                    156:     
                    157:     bs->read_only = 0;
                    158:     bs->is_temporary = 0;
                    159:     bs->encrypted = 0;
                    160: 
                    161:     if (snapshot) {
                    162:         BlockDriverState *bs1;
                    163:         int64_t total_size;
                    164:         
                    165:         /* if snapshot, we create a temporary backing file and open it
                    166:            instead of opening 'filename' directly */
                    167: 
                    168:         /* if there is a backing file, use it */
                    169:         bs1 = bdrv_new("");
                    170:         if (!bs1) {
                    171:             return -1;
                    172:         }
                    173:         if (bdrv_open(bs1, filename, 0) < 0) {
                    174:             bdrv_delete(bs1);
                    175:             return -1;
                    176:         }
                    177:         total_size = bs1->total_sectors;
                    178:         bdrv_delete(bs1);
                    179:         
                    180:         get_tmp_filename(tmp_filename, sizeof(tmp_filename));
                    181:         /* XXX: use cow for linux as it is more efficient ? */
                    182:         if (bdrv_create(&bdrv_qcow, tmp_filename, 
                    183:                         total_size, filename, 0) < 0) {
                    184:             return -1;
                    185:         }
                    186:         filename = tmp_filename;
                    187:         bs->is_temporary = 1;
                    188:     }
                    189: 
                    190:     pstrcpy(bs->filename, sizeof(bs->filename), filename);
                    191:     if (!drv) {
                    192:         drv = find_image_format(filename);
                    193:         if (!drv)
                    194:             return -1;
                    195:     }
                    196:     bs->drv = drv;
                    197:     bs->opaque = qemu_mallocz(drv->instance_size);
                    198:     if (bs->opaque == NULL && drv->instance_size > 0)
                    199:         return -1;
                    200:     
                    201:     ret = drv->bdrv_open(bs, filename);
                    202:     if (ret < 0) {
                    203:         qemu_free(bs->opaque);
                    204:         return -1;
                    205:     }
                    206: #ifndef _WIN32
                    207:     if (bs->is_temporary) {
                    208:         unlink(filename);
                    209:     }
                    210: #endif
                    211:     if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
                    212:         /* if there is a backing file, use it */
                    213:         bs->backing_hd = bdrv_new("");
                    214:         if (!bs->backing_hd) {
                    215:         fail:
                    216:             bdrv_close(bs);
                    217:             return -1;
                    218:         }
                    219:         if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
                    220:             goto fail;
                    221:     }
                    222: 
                    223:     bs->inserted = 1;
                    224: 
                    225:     /* call the change callback */
                    226:     if (bs->change_cb)
                    227:         bs->change_cb(bs->change_opaque);
                    228: 
                    229:     return 0;
                    230: }
                    231: 
                    232: void bdrv_close(BlockDriverState *bs)
                    233: {
                    234:     if (bs->inserted) {
                    235:         if (bs->backing_hd)
                    236:             bdrv_delete(bs->backing_hd);
                    237:         bs->drv->bdrv_close(bs);
                    238:         qemu_free(bs->opaque);
                    239: #ifdef _WIN32
                    240:         if (bs->is_temporary) {
                    241:             unlink(bs->filename);
                    242:         }
                    243: #endif
                    244:         bs->opaque = NULL;
                    245:         bs->drv = NULL;
                    246:         bs->inserted = 0;
                    247: 
                    248:         /* call the change callback */
                    249:         if (bs->change_cb)
                    250:             bs->change_cb(bs->change_opaque);
                    251:     }
                    252: }
                    253: 
                    254: void bdrv_delete(BlockDriverState *bs)
                    255: {
                    256:     /* XXX: remove the driver list */
                    257:     bdrv_close(bs);
                    258:     qemu_free(bs);
                    259: }
                    260: 
                    261: /* commit COW file into the raw image */
                    262: int bdrv_commit(BlockDriverState *bs)
                    263: {
                    264:     int64_t i;
                    265:     int n, j;
                    266:     unsigned char sector[512];
                    267: 
                    268:     if (!bs->inserted)
                    269:         return -ENOENT;
                    270: 
                    271:     if (bs->read_only) {
                    272:        return -EACCES;
                    273:     }
                    274: 
                    275:     if (!bs->backing_hd) {
                    276:        return -ENOTSUP;
                    277:     }
                    278: 
                    279:     for (i = 0; i < bs->total_sectors;) {
                    280:         if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
                    281:             for(j = 0; j < n; j++) {
                    282:                 if (bdrv_read(bs, i, sector, 1) != 0) {
                    283:                     return -EIO;
                    284:                 }
                    285: 
                    286:                 if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
                    287:                     return -EIO;
                    288:                 }
                    289:                 i++;
                    290:            }
                    291:        } else {
                    292:             i += n;
                    293:         }
                    294:     }
                    295:     return 0;
                    296: }
                    297: 
                    298: /* return -1 if error */
                    299: int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
                    300:               uint8_t *buf, int nb_sectors)
                    301: {
                    302:     int ret, n;
                    303:     BlockDriver *drv = bs->drv;
                    304: 
                    305:     if (!bs->inserted)
                    306:         return -1;
                    307: 
                    308:     while (nb_sectors > 0) {
                    309:         if (sector_num == 0 && bs->boot_sector_enabled) {
                    310:             memcpy(buf, bs->boot_sector_data, 512);
                    311:             n = 1;
                    312:         } else if (bs->backing_hd) {
                    313:             if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
                    314:                 ret = drv->bdrv_read(bs, sector_num, buf, n);
                    315:                 if (ret < 0)
                    316:                     return -1;
                    317:             } else {
                    318:                 /* read from the base image */
                    319:                 ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
                    320:                 if (ret < 0)
                    321:                     return -1;
                    322:             }
                    323:         } else {
                    324:             ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
                    325:             if (ret < 0)
                    326:                 return -1;
                    327:             /* no need to loop */
                    328:             break;
                    329:         }
                    330:         nb_sectors -= n;
                    331:         sector_num += n;
                    332:         buf += n * 512;
                    333:     }
                    334:     return 0;
                    335: }
                    336: 
                    337: /* return -1 if error */
                    338: int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
                    339:                const uint8_t *buf, int nb_sectors)
                    340: {
                    341:     if (!bs->inserted)
                    342:         return -1;
                    343:     if (bs->read_only)
                    344:         return -1;
                    345:     return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
                    346: }
                    347: 
                    348: void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
                    349: {
                    350:     *nb_sectors_ptr = bs->total_sectors;
                    351: }
                    352: 
                    353: /* force a given boot sector. */
                    354: void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
                    355: {
                    356:     bs->boot_sector_enabled = 1;
                    357:     if (size > 512)
                    358:         size = 512;
                    359:     memcpy(bs->boot_sector_data, data, size);
                    360:     memset(bs->boot_sector_data + size, 0, 512 - size);
                    361: }
                    362: 
                    363: void bdrv_set_geometry_hint(BlockDriverState *bs, 
                    364:                             int cyls, int heads, int secs)
                    365: {
                    366:     bs->cyls = cyls;
                    367:     bs->heads = heads;
                    368:     bs->secs = secs;
                    369: }
                    370: 
                    371: void bdrv_set_type_hint(BlockDriverState *bs, int type)
                    372: {
                    373:     bs->type = type;
                    374:     bs->removable = ((type == BDRV_TYPE_CDROM ||
                    375:                       type == BDRV_TYPE_FLOPPY));
                    376: }
                    377: 
                    378: void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
                    379: {
                    380:     bs->translation = translation;
                    381: }
                    382: 
                    383: void bdrv_get_geometry_hint(BlockDriverState *bs, 
                    384:                             int *pcyls, int *pheads, int *psecs)
                    385: {
                    386:     *pcyls = bs->cyls;
                    387:     *pheads = bs->heads;
                    388:     *psecs = bs->secs;
                    389: }
                    390: 
                    391: int bdrv_get_type_hint(BlockDriverState *bs)
                    392: {
                    393:     return bs->type;
                    394: }
                    395: 
                    396: int bdrv_get_translation_hint(BlockDriverState *bs)
                    397: {
                    398:     return bs->translation;
                    399: }
                    400: 
                    401: int bdrv_is_removable(BlockDriverState *bs)
                    402: {
                    403:     return bs->removable;
                    404: }
                    405: 
                    406: int bdrv_is_read_only(BlockDriverState *bs)
                    407: {
                    408:     return bs->read_only;
                    409: }
                    410: 
                    411: int bdrv_is_inserted(BlockDriverState *bs)
                    412: {
                    413:     return bs->inserted;
                    414: }
                    415: 
                    416: int bdrv_is_locked(BlockDriverState *bs)
                    417: {
                    418:     return bs->locked;
                    419: }
                    420: 
                    421: void bdrv_set_locked(BlockDriverState *bs, int locked)
                    422: {
                    423:     bs->locked = locked;
                    424: }
                    425: 
                    426: void bdrv_set_change_cb(BlockDriverState *bs, 
                    427:                         void (*change_cb)(void *opaque), void *opaque)
                    428: {
                    429:     bs->change_cb = change_cb;
                    430:     bs->change_opaque = opaque;
                    431: }
                    432: 
                    433: int bdrv_is_encrypted(BlockDriverState *bs)
                    434: {
                    435:     if (bs->backing_hd && bs->backing_hd->encrypted)
                    436:         return 1;
                    437:     return bs->encrypted;
                    438: }
                    439: 
                    440: int bdrv_set_key(BlockDriverState *bs, const char *key)
                    441: {
                    442:     int ret;
                    443:     if (bs->backing_hd && bs->backing_hd->encrypted) {
                    444:         ret = bdrv_set_key(bs->backing_hd, key);
                    445:         if (ret < 0)
                    446:             return ret;
                    447:         if (!bs->encrypted)
                    448:             return 0;
                    449:     }
                    450:     if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
                    451:         return -1;
                    452:     return bs->drv->bdrv_set_key(bs, key);
                    453: }
                    454: 
                    455: void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
                    456: {
                    457:     if (!bs->inserted || !bs->drv) {
                    458:         buf[0] = '\0';
                    459:     } else {
                    460:         pstrcpy(buf, buf_size, bs->drv->format_name);
                    461:     }
                    462: }
                    463: 
                    464: void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 
                    465:                          void *opaque)
                    466: {
                    467:     BlockDriver *drv;
                    468: 
                    469:     for (drv = first_drv; drv != NULL; drv = drv->next) {
                    470:         it(opaque, drv->format_name);
                    471:     }
                    472: }
                    473: 
                    474: BlockDriverState *bdrv_find(const char *name)
                    475: {
                    476:     BlockDriverState *bs;
                    477: 
                    478:     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
                    479:         if (!strcmp(name, bs->device_name))
                    480:             return bs;
                    481:     }
                    482:     return NULL;
                    483: }
                    484: 
                    485: void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
                    486: {
                    487:     BlockDriverState *bs;
                    488: 
                    489:     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
                    490:         it(opaque, bs->device_name);
                    491:     }
                    492: }
                    493: 
                    494: const char *bdrv_get_device_name(BlockDriverState *bs)
                    495: {
                    496:     return bs->device_name;
                    497: }
                    498: 
                    499: void bdrv_info(void)
                    500: {
                    501:     BlockDriverState *bs;
                    502: 
                    503:     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
                    504:         term_printf("%s:", bs->device_name);
                    505:         term_printf(" type=");
                    506:         switch(bs->type) {
                    507:         case BDRV_TYPE_HD:
                    508:             term_printf("hd");
                    509:             break;
                    510:         case BDRV_TYPE_CDROM:
                    511:             term_printf("cdrom");
                    512:             break;
                    513:         case BDRV_TYPE_FLOPPY:
                    514:             term_printf("floppy");
                    515:             break;
                    516:         }
                    517:         term_printf(" removable=%d", bs->removable);
                    518:         if (bs->removable) {
                    519:             term_printf(" locked=%d", bs->locked);
                    520:         }
                    521:         if (bs->inserted) {
                    522:             term_printf(" file=%s", bs->filename);
                    523:             if (bs->backing_file[0] != '\0')
                    524:                 term_printf(" backing_file=%s", bs->backing_file);
                    525:             term_printf(" ro=%d", bs->read_only);
                    526:             term_printf(" drv=%s", bs->drv->format_name);
                    527:             if (bs->encrypted)
                    528:                 term_printf(" encrypted");
                    529:         } else {
                    530:             term_printf(" [not inserted]");
                    531:         }
                    532:         term_printf("\n");
                    533:     }
                    534: }
                    535: 
                    536: 
                    537: /**************************************************************/
                    538: /* RAW block driver */
                    539: 
                    540: typedef struct BDRVRawState {
                    541:     int fd;
                    542: } BDRVRawState;
                    543: 
                    544: static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
                    545: {
                    546:     return 1; /* maybe */
                    547: }
                    548: 
                    549: static int raw_open(BlockDriverState *bs, const char *filename)
                    550: {
                    551:     BDRVRawState *s = bs->opaque;
                    552:     int fd;
                    553:     int64_t size;
                    554: #ifdef _BSD
                    555:     struct stat sb;
                    556: #endif
                    557: 
                    558:     fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
                    559:     if (fd < 0) {
                    560:         fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
                    561:         if (fd < 0)
                    562:             return -1;
                    563:         bs->read_only = 1;
                    564:     }
                    565: #ifdef _BSD
                    566:     if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
                    567: #ifdef DIOCGMEDIASIZE
                    568:        if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
                    569: #endif
                    570:            size = lseek(fd, 0LL, SEEK_END);
                    571:     } else
                    572: #endif
                    573:     {
                    574:         size = lseek(fd, 0, SEEK_END);
                    575:     }
                    576: #ifdef _WIN32
                    577:     /* On Windows hosts it can happen that we're unable to get file size
                    578:        for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
                    579:     if (size == -1)
                    580:         size = LONG_LONG_MAX;
                    581: #endif
                    582:     bs->total_sectors = size / 512;
                    583:     s->fd = fd;
                    584:     return 0;
                    585: }
                    586: 
                    587: static int raw_read(BlockDriverState *bs, int64_t sector_num, 
                    588:                     uint8_t *buf, int nb_sectors)
                    589: {
                    590:     BDRVRawState *s = bs->opaque;
                    591:     int ret;
                    592:     
                    593:     lseek(s->fd, sector_num * 512, SEEK_SET);
                    594:     ret = read(s->fd, buf, nb_sectors * 512);
                    595:     if (ret != nb_sectors * 512) 
                    596:         return -1;
                    597:     return 0;
                    598: }
                    599: 
                    600: static int raw_write(BlockDriverState *bs, int64_t sector_num, 
                    601:                      const uint8_t *buf, int nb_sectors)
                    602: {
                    603:     BDRVRawState *s = bs->opaque;
                    604:     int ret;
                    605:     
                    606:     lseek(s->fd, sector_num * 512, SEEK_SET);
                    607:     ret = write(s->fd, buf, nb_sectors * 512);
                    608:     if (ret != nb_sectors * 512) 
                    609:         return -1;
                    610:     return 0;
                    611: }
                    612: 
                    613: static void raw_close(BlockDriverState *bs)
                    614: {
                    615:     BDRVRawState *s = bs->opaque;
                    616:     close(s->fd);
                    617: }
                    618: 
                    619: static int raw_create(const char *filename, int64_t total_size,
                    620:                       const char *backing_file, int flags)
                    621: {
                    622:     int fd;
                    623: 
                    624:     if (flags || backing_file)
                    625:         return -ENOTSUP;
                    626: 
                    627:     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
                    628:               0644);
                    629:     if (fd < 0)
                    630:         return -EIO;
                    631:     ftruncate(fd, total_size * 512);
                    632:     close(fd);
                    633:     return 0;
                    634: }
                    635: 
                    636: BlockDriver bdrv_raw = {
                    637:     "raw",
                    638:     sizeof(BDRVRawState),
                    639:     raw_probe,
                    640:     raw_open,
                    641:     raw_read,
                    642:     raw_write,
                    643:     raw_close,
                    644:     raw_create,
                    645: };
                    646: 
                    647: void bdrv_init(void)
                    648: {
                    649:     bdrv_register(&bdrv_raw);
                    650: #ifndef _WIN32
                    651:     bdrv_register(&bdrv_cow);
                    652: #endif
                    653:     bdrv_register(&bdrv_qcow);
                    654:     bdrv_register(&bdrv_vmdk);
                    655:     bdrv_register(&bdrv_cloop);
                    656:     bdrv_register(&bdrv_dmg);
                    657:     bdrv_register(&bdrv_bochs);
                    658:     bdrv_register(&bdrv_vpc);
                    659:     bdrv_register(&bdrv_vvfat);
                    660: }

unix.superglobalmegacorp.com