This adds support for virt-core: generic glue making it possible to implement
kernel-level accelerators (drivers) which are independent of a hypervisor, that
is can in theory work on top of either kvm or lguest.

Each driver and hypervisor registers with core, and then when user adds a
virtual device, drivers can find and interfact with hypervisors through the
virt_dev object.

Users add devices by making a hypervisor-specific system call (e.g. ioctl)
the result of which is a file descriptor controlling the device.

Signed-off-by: Michael S. Tsirkin <m...@redhat.com>
---
 arch/x86/kvm/Kconfig     |    1 +
 drivers/Makefile         |    1 +
 drivers/virt/Kconfig     |    5 ++
 drivers/virt/Makefile    |    1 +
 drivers/virt/virt_core.c |  111 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/virt.h     |   94 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 213 insertions(+), 0 deletions(-)
 create mode 100644 drivers/virt/Kconfig
 create mode 100644 drivers/virt/Makefile
 create mode 100644 drivers/virt/virt_core.c
 create mode 100644 include/linux/virt.h

diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index a58504e..693b807 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -71,6 +71,7 @@ config KVM_TRACE
 
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
+source drivers/virt/Kconfig
 source drivers/lguest/Kconfig
 source drivers/virtio/Kconfig
 
diff --git a/drivers/Makefile b/drivers/Makefile
index 1266ead..9f14b08 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -104,6 +104,7 @@ obj-$(CONFIG_HID)           += hid/
 obj-$(CONFIG_PPC_PS3)          += ps3/
 obj-$(CONFIG_OF)               += of/
 obj-$(CONFIG_SSB)              += ssb/
+obj-$(CONFIG_VIRT_CORE)                += virt/
 obj-$(CONFIG_VIRTIO)           += virtio/
 obj-$(CONFIG_STAGING)          += staging/
 obj-y                          += platform/
diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig
new file mode 100644
index 0000000..ace7b2e
--- /dev/null
+++ b/drivers/virt/Kconfig
@@ -0,0 +1,5 @@
+config VIRT_CORE
+       tristate "Generic virtual device binding support"
+       ---help---
+         Core support for binding kernel drivers to virtual devices.
+         Make sure to also select any drivers you wish to use.
diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile
new file mode 100644
index 0000000..7a77047
--- /dev/null
+++ b/drivers/virt/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIRT_CORE) += virt_core.o
diff --git a/drivers/virt/virt_core.c b/drivers/virt/virt_core.c
new file mode 100644
index 0000000..89e1f53
--- /dev/null
+++ b/drivers/virt/virt_core.c
@@ -0,0 +1,111 @@
+/*
+ * Virt core support: this is the glue that binds together drivers for virtual 
devices
+ * and hypervisors.
+ *
+ * Copyright (c) 2009 Red Hat Inc.
+ *
+ * Author: Michael S. Tsirkin <m...@redhat.com>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/anon_inodes.h>
+
+#include <linux/virt.h>
+
+/* virt bus implementation */
+static LIST_HEAD(driver_list);
+static LIST_HEAD(hypervisor_list);
+static DEFINE_MUTEX(driver_lock);
+static DEFINE_MUTEX(hypervisor_lock);
+
+static int virt_close(struct inode *inode, struct file *filp)
+{
+       struct virt_dev *dev = filp->private_data;
+       dev->driver->device_remove(dev->driver, dev);
+       dev->hypervisor->put(dev->hypervisor);
+       kfree(dev);
+       return 0;
+}
+
+void virt_driver_register(struct virt_driver *driver,
+                            struct file_operations *fops)
+{
+       BUG_ON(fops->release);
+       BUG_ON(fops->open);
+       driver->f_ops = fops;
+       fops->release = virt_close;
+       mutex_lock(&driver_lock);
+       list_add(&driver->list, &driver_list);
+       mutex_unlock(&driver_lock);
+}
+EXPORT_SYMBOL_GPL(virt_driver_register);
+
+void virt_driver_unregister(struct virt_driver *driver)
+{
+       mutex_lock(&driver_lock);
+       list_del(&driver->list);
+       mutex_unlock(&driver_lock);
+}
+EXPORT_SYMBOL_GPL(virt_driver_unregister);
+
+void virt_hypervisor_register(struct virt_hypervisor *hypervisor)
+{
+       mutex_lock(&hypervisor_lock);
+       list_add(&hypervisor->list, &hypervisor_list);
+       mutex_unlock(&hypervisor_lock);
+}
+EXPORT_SYMBOL_GPL(virt_hypervisor_register);
+
+void virt_hypervisor_unregister(struct virt_hypervisor *hypervisor)
+{
+       mutex_lock(&hypervisor_lock);
+       list_del(&hypervisor->list);
+       mutex_unlock(&hypervisor_lock);
+}
+EXPORT_SYMBOL_GPL(virt_hypervisor_unregister);
+
+int virt_device_create(struct virt_hypervisor *hypervisor, int flags,
+                      const u8 *id, int id_len)
+{
+       struct virt_dev *dev = kmalloc(sizeof *dev, GFP_KERNEL);
+       struct virt_driver *driver;
+       const struct file_operations *fops;
+       int ret;
+       if (!dev)
+               return -ENOMEM;
+       dev->hypervisor = hypervisor;
+       hypervisor->get(hypervisor);
+
+       mutex_lock(&driver_lock);
+       ret = -ENODEV;
+       list_for_each_entry(driver, &driver_list, list) {
+               ret = driver->device_probe(driver, dev, id, id_len);
+               if (ret != -ENODEV)
+                       break;
+       }
+       mutex_unlock(&driver_lock);
+       if (ret)
+               goto err_probe;
+
+       fops = fops_get(driver->f_ops);
+       if (!fops) {
+               ret = -ENOMEM;
+               goto err_file;
+       }
+
+       ret = anon_inode_getfd(driver->name, fops, dev, flags);
+       if (ret < 0)
+               goto err_file;
+       return ret;
+err_file:
+       driver->device_remove(driver, dev);
+err_probe:
+       hypervisor->put(hypervisor);
+       kfree(dev);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(virt_device_create);
diff --git a/include/linux/virt.h b/include/linux/virt.h
new file mode 100644
index 0000000..ecc0aef
--- /dev/null
+++ b/include/linux/virt.h
@@ -0,0 +1,94 @@
+#ifndef LINUX_VIRT_H
+#define LINUX_VIRT_H
+/* Virt core support.
+ * Each driver and hypervisor register with core, and then drivers can find
+ * and interfact with hypervisors through the virt_dev object.
+ */
+
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+
+struct virt_dev;
+
+struct virt_hypervisor {
+       /* Fields set by virt core. */
+       struct list_head list;
+       /* Fields set by hypervisor. */
+       /* Operations supported by this hypervisor. */
+       /* core uses reference counting to make sure hypervisor does not
+        * go away while there are devices attached to it. */
+       void (*get)(struct virt_hypervisor *);
+       void (*put)(struct virt_hypervisor *);
+       /* Optional interrupt injection support */
+       int (*set_irq)(struct virt_hypervisor *,
+                      int source, int irq, int level);
+};
+
+struct virt_driver {
+       /* Fields set by virt core. */
+       struct list_head list;
+       const struct file_operations *f_ops;
+       /* Fields set by driver. */
+       const char *name;
+       /* Check whether this driver wants this device,
+        * and bind driver to device if yes.
+        * Return -ENODEV if driver does not match this device,
+        * 0 on success, any other value is an error. */
+       int  (*device_probe)(struct virt_driver *, struct virt_dev *,
+                            const void *id, int id_len);
+       /* Called on removal of all devices where this driver's probe
+        * returned success */
+       void (*device_remove)(struct virt_driver *, struct virt_dev *);
+};
+
+/* Device objects are allocated and freed by virt core. */
+struct virt_dev {
+       struct virt_driver *driver;
+       void *driver_ctx;
+       struct virt_hypervisor *hypervisor;
+};
+
+/* Utility function for file_operations in drivers. */
+static inline struct virt_dev *virt_dev_get(struct file *file)
+{
+       return file->private_data;
+}
+
+#ifdef CONFIG_VIRT_CORE_MODULE
+void virt_driver_register(struct virt_driver *, struct file_operations *);
+void virt_driver_unregister(struct virt_driver *);
+
+void virt_hypervisor_register(struct virt_hypervisor *);
+void virt_hypervisor_unregister(struct virt_hypervisor *);
+
+
+/* Users add devices by making a hypervisor-specific system call (e.g. ioctl)
+ * the result of which is a file descriptor controlling the device.
+ * Hypervisors implement this by calling virt_device_create to get struct file
+ * and install it in file descriptor table.  Device is later released by
+ * closing the file descriptor */
+/* Associate a file descriptor with the device and return it.
+ * Returns a value < 0 on failure. */
+int virt_device_create(struct virt_hypervisor *, int flags,
+                      const u8 *id, int id_len);
+#else
+static inline
+void virt_driver_register(struct virt_driver *d, struct file_operations *o) {}
+static inline
+void virt_driver_unregister(struct virt_driver *d) {}
+
+static inline
+void virt_hypervisor_register(struct virt_hypervisor *h) {}
+static inline
+void virt_hypervisor_unregister(struct virt_hypervisor *h) {}
+
+static inline
+struct file *virt_device_create(struct virt_hypervisor *h, int flags,
+                               const u8 *id, int id_len)
+{
+       return ERR_PTR(-ENOTTY);
+}
+#endif
+
+#endif
-- 
1.6.3.1.175.g3be7e0

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to