Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Cleanup of locking in host device interface
[palacios.git] / linux_module / iface-host-dev.c
index 23d05e7..c9c586e 100644 (file)
@@ -126,22 +126,19 @@ struct palacios_host_dev {
 #define DEEP_DEBUG    0
 #define SHALLOW_DEBUG 0
 
-#if DEEP_DEBUG
-#define DEEP_DEBUG_PRINT(fmt, args...) printk((fmt), ##args)
+#if DEEP_DEBUG == 1
+#define DEEP_DEBUG_PRINT(fmt, args...) DEBUG(fmt, ##args)
 #else
 #define DEEP_DEBUG_PRINT(fmt, args...) 
 #endif
 
-#if SHALLOW_DEBUG
-#define SHALLOW_DEBUG_PRINT(fmt, args...) printk((fmt), ##args)
+#if SHALLOW_DEBUG == 1
+#define SHALLOW_DEBUG_PRINT(fmt, args...) INFO(fmt, ##args)
 #else
 #define SHALLOW_DEBUG_PRINT(fmt, args...) 
 #endif
 
 
-#define ERROR(fmt, args...) printk((fmt), ##args)
-#define INFO(fmt, args...) printk((fmt), ##args)
-
 struct palacios_host_device_user {
     spinlock_t lock;
     int      connected;    // is the user space connected to this?
@@ -152,6 +149,7 @@ struct palacios_host_device_user {
     char     url[MAX_URL]; // what is the url describing the device
 
     v3_guest_dev_t guestdev; // what is the palacios-side device
+    v3_guest_dev_intr_t guestintr; // what is the palacios-side device interrupt info
 
     wait_queue_head_t  user_wait_queue; // user space processes waiting on us (should be only one)
     wait_queue_head_t  host_wait_queue; // host threads (should only be one) waiting on user space
@@ -171,14 +169,14 @@ struct palacios_host_device_user {
 static void palacios_host_dev_user_free(struct palacios_host_device_user *dev)
 {
     if (dev->req) {
-       kfree(dev->req);
+       palacios_free(dev->req);
        dev->req=0;
     } 
     if (dev->resp) { 
-       kfree(dev->resp);
+       palacios_free(dev->resp);
        dev->resp=0;
     }
-    kfree(dev);
+    palacios_free(dev);
 }
 
 
@@ -216,8 +214,8 @@ static int palacios_resize_reqresp(struct palacios_host_dev_host_request_respons
     if ((*r)==0) { 
        // allocate it
        DEEP_DEBUG_PRINT("palacios: hostdev: attempt alloc\n");
-       *r = kmalloc(sizeof(struct palacios_host_dev_host_request_response)+data_size,GFP_KERNEL);
-       DEEP_DEBUG_PRINT("palacios: hostdev: kmalloc done\n");
+       *r = palacios_alloc(sizeof(struct palacios_host_dev_host_request_response)+data_size);
+       DEEP_DEBUG_PRINT("palacios: hostdev: palacios_alloc done\n");
        if ((*r)==0) { 
            ERROR("palacios: hostdev: failed to allocate\n");
            return -1;
@@ -238,10 +236,10 @@ static int palacios_resize_reqresp(struct palacios_host_dev_host_request_respons
            struct palacios_host_dev_host_request_response *new;
 
            if (!copy) { 
-               kfree(*r);
+               palacios_free(*r);
                *r=0;
            }
-           new = kmalloc(sizeof(struct palacios_host_dev_host_request_response)+data_size,GFP_KERNEL);
+           new = palacios_alloc(sizeof(struct palacios_host_dev_host_request_response)+data_size);
            if (!new) { 
                ERROR("palacios: hostdev: failed to reallocate\n");
                return -1;
@@ -250,7 +248,7 @@ static int palacios_resize_reqresp(struct palacios_host_dev_host_request_respons
                if (copy) { 
                    memcpy(new->data,(*r)->data,(*r)->data_len-sizeof(struct palacios_host_dev_host_request_response));
                    new->data_len=(*r)->data_len;
-                   kfree(*r);
+                   palacios_free(*r);
                }
                *r=new;
                DEEP_DEBUG_PRINT("palacios: hostdev: reallocated\n");
@@ -302,21 +300,22 @@ static unsigned int host_dev_poll(struct file * filp,
        return -EFAULT;
     }
 
-    spin_lock_irqsave(&(dev->lock),f);
+    palacios_spinlock_lock_irqsave(&(dev->lock),f);
+
+
+    // register ourselves on the user wait queue
+    poll_wait(filp, &(dev->user_wait_queue), poll_tb);
 
     if (dev->waiting) { 
        // Yes, we have a request if you want it!
-       spin_unlock_irqrestore(&(dev->lock),f);
+       palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        DEEP_DEBUG_PRINT("palacios: hostdev: poll done immediate\n");
        return  POLLIN | POLLRDNORM;
     } 
 
     // No request yet, so we need to wait for one to show up.
 
-    // register ourselves on the user wait queue
-    poll_wait(filp, &(dev->user_wait_queue), poll_tb);
-
-    spin_unlock_irqrestore(&(dev->lock),f);
+    palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
 
     DEEP_DEBUG_PRINT("palacios: hostdev: poll delayed\n");
     // We will get called again when that queue is woken up
@@ -332,9 +331,9 @@ static int host_dev_release(struct inode * i, struct file * filp)
 
     INFO("palacios: user side is closing host device \"%s\"\n",dev->url);
     
-    spin_lock_irqsave(&(dev->lock), f);
+    palacios_spinlock_lock_irqsave(&(dev->lock), f);
     dev->connected = 0;
-    spin_unlock_irqrestore(&(dev->lock), f);
+    palacios_spinlock_unlock_irqrestore(&(dev->lock), f);
 
     // it is the palacios->host interface's responsibility to ignore
     // reads/writes until connected is true
@@ -342,8 +341,7 @@ static int host_dev_release(struct inode * i, struct file * filp)
     return 0;
 }
 
-
-static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, unsigned long arg)
+static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg)
 {
     void __user *argp = (void __user *)arg;
 
@@ -371,7 +369,7 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
            
            switch (op.type) { 
                case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: {
-                   void *temp = kmalloc(op.len,GFP_KERNEL);
+                   void *temp = palacios_alloc(op.len);
 
                    DEEP_DEBUG_PRINT("palacios: hostdev: read guest\n");
 
@@ -386,17 +384,17 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
                                                   temp,
                                                   op.len) != op.len) {
                        ERROR("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
-                       kfree(temp);
+                       palacios_free(temp);
                        return -EFAULT;
                    }
                    
                    if (copy_to_user(op.data,temp,op.len)) { 
                        ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
-                       kfree(temp);
+                       palacios_free(temp);
                        return -EFAULT;
                    }
 
-                   kfree(temp);
+                   palacios_free(temp);
 
                    return op.len;
                }
@@ -408,7 +406,7 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
                    
                    DEEP_DEBUG_PRINT("palacios: hostdev: write guest\n");
 
-                   temp = kmalloc(op.len,GFP_KERNEL);
+                   temp = palacios_alloc(op.len);
 
                    if (!temp) { 
                        ERROR("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
@@ -417,7 +415,7 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
                    
                    if (copy_from_user(temp,op.data,op.len)) { 
                        ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
-                       kfree(temp);
+                       palacios_free(temp);
                        return -EFAULT;
                    }
                    
@@ -427,21 +425,28 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
                                                    temp,
                                                    op.len) != op.len) {
                        ERROR("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
-                       kfree(temp);
+                       palacios_free(temp);
                        return -EFAULT;
                    }
 
-                   kfree(temp);
+                   palacios_free(temp);
                    
                    return op.len;
                }
                    break;
 
-               case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: {
+               case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_RAISE_GUEST: {
+
+                   DEEP_DEBUG_PRINT("palacios: hostdev: irq raise guest\n");
 
-                   DEEP_DEBUG_PRINT("palacios: hostdev: irq guest\n");
+                   return  v3_host_dev_raise_irq(dev, dev->guestdev, dev->guestintr, op.irq);
+               }
+                   break;
+               case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_LOWER_GUEST: {
+
+                   DEEP_DEBUG_PRINT("palacios: hostdev: irq lower guest\n");
 
-                   return  v3_host_dev_raise_irq(dev, dev->guestdev, op.irq);
+                   return  v3_host_dev_lower_irq(dev, dev->guestdev, dev->guestintr, op.irq);
                }
                    break;
 
@@ -460,24 +465,26 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
 
            DEEP_DEBUG_PRINT("palacios: hostdev: request size of request\n");
            
-           spin_lock_irqsave(&(dev->lock),f);
+           palacios_spinlock_lock_irqsave(&(dev->lock),f);
            
            if (!(dev->waiting)) { 
-               spin_unlock_irqrestore(&(dev->lock),f);
+               palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
                DEEP_DEBUG_PRINT("palacios: hostdev: no request available\n");
                schedule();  // avoid livelock for polling user space process  SUSPICOUS
                return 0; // no request available now
            } 
-           
+
+           // safe to unlock here since if we are in the waiting state
+           // the palacios side will not modify the request
+           palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
+
            if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) { 
-               spin_unlock_irqrestore(&(dev->lock),f);
+               palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
                ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
                return -EFAULT; // failed to copy!
 
            }
            
-           spin_unlock_irqrestore(&(dev->lock),f);
-
            DEEP_DEBUG_PRINT("palacios: hostdev: have request\n");
 
            return 1; // have request for you
@@ -490,25 +497,25 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
            
            unsigned long f;
            
-           spin_lock_irqsave(&(dev->lock),f);
+           palacios_spinlock_lock_irqsave(&(dev->lock),f);
            
            DEEP_DEBUG_PRINT("palacios: hostdev: pull request\n");
 
            if (!(dev->waiting) || !(dev->req)) { 
-               spin_unlock_irqrestore(&(dev->lock),f);
+               palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
                DEEP_DEBUG_PRINT("palacios: hostdev: no request to pull\n");
                return 0; // no request available now
            } 
 
+           // Safe to unlock here since if we are in the waiting 
+           // state, the request will not be modified by the palacios side
+           palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
            
            if (copy_to_user(argp,dev->req,dev->req->data_len)) { 
-               spin_unlock_irqrestore(&(dev->lock),f);
                ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
                return -EFAULT; // failed to copy!
            }
     
-           spin_unlock_irqrestore(&(dev->lock),f);
-
            DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n");
            
            return 1; // copied request for you
@@ -521,47 +528,41 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
            uint64_t user_datalen;
            uint64_t old_len;
            
-           spin_lock_irqsave(&(dev->lock),f);
+           palacios_spinlock_lock_irqsave(&(dev->lock),f);
            
            DEEP_DEBUG_PRINT("palacios: hostdev: push response\n");
 
            if (!(dev->waiting)) { 
-               spin_unlock_irqrestore(&(dev->lock),f);
+               palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
                ERROR("palacios: hostdev: no matching request for pushed response\n");
                return 0; // no request outstanding, so we do not need a response!
            }
            
+           // Safe to unlock here as the palacios side will not
+           // modify the request or copy the response until we
+           // reset dev->waiting
+           palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
+
            if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) { 
-               spin_unlock_irqrestore(&(dev->lock),f);
                ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
                return -EFAULT; // failed to copy!
            } 
 
            if (user_datalen<sizeof(struct palacios_host_dev_host_request_response)) { 
                // bad user
-               spin_unlock_irqrestore(&(dev->lock),f);
                ERROR("palacios: user has response that is too small on host device \"%s\"\n",dev->url);
                return -EFAULT;
            }
 
            if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) {
                // not enough room.
-               // we drop the lock, turn on interrupts, resize, and then retry
-               DEEP_DEBUG_PRINT("palacios: response not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
+               DEEP_DEBUG_PRINT("palacios: response not big enough, resizing on device \"%s\"\n",dev->url);
 
-               spin_unlock_irqrestore(&(dev->lock),f);
                
                if (palacios_resize_reqresp(&(dev->resp),user_datalen-sizeof(struct palacios_host_dev_host_request_response),0)) {
                    ERROR("palacios: unable to resize to accept response of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
                    return -EFAULT;
-               } else {
-                   // reacquire the lock
-                   // There shouldn't be a race here, since there should
-                   // be exactly one user space thread giving us a response for this device
-                   // and it is blocked waiting for us to finish
-                   spin_lock_irqsave(&(dev->lock),f);
-                   DEEP_DEBUG_PRINT("palacios: reacuired lock on device \"%s\"\n",dev->url);
-               }
+               } 
            }
 
            //We only copy data_len bytes from user, but we will
@@ -569,7 +570,6 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
            old_len = dev->resp->len;
            if (copy_from_user(dev->resp, argp, user_datalen)) { 
                dev->resp->len=old_len;
-               spin_unlock_irqrestore(&(dev->lock),f);
                ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
                return -EFAULT; // failed to copy!
            } 
@@ -579,8 +579,6 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
            // now have valid response!
            dev->waiting=0;
 
-           spin_unlock_irqrestore(&(dev->lock),f);
-
            // wake the palacios side up so that it sees it
            cycle_response_request(dev);
 
@@ -596,13 +594,11 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u
     
 }
 
-
-
-
 static struct file_operations host_dev_fops = {
     .poll     = host_dev_poll,
     .release  = host_dev_release,
-    .ioctl    = host_dev_ioctl,
+    .compat_ioctl = host_dev_ioctl,
+    .unlocked_ioctl = host_dev_ioctl,
 };
 
 
@@ -619,7 +615,7 @@ static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned
 
 
     if (copy_from_user(url, argp, MAX_URL)) {
-       printk("copy from user error getting url for host device connect...\n");
+       ERROR("copy from user error getting url for host device connect...\n");
        return -EFAULT;
     }
 
@@ -635,43 +631,43 @@ static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned
     // URL.  If we don't find it after a while, we give up
     
     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
-       spin_lock_irqsave(&(host_dev->lock),f1);
+       palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
        list_for_each_entry(dev,&(host_dev->devs), node) {
            if (!strncasecmp(url,dev->url,MAX_URL)) { 
                // found it
-               spin_lock_irqsave(&(dev->lock),f2);
+               palacios_spinlock_lock_irqsave(&(dev->lock),f2);
                if (dev->connected) { 
                    ERROR("palacios: device for \"%s\" is already connected!\n",url);
-                   spin_unlock_irqrestore(&(dev->lock),f2);
-                   spin_unlock_irqrestore(&(host_dev->lock),f1);
+                   palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
+                   palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
                    return -1;
                } else {
                    dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
                    if (dev->fd<0) { 
                        ERROR("palacios: cannot create fd for device \"%s\"\n",url);
-                       spin_unlock_irqrestore(&(dev->lock),f2);
-                       spin_unlock_irqrestore(&(host_dev->lock),f1);
+                       palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
+                       palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
                        return -1;
                    }
                    dev->connected=1;
                    dev->waiting=0;
                    if (dev->req) { 
-                       kfree(dev->req);
+                       palacios_free(dev->req);
                        dev->req=0;
                    } 
                    if (dev->resp) { 
-                       kfree(dev->resp);
+                       palacios_free(dev->resp);
                        dev->resp=0;
                    }
                    INFO("palacios: connected fd for device \"%s\"\n",url);
-                   spin_unlock_irqrestore(&(dev->lock),f2);
-                   spin_unlock_irqrestore(&(host_dev->lock),f1);
+                   palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
+                   palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
                    return dev->fd;
                }
-               spin_unlock_irqrestore(&(dev->lock),f2);
+               palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
            }
        }
-       spin_unlock_irqrestore(&(host_dev->lock),f1);
+       palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
        
        ssleep(RENDEZVOUS_RETRY_SECS);
     }
@@ -711,13 +707,13 @@ static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
 
     // Now wait until we are noticed!
     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
-       spin_lock_irqsave(&(dev->lock),f);
+       palacios_spinlock_lock_irqsave(&(dev->lock),f);
        if (dev->connected) { 
            INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
-           spin_unlock_irqrestore(&(dev->lock),f);
+           palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
            return 0;
        }
-       spin_unlock_irqrestore(&(dev->lock),f);
+       palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ssleep(RENDEZVOUS_RETRY_SECS);
     }
     
@@ -733,6 +729,7 @@ static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
 static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
                                                     v3_bus_class_t bus,
                                                     v3_guest_dev_t gdev,
+                                                    v3_guest_dev_intr_t gintr,
                                                     void *host_priv_data)
 {
     struct v3_guest *guest= (struct v3_guest*)host_priv_data;
@@ -753,7 +750,7 @@ static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
     host_dev = get_vm_ext_data(guest, "HOST_DEVICE_INTERFACE");
 
     if (host_dev == NULL) {
-       printk("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
+       ERROR("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
        return 0;
     }
 
@@ -764,21 +761,21 @@ static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
     }
 
     // Check to see if a device of this url already exists, which would be ugly
-    spin_lock_irqsave(&(host_dev->lock),f);
+    palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
     list_for_each_entry(dev,&(host_dev->devs), node) {
        if (!strncasecmp(url,dev->url,MAX_URL)) { 
            // found it
-           spin_unlock_irqrestore(&(host_dev->lock),f);
+           palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
            ERROR("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
            return NULL;
        }
     }
-    spin_unlock_irqrestore(&(host_dev->lock),f);
+    palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
 
 
     INFO("palacios: creating host device \"%s\"\n",url);
 
-    dev = kmalloc(sizeof(struct palacios_host_device_user),GFP_KERNEL);
+    dev = palacios_alloc(sizeof(struct palacios_host_device_user));
     
     if (!dev) { 
        ERROR("palacios: cannot allocate for host device \"%s\"\n",url);
@@ -791,17 +788,19 @@ static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
     
     dev->guestdev = gdev;
     
+    dev->guestintr = gintr;
+    
     dev->guest = guest;
 
-    spin_lock_init(&(dev->lock));
+    palacios_spinlock_init(&(dev->lock));
 
     init_waitqueue_head(&(dev->user_wait_queue));
     init_waitqueue_head(&(dev->host_wait_queue));
 
     // Insert ourselves into the list
-    spin_lock_irqsave(&(host_dev->lock),f);
+    palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
     list_add(&(dev->node),&(host_dev->devs));
-    spin_unlock_irqrestore(&(host_dev->lock),f);
+    palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
 
     INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
 
@@ -831,9 +830,9 @@ static int palacios_host_dev_close(v3_host_dev_t hostdev)
        return -1;
     }
 
-    spin_lock_irqsave(&(host_dev->lock),f1);
+    palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
 
-    spin_lock_irqsave(&(dev->lock),f2);
+    palacios_spinlock_lock_irqsave(&(dev->lock),f2);
 
     if (dev->connected) { 
        dev->connected=0;
@@ -842,9 +841,11 @@ static int palacios_host_dev_close(v3_host_dev_t hostdev)
 
     list_del(&(dev->node));
     
-    spin_unlock_irqrestore(&(dev->lock),f2);
-    spin_unlock_irqrestore(&(host_dev->lock),f1);
+    palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
+    palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
     
+    palacios_spinlock_deinit(&(dev->lock));
+
     palacios_host_dev_user_free(dev);
 
     return 0;
@@ -864,41 +865,31 @@ static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
 
     DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
            
-
-    spin_lock_irqsave(&(dev->lock),f);
-    
     if (palacios_host_dev_rendezvous(dev)) {
-       spin_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
        return 0;
     }
+    palacios_spinlock_lock_irqsave(&(dev->lock),f);
 
     if (dev->waiting) { 
-       spin_unlock_irqrestore(&(dev->lock),f);
+       palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: guest issued i/o read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
        return 0;
     }
 
-    
+    // if we're not waiting on user, we have access to
+    // to the request and response fields
+    palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
     
     // resize request (no data)
     if (!palacios_bigenough_reqresp(dev->req,0)) {
        // not enough room.
-       // we drop the lock, turn on interrupts, resize, and then retry
-       DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
-       
-       spin_unlock_irqrestore(&(dev->lock),f);
+       DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
        
        if (palacios_resize_reqresp(&(dev->req),0,0)) {
            ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
            return 0;
-       } else {
-           // reacquire the lock
-           // There shouldn't be a race here since there should not be another
-           // request from palacios until this one finishes
-           spin_lock_irqsave(&(dev->lock),f);
-           DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
-       }
+       } 
     }
     
 
@@ -911,21 +902,17 @@ static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
 
     dev->waiting=1;
     
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     // hand over to the user space and wait for it to respond
     cycle_request_response(dev);
 
     // We're back!   So now we'll hand the response back to Palacios
-
-    spin_lock_irqsave(&(dev->lock),f);
+    // no need to lock, we own the response since 
+    // waiting is now 0
 
     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
 
     memcpy(dest,dev->resp->data, op_len);
     
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     return op_len;
 }
 
@@ -940,37 +927,31 @@ static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
 
     DEEP_DEBUG_PRINT("palacios: hostdev: read mem  0x%p\n",gpa);
 
-    spin_lock_irqsave(&(dev->lock),f);
     
     if (palacios_host_dev_rendezvous(dev)) {
-       spin_unlock_irqrestore(&(dev->lock),f);
+       //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
        return 0;
     }
+    palacios_spinlock_lock_irqsave(&(dev->lock),f);
 
     if (dev->waiting) { 
-       spin_unlock_irqrestore(&(dev->lock),f);
+       palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: guest issued memory read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
        return 0;
     }
+
+    // We now are assured to have ownership over request
+    palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
     
     // resize request (no data)
     if (!palacios_bigenough_reqresp(dev->req,0)) {
        // not enough room.
-       // we drop the lock, turn on interrupts, resize, and then retry
-       DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
-       
-       spin_unlock_irqrestore(&(dev->lock),f);
+       DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
        
        if (palacios_resize_reqresp(&(dev->req),0,0)) {
            ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
            return 0;
-       } else {
-           // reacquire the lock
-           // There shouldn't be a race here since there should not be another
-           // request from palacios until this one finishes
-           spin_lock_irqsave(&(dev->lock),f);
-           DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
        }
     }
 
@@ -983,21 +964,15 @@ static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
 
     dev->waiting=1;
     
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     // hand over to the user space and wait for it to respond
     cycle_request_response(dev);
 
     // We're back!   So now we'll hand the response back to Palacios
 
-    spin_lock_irqsave(&(dev->lock),f);
-
     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
 
     memcpy(dest,dev->resp->data, op_len);
     
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     return op_len;
 }
 
@@ -1010,40 +985,34 @@ static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
     unsigned long f;
     uint64_t op_len;
 
-    DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p\n",(void*)offset);
+    DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p (len=%lld)\n",(void*)offset, len);
 
-    spin_lock_irqsave(&(dev->lock),f);
     
     if (palacios_host_dev_rendezvous(dev)) {
-       spin_unlock_irqrestore(&(dev->lock),f);
+       //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
        return 0;
     }
+    palacios_spinlock_lock_irqsave(&(dev->lock),f);
 
     if (dev->waiting) { 
-       spin_unlock_irqrestore(&(dev->lock),f);
+       palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: guest issued config read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
        return 0;
     }
     
+    // Now have exclusive access to request
+    palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
+
     // resize request (no data)
     if (!palacios_bigenough_reqresp(dev->req,0)) {
        // not enough room.
-       // we drop the lock, turn on interrupts, resize, and then retry
-       DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
-       
-       spin_unlock_irqrestore(&(dev->lock),f);
+       DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
        
        if (palacios_resize_reqresp(&(dev->req),0,0)) {
            ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
            return 0;
-       } else {
-           // reacquire the lock
-           // There shouldn't be a race here since there should not be another
-           // request from palacios until this one finishes
-           spin_lock_irqsave(&(dev->lock),f);
-           DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
-       }
+       } 
     }
 
     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
@@ -1055,21 +1024,15 @@ static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
 
     dev->waiting=1;
     
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     // hand over to the user space and wait for it to respond
     cycle_request_response(dev);
 
     // We're back!   So now we'll hand the response back to Palacios
 
-    spin_lock_irqsave(&(dev->lock),f);
-
     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
 
     memcpy(dest,dev->resp->data, op_len);
     
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     return op_len;
 }
 
@@ -1085,38 +1048,32 @@ static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
 
     DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
 
-    spin_lock_irqsave(&(dev->lock),f);
     
     if (palacios_host_dev_rendezvous(dev)) {
-       spin_unlock_irqrestore(&(dev->lock),f);
+       //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
        return 0;
     }
+    palacios_spinlock_lock_irqsave(&(dev->lock),f);
 
     if (dev->waiting) { 
-       spin_unlock_irqrestore(&(dev->lock),f);
+       palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: guest issued i/o write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
        return 0;
     }
 
+    // have exclusive access to request
+    palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
+       
     // resize request 
     if (!palacios_bigenough_reqresp(dev->req,len)) {
        // not enough room.
-       // we drop the lock, turn on interrupts, resize, and then retry
-       DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
-       
-       spin_unlock_irqrestore(&(dev->lock),f);
+       DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
        
        if (palacios_resize_reqresp(&(dev->req),len,0)) {
            ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
            return 0;
-       } else {
-           // reacquire the lock
-           // There shouldn't be a race here since there should not be another
-           // request from palacios until this one finishes
-           spin_lock_irqsave(&(dev->lock),f);
-           DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
-       }
+       } 
     }
 
     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
@@ -1130,19 +1087,13 @@ static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
 
     dev->waiting=1;
 
-    spin_unlock_irqrestore(&(dev->lock),f);
-   
     // hand over to the user space and wait for it to respond
     cycle_request_response(dev);
 
     // We're back!   So now we'll hand the response back to Palacios
 
-    spin_lock_irqsave(&(dev->lock),f);
-
     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
 
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     return op_len;
 }
 
@@ -1158,38 +1109,33 @@ static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
 
     DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
 
-    spin_lock_irqsave(&(dev->lock),f);
     
     if (palacios_host_dev_rendezvous(dev)) {
-       spin_unlock_irqrestore(&(dev->lock),f);
+       //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
        return 0;
     }
 
+    palacios_spinlock_lock_irqsave(&(dev->lock),f);
+
     if (dev->waiting) { 
-       spin_unlock_irqrestore(&(dev->lock),f);
+       palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: guest issued memory write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
        return 0;
     }
     
+    // Now have exclusive access to request
+    palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
+    
     // resize request 
     if (!palacios_bigenough_reqresp(dev->req,len)) {
        // not enough room.
-       // we drop the lock, turn on interrupts, resize, and then retry
-       DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
-       
-       spin_unlock_irqrestore(&(dev->lock),f);
+       DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
        
        if (palacios_resize_reqresp(&(dev->req),len,0)) {
            ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
            return 0;
-       } else {
-           // reacquire the lock
-           // There shouldn't be a race here since there should not be another
-           // request from palacios until this one finishes
-           spin_lock_irqsave(&(dev->lock),f);
-           DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
-       }
+       } 
     }
 
     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
@@ -1203,19 +1149,13 @@ static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
 
     dev->waiting=1;
     
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     // hand over to the user space and wait for it to respond
     cycle_request_response(dev);
 
     // We're back!   So now we'll hand the response back to Palacios
 
-    spin_lock_irqsave(&(dev->lock),f);
-
     op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
 
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     return op_len;
 }
 
@@ -1233,38 +1173,32 @@ static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
 
     DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
 
-    spin_lock_irqsave(&(dev->lock),f);
     
     if (palacios_host_dev_rendezvous(dev)) {
-       spin_unlock_irqrestore(&(dev->lock),f);
+       //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
        return 0;
     }
+    palacios_spinlock_lock_irqsave(&(dev->lock),f);
 
     if (dev->waiting) { 
-       spin_unlock_irqrestore(&(dev->lock),f);
+       palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
        ERROR("palacios: guest issued config write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
        return 0;
     }
     
+    // Have exclusive access to request
+    palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
+
     // resize request 
     if (!palacios_bigenough_reqresp(dev->req,len)) {
        // not enough room.
-       // we drop the lock, turn on interrupts, resize, and then retry
-       DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
-       
-       spin_unlock_irqrestore(&(dev->lock),f);
+       DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
        
        if (palacios_resize_reqresp(&(dev->req),len,0)) {
            ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
            return 0;
-       } else {
-           // reacquire the lock
-           // There shouldn't be a race here since there should not be another
-           // request from palacios until this one finishes
-           spin_lock_irqsave(&(dev->lock),f);
-           DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
-       }
+       } 
     }
 
     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
@@ -1277,20 +1211,14 @@ static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
     memcpy(dev->req->data,src,len);
 
     dev->waiting=1;
-    
-    spin_unlock_irqrestore(&(dev->lock),f);
 
     // hand over to the user space and wait for it to respond
     cycle_request_response(dev);
 
     // We're back!   So now we'll hand the response back to Palacios
 
-    spin_lock_irqsave(&(dev->lock),f);
-
     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
 
-    spin_unlock_irqrestore(&(dev->lock),f);
-
     return op_len;
 }
  
@@ -1326,8 +1254,13 @@ static int host_dev_init( void ) {
 }
 
 
+static int host_dev_deinit(void) { 
+    // nothing to do
+    return 0;
+}
+
 static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
-    struct palacios_host_dev * host_dev = kmalloc(sizeof(struct palacios_host_dev), GFP_KERNEL);
+    struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev));
 
     if (!host_dev) { 
        ERROR("palacios: failed to do guest_init for host device\n");
@@ -1336,7 +1269,7 @@ static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
     
     
     INIT_LIST_HEAD(&(host_dev->devs));
-    spin_lock_init(&(host_dev->lock));
+    palacios_spinlock_init(&(host_dev->lock));
 
     *vm_data = host_dev;
 
@@ -1347,15 +1280,24 @@ static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
 }
 
 
+static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
+
+    struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data;
+    remove_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT);
+    palacios_spinlock_deinit(&(host_dev->lock));
+    palacios_free(host_dev);
+    return 0;
+}
+
 
 
 
 static struct linux_ext host_dev_ext = {
     .name = "HOST_DEVICE_INTERFACE",
     .init = host_dev_init,
-    .deinit = NULL,
+    .deinit = host_dev_deinit,
     .guest_init = host_dev_guest_init,
-    .guest_deinit = NULL
+    .guest_deinit = host_dev_guest_deinit
 };