[RFC,02/17] vbus: add virtual-bus definitions
diff mbox

Message ID 20090331184257.28333.64028.stgit@dev.haskins.net
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Gregory Haskins March 31, 2009, 6:42 p.m. UTC
See Documentation/vbus.txt for details

Signed-off-by: Gregory Haskins <ghaskins@novell.com>
---

 Documentation/vbus.txt      |  386 +++++++++++++++++++++++++++++
 arch/x86/Kconfig            |    2 
 fs/proc/base.c              |   96 +++++++
 include/linux/sched.h       |    4 
 include/linux/vbus.h        |  147 +++++++++++
 include/linux/vbus_device.h |  416 ++++++++++++++++++++++++++++++++
 kernel/Makefile             |    1 
 kernel/exit.c               |    2 
 kernel/fork.c               |    2 
 kernel/vbus/Kconfig         |   14 +
 kernel/vbus/Makefile        |    1 
 kernel/vbus/attribute.c     |   52 ++++
 kernel/vbus/config.c        |  275 +++++++++++++++++++++
 kernel/vbus/core.c          |  567 +++++++++++++++++++++++++++++++++++++++++++
 kernel/vbus/devclass.c      |  124 +++++++++
 kernel/vbus/map.c           |   72 +++++
 kernel/vbus/map.h           |   41 +++
 kernel/vbus/vbus.h          |  116 +++++++++
 18 files changed, 2318 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/vbus.txt
 create mode 100644 include/linux/vbus.h
 create mode 100644 include/linux/vbus_device.h
 create mode 100644 kernel/vbus/Kconfig
 create mode 100644 kernel/vbus/Makefile
 create mode 100644 kernel/vbus/attribute.c
 create mode 100644 kernel/vbus/config.c
 create mode 100644 kernel/vbus/core.c
 create mode 100644 kernel/vbus/devclass.c
 create mode 100644 kernel/vbus/map.c
 create mode 100644 kernel/vbus/map.h
 create mode 100644 kernel/vbus/vbus.h


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

Comments

Ben Hutchings April 2, 2009, 4:06 p.m. UTC | #1
On Tue, 2009-03-31 at 14:42 -0400, Gregory Haskins wrote:
[...]
> +Create a device instance
> +------------------------
> +
> +Devices are instantiated by again utilizing the /config/vbus configfs area.
> +At first you may suspect that devices are created as subordinate objects of a
> +bus/container instance, but you would be mistaken.

This is kind of patronising; why don't you simply lay out how things
_do_ work?

>  Devices are actually
> +root-level objects in vbus specifically to allow greater flexibility in the
> +association of a device.  For instance, it may be desirable to have a single
> +device that spans multiple VMs (consider an ethernet switch, or a shared disk
> +for a cluster).  Therefore, device lifecycles are managed by creating/deleting
> +objects in /config/vbus/devices.
> +
> +Note: Creating a device instance is actually a two step process:  We need to
> +give the device instance a unique name, and we also need to give it a specific
> +device type.  It is hard to express both parameters using standard filesystem
> +operations like mkdir, so the design decision was made to require performing
> +the operation in two steps.

How about exposing a subdir for each device class under
/config/vbus/devices/ and allowing device creation only within those?
Two-stage construction is a pain for both users and implementors.

[...]
> +At this point, we are ready to roll.  Pid 4382 has access to a virtual-bus
> +namespace with one device, id=0.  Its type is:
> +
> +# cat /sys/vbus/instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0/type
> +virtual-ethernet
> +
> +"virtual-ethernet"?  Why is it not "venet-tap"?  Device-classes are allowed to
> +register their interfaces under an id that is not required to be the same as
> +their deviceclass.  This supports device polymorphism.   For instance,
> +consider that an interface "virtual-ethernet" may provide basic 802.x packet
> +exchange.  However, we could have various implementations of a device that
> +supports the 802.x interface, while having various implementations behind
> +them.
[...]

It seems to me that your "device-classes" correspond to drivers and
"interfaces" correspond to device classes in the LDM.  To avoid
confusion, I think the vbus terminology should be made consistent with
LDM.  And certainly these should not both be called simply "type" in the
configfs/sysfs interface.

Ben.
Gregory Haskins April 2, 2009, 6:13 p.m. UTC | #2
Hi Ben

Ben Hutchings wrote:
> On Tue, 2009-03-31 at 14:42 -0400, Gregory Haskins wrote:
> [...]
>   
>> +Create a device instance
>> +------------------------
>> +
>> +Devices are instantiated by again utilizing the /config/vbus configfs area.
>> +At first you may suspect that devices are created as subordinate objects of a
>> +bus/container instance, but you would be mistaken.
>>     
>
> This is kind of patronising; why don't you simply lay out how things
> _do_ work?
>   

Ya, point taken.  I think that was written really to myself, because my
first design *had* the device as a subordinate object.  Then I realized
later that I didn't like that design :)

I will fix this.

>   
>>  Devices are actually
>> +root-level objects in vbus specifically to allow greater flexibility in the
>> +association of a device.  For instance, it may be desirable to have a single
>> +device that spans multiple VMs (consider an ethernet switch, or a shared disk
>> +for a cluster).  Therefore, device lifecycles are managed by creating/deleting
>> +objects in /config/vbus/devices.
>> +
>> +Note: Creating a device instance is actually a two step process:  We need to
>> +give the device instance a unique name, and we also need to give it a specific
>> +device type.  It is hard to express both parameters using standard filesystem
>> +operations like mkdir, so the design decision was made to require performing
>> +the operation in two steps.
>>     
>
> How about exposing a subdir for each device class under
> /config/vbus/devices/ and allowing device creation only within those?
> Two-stage construction is a pain for both users and implementors.
>
>   
I am not sure I follow.  It sounds like you are suggesting exactly what
I do today.

> [...]
>   
>> +At this point, we are ready to roll.  Pid 4382 has access to a virtual-bus
>> +namespace with one device, id=0.  Its type is:
>> +
>> +# cat /sys/vbus/instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0/type
>> +virtual-ethernet
>> +
>> +"virtual-ethernet"?  Why is it not "venet-tap"?  Device-classes are allowed to
>>     

I think I worded this awkwardly.  A device-class creates a
device-instance.  A device-instance registers one or more interfaces. 
There are device types (of which I would classify both the device-class
and its instantiated device object as the same "type"), and there are
interface types.  The interface types may overlap across different
device types, as demonstrated below.  I will update the doc to be more
clear, here (assuming I didn't muddle it up even more ;)

>> +register their interfaces under an id that is not required to be the same as
>> +their deviceclass.  This supports device polymorphism.   For instance,
>> +consider that an interface "virtual-ethernet" may provide basic 802.x packet
>> +exchange.  However, we could have various implementations of a device that
>> +supports the 802.x interface, while having various implementations behind
>> +them.
>>     
> [...]
>
> It seems to me that your "device-classes" correspond to drivers and
> "interfaces" correspond to device classes in the LDM.
I don't think that is quite right, but I might be missing your point. 
All of these objects exist on the "backend", of which there isnt a
specific precedent with LDM to express.  Normally in LDM, you would have
some kind of physical device object in the hardware (say a SATA disk),
and an LDM "block device" that represents it in software.  So we call
the LDM model for that disk a "device" but really its like a proxy or a
software representative of the actual device itself.  And I am not
knocking this designation, as I think it makes a lot of sense.

However, what I will point out is that what we are creating here in vbus
is more akin to the SATA disk itself, not the LDM "block device"
representation of the device.   There was no really great existing way
to express this type of object, which is why I had to create a new
namespace in sysfs.

To dig down into this a little further, the device and interface are
inextricably linked in a relationship very close to this "physical
device" concept.  Therefore the "driver" portion of LDM that you
referenced w.r.t. the device-class doesnt even enter the picture here
(that would actually be up in the guest or userspace, actually. 
Discussed below).

As an example, consider a e1000 network card.  The PCI-ID and REV for
the e1000 card and the associated ABI are like its "interface".  Whereas
if its a physical card plugged into a physical pci slot, or its an
emulated e1000 inside qemu-kvm are like its device-instance.  In theory,
I can substitute either device-instance transparently with any driver
that understands the ABI associated with the e1000 PCI-ID
interchangeably (assuming all the plumbing is there, etc).  Its the same
deal here.  Taking a little creative license here to use that example in
terms of vbus concepts, I would have a device-class type =
"physical-e1000-card", and another "qemu-e1000-model".  I could
instantiate either one of those and they would ultimately register an
interface of type "e1000".

So where traditional LDM starts to play here is actually on the other
side (e.g. the guest).  So the host has this vbus context with our
"e1000" interface registered on it.  When the guest loads, it would
create an LDM "device" object for the e1000, as well as a driver
instance if one was present.  From here, things would look more like
normal LDM concepts that we are used to.

HTH

-Greg

Patch
diff mbox

diff --git a/Documentation/vbus.txt b/Documentation/vbus.txt
new file mode 100644
index 0000000..e8a05da
--- /dev/null
+++ b/Documentation/vbus.txt
@@ -0,0 +1,386 @@ 
+
+Virtual-Bus:
+======================
+Author: Gregory Haskins <ghaskins@novell.com>
+
+
+
+
+What is it?
+--------------------
+
+Virtual-Bus is a kernel based IO resource container technology.  It is modeled
+on a concept similar to the Linux Device-Model (LDM), where we have buses,
+devices, and drivers as the primary actors.  However, VBUS has several
+distinctions when contrasted with LDM:
+
+  1) "Busses" in LDM are relatively static and global to the kernel (e.g.
+     "PCI", "USB", etc).  VBUS buses are arbitrarily created and destroyed
+     dynamically, and are not globally visible.  Instead they are defined as
+     visible only to a specific subset of the system (the contained context).
+  2) "Devices" in LDM are typically tangible physical (or sometimes logical)
+     devices.  VBUS devices are purely software abstractions (which may or
+     may not have one or more physical devices behind them).  Devices may
+     also be arbitrarily created or destroyed by software/administrative action
+     as opposed to by a hardware discovery mechanism.
+  3) "Drivers" in LDM sit within the same kernel context as the busses and
+     devices they interact with.  VBUS drivers live in a foreign
+     context (such as userspace, or a virtual-machine guest).
+
+The idea is that a vbus is created to contain access to some IO services.
+Virtual devices are then instantiated and linked to a bus to grant access to
+drivers actively present on the bus.  Drivers will only have visibility to
+devices present on their respective bus, and nothing else.
+
+Virtual devices are defined by modules which register a deviceclass with the
+system.  A deviceclass simply represents a type of device that _may_ be
+instantiated into a device, should an administrator wish to do so.  Once
+this has happened, the device may be associated with one or more buses where
+it will become visible to all clients of those respective buses.
+
+Why do we need this?
+----------------------
+
+There are various reasons why such a construct may be useful.  One of the
+most interesting use cases is for virtualization, such as KVM.  Hypervisors
+today provide virtualized IO resources to a guest, but this is often at a cost
+in both latency and throughput compared to bare metal performance.  Utilizing
+para-virtual resources instead of emulated devices helps to mitigate this
+penalty, but even these techniques to date have not fully realized the
+potential of the underlying bare-metal hardware.
+
+Some of the performance differential is unavoidable just given the extra
+processing that occurs due to the deeper stack (guest+host).  However, some of
+this overhead is a direct result of the rather indirect path most hypervisors
+use to route IO.  For instance, KVM uses PIO faults from the guest to trigger
+a guest->host-kernel->host-userspace->host-kernel sequence of events.
+Contrast this to a typical userspace application on the host which must only
+traverse app->kernel for most IO.
+
+The fact is that the linux kernel is already great at managing access to IO
+resources.  Therefore, if you have a hypervisor that is based on the linux
+kernel, is there some way that we can allow the hypervisor to manage IO
+directly instead of forcing this convoluted path?
+
+The short answer is: "not yet" ;)
+
+In order to use such a concept, we need some new facilties.  For one, we
+need to be able to define containers with their corresponding access-control so
+that guests do not have unmitigated access to anything they wish.  Second,
+we also need to define some forms of memory access that is uniform in the face
+of various clients (e.g. "copy_to_user()" cannot be assumed to work for, say,
+a KVM vcpu context).  Lastly, we need to provide access to these resources in
+a way that makes sense for the application, such as asynchronous communication
+paths and minimizing context switches.
+
+So we introduce VBUS as a framework to provide such facilities.  The net
+result is a *substantial* reduction in IO overhead, even when compared to
+state of the art para-virtualization techniques (such as virtio-net).
+
+How do I use it?
+------------------------
+
+There are two components to utilizing a virtual-bus.  One is the
+administrative function (creating and configuring a bus and its devices).  The
+other is the consumption of the resources on the bus by a client (e.g. a
+virtual machine, or a userspace application).  The former occurs on the host
+kernel by means of interacting with various special filesystems (e.g. sysfs,
+configfs, etc).  The latter occurs by means of a "vbus connector" which must
+be developed specifically to bridge a particular environment.  To date, we
+have developed such connectors for host-userspace and kvm-guests.  Conceivably
+we could develop other connectors as needs arise (e.g. lguest, xen,
+guest-userspace, etc).  This document deals with the administrative interface.
+Details about developing a connector are out of scope for this document.
+
+Interacting with vbus
+------------------------
+
+The first step is to enable virtual-bus support (CONFIG_VBUS) as well as any
+desired vbus-device modules (e.g. CONFIG_VBUS_VENETTAP), and ensure that your
+environment mounts both sysfs and configfs somewhere in the filesystem.  This
+document will assume they are mounted to /sys and /config, respectively.
+
+VBUS will create a top-level directory "vbus" in each of the two respective
+filesystems.  At boot-up, they will look like the following:
+
+/sys/vbus/
+|-- deviceclass
+|-- devices
+|-- instances
+`-- version
+
+/config/vbus/
+|-- devices
+`-- instances
+
+Following their respective roles, /config/vbus is for userspace to manage the
+lifetime of some number of objects/attributes.  This is in contrast to
+/sys/vbus which is a reflection of objects managed by the kernel.  It is
+assumed the reader is already familiar with these two facilities, so we will
+not go into depth about their general operation.  Suffice to say that vbus
+consists of objects that are managed both by userspace and the kernel.
+Modification of objects via /config/vbus will typically be reflected in the
+/sys/vbus area.
+
+It all starts with a deviceclass
+--------------------------------
+
+Before you can do anything useful with vbus, you need some registered
+deviceclasses.  A deviceclass provides the implementation of a specific type
+of virtual device.  A deviceclass will typically be registered by loading a
+kernel-module.  Once loaded, the available device types are enumerated under
+/sys/vbus/deviceclass.  For example, we will load our "venet-tap" module,
+which provides network services:
+
+# modprobe venet-tap
+# tree /sys/vbus
+/sys/vbus
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|-- instances
+`-- version
+
+An administrative agent should be able to enumerate /sys/vbus/deviceclass to
+determine what services are available on a given platform.
+
+Create the container
+-------------------
+
+The next step is to create a new container.  In vbus, this comes in the form
+of a vbus-instance and it is created by a simple "mkdir" in the
+/config/vbus/instances area.  The only requirement is that the instance is
+given a host-wide unique name.  This may be some kind of association to the
+application (e.g. the unique VM GUID) or it can be arbitrary.  For the
+purposes of example, we will let $(uuidgen) generate a random UUID for us.
+
+# mkdir /config/vbus/instances/$(uuidgen)
+# tree /sys/vbus/
+/sys/vbus/
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       `-- members
+`-- version
+
+So we can see that we have now created a vbus called
+
+               "beb4df8f-7483-4028-b3f7-767512e2a18c"
+
+in the /config area, and it was immediately reflected in the
+/sys/vbus/instances area as well (with a few subobjects of its own: "devices"
+and "members").  The "devices" object denotes any devices that are present on
+the bus (in this case: none).  Likewise, "members" denotes the pids of any
+tasks that are members of the bus (in this case: none).  We will come back to
+this later.  For now, we move on to the next step
+
+Create a device instance
+------------------------
+
+Devices are instantiated by again utilizing the /config/vbus configfs area.
+At first you may suspect that devices are created as subordinate objects of a
+bus/container instance, but you would be mistaken.  Devices are actually
+root-level objects in vbus specifically to allow greater flexibility in the
+association of a device.  For instance, it may be desirable to have a single
+device that spans multiple VMs (consider an ethernet switch, or a shared disk
+for a cluster).  Therefore, device lifecycles are managed by creating/deleting
+objects in /config/vbus/devices.
+
+Note: Creating a device instance is actually a two step process:  We need to
+give the device instance a unique name, and we also need to give it a specific
+device type.  It is hard to express both parameters using standard filesystem
+operations like mkdir, so the design decision was made to require performing
+the operation in two steps.
+
+Our first step is to create a unique instance.  We will again utilize
+$(uuidgen) to yield an arbitrary name.  Any name will suffice as long as it is
+unqie on this particular host.
+
+# mkdir /config/vbus/devices/$(uuidgen)
+# tree /sys/vbus
+/sys/vbus
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|   `-- 6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       `-- interfaces
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       `-- members
+`-- version
+
+At this point we have created a partial instance, since we have not yet
+assigned a type to the device.  Even so, we can see that some state has
+changed under /sys/vbus/devices.  We now have an instance named
+
+	      	 6a1aff24-5dc0-4aea-9c35-435daef90e55
+
+and it has a single subordinate object: "interfaces".  This object in
+particular is provided by the infrastructure, though do note that a
+deviceclass may also provide its own attributes/objects once it is created.
+
+We will go ahead and give this device a type to complete its construction.  We
+do this by setting the /config/vbus/devices/$devname/type attribute with a
+valid deviceclass type:
+
+# echo foo > /config/vbus/devices/6a1aff24-5dc0-4aea-9c35-435daef90e55/type
+bash: echo: write error: No such file or directory
+
+Oops!  What happened?  "foo" is not a valid deviceclass.  We need to consult
+the /sys/vbus/deviceclass area to find out what our options are:
+
+# tree /sys/vbus/deviceclass/
+/sys/vbus/deviceclass/
+`-- venet-tap
+
+Lets try again:
+
+# echo venet-tap > /config/vbus/devices/6a1aff24-5dc0-4aea-9c35-435daef90e55/type
+# tree /sys/vbus/
+/sys/vbus/
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|   `-- 6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |-- class -> ../../deviceclass/venet-tap
+|       |-- client_mac
+|       |-- enabled
+|       |-- host_mac
+|       |-- ifname
+|       `-- interfaces
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       `-- members
+`-- version
+
+Ok, that looks better.  And note that /sys/vbus/devices now has some more
+subordinate objects.  Most of those were registered when the venet-tap
+deviceclass was given a chance to create an instance of itself.  Those
+attributes are a property of the venet-tap and therefore are out of scope
+for this document.  Please see the documentation that accompanies a particular
+module for more details.
+
+Put the device on the bus
+-------------------------
+
+The next administrative step is to associate our new device with our bus.
+This is accomplished using a symbolic link from the bus instance to our device
+instance.
+
+ln -s /config/vbus/devices/6a1aff24-5dc0-4aea-9c35-435daef90e55/ /config/vbus/instances/beb4df8f-7483-4028-b3f7-767512e2a18c/
+# tree /sys/vbus/
+/sys/vbus/
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|   `-- 6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |-- class -> ../../deviceclass/venet-tap
+|       |-- client_mac
+|       |-- enabled
+|       |-- host_mac
+|       |-- ifname
+|       `-- interfaces
+|           `-- 0 -> ../../../instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       |   `-- 0
+|       |       |-- device -> ../../../../devices/6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |       `-- type
+|       `-- members
+`-- version
+
+We can now see that the device indicates that it has an interface registered
+to a bus:
+
+/sys/vbus/devices/6a1aff24-5dc0-4aea-9c35-435daef90e55/interfaces/
+`-- 0 -> ../../../instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0
+
+Likewise, we can see that the bus has a device listed (id = "0"):
+
+/sys/vbus/instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/
+`-- 0
+    |-- device -> ../../../../devices/6a1aff24-5dc0-4aea-9c35-435daef90e55
+    `-- type
+
+At this point, our container is ready for use.  However, it currently has 0
+members, so lets fix that
+
+Add some members
+--------------------
+
+Membership is controlled by an attribute: /proc/$pid/vbus.  A pid can only be
+a member of one (or zero) busses at a time.  To establish membership, we set
+the name of the bus, like so:
+
+# echo beb4df8f-7483-4028-b3f7-767512e2a18c > /proc/self/vbus
+# tree /sys/vbus/
+/sys/vbus/
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|   `-- 6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |-- class -> ../../deviceclass/venet-tap
+|       |-- client_mac
+|       |-- enabled
+|       |-- host_mac
+|       |-- ifname
+|       `-- interfaces
+|           `-- 0 -> ../../../instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       |   `-- 0
+|       |       |-- device -> ../../../../devices/6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |       `-- type
+|       `-- members
+|           |-- 4382
+|           `-- 4588
+`-- version
+
+Woah!  Why are there two members?  VBUS membership is inherited by forked
+tasks.  Therefore 4382 is the pid of our shell (which we set via /proc/self),
+and 4588 is the pid of the forked/exec'ed "tree" process.  This property can
+be useful for having things like qemu set up the bus and then forking each
+vcpu which will inherit access.
+
+At this point, we are ready to roll.  Pid 4382 has access to a virtual-bus
+namespace with one device, id=0.  Its type is:
+
+# cat /sys/vbus/instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0/type
+virtual-ethernet
+
+"virtual-ethernet"?  Why is it not "venet-tap"?  Device-classes are allowed to
+register their interfaces under an id that is not required to be the same as
+their deviceclass.  This supports device polymorphism.   For instance,
+consider that an interface "virtual-ethernet" may provide basic 802.x packet
+exchange.  However, we could have various implementations of a device that
+supports the 802.x interface, while having various implementations behind
+them.
+
+For instance, "venet-tap" might act like a tuntap module, while
+"venet-loopback" would loop packets back and "venet-switch" would form a
+layer-2 domain among the participating guests.  All three modules would
+presumably support the same basic 802.x interface, yet all three have
+completely different implementations.
+
+Drivers on this particular bus would see this instance id=0 as a type
+"virtual-ethernet" even though the underlying implementation happens to be a
+tap device.  This means a single driver that supports the protocol advertised
+by the "virtual-ethernet" type would be able to support the plethera of
+available device types that we may wish to create.
+
+Teardown:
+---------------
+
+We can descontruct a vbus container doing pretty much the opposite of what we
+did to create it.  Echo "0" into /proc/self/vbus, rm the symlink between the
+bus and device, and rmdir the bus and device objects.  Once that is done, we
+can even rmmod the venet-tap module.  Note that the infrastructure will
+maintain a module-ref while it is configured in a container, so be sure to
+completely tear down the vbus/device before trying this.
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bc2fbad..3fca247 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1939,6 +1939,8 @@  source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
 
+source "kernel/vbus/Kconfig"
+
 endmenu
 
 
diff --git a/fs/proc/base.c b/fs/proc/base.c
index beaa0ce..03993fb 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -80,6 +80,7 @@ 
 #include <linux/oom.h>
 #include <linux/elf.h>
 #include <linux/pid_namespace.h>
+#include <linux/vbus.h>
 #include "internal.h"
 
 /* NOTE:
@@ -1065,6 +1066,98 @@  static const struct file_operations proc_oom_adjust_operations = {
 	.write		= oom_adjust_write,
 };
 
+#ifdef CONFIG_VBUS
+
+static ssize_t vbus_read(struct file *file, char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+	struct vbus *vbus;
+	const char *name;
+	char buffer[256];
+	size_t len;
+
+	if (!task)
+		return -ESRCH;
+
+	vbus = task_vbus_get(task);
+
+	put_task_struct(task);
+
+	name = vbus_name(vbus);
+
+	len = snprintf(buffer, sizeof(buffer), "%s\n", name ? name : "<none>");
+
+	vbus_put(vbus);
+
+	return simple_read_from_buffer(buf, count, ppos, buffer, len);
+}
+
+static ssize_t vbus_write(struct file *file, const char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	struct task_struct *task;
+	struct vbus *vbus = NULL;
+	char buffer[256];
+	int disable = 0;
+
+	memset(buffer, 0, sizeof(buffer));
+	if (count > sizeof(buffer) - 1)
+		count = sizeof(buffer) - 1;
+	if (copy_from_user(buffer, buf, count))
+		return -EFAULT;
+
+	if (buffer[count-1] == '\n')
+		buffer[count-1] = 0;
+
+	task = get_proc_task(file->f_path.dentry->d_inode);
+	if (!task)
+		return -ESRCH;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		put_task_struct(task);
+		return -EACCES;
+	}
+
+	if (strcmp(buffer, "0") == 0)
+		disable = 1;
+	else
+		vbus = vbus_find(buffer);
+
+	if (disable || vbus)
+		task_vbus_disassociate(task);
+
+	if (vbus) {
+		int ret = vbus_associate(vbus, task);
+
+		if (ret < 0)
+			printk(KERN_ERR \
+			       "vbus: could not associate %s/%d with bus %s",
+			       task->comm, task->pid, vbus_name(vbus));
+		else
+			rcu_assign_pointer(task->vbus, vbus);
+
+		vbus_put(vbus); /* Counter the vbus_find() */
+	} else if (!disable) {
+		put_task_struct(task);
+		return -ENOENT;
+	}
+
+	put_task_struct(task);
+
+	if (count == sizeof(buffer)-1)
+		return -EIO;
+
+	return count;
+}
+
+static const struct file_operations proc_vbus_operations = {
+	.read		= vbus_read,
+	.write		= vbus_write,
+};
+
+#endif /* CONFIG_VBUS */
+
 #ifdef CONFIG_AUDITSYSCALL
 #define TMPBUFLEN 21
 static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
@@ -2556,6 +2649,9 @@  static const struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_TASK_IO_ACCOUNTING
 	INF("io",	S_IRUGO, proc_tgid_io_accounting),
 #endif
+#ifdef CONFIG_VBUS
+	REG("vbus", S_IRUGO|S_IWUSR, proc_vbus_operations),
+#endif
 };
 
 static int proc_tgid_base_readdir(struct file * filp,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 011db2f..cd2f9b1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -97,6 +97,7 @@  struct futex_pi_state;
 struct robust_list_head;
 struct bio;
 struct bts_tracer;
+struct vbus;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -1329,6 +1330,9 @@  struct task_struct {
 	unsigned int lockdep_recursion;
 	struct held_lock held_locks[MAX_LOCK_DEPTH];
 #endif
+#ifdef CONFIG_VBUS
+	struct vbus *vbus;
+#endif
 
 /* journalling filesystem info */
 	void *journal_info;
diff --git a/include/linux/vbus.h b/include/linux/vbus.h
new file mode 100644
index 0000000..5f0566c
--- /dev/null
+++ b/include/linux/vbus.h
@@ -0,0 +1,147 @@ 
+/*
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * Virtual-Bus
+ *
+ * Author:
+ *      Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VBUS_H
+#define _LINUX_VBUS_H
+
+#ifdef CONFIG_VBUS
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/rcupdate.h>
+#include <linux/vbus_device.h>
+
+struct vbus;
+struct task_struct;
+
+/**
+ * vbus_associate() - associate a task with a vbus
+ * @vbus:      The bus context to associate with
+ * @p:         The task to associate
+ *
+ * This function adds a task as a member of a vbus.  Tasks must be members
+ * of a bus before they are allowed to use its resources.  Tasks may only
+ * associate with a single bus at a time.
+ *
+ * Note: children inherit any association present at fork().
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int vbus_associate(struct vbus *vbus, struct task_struct *p);
+
+/**
+ * vbus_disassociate() - disassociate a task with a vbus
+ * @vbus:      The bus context to disassociate with
+ * @p:         The task to disassociate
+ *
+ * This function removes a task as a member of a vbus.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int vbus_disassociate(struct vbus *vbus, struct task_struct *p);
+
+struct vbus *vbus_get(struct vbus *);
+void vbus_put(struct vbus *);
+
+/**
+ * vbus_name() - returns the name of a bus
+ * @vbus:      The bus context
+ *
+ * Returns: (char *) name of bus
+ *
+ **/
+const char *vbus_name(struct vbus *vbus);
+
+/**
+ * vbus_find() - retreives a vbus pointer from its name
+ * @name:      The name of the bus to find
+ *
+ * Returns: NULL = failure, non-null = (vbus *)bus-pointer
+ *
+ **/
+struct vbus *vbus_find(const char *name);
+
+/**
+ * task_vbus_get() - retreives an associated vbus pointer from a task
+ * @p:         The task context
+ *
+ * Safely retreives a pointer to an associated (if any) vbus from a task
+ *
+ * Returns: NULL = no association, non-null = (vbus *)bus-pointer
+ *
+ **/
+static inline struct vbus *task_vbus_get(struct task_struct *p)
+{
+	struct vbus *vbus;
+
+	rcu_read_lock();
+	vbus = rcu_dereference(p->vbus);
+	if (vbus)
+		vbus_get(vbus);
+	rcu_read_unlock();
+
+	return vbus;
+}
+
+/**
+ * fork_vbus() - Helper function to handle associated task forking
+ * @p:         The task context
+ *
+ **/
+static inline void fork_vbus(struct task_struct *p)
+{
+	struct vbus *vbus = task_vbus_get(p);
+
+	if (vbus) {
+		BUG_ON(vbus_associate(vbus, p) < 0);
+		vbus_put(vbus);
+	}
+}
+
+/**
+ * task_vbus_disassociate() - Helper function to handle disassociating tasks
+ * @p:         The task context
+ *
+ **/
+static inline void task_vbus_disassociate(struct task_struct *p)
+{
+	struct vbus *vbus = task_vbus_get(p);
+
+	if (vbus) {
+		rcu_assign_pointer(p->vbus, NULL);
+		synchronize_rcu();
+
+		vbus_disassociate(vbus, p);
+		vbus_put(vbus);
+	}
+}
+
+#else /* CONFIG_VBUS */
+
+#define fork_vbus(p) do { } while (0)
+#define task_vbus_disassociate(p) do { } while (0)
+
+#endif /* CONFIG_VBUS */
+
+#endif /* _LINUX_VBUS_H */
diff --git a/include/linux/vbus_device.h b/include/linux/vbus_device.h
new file mode 100644
index 0000000..705d92e
--- /dev/null
+++ b/include/linux/vbus_device.h
@@ -0,0 +1,416 @@ 
+/*
+ * VBUS device models
+ *
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * Author:
+ *      Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file deals primarily with the definitions for interfacing a virtual
+ * device model to a virtual bus.  In a nutshell, a devclass begets a device,
+ * which begets a device_interface, which begets a connection.
+ *
+ * devclass
+ * -------
+ *
+ * To develop a vbus device, it all starts with a devclass.  You must register
+ * a devclass using vbus_devclass_register().  Each registered devclass is
+ * enumerated under /sys/vbus/deviceclass.
+ *
+ * In of itself, a devclass doesnt do much.  It is just an object factory for
+ * a device whose lifetime is managed by userspace.  When userspace decides
+ * it would like to create an instance of a particular devclass, the
+ * devclass::create() callback is invoked (registered as part of the ops
+ * structure during vbus_devclass_register()).  How and when userspace decides
+ * to do this is beyond the scope of this document.  Please see:
+ *
+ *                         Documentation/vbus.txt
+ *
+ * for more details.
+ *
+ * device
+ * -------
+ *
+ * A vbus device is created by a particular devclass during the invokation
+ * of its devclass::create() callback.  A device is initially created without
+ * any association with a bus.  One or more buses may attempt to connect to
+ * a device (controlled, again, by userspace).  When this occurs, a
+ * device::bus_connect() callback is invoked.
+ *
+ * This bus_connect() callback gives the device a chance to decide if it will
+ * accept the connection, and if so, to register its interfaces.  Most devices
+ * will likely only allow a connection to one bus.  Therefore, they may return
+ * -EBUSY another bus is already connected.
+ *
+ * If the device accepts the connection, it should register one of more
+ * interfaces with the bus using vbus_device_interface_register().  Most
+ * devices will only support one interface, and therefore will only invoke
+ * this method once.  However, some more elaborate devices may have multiple
+ * functions, or abstracted topologies.  Therefore they may opt at their own
+ * discretion to register more than one interface.  The interfaces do not need
+ * to be uniform in type.
+ *
+ * device_interface
+ * -------------------
+ *
+ * The purpose of an interface is two fold: 1) advertise a particular ABI
+ * for communcation to a driver, 2) handle the initial connection of a driver.
+ *
+ * As such, a device_interface has a string "type" (which is akin to the
+ * abi type that this interface supports, like a PCI-ID).  It also sports
+ * an interface::open() method.
+ *
+ * The interface::open callback is invoked whenever a driver attempts to
+ * connect to this device.  The device implements its own policy regarding
+ * whether it accepts multiple connections or not.  Most devices will likely
+ * only accept one connection at a time, and therefore will return -EBUSY if
+ * subsequent attempts are made.
+ *
+ * However, if successful, the interface::open() should return a
+ * vbus_connection object
+ *
+ * connections
+ * -----------
+ *
+ * A connection represents an interface that is succesfully opened.  It will
+ * remain in an active state as long as the client retains the connection.
+ * The connection::release() method is invoked if the client should die,
+ * restart, or explicitly close the connection.  The device-model should use
+ * this release() callback as the indication to clean up any resources
+ * associated with a particular connection such as allocated queues, etc.
+ *
+ * ---
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VBUS_DEVICE_H
+#define _LINUX_VBUS_DEVICE_H
+
+#include <linux/module.h>
+#include <linux/configfs.h>
+#include <linux/rbtree.h>
+#include <linux/shm_signal.h>
+#include <linux/vbus.h>
+#include <asm/atomic.h>
+
+struct vbus_device_interface;
+struct vbus_connection;
+struct vbus_device;
+struct vbus_devclass;
+struct vbus_memctx;
+
+/*
+ * ----------------------
+ * devclass
+ * ----------------------
+ */
+struct vbus_devclass_ops {
+	int (*create)(struct vbus_devclass *dc,
+		      struct vbus_device **dev);
+	void (*release)(struct vbus_devclass *dc);
+};
+
+struct vbus_devclass {
+	const char *name;
+	struct vbus_devclass_ops *ops;
+	struct rb_node node;
+	struct kobject kobj;
+	struct module *owner;
+};
+
+/**
+ * vbus_devclass_register() - register a devclass with the system
+ * @devclass:   The devclass context to register
+ *
+ * Establishes a new device-class for consumption.  Registered device-classes
+ * are enumerated under /sys/vbus/deviceclass.  For more details, please see
+ * Documentation/vbus*
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int vbus_devclass_register(struct vbus_devclass *devclass);
+
+/**
+ * vbus_devclass_unregister() - unregister a devclass with the system
+ * @devclass:   The devclass context to unregister
+ *
+ * Removes a devclass from the system
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int vbus_devclass_unregister(struct vbus_devclass *devclass);
+
+/**
+ * vbus_devclass_get() - acquire a devclass context reference
+ * @devclass:      devclass context
+ *
+ **/
+static inline struct vbus_devclass *
+vbus_devclass_get(struct vbus_devclass *devclass)
+{
+	if (!try_module_get(devclass->owner))
+		return NULL;
+
+	kobject_get(&devclass->kobj);
+	return devclass;
+}
+
+/**
+ * vbus_devclass_put() - release a devclass context reference
+ * @devclass:      devclass context
+ *
+ **/
+static inline void
+vbus_devclass_put(struct vbus_devclass *devclass)
+{
+	kobject_put(&devclass->kobj);
+	module_put(devclass->owner);
+}
+
+/*
+ * ----------------------
+ * device
+ * ----------------------
+ */
+struct vbus_device_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct vbus_device *dev,
+			struct vbus_device_attribute *attr,
+			char *buf);
+	ssize_t (*store)(struct vbus_device *dev,
+			 struct vbus_device_attribute *attr,
+			 const char *buf, size_t count);
+};
+
+struct vbus_device_ops {
+	int (*bus_connect)(struct vbus_device *dev, struct vbus *vbus);
+	int (*bus_disconnect)(struct vbus_device *dev, struct vbus *vbus);
+	void (*release)(struct vbus_device *dev);
+};
+
+struct vbus_device {
+	const char *type;
+	struct vbus_device_ops *ops;
+	struct attribute_group *attrs;
+	struct kobject *kobj;
+};
+
+/*
+ * ----------------------
+ * device_interface
+ * ----------------------
+ */
+struct vbus_device_interface_ops {
+	int (*open)(struct vbus_device_interface *intf,
+		    struct vbus_memctx *ctx,
+		    int version,
+		    struct vbus_connection **conn);
+	void (*release)(struct vbus_device_interface *intf);
+};
+
+struct vbus_device_interface {
+	const char *name;
+	const char *type;
+	struct vbus_device_interface_ops *ops;
+	unsigned long id;
+	struct vbus_device *dev;
+	struct vbus *vbus;
+	struct rb_node node;
+	struct kobject kobj;
+};
+
+/**
+ * vbus_device_interface_register() - register an interface with a bus
+ * @dev:        The device context of the caller
+ * @vbus:       The bus context to register with
+ * @intf:       The interface context to register
+ *
+ * This function is invoked (usually in the context of a device::bus_connect()
+ * callback) to register a interface on a bus.  We make this an explicit
+ * operation instead of implicit on the bus_connect() to facilitate devices
+ * that may present multiple interfaces to a bus.  In those cases, a device
+ * may invoke this function multiple times (one per supported interface).
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int vbus_device_interface_register(struct vbus_device *dev,
+				   struct vbus *vbus,
+				   struct vbus_device_interface *intf);
+
+/**
+ * vbus_device_interface_unregister() - unregister an interface with a bus
+ * @intf:       The interface context to unregister
+ *
+ * This function is the converse of interface_register.  It is typically
+ * invoked in the context of a device::bus_disconnect().
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int vbus_device_interface_unregister(struct vbus_device_interface *intf);
+
+/*
+ * ----------------------
+ * memory context
+ * ----------------------
+ */
+struct vbus_memctx_ops {
+	unsigned long (*copy_to)(struct vbus_memctx *ctx,
+				 void *dst,
+				 const void *src,
+				 unsigned long len);
+	unsigned long (*copy_from)(struct vbus_memctx *ctx,
+				   void *dst,
+				   const void *src,
+				   unsigned long len);
+	void (*release)(struct vbus_memctx *ctx);
+};
+
+struct vbus_memctx {
+	atomic_t refs;
+	struct vbus_memctx_ops *ops;
+};
+
+static inline void
+vbus_memctx_init(struct vbus_memctx *ctx, struct vbus_memctx_ops *ops)
+{
+	memset(ctx, 0, sizeof(*ctx));
+	atomic_set(&ctx->refs, 1);
+	ctx->ops = ops;
+}
+
+#define VBUS_MEMCTX_INIT(_ops) {                                   \
+	.refs = ATOMIC_INIT(1),                                    \
+	.ops = _ops,                                               \
+}
+
+static inline void
+vbus_memctx_get(struct vbus_memctx *ctx)
+{
+	atomic_inc(&ctx->refs);
+}
+
+static inline void
+vbus_memctx_put(struct vbus_memctx *ctx)
+{
+	if (atomic_dec_and_test(&ctx->refs))
+		ctx->ops->release(ctx);
+}
+
+/*
+ * ----------------------
+ * memory context
+ * ----------------------
+ */
+struct vbus_shm;
+
+struct vbus_shm_ops {
+	void (*release)(struct vbus_shm *shm);
+};
+
+struct vbus_shm {
+	atomic_t refs;
+	struct vbus_shm_ops *ops;
+	void                *ptr;
+	size_t               len;
+};
+
+static inline void
+vbus_shm_init(struct vbus_shm *shm, struct vbus_shm_ops *ops,
+	      void *ptr, size_t len)
+{
+	memset(shm, 0, sizeof(*shm));
+	atomic_set(&shm->refs, 1);
+	shm->ops = ops;
+	shm->ptr = ptr;
+	shm->len = len;
+}
+
+static inline void
+vbus_shm_get(struct vbus_shm *shm)
+{
+	atomic_inc(&shm->refs);
+}
+
+static inline void
+vbus_shm_put(struct vbus_shm *shm)
+{
+	if (atomic_dec_and_test(&shm->refs))
+		shm->ops->release(shm);
+}
+
+/*
+ * ----------------------
+ * connection
+ * ----------------------
+ */
+struct vbus_connection_ops {
+	int (*call)(struct vbus_connection *conn,
+		    unsigned long func,
+		    void *data,
+		    unsigned long len,
+		    unsigned long flags);
+	int (*shm)(struct vbus_connection *conn,
+		   unsigned long id,
+		   struct vbus_shm *shm,
+		   struct shm_signal *signal,
+		   unsigned long flags);
+	void (*release)(struct vbus_connection *conn);
+};
+
+struct vbus_connection {
+	atomic_t refs;
+	struct vbus_connection_ops *ops;
+};
+
+/**
+ * vbus_connection_init() - initialize a vbus_connection
+ * @conn:       connection context
+ * @ops:        ops structure to assign to context
+ *
+ **/
+static inline void vbus_connection_init(struct vbus_connection *conn,
+					struct vbus_connection_ops *ops)
+{
+	memset(conn, 0, sizeof(*conn));
+	atomic_set(&conn->refs, 1);
+	conn->ops = ops;
+}
+
+/**
+ * vbus_connection_get() - acquire a connection context reference
+ * @conn:       connection context
+ *
+ **/
+static inline void vbus_connection_get(struct vbus_connection *conn)
+{
+	atomic_inc(&conn->refs);
+}
+
+/**
+ * vbus_connection_put() - release a connection context reference
+ * @conn:       connection context
+ *
+ **/
+static inline void vbus_connection_put(struct vbus_connection *conn)
+{
+	if (atomic_dec_and_test(&conn->refs))
+		conn->ops->release(conn);
+}
+
+#endif /* _LINUX_VBUS_DEVICE_H */
diff --git a/kernel/Makefile b/kernel/Makefile
index e4791b3..99a98a7 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -93,6 +93,7 @@  obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
 obj-$(CONFIG_FUNCTION_TRACER) += trace/
 obj-$(CONFIG_TRACING) += trace/
 obj-$(CONFIG_SMP) += sched_cpupri.o
+obj-$(CONFIG_VBUS) += vbus/
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/exit.c b/kernel/exit.c
index efd30cc..8736de6 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -48,6 +48,7 @@ 
 #include <linux/tracehook.h>
 #include <linux/init_task.h>
 #include <trace/sched.h>
+#include <linux/vbus.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -1081,6 +1082,7 @@  NORET_TYPE void do_exit(long code)
 	check_stack_usage();
 	exit_thread();
 	cgroup_exit(tsk, 1);
+	task_vbus_disassociate(tsk);
 
 	if (group_dead && tsk->signal->leader)
 		disassociate_ctty(1);
diff --git a/kernel/fork.c b/kernel/fork.c
index 4854c2c..5536053 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -61,6 +61,7 @@ 
 #include <linux/proc_fs.h>
 #include <linux/blkdev.h>
 #include <trace/sched.h>
+#include <linux/vbus.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -1274,6 +1275,7 @@  static struct task_struct *copy_process(unsigned long clone_flags,
 	write_unlock_irq(&tasklist_lock);
 	proc_fork_connector(p);
 	cgroup_post_fork(p);
+	fork_vbus(p);
 	return p;
 
 bad_fork_free_graph:
diff --git a/kernel/vbus/Kconfig b/kernel/vbus/Kconfig
new file mode 100644
index 0000000..f2b92f5
--- /dev/null
+++ b/kernel/vbus/Kconfig
@@ -0,0 +1,14 @@ 
+#
+# Virtual-Bus (VBus) configuration
+#
+
+config VBUS
+       bool "Virtual Bus"
+       select CONFIGFS_FS
+       select SHM_SIGNAL
+       default n
+       help
+        Provides a mechansism for declaring virtual-bus objects and binding
+	various tasks and devices which reside on the bus.
+
+	If unsure, say N
diff --git a/kernel/vbus/Makefile b/kernel/vbus/Makefile
new file mode 100644
index 0000000..367f65b
--- /dev/null
+++ b/kernel/vbus/Makefile
@@ -0,0 +1 @@ 
+obj-$(CONFIG_VBUS) += core.o devclass.o config.o attribute.o map.o
diff --git a/kernel/vbus/attribute.c b/kernel/vbus/attribute.c
new file mode 100644
index 0000000..3928228
--- /dev/null
+++ b/kernel/vbus/attribute.c
@@ -0,0 +1,52 @@ 
+#include <linux/vbus.h>
+#include <linux/uaccess.h>
+#include <linux/kobject.h>
+#include <linux/kallsyms.h>
+
+#include "vbus.h"
+
+static struct vbus_device_attribute *to_vattr(struct attribute *attr)
+{
+	return container_of(attr, struct vbus_device_attribute, attr);
+}
+
+static struct vbus_devshell *to_devshell(struct kobject *kobj)
+{
+	return container_of(kobj, struct vbus_devshell, kobj);
+}
+
+static ssize_t _dev_attr_show(struct kobject *kobj, struct attribute *attr,
+			     char *buf)
+{
+	struct vbus_devshell *ds = to_devshell(kobj);
+	struct vbus_device_attribute *vattr = to_vattr(attr);
+	ssize_t ret = -EIO;
+
+	if (vattr->show)
+		ret = vattr->show(ds->dev, vattr, buf);
+
+	if (ret >= (ssize_t)PAGE_SIZE) {
+		print_symbol("vbus_attr_show: %s returned bad count\n",
+				(unsigned long)vattr->show);
+	}
+
+	return ret;
+}
+
+static ssize_t _dev_attr_store(struct kobject *kobj, struct attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct vbus_devshell *ds = to_devshell(kobj);
+	struct vbus_device_attribute *vattr = to_vattr(attr);
+	ssize_t ret = -EIO;
+
+	if (vattr->store)
+		ret = vattr->store(ds->dev, vattr, buf, count);
+
+	return ret;
+}
+
+struct sysfs_ops vbus_dev_attr_ops = {
+	.show	= _dev_attr_show,
+	.store	= _dev_attr_store,
+};
diff --git a/kernel/vbus/config.c b/kernel/vbus/config.c
new file mode 100644
index 0000000..a40dbf1
--- /dev/null
+++ b/kernel/vbus/config.c
@@ -0,0 +1,275 @@ 
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/vbus.h>
+#include <linux/configfs.h>
+
+#include "vbus.h"
+
+static struct config_item_type perms_type = {
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct vbus *to_vbus(struct config_group *group)
+{
+	return group ? container_of(group, struct vbus, ci.group) : NULL;
+}
+
+static struct vbus *item_to_vbus(struct config_item *item)
+{
+	return to_vbus(to_config_group(item));
+}
+
+static struct vbus_devshell *to_devshell(struct config_group *group)
+{
+	return group ? container_of(group, struct vbus_devshell, ci_group)
+		: NULL;
+}
+
+static struct vbus_devshell *to_vbus_devshell(struct config_item *item)
+{
+	return to_devshell(to_config_group(item));
+}
+
+static int
+device_bus_connect(struct config_item *src, struct config_item *target)
+{
+	struct vbus *vbus = item_to_vbus(src);
+	struct vbus_devshell *ds;
+
+	/* We only allow connections to devices */
+	if (target->ci_parent != &vbus_root.devices.ci_group.cg_item)
+		return -EINVAL;
+
+	ds = to_vbus_devshell(target);
+	BUG_ON(!ds);
+
+	if (!ds->dev)
+		return -EINVAL;
+
+	return ds->dev->ops->bus_connect(ds->dev, vbus);
+}
+
+static int
+device_bus_disconnect(struct config_item *src, struct config_item *target)
+{
+	struct vbus *vbus = item_to_vbus(src);
+	struct vbus_devshell *ds;
+
+	ds = to_vbus_devshell(target);
+	BUG_ON(!ds);
+
+	if (!ds->dev)
+		return -EINVAL;
+
+	return ds->dev->ops->bus_disconnect(ds->dev, vbus);
+}
+
+struct configfs_item_operations bus_ops = {
+	.allow_link = device_bus_connect,
+	.drop_link = device_bus_disconnect,
+};
+
+static struct config_item_type bus_type = {
+	.ct_item_ops    = &bus_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_group *bus_create(struct config_group *group,
+				       const char *name)
+{
+	struct vbus *bus = NULL;
+	int ret;
+
+	ret = vbus_create(name, &bus);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	config_group_init_type_name(&bus->ci.group, name, &bus_type);
+	bus->ci.group.default_groups = bus->ci.defgroups;
+	bus->ci.group.default_groups[0] = &bus->ci.perms;
+	bus->ci.group.default_groups[1] = NULL;
+
+	config_group_init_type_name(&bus->ci.perms, "perms", &perms_type);
+
+	return &bus->ci.group;
+}
+
+static void bus_destroy(struct config_group *group, struct config_item *item)
+{
+	struct vbus *vbus = item_to_vbus(item);
+
+	vbus_put(vbus);
+}
+
+static struct configfs_group_operations buses_ops = {
+	.make_group	= bus_create,
+	.drop_item      = bus_destroy,
+};
+
+static struct config_item_type buses_type = {
+	.ct_group_ops	= &buses_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+CONFIGFS_ATTR_STRUCT(vbus_devshell);
+#define DEVSHELL_ATTR(_name, _mode, _show, _store)	\
+struct vbus_devshell_attribute vbus_devshell_attr_##_name = \
+    __CONFIGFS_ATTR(_name, _mode, _show, _store)
+
+static ssize_t devshell_type_read(struct vbus_devshell *ds, char *page)
+{
+	if (ds->dev)
+		return sprintf(page, "%s\n", ds->dev->type);
+	else
+		return sprintf(page, "\n");
+}
+
+static ssize_t devshell_type_write(struct vbus_devshell *ds, const char *page,
+				   size_t count)
+{
+	struct vbus_devclass *dc;
+	struct vbus_device *dev;
+	char name[256];
+	int ret;
+
+	/*
+	 * The device-type can only be set once, and then it is permenent.
+	 * The admin should delete the device-shell if they want to create
+	 * a new type
+	 */
+	if (ds->dev)
+		return -EINVAL;
+
+	if (count > sizeof(name))
+		return -EINVAL;
+
+	strcpy(name, page);
+	if (name[count-1] == '\n')
+		name[count-1] = 0;
+
+	dc = vbus_devclass_find(name);
+	if (!dc)
+		return -ENOENT;
+
+	ret = dc->ops->create(dc, &dev);
+	if (ret < 0) {
+		vbus_devclass_put(dc);
+		return ret;
+	}
+
+	ds->dev = dev;
+	ds->dc = dc;
+	dev->kobj = &ds->kobj;
+
+	ret = vbus_devshell_type_set(ds);
+	if (ret < 0) {
+		vbus_devclass_put(dc);
+		return ret;
+	}
+
+	return count;
+}
+
+DEVSHELL_ATTR(type, S_IRUGO | S_IWUSR, devshell_type_read,
+	    devshell_type_write);
+
+static struct configfs_attribute *devshell_attrs[] = {
+	&vbus_devshell_attr_type.attr,
+	NULL,
+};
+
+CONFIGFS_ATTR_OPS(vbus_devshell);
+static struct configfs_item_operations devshell_item_ops = {
+	.show_attribute		= vbus_devshell_attr_show,
+	.store_attribute	= vbus_devshell_attr_store,
+};
+
+static struct config_item_type devshell_type = {
+	.ct_item_ops	= &devshell_item_ops,
+	.ct_attrs	= devshell_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_group *devshell_create(struct config_group *group,
+					    const char *name)
+{
+	struct vbus_devshell *ds = NULL;
+	int ret;
+
+	ret = vbus_devshell_create(name, &ds);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	config_group_init_type_name(&ds->ci_group, name, &devshell_type);
+
+	return &ds->ci_group;
+}
+
+static void devshell_release(struct config_group *group,
+			     struct config_item *item)
+{
+	struct vbus_devshell *ds = to_vbus_devshell(item);
+
+	kobject_put(&ds->kobj);
+
+	if (ds->dc)
+		vbus_devclass_put(ds->dc);
+}
+
+static struct configfs_group_operations devices_ops = {
+	.make_group	= devshell_create,
+	.drop_item      = devshell_release,
+};
+
+static struct config_item_type devices_type = {
+	.ct_group_ops	= &devices_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_item_type root_type = {
+	.ct_owner	= THIS_MODULE,
+};
+
+int __init vbus_config_init(void)
+{
+	int ret;
+	struct configfs_subsystem *subsys = &vbus_root.ci.subsys;
+
+	config_group_init_type_name(&subsys->su_group, "vbus", &root_type);
+	mutex_init(&subsys->su_mutex);
+
+	subsys->su_group.default_groups = vbus_root.ci.defgroups;
+	subsys->su_group.default_groups[0] = &vbus_root.buses.ci_group;
+	subsys->su_group.default_groups[1] = &vbus_root.devices.ci_group;
+	subsys->su_group.default_groups[2] = NULL;
+
+	config_group_init_type_name(&vbus_root.buses.ci_group,
+				    "instances", &buses_type);
+
+	config_group_init_type_name(&vbus_root.devices.ci_group,
+				    "devices", &devices_type);
+
+	ret = configfs_register_subsystem(subsys);
+	if (ret) {
+		printk(KERN_ERR "Error %d while registering subsystem %s\n",
+		       ret,
+		       subsys->su_group.cg_item.ci_namebuf);
+		goto out_unregister;
+	}
+
+	return 0;
+
+out_unregister:
+	configfs_unregister_subsystem(subsys);
+
+	return ret;
+}
+
+void __exit vbus_config_exit(void)
+{
+	configfs_unregister_subsystem(&vbus_root.ci.subsys);
+}
+
+
diff --git a/kernel/vbus/core.c b/kernel/vbus/core.c
new file mode 100644
index 0000000..033999f
--- /dev/null
+++ b/kernel/vbus/core.c
@@ -0,0 +1,567 @@ 
+/*
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * Author:
+ *      Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/vbus.h>
+#include <linux/uaccess.h>
+
+#include "vbus.h"
+
+static struct vbus_device_interface *kobj_to_intf(struct kobject *kobj)
+{
+	return container_of(kobj, struct vbus_device_interface, kobj);
+}
+
+static struct vbus_devshell *to_devshell(struct kobject *kobj)
+{
+	return container_of(kobj, struct vbus_devshell, kobj);
+}
+
+static void interface_release(struct kobject *kobj)
+{
+	struct vbus_device_interface *intf = kobj_to_intf(kobj);
+
+	if (intf->ops->release)
+		intf->ops->release(intf);
+}
+
+static struct kobj_type interface_ktype = {
+	.release = interface_release,
+	.sysfs_ops = &kobj_sysfs_ops,
+};
+
+static ssize_t
+type_show(struct kobject *kobj, struct kobj_attribute *attr,
+		  char *buf)
+{
+	struct vbus_device_interface *intf = kobj_to_intf(kobj);
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", intf->type);
+}
+
+static struct kobj_attribute devattr_type =
+	__ATTR_RO(type);
+
+static struct attribute *attrs[] = {
+	&devattr_type.attr,
+	NULL,
+};
+
+static struct attribute_group attr_group = {
+	.attrs = attrs,
+};
+
+/*
+ * Assumes dev->bus->lock is held
+ */
+static void _interface_unregister(struct vbus_device_interface *intf)
+{
+	struct vbus *vbus = intf->vbus;
+	struct vbus_devshell *ds = to_devshell(intf->dev->kobj);
+
+	map_del(&vbus->devices.map, &intf->node);
+	sysfs_remove_link(&ds->intfs, intf->name);
+	sysfs_remove_link(&intf->kobj, "device");
+	sysfs_remove_group(&intf->kobj, &attr_group);
+}
+
+int vbus_device_interface_register(struct vbus_device *dev,
+				   struct vbus *vbus,
+				   struct vbus_device_interface *intf)
+{
+	int ret;
+	struct vbus_devshell *ds = to_devshell(dev->kobj);
+
+	mutex_lock(&vbus->lock);
+
+	if (vbus->next_id == -1) {
+		mutex_unlock(&vbus->lock);
+		return -ENOSPC;
+	}
+
+	intf->id = vbus->next_id++;
+	intf->dev = dev;
+	intf->vbus = vbus;
+
+	ret = map_add(&vbus->devices.map, &intf->node);
+	if (ret < 0) {
+		mutex_unlock(&vbus->lock);
+		return ret;
+	}
+
+	kobject_init_and_add(&intf->kobj, &interface_ktype,
+			     &vbus->devices.kobj, "%ld", intf->id);
+
+	/* Create the basic attribute files associated with this kobject */
+	ret = sysfs_create_group(&intf->kobj, &attr_group);
+	if (ret)
+		goto error;
+
+	/* Create cross-referencing links between the device and bus */
+	ret = sysfs_create_link(&intf->kobj, dev->kobj, "device");
+	if (ret)
+		goto error;
+
+	ret = sysfs_create_link(&ds->intfs, &intf->kobj, intf->name);
+	if (ret)
+		goto error;
+
+	mutex_unlock(&vbus->lock);
+
+	return 0;
+
+error:
+	_interface_unregister(intf);
+	mutex_unlock(&vbus->lock);
+
+	kobject_put(&intf->kobj);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vbus_device_interface_register);
+
+int vbus_device_interface_unregister(struct vbus_device_interface *intf)
+{
+	struct vbus *vbus = intf->vbus;
+
+	mutex_lock(&vbus->lock);
+	_interface_unregister(intf);
+	mutex_unlock(&vbus->lock);
+
+	kobject_put(&intf->kobj);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vbus_device_interface_unregister);
+
+static struct vbus_device_interface *node_to_intf(struct rb_node *node)
+{
+	return node ? container_of(node, struct vbus_device_interface, node)
+		: NULL;
+}
+
+static int interface_item_compare(struct rb_node *lhs, struct rb_node *rhs)
+{
+	struct vbus_device_interface *lintf = node_to_intf(lhs);
+	struct vbus_device_interface *rintf = node_to_intf(rhs);
+
+	return lintf->id - rintf->id;
+}
+
+static int interface_key_compare(const void *key, struct rb_node *node)
+{
+	struct vbus_device_interface *intf = node_to_intf(node);
+	unsigned long id = *(unsigned long *)key;
+
+	return id - intf->id;
+}
+
+static struct map_ops interface_map_ops = {
+	.key_compare = &interface_key_compare,
+	.item_compare = &interface_item_compare,
+};
+
+/*
+ *-----------------
+ * member
+ *-----------------
+ */
+
+static struct vbus_member *node_to_member(struct rb_node *node)
+{
+	return node ? container_of(node, struct vbus_member, node) : NULL;
+}
+
+static struct vbus_member *kobj_to_member(struct kobject *kobj)
+{
+	return kobj ? container_of(kobj, struct vbus_member, kobj) : NULL;
+}
+
+static int member_item_compare(struct rb_node *lhs, struct rb_node *rhs)
+{
+	struct vbus_member *lmember = node_to_member(lhs);
+	struct vbus_member *rmember = node_to_member(rhs);
+
+	return lmember->tsk->pid - rmember->tsk->pid;
+}
+
+static int member_key_compare(const void *key, struct rb_node *node)
+{
+	struct vbus_member *member = node_to_member(node);
+	pid_t pid = *(pid_t *)key;
+
+	return pid - member->tsk->pid;
+}
+
+static struct map_ops member_map_ops = {
+	.key_compare = &member_key_compare,
+	.item_compare = &member_item_compare,
+};
+
+static void member_release(struct kobject *kobj)
+{
+	struct vbus_member *member = kobj_to_member(kobj);
+
+	vbus_put(member->vbus);
+	put_task_struct(member->tsk);
+
+	kfree(member);
+}
+
+static struct kobj_type member_ktype = {
+	.release = member_release,
+};
+
+int vbus_associate(struct vbus *vbus, struct task_struct *tsk)
+{
+	struct vbus_member *member;
+	int ret;
+
+	member = kzalloc(sizeof(struct vbus_member), GFP_KERNEL);
+	if (!member)
+		return -ENOMEM;
+
+	mutex_lock(&vbus->lock);
+
+	get_task_struct(tsk);
+	vbus_get(vbus);
+
+	member->vbus = vbus;
+	member->tsk = tsk;
+
+	ret = kobject_init_and_add(&member->kobj, &member_ktype,
+				   &vbus->members.kobj,
+				   "%d", tsk->pid);
+	if (ret < 0)
+		goto error;
+
+	ret = map_add(&vbus->members.map, &member->node);
+	if (ret < 0)
+		goto error;
+
+out:
+	mutex_unlock(&vbus->lock);
+	return 0;
+
+error:
+	kobject_put(&member->kobj);
+	goto out;
+}
+
+int vbus_disassociate(struct vbus *vbus, struct task_struct *tsk)
+{
+	struct vbus_member *member;
+
+	mutex_lock(&vbus->lock);
+
+	member = node_to_member(map_find(&vbus->members.map, &tsk->pid));
+	BUG_ON(!member);
+
+	map_del(&vbus->members.map, &member->node);
+
+	mutex_unlock(&vbus->lock);
+
+	kobject_put(&member->kobj);
+
+	return 0;
+}
+
+/*
+ *-----------------
+ * vbus_subdir
+ *-----------------
+ */
+
+static void vbus_subdir_init(struct vbus_subdir *subdir,
+			     const char *name,
+			     struct kobject *parent,
+			     struct kobj_type *type,
+			     struct map_ops *map_ops)
+{
+	int ret;
+
+	map_init(&subdir->map, map_ops);
+
+	ret = kobject_init_and_add(&subdir->kobj, type, parent, name);
+	BUG_ON(ret < 0);
+}
+
+/*
+ *-----------------
+ * vbus
+ *-----------------
+ */
+
+static void vbus_destroy(struct kobject *kobj)
+{
+	struct vbus *vbus = container_of(kobj, struct vbus, kobj);
+
+	kfree(vbus);
+}
+
+static struct kobj_type vbus_ktype = {
+	.release = vbus_destroy,
+};
+
+static struct kobj_type null_ktype = {
+};
+
+int vbus_create(const char *name, struct vbus **bus)
+{
+	struct vbus *_bus = NULL;
+	int ret;
+
+	_bus = kzalloc(sizeof(struct vbus), GFP_KERNEL);
+	if (!_bus)
+		return -ENOMEM;
+
+	atomic_set(&_bus->refs, 1);
+	mutex_init(&_bus->lock);
+
+	kobject_init_and_add(&_bus->kobj, &vbus_ktype,
+			     vbus_root.buses.kobj, name);
+
+	vbus_subdir_init(&_bus->devices, "devices", &_bus->kobj,
+			 &null_ktype, &interface_map_ops);
+	vbus_subdir_init(&_bus->members, "members", &_bus->kobj,
+			 &null_ktype, &member_map_ops);
+
+	_bus->next_id = 0;
+
+	mutex_lock(&vbus_root.lock);
+
+	ret = map_add(&vbus_root.buses.map, &_bus->node);
+	BUG_ON(ret < 0);
+
+	mutex_unlock(&vbus_root.lock);
+
+	*bus = _bus;
+
+	return 0;
+}
+
+static void devshell_release(struct kobject *kobj)
+{
+	struct vbus_devshell *ds = container_of(kobj,
+						struct vbus_devshell, kobj);
+
+	if (ds->dev) {
+		if (ds->dev->attrs)
+			sysfs_remove_group(&ds->kobj, ds->dev->attrs);
+
+		if (ds->dev->ops->release)
+			ds->dev->ops->release(ds->dev);
+	}
+
+	if (ds->dc)
+		sysfs_remove_link(&ds->kobj, "class");
+
+	kobject_put(&ds->intfs);
+	kfree(ds);
+}
+
+static struct kobj_type devshell_ktype = {
+	.release = devshell_release,
+	.sysfs_ops = &vbus_dev_attr_ops,
+};
+
+static void _interfaces_init(struct vbus_devshell *ds)
+{
+	kobject_init_and_add(&ds->intfs, &null_ktype, &ds->kobj, "interfaces");
+}
+
+int vbus_devshell_create(const char *name, struct vbus_devshell **ds)
+{
+	struct vbus_devshell *_ds = NULL;
+
+	_ds = kzalloc(sizeof(*_ds), GFP_KERNEL);
+	if (!_ds)
+		return -ENOMEM;
+
+	kobject_init_and_add(&_ds->kobj, &devshell_ktype,
+			     vbus_root.devices.kobj, name);
+
+	_interfaces_init(_ds);
+
+	*ds = _ds;
+
+	return 0;
+}
+
+int vbus_devshell_type_set(struct vbus_devshell *ds)
+{
+	int ret;
+
+	if (!ds->dev)
+		return -EINVAL;
+
+	if (!ds->dev->attrs)
+		return 0;
+
+	ret = sysfs_create_link(&ds->kobj, &ds->dc->kobj, "class");
+	if (ret < 0)
+		return ret;
+
+	return sysfs_create_group(&ds->kobj, ds->dev->attrs);
+}
+
+struct vbus *vbus_get(struct vbus *vbus)
+{
+	if (vbus)
+		atomic_inc(&vbus->refs);
+
+	return vbus;
+}
+EXPORT_SYMBOL_GPL(vbus_get);
+
+void vbus_put(struct vbus *vbus)
+{
+	if (vbus && atomic_dec_and_test(&vbus->refs)) {
+		kobject_put(&vbus->devices.kobj);
+		kobject_put(&vbus->members.kobj);
+		kobject_put(&vbus->kobj);
+	}
+}
+EXPORT_SYMBOL_GPL(vbus_put);
+
+long vbus_interface_find(struct vbus *bus,
+			 unsigned long id,
+			 struct vbus_device_interface **intf)
+{
+	struct vbus_device_interface *_intf;
+
+	BUG_ON(!bus);
+
+	mutex_lock(&bus->lock);
+
+	_intf = node_to_intf(map_find(&bus->devices.map, &id));
+	if (likely(_intf))
+		kobject_get(&_intf->kobj);
+
+	mutex_unlock(&bus->lock);
+
+	if (!_intf)
+		return -ENOENT;
+
+	*intf = _intf;
+
+	return 0;
+}
+
+const char *vbus_name(struct vbus *vbus)
+{
+	return vbus ? vbus->kobj.name : NULL;
+}
+
+/*
+ *---------------------
+ * vbus_buses
+ *---------------------
+ */
+
+static struct vbus *node_to_bus(struct rb_node *node)
+{
+	return node ? container_of(node, struct vbus, node) : NULL;
+}
+
+static int bus_item_compare(struct rb_node *lhs, struct rb_node *rhs)
+{
+	struct vbus *lbus = node_to_bus(lhs);
+	struct vbus *rbus = node_to_bus(rhs);
+
+	return strcmp(lbus->kobj.name, rbus->kobj.name);
+}
+
+static int bus_key_compare(const void *key, struct rb_node *node)
+{
+	struct vbus *bus = node_to_bus(node);
+
+	return strcmp(key, bus->kobj.name);
+}
+
+static struct map_ops bus_map_ops = {
+	.key_compare = &bus_key_compare,
+	.item_compare = &bus_item_compare,
+};
+
+struct vbus *vbus_find(const char *name)
+{
+	struct vbus *bus;
+
+	mutex_lock(&vbus_root.lock);
+
+	bus = node_to_bus(map_find(&vbus_root.buses.map, name));
+	if (!bus)
+		goto out;
+
+	vbus_get(bus);
+
+out:
+	mutex_unlock(&vbus_root.lock);
+
+	return bus;
+
+}
+
+struct vbus_root vbus_root;
+
+static ssize_t version_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", VBUS_VERSION);
+}
+
+static struct kobj_attribute version_attr =
+	__ATTR(version, S_IRUGO, version_show, NULL);
+
+static int __init vbus_init(void)
+{
+	int ret;
+
+	mutex_init(&vbus_root.lock);
+
+	ret = vbus_config_init();
+	BUG_ON(ret < 0);
+
+	vbus_root.kobj = kobject_create_and_add("vbus", NULL);
+	BUG_ON(!vbus_root.kobj);
+
+	ret = sysfs_create_file(vbus_root.kobj, &version_attr.attr);
+	BUG_ON(ret);
+
+	ret = vbus_devclass_init();
+	BUG_ON(ret < 0);
+
+	map_init(&vbus_root.buses.map, &bus_map_ops);
+	vbus_root.buses.kobj = kobject_create_and_add("instances",
+						      vbus_root.kobj);
+	BUG_ON(!vbus_root.buses.kobj);
+
+	vbus_root.devices.kobj = kobject_create_and_add("devices",
+							vbus_root.kobj);
+	BUG_ON(!vbus_root.devices.kobj);
+
+	return 0;
+}
+
+late_initcall(vbus_init);
+
+
diff --git a/kernel/vbus/devclass.c b/kernel/vbus/devclass.c
new file mode 100644
index 0000000..3f5ef0d
--- /dev/null
+++ b/kernel/vbus/devclass.c
@@ -0,0 +1,124 @@ 
+/*
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * Author:
+ *      Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/vbus.h>
+
+#include "vbus.h"
+
+static struct vbus_devclass *node_to_devclass(struct rb_node *node)
+{
+	return node ? container_of(node, struct vbus_devclass, node) : NULL;
+}
+
+static int devclass_item_compare(struct rb_node *lhs, struct rb_node *rhs)
+{
+	struct vbus_devclass *ldc = node_to_devclass(lhs);
+	struct vbus_devclass *rdc = node_to_devclass(rhs);
+
+	return strcmp(ldc->name, rdc->name);
+}
+
+static int devclass_key_compare(const void *key, struct rb_node *node)
+{
+	struct vbus_devclass *dc = node_to_devclass(node);
+
+	return strcmp((const char *)key, dc->name);
+}
+
+static struct map_ops devclass_map_ops = {
+	.key_compare = &devclass_key_compare,
+	.item_compare = &devclass_item_compare,
+};
+
+int __init vbus_devclass_init(void)
+{
+	struct vbus_devclasses *c = &vbus_root.devclasses;
+
+	map_init(&c->map, &devclass_map_ops);
+
+	c->kobj = kobject_create_and_add("deviceclass", vbus_root.kobj);
+	BUG_ON(!c->kobj);
+
+	return 0;
+}
+
+static void devclass_release(struct kobject *kobj)
+{
+	struct vbus_devclass *dc = container_of(kobj,
+						struct vbus_devclass,
+						kobj);
+
+	if (dc->ops->release)
+		dc->ops->release(dc);
+}
+
+static struct kobj_type devclass_ktype = {
+	.release = devclass_release,
+};
+
+int vbus_devclass_register(struct vbus_devclass *dc)
+{
+	int ret;
+
+	mutex_lock(&vbus_root.lock);
+
+	ret = map_add(&vbus_root.devclasses.map, &dc->node);
+	if (ret < 0)
+		goto out;
+
+	ret = kobject_init_and_add(&dc->kobj, &devclass_ktype,
+				   vbus_root.devclasses.kobj, dc->name);
+	if (ret < 0) {
+		map_del(&vbus_root.devclasses.map, &dc->node);
+		goto out;
+	}
+
+out:
+	mutex_unlock(&vbus_root.lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vbus_devclass_register);
+
+int vbus_devclass_unregister(struct vbus_devclass *dc)
+{
+	mutex_lock(&vbus_root.lock);
+	map_del(&vbus_root.devclasses.map, &dc->node);
+	mutex_unlock(&vbus_root.lock);
+
+	kobject_put(&dc->kobj);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vbus_devclass_unregister);
+
+struct vbus_devclass *vbus_devclass_find(const char *name)
+{
+	struct vbus_devclass *dev;
+
+	mutex_lock(&vbus_root.lock);
+	dev = node_to_devclass(map_find(&vbus_root.devclasses.map, name));
+	if (dev)
+		dev = vbus_devclass_get(dev);
+	mutex_unlock(&vbus_root.lock);
+
+	return dev;
+}
diff --git a/kernel/vbus/map.c b/kernel/vbus/map.c
new file mode 100644
index 0000000..a3bd841
--- /dev/null
+++ b/kernel/vbus/map.c
@@ -0,0 +1,72 @@ 
+
+#include <linux/errno.h>
+
+#include "map.h"
+
+void map_init(struct map *map, struct map_ops *ops)
+{
+	map->root = RB_ROOT;
+	map->ops = ops;
+}
+
+int map_add(struct map *map, struct rb_node *node)
+{
+	int		ret = 0;
+	struct rb_root *root;
+	struct rb_node **new, *parent = NULL;
+
+	root = &map->root;
+	new  = &(root->rb_node);
+
+	/* Figure out where to put new node */
+	while (*new) {
+		int val;
+
+		parent = *new;
+
+		val = map->ops->item_compare(node, *new);
+		if (val < 0)
+			new = &((*new)->rb_left);
+		else if (val > 0)
+			new = &((*new)->rb_right);
+		else {
+			ret = -EEXIST;
+			break;
+		}
+	}
+
+	if (!ret) {
+		/* Add new node and rebalance tree. */
+		rb_link_node(node, parent, new);
+		rb_insert_color(node, root);
+	}
+
+	return ret;
+}
+
+struct rb_node *map_find(struct map *map, const void *key)
+{
+	struct rb_node *node;
+
+	node = map->root.rb_node;
+
+	while (node) {
+		int val;
+
+		val = map->ops->key_compare(key, node);
+		if (val < 0)
+			node = node->rb_left;
+		else if (val > 0)
+			node = node->rb_right;
+		else
+			break;
+	}
+
+	return node;
+}
+
+void map_del(struct map *map, struct rb_node *node)
+{
+	rb_erase(node, &map->root);
+}
+
diff --git a/kernel/vbus/map.h b/kernel/vbus/map.h
new file mode 100644
index 0000000..7fb5164
--- /dev/null
+++ b/kernel/vbus/map.h
@@ -0,0 +1,41 @@ 
+/*
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * Author:
+ *      Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __VBUS_MAP_H__
+#define __VBUS_MAP_H__
+
+#include <linux/rbtree.h>
+
+struct map_ops {
+	int (*item_compare)(struct rb_node *lhs, struct rb_node *rhs);
+	int (*key_compare)(const void *key, struct rb_node *item);
+};
+
+struct map {
+	struct rb_root root;
+	struct map_ops *ops;
+};
+
+void map_init(struct map *map, struct map_ops *ops);
+int map_add(struct map *map, struct rb_node *node);
+struct rb_node *map_find(struct map *map, const void *key);
+void map_del(struct map *map, struct rb_node *node);
+
+#endif /* __VBUS_MAP_H__ */
diff --git a/kernel/vbus/vbus.h b/kernel/vbus/vbus.h
new file mode 100644
index 0000000..1266d69
--- /dev/null
+++ b/kernel/vbus/vbus.h
@@ -0,0 +1,116 @@ 
+/*
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * Author:
+ *      Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __VBUS_H__
+#define __VBUS_H__
+
+#include <linux/configfs.h>
+#include <linux/rbtree.h>
+#include <linux/mutex.h>
+#include <linux/kobject.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+
+#include "map.h"
+
+#define VBUS_VERSION 1
+
+struct vbus_subdir {
+	struct map     map;
+	struct kobject kobj;
+};
+
+struct vbus {
+	struct {
+		struct config_group group;
+		struct config_group perms;
+		struct config_group *defgroups[2];
+	} ci;
+
+	atomic_t refs;
+	struct mutex lock;
+	struct kobject kobj;
+	struct vbus_subdir devices;
+	struct vbus_subdir members;
+	unsigned long next_id;
+	struct rb_node node;
+};
+
+struct vbus_member {
+	struct rb_node      node;
+	struct task_struct *tsk;
+	struct vbus        *vbus;
+	struct kobject      kobj;
+};
+
+struct vbus_devclasses {
+	struct kobject *kobj;
+	struct map map;
+};
+
+struct vbus_buses {
+	struct config_group ci_group;
+	struct map map;
+	struct kobject *kobj;
+};
+
+struct vbus_devshell {
+	struct config_group ci_group;
+	struct vbus_device *dev;
+	struct vbus_devclass *dc;
+	struct kobject kobj;
+	struct kobject intfs;
+};
+
+struct vbus_devices {
+	struct config_group ci_group;
+	struct kobject *kobj;
+};
+
+struct vbus_root {
+	struct {
+		struct configfs_subsystem subsys;
+		struct config_group      *defgroups[3];
+	} ci;
+
+	struct mutex            lock;
+	struct kobject         *kobj;
+	struct vbus_devclasses  devclasses;
+	struct vbus_buses       buses;
+	struct vbus_devices     devices;
+};
+
+extern struct vbus_root vbus_root;
+extern struct sysfs_ops vbus_dev_attr_ops;
+
+int vbus_config_init(void);
+int vbus_devclass_init(void);
+
+int vbus_create(const char *name, struct vbus **bus);
+
+int vbus_devshell_create(const char *name, struct vbus_devshell **ds);
+struct vbus_devclass *vbus_devclass_find(const char *name);
+int vbus_devshell_type_set(struct vbus_devshell *ds);
+
+long vbus_interface_find(struct vbus *vbus,
+			 unsigned long id,
+			 struct vbus_device_interface **intf);
+
+#endif /* __VBUS_H__ */