#include "xen_blkif.h"
#include "trace.h"
-typedef enum XenVdevType {
- XEN_VDEV_TYPE_XVD,
- XEN_VDEV_TYPE_HD,
- XEN_VDEV_TYPE_SD,
- XEN_VDEV_TYPE__MAX
-} XenVdevType;
+typedef enum XenQdiskVdevType {
+ XEN_QDISK_VDEV_TYPE_DP,
+ XEN_QDISK_VDEV_TYPE_XVD,
+ XEN_QDISK_VDEV_TYPE_HD,
+ XEN_QDISK_VDEV_TYPE_SD,
+ XEN_QDISK_VDEV_TYPE__MAX
+} XenQdiskVdevType;
+
+typedef struct XenQdiskVdev {
+ XenQdiskVdevType type;
+ unsigned int disk;
+ unsigned int partition;
+ bool valid;
+} XenQdiskVdev;
#define TYPE_XEN_QDISK_BACKEND "xen-qdisk"
#define XEN_QDISK_BACKEND(obj) \
struct XenQdiskBackend {
XenBackend xendev;
- XenVdevType type;
- int disk;
- unsigned int partition;
BlockConf conf;
+ XenQdiskVdev vdev;
bool discard_enable;
unsigned int max_ring_page_order;
BlockBackend *blk;
static char *xen_qdisk_get_name(XenBackend *dev, Error **errp)
{
XenQdiskBackend *d = XEN_QDISK_BACKEND(dev);
+ XenQdiskVdev *vdev = &d->vdev;
unsigned int number;
- if (d->disk < 0) {
- error_setg(errp, "invalid disk number (%d)", d->disk);
- return NULL;
- }
-
- switch (d->type) {
- case XEN_VDEV_TYPE_XVD:
- if (d->disk < (1 << 4) && d->partition < (1 << 4)) {
- number = (202 << 8) | (d->disk << 4) | d->partition;
- } else if (d->disk < (1 << 20) && d->partition < (1 << 8)) {
- number = (1 << 28) | (d ->disk << 8) | d->partition;
+ switch (vdev->type) {
+ case XEN_QDISK_VDEV_TYPE_DP:
+ case XEN_QDISK_VDEV_TYPE_XVD:
+ if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
+ number = (202 << 8) | (vdev->disk << 4) | vdev->partition;
+ } else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) {
+ number = (1 << 28) | (vdev ->disk << 8) | vdev->partition;
} else {
- error_setg(errp, "cannot use xvd encoding for d%up%u", d->disk,
- d->partition);
+ error_setg(errp, "cannot use xvd encoding for d%up%u",
+ vdev->disk, vdev->partition);
return NULL;
}
break;
- case XEN_VDEV_TYPE_HD:
- if ((d->disk == 0 || d->disk == 1) && d->partition < (1 << 4)) {
- number = (3 << 8) | (d->disk << 6) | d->partition;
- } else if ((d->disk == 2 || d->disk == 3) &&
- d->partition < (1 << 4)) {
- number = (22 << 8) | ((d->disk - 2) << 6) | d->partition;
+ case XEN_QDISK_VDEV_TYPE_HD:
+ if ((vdev->disk == 0 || vdev->disk == 1) &&
+ vdev->partition < (1 << 4)) {
+ number = (3 << 8) | (vdev->disk << 6) | vdev->partition;
+ } else if ((vdev->disk == 2 || vdev->disk == 3) &&
+ vdev->partition < (1 << 4)) {
+ number = (22 << 8) | ((vdev->disk - 2) << 6) | vdev->partition;
} else {
- error_setg(errp, "cannot use hd encoding for d%up%u", d->disk,
- d->partition);
+ error_setg(errp, "cannot use hd encoding for d%up%u",
+ vdev->disk, vdev->partition);
return NULL;
}
break;
- case XEN_VDEV_TYPE_SD:
- if (d->disk < (1 << 4) && d->partition < (1 << 4)) {
- number = (8 << 8) | (d->disk << 4) | d->partition;
+ case XEN_QDISK_VDEV_TYPE_SD:
+ if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
+ number = (8 << 8) | (vdev->disk << 4) | vdev->partition;
} else {
- error_setg(errp, "cannot use sd encoding for d%up%u", d->disk,
- d->partition);
+ error_setg(errp, "cannot use sd encoding for d%up%u",
+ vdev->disk, vdev->partition);
return NULL;
}
break;
unsigned int info;
int64_t size;
- trace_xen_qdisk_realize(d->disk, d->partition);
+ trace_xen_qdisk_realize(d->vdev.disk, d->vdev.partition);
if (!d->conf.blk) {
error_setg(errp, "drive property not set");
return;
}
+ if (!d->vdev.valid) {
+ error_setg(errp, "vdev property not set");
+ return;
+ }
+
if (!blk_is_inserted(d->conf.blk)) {
error_setg(errp, "Device needs media, but drive is empty");
return;
}
dinfo = blk_legacy_dinfo(d->conf.blk);
- if (dinfo && dinfo->media_cd)
- is_cdrom = true;
+ is_cdrom = (dinfo && dinfo->media_cd);
blkconf_blocksizes(&d->conf);
xenstore_backend_printf(dev, "info", "%u", info);
xenstore_frontend_printf(dev, "device-type", "%s",
- dinfo->media_cd ? "cdrom" : "disk");
+ is_cdrom ? "cdrom" : "disk");
size = blk_getlength(d->blk);
xenstore_backend_printf(dev, "sector-size", "%u",
unsigned int ring_size;
uint32_t *domids;
- trace_xen_qdisk_initialize(d->disk, d->partition);
+ trace_xen_qdisk_initialize(d->vdev.disk, d->vdev.partition);
if (xenstore_frontend_scanf(dev, "ring-page-order", "%u",
&order) != 1) {
{
XenQdiskBackend *d = XEN_QDISK_BACKEND(dev);
- trace_xen_qdisk_disconnect(d->disk, d->partition);
+ trace_xen_qdisk_disconnect(d->vdev.disk, d->vdev.partition);
if (d->xeh) {
aio_context_acquire(d->ctx);
{
XenQdiskBackend *d = XEN_QDISK_BACKEND(dev);
- trace_xen_qdisk_unrealize(d->disk, d->partition);
+ trace_xen_qdisk_unrealize(d->vdev.disk, d->vdev.partition);
while (!QLIST_EMPTY(&d->freelist)) {
struct ioreq *ioreq = QLIST_FIRST(&d->freelist);
qemu_bh_delete(d->bh);
}
-static void xen_vdev_get_type(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+static char *disk_to_vbd_name(unsigned int disk)
{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- int *ptr = qdev_get_prop_ptr(dev, prop);
+ unsigned int len = DIV_ROUND_UP(disk, 26);
+ char *name = g_malloc0(len + 1);
- visit_type_enum(v, prop->name, ptr, prop->info->enum_table, errp);
+ do {
+ name[len--] = 'a' + (disk % 26);
+ disk /= 26;
+ } while (disk != 0);
+ assert(len == 0);
+
+ return name;
}
-static void xen_vdev_set_type(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+static void xen_qdisk_get_vdev(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
- int *ptr = qdev_get_prop_ptr(dev, prop);
+ XenQdiskVdev *vdev = qdev_get_prop_ptr(dev, prop);
+ char *str;
- if (dev->realized) {
- qdev_prop_set_after_realize(dev, name, errp);
+ switch (vdev->type) {
+ case XEN_QDISK_VDEV_TYPE_DP:
+ str = g_strdup_printf("d%up%u", vdev->disk, vdev->partition);
+ break;
+
+ case XEN_QDISK_VDEV_TYPE_XVD:
+ case XEN_QDISK_VDEV_TYPE_HD:
+ case XEN_QDISK_VDEV_TYPE_SD: {
+ char *name = disk_to_vbd_name(vdev->disk);
+
+ str = g_strdup_printf("%s%s%u",
+ (vdev->type == XEN_QDISK_VDEV_TYPE_XVD) ?
+ "xvd" :
+ (vdev->type == XEN_QDISK_VDEV_TYPE_HD) ?
+ "hd" :
+ "sd",
+ name, vdev->partition);
+ g_free(name);
+ break;
+ }
+ default:
+ error_setg(errp, "invalid vdev type");
return;
}
- visit_type_enum(v, prop->name, ptr, prop->info->enum_table, errp);
+ visit_type_str(v, name, &str, errp);
+ g_free(str);
}
-static void xen_vdev_set_default_value_enum(Object *obj,
- const Property *prop)
+static unsigned int vbd_name_to_disk(char *name, char **endp)
{
- object_property_set_str(obj,
- qapi_enum_lookup(prop->info->enum_table,
- prop->defval.i),
- prop->name, &error_abort);
+ unsigned int disk = 0;
+
+ while (*name != '\0') {
+ if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name))
+ break;
+
+ disk *= 26;
+ disk += *name++ - 'a';
+ }
+ *endp = name;
+
+ return disk;
}
+
+static void xen_qdisk_set_vdev(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ XenQdiskVdev *vdev = qdev_get_prop_ptr(dev, prop);
+ Error *local_err = NULL;
+ char *str, *p, *end;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
-static QEnumLookup xen_vdev_type_lookup = {
- .array = (const char *const[]) {
- "xvd",
- "hd",
- "sd",
- },
- .size = XEN_VDEV_TYPE__MAX,
-};
+ visit_type_str(v, name, &str, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ p = strchr(str, 'd');
+ if (!p) {
+ goto invalid;
+ }
-const PropertyInfo xen_qdisk_prop_type = {
+ *p++ = '\0';
+ if (*str == '\0') {
+ vdev->type = XEN_QDISK_VDEV_TYPE_DP;
+ } else if (strcmp(str, "xv") == 0) {
+ vdev->type = XEN_QDISK_VDEV_TYPE_XVD;
+ } else if (strcmp(str, "h") == 0) {
+ vdev->type = XEN_QDISK_VDEV_TYPE_HD;
+ } else if (strcmp(str, "s") == 0) {
+ vdev->type = XEN_QDISK_VDEV_TYPE_SD;
+ } else {
+ goto invalid;
+ }
+
+ if (vdev->type == XEN_QDISK_VDEV_TYPE_DP) {
+ vdev->disk = strtoul(p, &end, 10);
+
+ if (*end == 'p') {
+ p = ++end;
+ if (*end == '\0') {
+ goto invalid;
+ }
+ }
+ } else {
+ vdev->disk = vbd_name_to_disk(p, &end);
+ }
+
+ if (*end != '\0') {
+ p = end;
+ vdev->partition = strtoul(p, &end, 10);
+ if (*end != '\0') {
+ goto invalid;
+ }
+ } else {
+ vdev->partition = 0;
+ }
+
+ g_free(str);
+ vdev->valid = true;
+ return;
+
+invalid:
+ error_setg(errp, "invalid vbd name");
+ g_free(str);
+}
+
+const PropertyInfo xen_qdisk_prop_vdev = {
.name = "str",
- .description = "xvd/hd/sd",
- .enum_table = &xen_vdev_type_lookup,
- .get = xen_vdev_get_type,
- .set = xen_vdev_set_type,
- .set_default_value = xen_vdev_set_default_value_enum,
+ .description = "Virtual Disk specifier: d*p*/xvd*/hd*/sd*",
+ .get = xen_qdisk_get_vdev,
+ .set = xen_qdisk_set_vdev,
};
static Property xen_qdisk_props[] = {
- DEFINE_PROP_SIGNED("vdev-type", XenQdiskBackend, type, 0,
- xen_qdisk_prop_type, XenVdevType),
- DEFINE_PROP_INT32("disk", XenQdiskBackend,
- disk, -1),
- DEFINE_PROP_UINT32("partition", XenQdiskBackend,
- partition, 0),
DEFINE_BLOCK_PROPERTIES(XenQdiskBackend, conf),
+ DEFINE_PROP("vdev", XenQdiskBackend, vdev,
+ xen_qdisk_prop_vdev, XenQdiskVdev),
DEFINE_PROP_BOOL("discard-enable", XenQdiskBackend, discard_enable,
false),
DEFINE_PROP_UINT32("max-ring-page-order", XenQdiskBackend,
}
type_init(xen_qdisk_register_types)
+
+void xen_qdisk_backend_create(char *path)
+{
+ fprintf(stderr, "%s: %s\n", __func__, path);
+}
#include "hw/sysbus.h"
#include "hw/boards.h"
#include "qemu/log.h"
+#include "qemu/option.h"
+#include "qemu/config-file.h"
#include "qapi/error.h"
#include "hw/xen/xen.h"
#include "hw/xen/xen_bus.h"
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
+#include "sysemu/block-backend.h"
#include "trace.h"
static domid_t xen_backend_id;
g_free(msg);
}
-static void xen_backend_log(XenBackend *d, const char *fmt, ...)
+void xen_backend_log(XenBackend *d, const char *fmt, ...)
{
va_list ap;
va_end(ap);
}
-#define XEN_BACKEND_LOG(d, fmt, ...) \
- xen_backend_log(d, "%s: " fmt, __func__, __VA_ARGS__)
-
static int xenstore_vprintf(struct xs_handle *xsh, char *node,
const char *key, const char *fmt, va_list ap)
{
k->bus_type = TYPE_XEN_BUS;
}
+static void xen_backend_compat_scan(const char *type,
+ XenBackendCreate create)
+{
+ struct xs_handle *xsh;
+ char *path;
+ char **backend;
+ unsigned int i, count;
+
+ xsh = xs_open(0);
+ if (!xsh) {
+ return;
+ }
+
+ path = g_strdup_printf("backend/%s/%u", type, xen_domid);
+ backend = xs_directory(xsh, XBT_NULL, path, &count);
+ g_free(path);
+
+ if (!backend) {
+ xs_close(xsh);
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ path = g_strdup_printf("backend/%s/%u/%s", type, xen_domid,
+ backend[i]);
+
+ create(path);
+ g_free(path);
+ }
+
+ free(backend);
+
+ xs_close(xsh);
+}
+
void xen_bus_init(void)
{
DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE);
+#if 0
+ DeviceState *qdisk;
+ QemuOpts *opts;
+ BlockBackend *blk;
+#endif
XenBus *b;
qdev_init_nofail(dev);
/* Need a 'proper' way of getting current domid */
xen_backend_id = 0;
+
+ xen_backend_compat_scan("qdisk", xen_qdisk_backend_create);
+
+#if 0
+ opts = drive_def("id=extra");
+ qemu_opt_set(opts, "file", "/root/disk.qcow2", &error_abort);
+ qemu_opt_set(opts, "media", "disk", &error_abort);
+ qemu_opt_set(opts, "format", "qcow2", &error_abort);
+ qemu_opt_set_bool(opts, BDRV_OPT_CACHE_WB, true, &error_abort);
+ qemu_opt_set_bool(opts, BDRV_OPT_READ_ONLY, false, &error_abort);
+
+ drive_new(opts, IF_NONE);
+
+ qdisk = qdev_create(BUS(b), "xen-qdisk");
+ blk = blk_by_name("extra");
+ qdev_prop_set_drive(qdisk, "drive", blk, &error_abort);
+ qdev_prop_set_int32(qdisk, "disk", 1);
+ qdev_init_nofail(qdisk);
+#endif
}
static const TypeInfo xen_bridge_type_info = {