* THE SOFTWARE.
*/
#include "qemu-common.h"
-#ifndef QEMU_IMG
#include "console.h"
-#endif
#include "block_int.h"
#ifdef _BSD
const uint8_t *buf, int nb_sectors);
BlockDriverState *bdrv_first;
+
static BlockDriver *first_drv;
int path_is_absolute(const char *path)
void get_tmp_filename(char *filename, int size)
{
int fd;
- char *tmpdir;
+ const char *tmpdir;
/* XXX: race condition possible */
tmpdir = getenv("TMPDIR");
if (!tmpdir)
if (flags & BDRV_O_SNAPSHOT) {
BlockDriverState *bs1;
int64_t total_size;
+ int is_protocol = 0;
/* if snapshot, we create a temporary backing file and open it
instead of opening 'filename' directly */
return -1;
}
total_size = bdrv_getlength(bs1) >> SECTOR_BITS;
+
+ if (bs1->drv && bs1->drv->protocol_name)
+ is_protocol = 1;
+
bdrv_delete(bs1);
get_tmp_filename(tmp_filename, sizeof(tmp_filename));
- realpath(filename, backing_filename);
+
+ /* Real path is meaningless for protocols */
+ if (is_protocol)
+ snprintf(backing_filename, sizeof(backing_filename),
+ "%s", filename);
+ else
+ realpath(filename, backing_filename);
+
if (bdrv_create(&bdrv_qcow2, tmp_filename,
total_size, backing_filename, 0) < 0) {
return -1;
/* Note: for compatibility, we open disk image files as RDWR, and
RDONLY as fallback */
if (!(flags & BDRV_O_FILE))
- open_flags = BDRV_O_RDWR | (flags & BDRV_O_DIRECT);
+ open_flags = BDRV_O_RDWR | (flags & BDRV_O_CACHE_MASK);
else
open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
ret = drv->bdrv_open(bs, filename, open_flags);
- if (ret == -EACCES && !(flags & BDRV_O_FILE)) {
- ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY);
+ if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE)) {
+ ret = drv->bdrv_open(bs, filename, open_flags & ~BDRV_O_RDWR);
bs->read_only = 1;
}
if (ret < 0) {
}
path_combine(backing_filename, sizeof(backing_filename),
filename, bs->backing_file);
- if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0)
+ if (bdrv_open(bs->backing_hd, backing_filename, open_flags) < 0)
goto fail;
}
if (!drv)
return -ENOMEDIUM;
- if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
- memcpy(buf, bs->boot_sector_data, 512);
- sector_num++;
- nb_sectors--;
- buf += 512;
- if (nb_sectors == 0)
- return 0;
- }
if (drv->bdrv_pread) {
int ret, len;
len = nb_sectors * 512;
return -ENOMEDIUM;
if (bs->read_only)
return -EACCES;
- if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
- memcpy(bs->boot_sector_data, buf, 512);
- }
if (drv->bdrv_pwrite) {
int ret, len;
len = nb_sectors * 512;
*nb_sectors_ptr = length;
}
-/* force a given boot sector. */
-void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
+struct partition {
+ uint8_t boot_ind; /* 0x80 - active */
+ uint8_t head; /* starting head */
+ uint8_t sector; /* starting sector */
+ uint8_t cyl; /* starting cylinder */
+ uint8_t sys_ind; /* What partition type */
+ uint8_t end_head; /* end head */
+ uint8_t end_sector; /* end sector */
+ uint8_t end_cyl; /* end cylinder */
+ uint32_t start_sect; /* starting sector counting from 0 */
+ uint32_t nr_sects; /* nr of sectors in partition */
+} __attribute__((packed));
+
+/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
+static int guess_disk_lchs(BlockDriverState *bs,
+ int *pcylinders, int *pheads, int *psectors)
+{
+ uint8_t buf[512];
+ int ret, i, heads, sectors, cylinders;
+ struct partition *p;
+ uint32_t nr_sects;
+ int64_t nb_sectors;
+
+ bdrv_get_geometry(bs, &nb_sectors);
+
+ ret = bdrv_read(bs, 0, buf, 1);
+ if (ret < 0)
+ return -1;
+ /* test msdos magic */
+ if (buf[510] != 0x55 || buf[511] != 0xaa)
+ return -1;
+ for(i = 0; i < 4; i++) {
+ p = ((struct partition *)(buf + 0x1be)) + i;
+ nr_sects = le32_to_cpu(p->nr_sects);
+ if (nr_sects && p->end_head) {
+ /* We make the assumption that the partition terminates on
+ a cylinder boundary */
+ heads = p->end_head + 1;
+ sectors = p->end_sector & 63;
+ if (sectors == 0)
+ continue;
+ cylinders = nb_sectors / (heads * sectors);
+ if (cylinders < 1 || cylinders > 16383)
+ continue;
+ *pheads = heads;
+ *psectors = sectors;
+ *pcylinders = cylinders;
+#if 0
+ printf("guessed geometry: LCHS=%d %d %d\n",
+ cylinders, heads, sectors);
+#endif
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs)
{
- bs->boot_sector_enabled = 1;
- if (size > 512)
- size = 512;
- memcpy(bs->boot_sector_data, data, size);
- memset(bs->boot_sector_data + size, 0, 512 - size);
+ int translation, lba_detected = 0;
+ int cylinders, heads, secs;
+ int64_t nb_sectors;
+
+ /* if a geometry hint is available, use it */
+ bdrv_get_geometry(bs, &nb_sectors);
+ bdrv_get_geometry_hint(bs, &cylinders, &heads, &secs);
+ translation = bdrv_get_translation_hint(bs);
+ if (cylinders != 0) {
+ *pcyls = cylinders;
+ *pheads = heads;
+ *psecs = secs;
+ } else {
+ if (guess_disk_lchs(bs, &cylinders, &heads, &secs) == 0) {
+ if (heads > 16) {
+ /* if heads > 16, it means that a BIOS LBA
+ translation was active, so the default
+ hardware geometry is OK */
+ lba_detected = 1;
+ goto default_geometry;
+ } else {
+ *pcyls = cylinders;
+ *pheads = heads;
+ *psecs = secs;
+ /* disable any translation to be in sync with
+ the logical geometry */
+ if (translation == BIOS_ATA_TRANSLATION_AUTO) {
+ bdrv_set_translation_hint(bs,
+ BIOS_ATA_TRANSLATION_NONE);
+ }
+ }
+ } else {
+ default_geometry:
+ /* if no geometry, use a standard physical disk geometry */
+ cylinders = nb_sectors / (16 * 63);
+
+ if (cylinders > 16383)
+ cylinders = 16383;
+ else if (cylinders < 2)
+ cylinders = 2;
+ *pcyls = cylinders;
+ *pheads = 16;
+ *psecs = 63;
+ if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) {
+ if ((*pcyls * *pheads) <= 131072) {
+ bdrv_set_translation_hint(bs,
+ BIOS_ATA_TRANSLATION_LARGE);
+ } else {
+ bdrv_set_translation_hint(bs,
+ BIOS_ATA_TRANSLATION_LBA);
+ }
+ }
+ }
+ bdrv_set_geometry_hint(bs, *pcyls, *pheads, *psecs);
+ }
}
void bdrv_set_geometry_hint(BlockDriverState *bs,
bdrv_flush(bs->backing_hd);
}
+void bdrv_flush_all(void)
+{
+ BlockDriverState *bs;
+
+ for (bs = bdrv_first; bs != NULL; bs = bs->next)
+ if (bs->drv && !bdrv_is_read_only(bs) &&
+ (!bdrv_is_removable(bs) || bdrv_is_inserted(bs)))
+ bdrv_flush(bs);
+}
+
/*
* Returns true iff the specified sector is present in the disk image. Drivers
* not implementing the functionality are assumed to not support backing files,
return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);
}
-#ifndef QEMU_IMG
void bdrv_info(void)
{
BlockDriverState *bs;
bs->rd_ops, bs->wr_ops);
}
}
-#endif
void bdrv_get_backing_filename(BlockDriverState *bs,
char *filename, int filename_size)
if (!drv)
return NULL;
- /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
- if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
- memcpy(buf, bs->boot_sector_data, 512);
- sector_num++;
- nb_sectors--;
- buf += 512;
- }
-
ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque);
if (ret) {
return NULL;
if (bs->read_only)
return NULL;
- if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
- memcpy(bs->boot_sector_data, buf, 512);
- }
ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);
/**************************************************************/
/* async block device emulation */
-#ifdef QEMU_IMG
-static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
- int64_t sector_num, uint8_t *buf, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque)
-{
- int ret;
- ret = bdrv_read(bs, sector_num, buf, nb_sectors);
- cb(opaque, ret);
- return NULL;
-}
-
-static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
- int64_t sector_num, const uint8_t *buf, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque)
-{
- int ret;
- ret = bdrv_write(bs, sector_num, buf, nb_sectors);
- cb(opaque, ret);
- return NULL;
-}
-
-static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb)
-{
-}
-#else
static void bdrv_aio_bh_cb(void *opaque)
{
BlockDriverAIOCBSync *acb = opaque;
qemu_bh_cancel(acb->bh);
qemu_aio_release(acb);
}
-#endif /* !QEMU_IMG */
/**************************************************************/
/* sync block device emulation */
BlockDriverAIOCB *acb;
async_ret = NOT_DONE;
- qemu_aio_wait_start();
acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors,
bdrv_rw_em_cb, &async_ret);
- if (acb == NULL) {
- qemu_aio_wait_end();
+ if (acb == NULL)
return -1;
- }
+
while (async_ret == NOT_DONE) {
qemu_aio_wait();
}
- qemu_aio_wait_end();
+
return async_ret;
}
BlockDriverAIOCB *acb;
async_ret = NOT_DONE;
- qemu_aio_wait_start();
acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors,
bdrv_rw_em_cb, &async_ret);
- if (acb == NULL) {
- qemu_aio_wait_end();
+ if (acb == NULL)
return -1;
- }
while (async_ret == NOT_DONE) {
qemu_aio_wait();
}
- qemu_aio_wait_end();
return async_ret;
}
bdrv_register(&bdrv_vvfat);
bdrv_register(&bdrv_qcow2);
bdrv_register(&bdrv_parallels);
-#ifndef _WIN32
bdrv_register(&bdrv_nbd);
-#endif
}
void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,