* entry retrieved from xenstore while "dst" points to the entry
* retrieve from JSON.
*/
-#define MERGE(type, ptr, compare, merge) \
- do { \
- libxl_device_##type *p = NULL; \
- int i, j, num; \
- \
- p = libxl_device_##type##_list(CTX, domid, &num); \
- if (p == NULL) { \
- LOG(DEBUG, \
- "no %s from xenstore for domain %d", \
- #type, domid); \
- } \
- \
- for (i = 0; i < d_config->num_##ptr; i++) { \
- libxl_device_##type *q = &d_config->ptr[i]; \
- for (j = 0; j < num; j++) { \
- if (compare(&p[j], q)) \
- break; \
- } \
- \
- if (j < num) { /* found in xenstore */ \
- libxl_device_##type *dst, *src; \
- dst = q; \
- src = &p[j]; \
- merge; \
- } else { /* not found in xenstore */ \
- LOG(WARN, \
- "Device present in JSON but not in xenstore, ignored"); \
- \
- libxl_device_##type##_dispose(q); \
- \
- for (j = i; j < d_config->num_##ptr - 1; j++) \
- memcpy(&d_config->ptr[j], &d_config->ptr[j+1], \
- sizeof(libxl_device_##type)); \
- \
- d_config->ptr = \
- libxl__realloc(NOGC, d_config->ptr, \
- sizeof(libxl_device_##type) * \
- (d_config->num_##ptr - 1)); \
- \
- /* rewind counters */ \
- d_config->num_##ptr--; \
- i--; \
- } \
- } \
- \
- for (i = 0; i < num; i++) \
- libxl_device_##type##_dispose(&p[i]); \
- free(p); \
- } while (0);
+ {
+ const struct libxl_device_type *dt;
+ int idx;
- MERGE(nic, nics, COMPARE_DEVID, {});
+ for (idx = 0;; idx++) {
+ void *p = NULL;
+ void **devs;
+ int i, j, num;
+ int *num_dev;
- MERGE(vtpm, vtpms, COMPARE_DEVID, {});
+ dt = device_type_tbl[idx];
+ if (!dt)
+ break;
- MERGE(pci, pcidevs, COMPARE_PCI, {});
+ if (!dt->list || !dt->compare)
+ continue;
- MERGE(usbctrl, usbctrls, COMPARE_USBCTRL, {});
+ num_dev = libxl__device_type_get_num(dt, d_config);
+ p = dt->list(CTX, domid, &num);
+ if (p == NULL) {
+ LOG(DEBUG, "no %s from xenstore for domain %d",
+ dt->type, domid);
+ }
+ devs = libxl__device_type_get_ptr(dt, d_config);
- MERGE(usbdev, usbdevs, COMPARE_USB, {});
+ for (i = 0; i < *num_dev; i++) {
+ void *q;
- /* Take care of removable device. We maintain invariant in the
- * insert / remove operation so that:
- * 1. if xenstore is "empty" while JSON is not, the result
- * is "empty"
- * 2. if xenstore has a different media than JSON, use the
- * one in JSON
- * 3. if xenstore and JSON have the same media, well, you
- * know the answer :-)
- *
- * Currently there is only one removable device -- CDROM.
- * Look for libxl_cdrom_insert for reference.
- */
- MERGE(disk, disks, COMPARE_DISK, {
- if (src->removable) {
- if (!src->pdev_path || *src->pdev_path == '\0') {
- /* 1, no media in drive */
- free(dst->pdev_path);
- dst->pdev_path = libxl__strdup(NOGC, "");
- dst->format = LIBXL_DISK_FORMAT_EMPTY;
- } else {
- /* 2 and 3, use JSON, no need to touch anything */
- ;
+ q = libxl__device_type_get_elem(dt, d_config, i);
+ for (j = 0; j < num; j++) {
+ if (dt->compare(p + dt->dev_elem_size * j, q))
+ break;
+ }
+
+ if (j < num) { /* found in xenstore */
+ if (dt->merge)
+ dt->merge(ctx, p + dt->dev_elem_size * j, q);
+ } else { /* not found in xenstore */
+ LOG(WARN,
+ "Device present in JSON but not in xenstore, ignored");
+
+ dt->dispose(q);
+
+ for (j = i; j < *num_dev - 1; j++)
+ memcpy(libxl__device_type_get_elem(dt, d_config, j),
+ libxl__device_type_get_elem(dt, d_config, j+1),
+ dt->dev_elem_size);
+
+ /* rewind counters */
+ (*num_dev)--;
+ i--;
+
+ *devs = libxl__realloc(NOGC, *devs,
+ dt->dev_elem_size * *num_dev);
}
}
- });
-#undef MERGE
+ for (i = 0; i < num; i++)
+ dt->dispose(p + dt->dev_elem_size * i);
+ free(p);
+ }
+ }
out:
if (lock) libxl__unlock_domain_userdata(lock);
return rc;
}
+static int libxl_device_disk_compare(libxl_device_disk *d1,
+ libxl_device_disk *d2)
+{
+ return COMPARE_DISK(d1, d2);
+}
+
+/* Take care of removable device. We maintain invariant in the
+ * insert / remove operation so that:
+ * 1. if xenstore is "empty" while JSON is not, the result
+ * is "empty"
+ * 2. if xenstore has a different media than JSON, use the
+ * one in JSON
+ * 3. if xenstore and JSON have the same media, well, you
+ * know the answer :-)
+ *
+ * Currently there is only one removable device -- CDROM.
+ * Look for libxl_cdrom_insert for reference.
+ */
+static void libxl_device_disk_merge(libxl_ctx *ctx, void *d1, void *d2)
+{
+ GC_INIT(ctx);
+ libxl_device_disk *src = d1;
+ libxl_device_disk *dst = d2;
+
+ if (src->removable) {
+ if (!src->pdev_path || *src->pdev_path == '\0') {
+ /* 1, no media in drive */
+ free(dst->pdev_path);
+ dst->pdev_path = libxl__strdup(NOGC, "");
+ dst->format = LIBXL_DISK_FORMAT_EMPTY;
+ } else {
+ /* 2 and 3, use JSON, no need to touch anything */
+ ;
+ }
+ }
+}
+
+static int libxl_device_nic_compare(libxl_device_nic *d1,
+ libxl_device_nic *d2)
+{
+ return COMPARE_DEVID(d1, d2);
+}
+
+static int libxl_device_vtpm_compare(libxl_device_vtpm *d1,
+ libxl_device_vtpm *d2)
+{
+ return COMPARE_DEVID(d1, d2);
+}
+
+DEFINE_DEVICE_TYPE_STRUCT(disk, .merge = libxl_device_disk_merge);
DEFINE_DEVICE_TYPE_STRUCT(nic);
DEFINE_DEVICE_TYPE_STRUCT(vtpm);
struct libxl_device_type {
char *type;
- int num_offset; /* Offset of # of devices in libxl_domain_config */
+ int ptr_offset; /* Offset of device array ptr in libxl_domain_config */
+ int num_offset; /* Offset of # of devices in libxl_domain_config */
+ int dev_elem_size; /* Size of one device element in array */
void (*add)(libxl__egc *, libxl__ao *, uint32_t, libxl_domain_config *,
libxl__multidev *);
+ void *(*list)(libxl_ctx *, uint32_t, int *);
+ void (*dispose)(void *);
+ int (*compare)(void *, void *);
+ void (*merge)(libxl_ctx *, void *, void *);
};
-#define DEFINE_DEVICE_TYPE_STRUCT(name) \
- const struct libxl_device_type libxl__ ## name ## _devtype = { \
- .type = #name, \
- .num_offset = offsetof(libxl_domain_config, num_ ## name ## s), \
- .add = libxl__add_ ## name ## s, \
+#define DEFINE_DEVICE_TYPE_STRUCT_X(name, sname, ...) \
+ const struct libxl_device_type libxl__ ## name ## _devtype = { \
+ .type = #sname, \
+ .ptr_offset = offsetof(libxl_domain_config, name ## s), \
+ .num_offset = offsetof(libxl_domain_config, num_ ## name ## s), \
+ .dev_elem_size = sizeof(libxl_device_ ## sname), \
+ .add = libxl__add_ ## name ## s, \
+ .list = (void *(*)(libxl_ctx *, uint32_t, int *)) \
+ libxl_device_ ## sname ## _list, \
+ .dispose = (void (*)(void *))libxl_device_ ## sname ## _dispose, \
+ .compare = (int (*)(void *, void *)) \
+ libxl_device_ ## sname ## _compare, \
+ __VA_ARGS__ \
}
+#define DEFINE_DEVICE_TYPE_STRUCT(name, ...) \
+ DEFINE_DEVICE_TYPE_STRUCT_X(name, name, __VA_ARGS__)
+
+static inline void **libxl__device_type_get_ptr(
+ const struct libxl_device_type *dt, const libxl_domain_config *d_config)
+{
+ return (void **)((void *)d_config + dt->ptr_offset);
+}
+
+static inline void *libxl__device_type_get_elem(
+ const struct libxl_device_type *dt, const libxl_domain_config *d_config,
+ int e)
+{
+ return *libxl__device_type_get_ptr(dt, d_config) + dt->dev_elem_size * e;
+}
+
+static inline int *libxl__device_type_get_num(
+ const struct libxl_device_type *dt, const libxl_domain_config *d_config)
+{
+ return (int *)((void *)d_config + dt->num_offset);
+}
+
+extern const struct libxl_device_type libxl__disk_devtype;
extern const struct libxl_device_type libxl__nic_devtype;
extern const struct libxl_device_type libxl__vtpm_devtype;
extern const struct libxl_device_type libxl__usbctrl_devtype;
extern const struct libxl_device_type libxl__usbdev_devtype;
extern const struct libxl_device_type libxl__pcidev_devtype;
+
+extern const struct libxl_device_type *device_type_tbl[];
+
/*----- Domain destruction -----*/
/* Domain destruction has been split into two functions: