diff --git a/drivers/virtio-vring.cc b/drivers/virtio-vring.cc
index c96c3446dd2d9bb258c125a306ecec8c5af68445..4df787c71111d3c752164dc4d5297e39fb4911cd 100644
--- a/drivers/virtio-vring.cc
+++ b/drivers/virtio-vring.cc
@@ -29,12 +29,22 @@ namespace virtio {
                 sizeof(u16) + VIRTIO_PCI_VRING_ALIGN-1) & ~(VIRTIO_PCI_VRING_ALIGN-1));
 
         // initialize the next pointer within the available ring
-        for (int i=0;i<num;i++) _avail->_ring[i] = i+1;
+        for (int i=0;i<num;i++) _desc[i]._next = i+1;
+        _desc[num-1]._next = 0;
+
+        _cookie = new void*[num];
+
+        _avail_head = 0;
+        _used_guest_head = 0;
+        _avail_added = 0;
+        _avail_count = num;
+
     }
 
     vring::~vring()
     {
         free(_vring_ptr);
+        delete [] _cookie;
     }
 
     u64 vring::get_paddr(void)
@@ -61,27 +71,30 @@ namespace virtio {
 
     bool
     vring::add_buf(sglist* sg, u16 out, u16 in, void* cookie) {
-        //if (_avail->count() < (in+out)) {
-            // what should I do?
-        //}
+        if (_avail_count < (in+out)) {
+            //make sure the interrupts get there
+            kick();
+            return false;
+        }
 
-        int i = 0;
-        vring_desc* desc = &_desc[_avail->_ring[_avail->_idx]];
+        int i = 0, idx, prev_idx;
+        idx = prev_idx = _avail_head;
         for (auto ii = sg->_nodes.begin();i<in+out;ii++) {
-            desc->_flags = vring_desc::VRING_DESC_F_NEXT | (i>in)? vring_desc::VRING_DESC_F_WRITE:0;
-            desc->_paddr = (*ii)._paddr;
-            desc->_len = (*ii)._len;
-            desc->_next = _avail->_ring[_avail->_idx];
-            _avail->_idx++;
-            desc = &_desc[_avail->_ring[desc->_next]];
-            i++;
+            _desc[idx]._flags = vring_desc::VRING_DESC_F_NEXT;
+            _desc[idx]._flags |= (i++>in)? vring_desc::VRING_DESC_F_WRITE:0;
+            _desc[idx]._paddr = (*ii)._paddr;
+            _desc[idx]._len = (*ii)._len;
+            prev_idx = idx;
+            idx = _avail->_ring[_desc[idx]._next];
         }
-        desc->_flags &= ~vring_desc::VRING_DESC_F_NEXT;
-
+        _desc[prev_idx]._flags &= ~vring_desc::VRING_DESC_F_NEXT;
 
+        _avail->_idx = _avail_head;
+        _cookie[_avail_head] = cookie;
 
-        //_avail->add(sg, in, out, cookie);
-        //used idx math
+        _avail_added += i;
+        _avail_count -= i;
+        _avail_head = idx;
 
         return true;
     }
diff --git a/drivers/virtio-vring.hh b/drivers/virtio-vring.hh
index 82ba3578d1300b9b6765a60e5386340cb419e2fd..3d62869c36071871271815f361643775d2fde2aa 100644
--- a/drivers/virtio-vring.hh
+++ b/drivers/virtio-vring.hh
@@ -129,12 +129,23 @@ class virtio_driver;
         
         // Total number of descriptors in ring
         unsigned int _num;
+
+        // Position of the next available descriptor
+        u16 _avail_head;
+        // Position of the used descriptor we've last seen
+        u16 _used_guest_head;
+        // The amount of avail descriptors we've added since last kick
+        u16 _avail_added;
+        u16 _avail_count;
+
         // Flat list of chained descriptors
         vring_desc *_desc;
         // Available for host consumption
         vring_avail *_avail;
         // Available for guest consumption
         vring_used *_used;
+        // cookies to store access to the upper layer pointers
+        void** _cookie;
     };