bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
- /*
- * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
- * write cache to the guest. We do need the fdatasync to flush
- * out transactions for block allocations, and we maybe have a
- * volatile write cache in our backing device to deal with.
- */
- if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
+ if (flags & BDRV_O_CACHE_WB)
bs->enable_write_cache = 1;
/*
open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
/*
- * Snapshots should be writeable.
+ * Snapshots should be writable.
*/
if (bs->is_temporary) {
open_flags |= BDRV_O_RDWR;
/* call the change callback */
bs->media_changed = 1;
if (bs->change_cb)
- bs->change_cb(bs->change_opaque);
+ bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
}
return 0;
/* call the change callback */
bs->media_changed = 1;
if (bs->change_cb)
- bs->change_cb(bs->change_opaque);
+ bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
}
}
}
}
+/* make a BlockDriverState anonymous by removing from bdrv_state list.
+ Also, NULL terminate the device_name to prevent double remove */
+void bdrv_make_anon(BlockDriverState *bs)
+{
+ if (bs->device_name[0] != '\0') {
+ QTAILQ_REMOVE(&bdrv_states, bs, list);
+ }
+ bs->device_name[0] = '\0';
+}
+
void bdrv_delete(BlockDriverState *bs)
{
assert(!bs->peer);
/* remove from list, if necessary */
- if (bs->device_name[0] != '\0') {
- QTAILQ_REMOVE(&bdrv_states, bs, list);
- }
+ bdrv_make_anon(bs);
bdrv_close(bs);
if (bs->file != NULL) {
* Run consistency checks on an image
*
* Returns 0 if the check could be completed (it doesn't mean that the image is
- * free of errors) or -errno when an internal error occured. The results of the
+ * free of errors) or -errno when an internal error occurred. The results of the
* check are stored in res.
*/
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res)
return -ENOTSUP;
if (bs->read_only)
return -EACCES;
+ if (bdrv_in_use(bs))
+ return -EBUSY;
ret = drv->bdrv_truncate(bs, offset);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
+ if (bs->change_cb) {
+ bs->change_cb(bs->change_opaque, CHANGE_SIZE);
+ }
}
return ret;
}
+/**
+ * Length of a allocated file in bytes. Sparse files are counted by actual
+ * allocated space. Return < 0 if error or unknown.
+ */
+int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv) {
+ return -ENOMEDIUM;
+ }
+ if (drv->bdrv_get_allocated_file_size) {
+ return drv->bdrv_get_allocated_file_size(bs);
+ }
+ if (bs->file) {
+ return bdrv_get_allocated_file_size(bs->file);
+ }
+ return -ENOTSUP;
+}
+
/**
* Length of a file in bytes. Return < 0 if error or unknown.
*/
if (!drv)
return -ENOMEDIUM;
- /* Fixed size devices use the total_sectors value for speed instead of
- issuing a length query (like lseek) on each call. Also, legacy block
- drivers don't provide a bdrv_getlength function and must use
- total_sectors. */
- if (!bs->growable || !drv->bdrv_getlength) {
- return bs->total_sectors * BDRV_SECTOR_SIZE;
+ if (bs->growable || bs->removable) {
+ if (drv->bdrv_getlength) {
+ return drv->bdrv_getlength(bs);
+ }
}
- return drv->bdrv_getlength(bs);
+ return bs->total_sectors * BDRV_SECTOR_SIZE;
}
/* return 0 as number of sectors if no device present or error */
bs->secs = secs;
}
-void bdrv_set_type_hint(BlockDriverState *bs, int type)
-{
- bs->type = type;
- bs->removable = ((type == BDRV_TYPE_CDROM ||
- type == BDRV_TYPE_FLOPPY));
-}
-
void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
{
bs->translation = translation;
*psecs = bs->secs;
}
-int bdrv_get_type_hint(BlockDriverState *bs)
+/* Recognize floppy formats */
+typedef struct FDFormat {
+ FDriveType drive;
+ uint8_t last_sect;
+ uint8_t max_track;
+ uint8_t max_head;
+} FDFormat;
+
+static const FDFormat fd_formats[] = {
+ /* First entry is default format */
+ /* 1.44 MB 3"1/2 floppy disks */
+ { FDRIVE_DRV_144, 18, 80, 1, },
+ { FDRIVE_DRV_144, 20, 80, 1, },
+ { FDRIVE_DRV_144, 21, 80, 1, },
+ { FDRIVE_DRV_144, 21, 82, 1, },
+ { FDRIVE_DRV_144, 21, 83, 1, },
+ { FDRIVE_DRV_144, 22, 80, 1, },
+ { FDRIVE_DRV_144, 23, 80, 1, },
+ { FDRIVE_DRV_144, 24, 80, 1, },
+ /* 2.88 MB 3"1/2 floppy disks */
+ { FDRIVE_DRV_288, 36, 80, 1, },
+ { FDRIVE_DRV_288, 39, 80, 1, },
+ { FDRIVE_DRV_288, 40, 80, 1, },
+ { FDRIVE_DRV_288, 44, 80, 1, },
+ { FDRIVE_DRV_288, 48, 80, 1, },
+ /* 720 kB 3"1/2 floppy disks */
+ { FDRIVE_DRV_144, 9, 80, 1, },
+ { FDRIVE_DRV_144, 10, 80, 1, },
+ { FDRIVE_DRV_144, 10, 82, 1, },
+ { FDRIVE_DRV_144, 10, 83, 1, },
+ { FDRIVE_DRV_144, 13, 80, 1, },
+ { FDRIVE_DRV_144, 14, 80, 1, },
+ /* 1.2 MB 5"1/4 floppy disks */
+ { FDRIVE_DRV_120, 15, 80, 1, },
+ { FDRIVE_DRV_120, 18, 80, 1, },
+ { FDRIVE_DRV_120, 18, 82, 1, },
+ { FDRIVE_DRV_120, 18, 83, 1, },
+ { FDRIVE_DRV_120, 20, 80, 1, },
+ /* 720 kB 5"1/4 floppy disks */
+ { FDRIVE_DRV_120, 9, 80, 1, },
+ { FDRIVE_DRV_120, 11, 80, 1, },
+ /* 360 kB 5"1/4 floppy disks */
+ { FDRIVE_DRV_120, 9, 40, 1, },
+ { FDRIVE_DRV_120, 9, 40, 0, },
+ { FDRIVE_DRV_120, 10, 41, 1, },
+ { FDRIVE_DRV_120, 10, 42, 1, },
+ /* 320 kB 5"1/4 floppy disks */
+ { FDRIVE_DRV_120, 8, 40, 1, },
+ { FDRIVE_DRV_120, 8, 40, 0, },
+ /* 360 kB must match 5"1/4 better than 3"1/2... */
+ { FDRIVE_DRV_144, 9, 80, 0, },
+ /* end */
+ { FDRIVE_DRV_NONE, -1, -1, 0, },
+};
+
+void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,
+ int *max_track, int *last_sect,
+ FDriveType drive_in, FDriveType *drive)
{
- return bs->type;
+ const FDFormat *parse;
+ uint64_t nb_sectors, size;
+ int i, first_match, match;
+
+ bdrv_get_geometry_hint(bs, nb_heads, max_track, last_sect);
+ if (*nb_heads != 0 && *max_track != 0 && *last_sect != 0) {
+ /* User defined disk */
+ } else {
+ bdrv_get_geometry(bs, &nb_sectors);
+ match = -1;
+ first_match = -1;
+ for (i = 0; ; i++) {
+ parse = &fd_formats[i];
+ if (parse->drive == FDRIVE_DRV_NONE) {
+ break;
+ }
+ if (drive_in == parse->drive ||
+ drive_in == FDRIVE_DRV_NONE) {
+ size = (parse->max_head + 1) * parse->max_track *
+ parse->last_sect;
+ if (nb_sectors == size) {
+ match = i;
+ break;
+ }
+ if (first_match == -1) {
+ first_match = i;
+ }
+ }
+ }
+ if (match == -1) {
+ if (first_match == -1) {
+ match = 1;
+ } else {
+ match = first_match;
+ }
+ parse = &fd_formats[match];
+ }
+ *nb_heads = parse->max_head + 1;
+ *max_track = parse->max_track;
+ *last_sect = parse->last_sect;
+ *drive = parse->drive;
+ }
}
int bdrv_get_translation_hint(BlockDriverState *bs)
/* XXX: no longer used */
void bdrv_set_change_cb(BlockDriverState *bs,
- void (*change_cb)(void *opaque), void *opaque)
+ void (*change_cb)(void *opaque, int reason),
+ void *opaque)
{
bs->change_cb = change_cb;
bs->change_opaque = opaque;
/* call the change callback now, we skipped it on open */
bs->media_changed = 1;
if (bs->change_cb)
- bs->change_cb(bs->change_opaque);
+ bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
}
return ret;
}
bs_dict = qobject_to_qdict(obj);
- monitor_printf(mon, "%s: type=%s removable=%d",
+ monitor_printf(mon, "%s: removable=%d",
qdict_get_str(bs_dict, "device"),
- qdict_get_str(bs_dict, "type"),
qdict_get_bool(bs_dict, "removable"));
if (qdict_get_bool(bs_dict, "removable")) {
QTAILQ_FOREACH(bs, &bdrv_states, list) {
QObject *bs_obj;
- const char *type = "unknown";
-
- switch(bs->type) {
- case BDRV_TYPE_HD:
- type = "hd";
- break;
- case BDRV_TYPE_CDROM:
- type = "cdrom";
- break;
- case BDRV_TYPE_FLOPPY:
- type = "floppy";
- break;
- }
- bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': %s, "
+ bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
"'removable': %i, 'locked': %i }",
- bs->device_name, type, bs->removable,
+ bs->device_name, bs->removable,
bs->locked);
if (bs->drv) {
MultiwriteCB *mcb;
int i;
+ /* don't submit writes if we don't have a medium */
+ if (bs->drv == NULL) {
+ for (i = 0; i < num_reqs; i++) {
+ reqs[i].error = -ENOMEDIUM;
+ }
+ return -1;
+ }
+
if (num_reqs == 0) {
return 0;
}
{
BlockDriver *drv = bs->drv;
+ trace_bdrv_aio_flush(bs, opaque);
+
if (bs->open_flags & BDRV_O_NO_FLUSH) {
return bdrv_aio_noop_em(bs, cb, opaque);
}
{
BlockDriver *drv = bs->drv;
+ trace_bdrv_set_locked(bs, locked);
+
bs->locked = locked;
if (drv && drv->bdrv_set_locked) {
drv->bdrv_set_locked(bs, locked);
return bs->dirty_count;
}
+void bdrv_set_in_use(BlockDriverState *bs, int in_use)
+{
+ assert(bs->in_use != in_use);
+ bs->in_use = in_use;
+}
+
+int bdrv_in_use(BlockDriverState *bs)
+{
+ return bs->in_use;
+}
+
int bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
char *options, uint64_t img_size, int flags)
{
QEMUOptionParameter *param = NULL, *create_options = NULL;
- QEMUOptionParameter *backing_fmt, *backing_file;
+ QEMUOptionParameter *backing_fmt, *backing_file, *size;
BlockDriverState *bs = NULL;
BlockDriver *drv, *proto_drv;
+ BlockDriver *backing_drv = NULL;
int ret = 0;
/* Find driver and parse its options */
backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
if (backing_fmt && backing_fmt->value.s) {
- if (!bdrv_find_format(backing_fmt->value.s)) {
+ backing_drv = bdrv_find_format(backing_fmt->value.s);
+ if (!backing_drv) {
error_report("Unknown backing file format '%s'",
backing_fmt->value.s);
ret = -EINVAL;
// The size for the image must always be specified, with one exception:
// If we are using a backing file, we can obtain the size from there
- if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
+ size = get_option_parameter(param, BLOCK_OPT_SIZE);
+ if (size && size->value.n == -1) {
if (backing_file && backing_file->value.s) {
uint64_t size;
char buf[32];
bs = bdrv_new("");
- ret = bdrv_open(bs, backing_file->value.s, flags, drv);
+ ret = bdrv_open(bs, backing_file->value.s, flags, backing_drv);
if (ret < 0) {
- error_report("Could not open '%s'", filename);
+ error_report("Could not open '%s'", backing_file->value.s);
goto out;
}
bdrv_get_geometry(bs, &size);