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.


Linux kernel compatability enhancements (through 3.19)
[palacios.git] / linux_module / iface-keyed-stream.c
index 68445d4..1f75aa0 100644 (file)
@@ -6,13 +6,13 @@
  * (c) Peter Dinda, 2011 (interface, mem + file implementations + recooked user impl)
  * (c) Clint Sbisa, 2011 (initial user space implementation on which this is based)
  * (c) Diana Palsetia & Steve Rangel, 2012 (network based implementation)      
+ * (c) Peter Dinda, 2012 (updated interface, textfile)
  */
 
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/uaccess.h>
 #include <linux/namei.h>
-#include <linux/vmalloc.h>
 #include <linux/poll.h>
 #include <linux/anon_inodes.h>
 
 
   "mem:"   Streams are stored in a hash table
   The values for this hash table are hash tables associated with 
-  each stream.   
+  each stream.   A key maps to an expanding memory buffer.
+  Data is stored in a buffer like:
+
+  [boundarytag][taglen][tag][datalen][data]
+  [boundarytag][taglen][tag][datalen][data]
+  ...
 
   "file:"  Streams are stored in files.  Each high-level
   open corresponds to a directory, while a key corresponds to
-  a distinct file in that directory. 
+  a distinct file in that directory.   Data is stored in a file
+  like:
+
+  [boundarytag][taglen][tag][datalen][data]
+  [boundarytag][taglen][tag][datalen][data]
+  ...
+
+  "textfile:" Same as file, but data is stored in text format, like a
+  windows style .ini file.  A key maps to a file, and data is stored
+  in a file like:
+
+  [key]
+  tag=data_in_hex
+  tag=data_in_hex
+
+  This format makes it possible to concentenate the files to
+  produce a single "ini" file with "sections".
+
 
   "net:"  Streams are carried over the network.  Each
    high level open corresponds to a TCP connection, while
    each key corresponds to a context on the stream.
       "net:a:<ip>:<port>" => Bind to <ip>:<port> and accept a connection
       "net:c:<ip>:<port>" => Connect to <ip>:<port>
+   "c" (client) 
+     open_stream: connect
+   "a" (server) 
+     open_stream: accept
+   "c" or "a":
+     open_key:  send [keylen-lastbyte-high-bit][key] (writer)
+           or   recv (same format as above)          (reader)
+     close_key: send [keylen-lastbyte-high-bit][key] (writer)
+           or   recv (same format as above)          (reader)
+     write_key: send [boundarytag][taglen][tag][datalen][data]
+     read_key:  recv (same format as above)
+     close_stream: close socket
 
   "user:" Stream requests are bounced to user space to be 
    handled there.  A rendezvous approach similar to the host 
    device userland support is used
+
+   All keyed streams store the tags.
    
 */
 
 #define STREAM_FILE    2
 #define STREAM_USER    3
 #define STREAM_NETWORK 4
+#define STREAM_TEXTFILE 5
 
 /*
   All keyed streams and streams indicate their implementation type within the first field
@@ -89,7 +126,10 @@ struct generic_stream {
     int stype;
 };
   
-
+/*
+  boundary tags are used for some othe raw formats. 
+*/
+static uint32_t BOUNDARY_TAG=0xabcd0123;
 
 
 /****************************************************************************************
@@ -120,17 +160,17 @@ struct mem_stream {
 
 static struct mem_stream *create_mem_stream_internal(uint64_t size)
 {
-    struct mem_stream *m = kmalloc(sizeof(struct mem_stream),GFP_KERNEL);
+    struct mem_stream *m = palacios_alloc(sizeof(struct mem_stream));
 
     if (!m) {
        return 0;
     }
 
 
-    m->data = vmalloc(size);
+    m->data = palacios_valloc(size);
     
     if (!m->data) { 
-       kfree(m);
+       palacios_free(m);
        return 0;
     }
 
@@ -152,16 +192,16 @@ static void destroy_mem_stream(struct mem_stream *m)
 {
     if (m) {
        if (m->data) {
-           kfree(m->data);
+           palacios_vfree(m->data);
        }
        m->data=0;
-       kfree(m);
+       palacios_free(m);
     }
 }
     
 static int expand_mem_stream(struct mem_stream *m, uint32_t new_size)
 {
-    void *data = vmalloc(new_size);
+    void *data = palacios_valloc(new_size);
     uint32_t nc;
 
     if (!data) { 
@@ -172,7 +212,7 @@ static int expand_mem_stream(struct mem_stream *m, uint32_t new_size)
 
     memcpy(data,m->data,nc);
 
-    kfree(m->data);
+    palacios_vfree(m->data);
 
     m->data=data;
     m->size=new_size;
@@ -200,6 +240,8 @@ static uint32_t write_mem_stream(struct mem_stream *m,
 
 }
 
+
+
 static uint32_t read_mem_stream(struct mem_stream *m,
                                void *data,
                                uint32_t len)
@@ -261,27 +303,27 @@ static v3_keyed_stream_t open_stream_mem(char *url,
            if (!mks) { 
                char *mykey;
 
-               mykey = kmalloc(strlen(url+4)+1,GFP_KERNEL);
+               mykey = palacios_alloc(strlen(url+4)+1);
 
                if (!mykey) { 
                    ERROR("cannot allocate space for new in-memory keyed stream %s\n",url);
                    return 0;
                }
 
-               strcpy(mykey,url+4);
+               strcpy(mykey,url+4); // will fit
                
-               mks = (struct mem_keyed_stream *) kmalloc(sizeof(struct mem_keyed_stream),GFP_KERNEL);
+               mks = (struct mem_keyed_stream *) palacios_alloc(sizeof(struct mem_keyed_stream));
 
                if (!mks) { 
-                   kfree(mykey);
+                   palacios_free(mykey);
                    ERROR("cannot allocate in-memory keyed stream %s\n",url);
                    return 0;
                }
            
                mks->ht = (void*) palacios_create_htable(DEF_NUM_KEYS,hash_func,hash_comp);
                if (!mks->ht) { 
-                   kfree(mks);
-                   kfree(mykey);
+                   palacios_free(mks);
+                   palacios_free(mykey);
                    ERROR("cannot allocate in-memory keyed stream %s\n",url);
                    return 0;
                }
@@ -289,8 +331,8 @@ static v3_keyed_stream_t open_stream_mem(char *url,
                
                if (!palacios_htable_insert(mem_streams,(addr_t)(mykey),(addr_t)mks)) { 
                    palacios_free_htable(mks->ht,1,1);
-                   kfree(mks);
-                   kfree(mykey);
+                   palacios_free(mks);
+                   palacios_free(mykey);
                    ERROR("cannot insert in-memory keyed stream %s\n",url);
                    return 0;
                }
@@ -333,26 +375,26 @@ static v3_keyed_stream_key_t open_key_mem(v3_keyed_stream_t stream,
     m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
 
     if (!m) { 
-       char *mykey = kmalloc(strlen(key)+1,GFP_KERNEL);
+       char *mykey = palacios_alloc(strlen(key)+1);
 
        if (!mykey) { 
            ERROR("cannot allocate copy of key for key %s\n",key);
            return 0;
        }
 
-       strcpy(mykey,key);
+       strcpy(mykey,key); // will fit
 
        m = create_mem_stream();
        
        if (!m) { 
-           kfree(mykey);
+           palacios_free(mykey);
            ERROR("cannot allocate mem keyed stream for key %s\n",key);
            return 0;
        }
 
        if (!palacios_htable_insert(s,(addr_t)mykey,(addr_t)m)) {
            destroy_mem_stream(m);
-           kfree(mykey);
+           palacios_free(mykey);
            ERROR("cannot insert mem keyed stream for key %s\n",key);
            return 0;
        }
@@ -382,14 +424,14 @@ static void preallocate_hint_key_mem(v3_keyed_stream_t stream,
     if (!m) {
        char *mykey;
        
-       mykey=kmalloc(strlen(key)+1,GFP_KERNEL);
+       mykey=palacios_alloc(strlen(key)+1);
        
        if (!mykey) { 
            ERROR("cannot allocate key space for preallocte for key %s\n",key);
            return;
        }
        
-       strcpy(mykey,key);
+       strcpy(mykey,key); // will fit
        
        m = create_mem_stream_internal(size);
        
@@ -425,62 +467,173 @@ static void close_key_mem(v3_keyed_stream_t stream,
 
 static sint64_t write_key_mem(v3_keyed_stream_t stream, 
                              v3_keyed_stream_key_t key,
+                             void *tag,
+                             sint64_t taglen,
                              void *buf,
                              sint64_t len)
 {
-    struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
-    struct mem_stream *m = (struct mem_stream *) key;
-    uint32_t mylen;
-    uint32_t writelen;
-
-    if (mks->ot!=V3_KS_WR_ONLY) {
-       return -1;
-    }
+  struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
+  struct mem_stream *m = (struct mem_stream *) key;
+  uint32_t mylen;
+  uint32_t writelen;
+  
+  if (mks->ot!=V3_KS_WR_ONLY) {
+    return -1;
+  }
+  
+  if (taglen<0 || len<0) { 
+    ERROR("Negative taglen or data len\n");
+    return -1;
+  }
+  
+  if (taglen>0xffffffffULL || len>0xffffffffULL) { 
+    ERROR("taglen or data len is too large\n");
+    return -1;
+  }
+      
+  writelen=write_mem_stream(m,&BOUNDARY_TAG,sizeof(BOUNDARY_TAG));
+  
+  if (writelen!=sizeof(BOUNDARY_TAG)) { 
+    ERROR("failed to write all data for boundary tag\n");
+    return -1;
+  }
+  
+  writelen=write_mem_stream(m,&taglen,sizeof(taglen));
+  
+  if (writelen!=sizeof(taglen)) { 
+    ERROR("failed to write taglen\n");
+    return -1;
+  }
+  
+  mylen = (uint32_t) taglen;
+  
+  writelen=write_mem_stream(m,tag,mylen);
+  
+  if (writelen!=mylen) { 
+    ERROR("failed to write all data for tag\n");
+    return -1;
+  } 
 
-    if (len<0) { 
-       return -1;
-    }
-    
-    mylen = (uint32_t) len;
+  writelen=write_mem_stream(m,&len,sizeof(len));
+  
+  if (writelen!=sizeof(len)) { 
+    ERROR("failed to write datalen\n");
+    return -1;
+  }
+  
+  mylen = (uint32_t) len;
 
-    writelen=write_mem_stream(m,buf,mylen);
+  writelen=write_mem_stream(m,buf,mylen);
 
-    if (writelen!=mylen) { 
-       ERROR("failed to write all data for key\n");
-       return -1;
-    } else {
-       return (sint64_t)writelen;
-    }
+  if (writelen!=mylen) { 
+    ERROR("failed to write all data for key\n");
+    return -1;
+  } else {
+    return (sint64_t)writelen;
+  }
 }
 
 static sint64_t read_key_mem(v3_keyed_stream_t stream, 
                             v3_keyed_stream_key_t key,
+                            void *tag,
+                            sint64_t taglen,
                             void *buf,
                             sint64_t len)
 {
-    struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
-    struct mem_stream *m = (struct mem_stream *) key;
-    uint32_t mylen;
-    uint32_t readlen;
-    
-    if (mks->ot!=V3_KS_RD_ONLY) {
-       return -1;
-    }
+  struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
+  struct mem_stream *m = (struct mem_stream *) key;
+  uint32_t mylen;
+  uint32_t readlen;
+  void *temptag;
+  uint32_t tempbt;
+  sint64_t templen;
+  
+  
+  if (mks->ot!=V3_KS_RD_ONLY) {
+    return -1;
+  }
+  
+  if (len<0 || taglen<0) { 
+    ERROR("taglen or data len is negative\n");
+    return -1;
+  }
 
-    if (len<0) { 
-       return -1;
-    }
+  if (len>0xffffffffULL || taglen>0xffffffffULL) { 
+    ERROR("taglen or data len is too large\n");
+    return -1;
+  }
+  
+  readlen=read_mem_stream(m,&tempbt,sizeof(tempbt));
+  
+  if (readlen!=sizeof(tempbt)) { 
+    ERROR("failed to read all data for boundary tag\n");
+    return -1;
+  } 
+  
+  if (tempbt!=BOUNDARY_TAG) { 
+    ERROR("boundary tag not found (read 0x%x)\n",tempbt);
+    return -1;
+  }
+  
+  readlen=read_mem_stream(m,&templen,sizeof(templen));
+
+  if (readlen!=sizeof(templen)) { 
+    ERROR("failed to read all data for taglen\n");
+    return -1;
+  } 
+
+  if (templen!=taglen) { 
+    ERROR("tag size mismatch (requested=%lld, actual=%lld)\n",taglen,templen);
+    return -1;
+  }
+  
+  temptag = palacios_alloc(taglen);
     
-    mylen = (uint32_t) len;
+  if (!temptag) { 
+    ERROR("cannot allocate temporary tag\n");
+    return -1;
+  }
+
+  mylen = (uint32_t) len;
     
-    readlen=read_mem_stream(m,buf,mylen);
+  readlen=read_mem_stream(m,temptag,mylen);
     
-    if (readlen!=mylen) { 
-       ERROR("failed to read all data for key\n");
-       return -1;
-    } else {
-       return (sint64_t)readlen;
-    }
+  if (readlen!=mylen) { 
+    ERROR("failed to read all data for tag\n");
+    palacios_free(temptag);
+    return -1;
+  } 
+
+  if (memcmp(tag,temptag,taglen)) { 
+    ERROR("tag mismatch\n");
+    palacios_free(temptag);
+    return -1;
+  }
+  
+  palacios_free(temptag);
+
+  readlen=read_mem_stream(m,&templen,sizeof(templen));
+
+  if (readlen!=sizeof(templen)) { 
+    ERROR("failed to read all data for data len\n");
+    return -1;
+  } 
+  
+  if (templen!=len) { 
+    ERROR("data size mismatch (requested=%lld, actual=%lld)\n",len,templen);
+    return -1;
+  }
+
+  mylen = (uint32_t) len;
+  
+  readlen=read_mem_stream(m,buf,mylen);
+  
+  if (readlen!=mylen) { 
+    ERROR("failed to read all data for key\n");
+    return -1;
+  } else {
+    return (sint64_t)readlen;
+  }
 }
 
 
@@ -504,111 +657,194 @@ struct file_stream {
     struct file *f;   // the opened file
 };
 
+/* lookup directory, see if it is writeable, and if so, create it if asked*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,41)
+
+static int lookup_check_mkdir(const char *path, int need_write, int create, unsigned short perms)
+{
+  struct nameidata nd;
+
+  if (path_lookup(path,LOOKUP_DIRECTORY|LOOKUP_FOLLOW,&nd)) { 
+    
+    // directory does does not exist.  
+    
+    if (!create) { 
+      // we are not being asked to create it
+      ERROR("attempt to open %s, which does not exist\n",path);
+      return -1;
+    } else {
+      // We are being asked to create it
+
+      struct dentry *de;
+      int err;
+      
+      // Find its parent
+      if (path_lookup(path,LOOKUP_PARENT|LOOKUP_FOLLOW,&nd)) { 
+       ERROR("attempt to create %s failed because its parent cannot be looked up\n",path);
+       return -1;
+      }
+      
+      // Can we write to the parent?
+      
+      if (inode_permission(nd.path.dentry->d_inode, MAY_WRITE | MAY_EXEC)) { 
+       ERROR("attempt to open %s, which has the wrong permissions for directory creation\n",path);
+       return -1;
+      }
+
+      // OK, we can, so let's create it
+      
+      de = lookup_create(&nd,1);
+      
+      if (!de || IS_ERR(de)) { 
+       ERROR("cannot allocate dentry\n");
+       return -1;
+      }
+
+      err = vfs_mkdir(nd.path.dentry->d_inode, de, perms);
+      
+      // lookup_create locks this for us!
+      
+      mutex_unlock(&(nd.path.dentry->d_inode->i_mutex));
+
+      if (err) {
+       ERROR("attempt to create %s failed because mkdir failed\n",path);
+       return -1;
+      }
+
+      // successfully created it. 
+      return 0;
+
+    }
+
+  } else {
+    
+    // it exists, can we read (and write, if needed) to it?
+    
+    if (inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_READ | need_write ? MAY_WRITE : 0 )) {
+      ERROR("attempt to open %s, which has the wrong permissions\n",path);
+      return -1;
+    }
+    
+    return 0;
+  }
+}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,41)
+static int lookup_check_mkdir(const char *path, int need_write, int create, unsigned short perms)
+{
+  struct path p; 
+
+  if (kern_path(path, LOOKUP_DIRECTORY|LOOKUP_FOLLOW, &p)) { 
+    
+    // directory does does not exist.  
+    
+    if (!create) { 
+      // we are not being asked to create it
+      ERROR("attempt to open %s, which does not exist\n",path);
+      return -1;
+    } else {
+      // We are being asked to create it
+
+      struct dentry *de;
+      int err;
+      
+      // Find its parent
+      if (kern_path(path,LOOKUP_PARENT|LOOKUP_FOLLOW,&p)) { 
+       ERROR("attempt to create %s failed because its parent cannot be looked up\n",path);
+       return -1;
+      }
+      
+      // Can we write to the parent?
+      
+      if (inode_permission(p.dentry->d_inode, MAY_WRITE | MAY_EXEC)) { 
+       ERROR("attempt to open %s, which has the wrong permissions for directory creation\n",path);
+       return -1;
+      }
+
+      // OK, we can, so let's create it
+      
+      de = kern_path_create(AT_FDCWD,path,&p,1);
+      
+      if (!de || IS_ERR(de)) { 
+       ERROR("cannot allocate dentry\n");
+       return -1;
+      }
+
+      err = vfs_mkdir(p.dentry->d_inode, de, perms);
+      
+      // lookup_create locks this for us!
+      
+      mutex_unlock(&(p.dentry->d_inode->i_mutex));
+
+      if (err) {
+       ERROR("attempt to create %s failed because mkdir failed\n",path);
+       return -1;
+      }
+
+      // successfully created it. 
+      return 0;
+
+    }
+    
+  } else {
+    
+    // it exists, can we read (and write, if needed) to it?
+    
+    if (inode_permission(p.dentry->d_inode, MAY_EXEC | MAY_READ | need_write ? MAY_WRITE : 0 )) {
+      ERROR("attempt to open %s, which has the wrong permissions\n",path);
+      return -1;
+    }
+    
+    return 0;
+  }
+}
+
+#endif
+
 
 static v3_keyed_stream_t open_stream_file(char *url,
                                          v3_keyed_stream_open_t ot)
 {
     struct file_keyed_stream *fks;
-    struct nameidata nd;
 
     if (strncasecmp(url,"file:",5)) { 
        WARNING("illegitimate attempt to open file stream \"%s\"\n",url);
        return 0;
     }
 
-    fks = kmalloc(sizeof(struct file_keyed_stream),GFP_KERNEL);
+    fks = palacios_alloc(sizeof(struct file_keyed_stream));
     
     if (!fks) { 
        ERROR("cannot allocate space for file stream\n");
        return 0;
     }
 
-    fks->path = (char*)kmalloc(strlen(url+5)+1,GFP_KERNEL);
+    fks->path = (char*)palacios_alloc(strlen(url+5)+1);
     
     if (!(fks->path)) { 
        ERROR("cannot allocate space for file stream\n");
-       kfree(fks);
+       palacios_free(fks);
        return 0;
     }
     
-    strcpy(fks->path,url+5);
+    strcpy(fks->path,url+5); // will fit
     
     fks->stype=STREAM_FILE;
 
     fks->ot= ot==V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot;
 
-    // Does the directory exist, and can we read/write it?
-   
-    if (path_lookup(fks->path,LOOKUP_DIRECTORY|LOOKUP_FOLLOW,&nd)) { 
-
-       // directory does does not exist.  
-
-       if (ot==V3_KS_RD_ONLY || ot==V3_KS_WR_ONLY) { 
-
-           // we are not being asked to create it
-           ERROR("attempt to open %s, which does not exist\n",fks->path);
-           goto fail_out;
-
-       } else {
-
-           // We are being asked to create it
-
-           struct dentry *de;
-           int err;
-
-           // Find its parent
-           if (path_lookup(fks->path,LOOKUP_PARENT|LOOKUP_FOLLOW,&nd)) { 
-               ERROR("attempt to create %s failed because its parent cannot be looked up\n",fks->path);
-               goto fail_out;
-           }
-
-           // Can we write to the parent?
-
-           if (inode_permission(nd.path.dentry->d_inode, MAY_WRITE | MAY_EXEC)) { 
-               ERROR("attempt to open %s, which has the wrong permissions for directory creation\n",fks->path);
-               goto fail_out;
-           }
-
-           // OK, we can, so let's create it
-
-           de = lookup_create(&nd,1);
-
-           if (IS_ERR(de)) { 
-               ERROR("cannot allocate dentry\n");
-               goto fail_out;
-           }
-
-           err = vfs_mkdir(nd.path.dentry->d_inode, de, 0700);
-
-           // lookup_create locks this for us!
-
-           mutex_unlock(&(nd.path.dentry->d_inode->i_mutex));
-
-           if (err) {
-               ERROR("attempt to create %s failed because mkdir failed\n",fks->path);
-               goto fail_out;
-           }
-
-           // now the directory should exist and have reasonable permissions
-           return (v3_keyed_stream_t) fks;
-       }
-    } 
-
-    
-    // we must be in V3_KS_RD_ONLY or V3_KS_WR_ONLY, 
-    // and the directory exists, so we must check the permissions
-
-    if (inode_permission(nd.path.dentry->d_inode, MAY_EXEC | (ot==V3_KS_RD_ONLY ? MAY_READ : MAY_WRITE))) {
-       ERROR("attempt to open %s, which has the wrong permissions\n",fks->path);
-       goto fail_out;
-    } else {
-       return (v3_keyed_stream_t) fks;
+    if (lookup_check_mkdir(fks->path,ot!=V3_KS_RD_ONLY,ot==V3_KS_WR_ONLY_CREATE,0700)) { 
+      ERROR("cannot find or create directory for stream\n");
+      goto fail_out;
     }
 
+    return fks;
 
  fail_out:
-    kfree(fks->path);
-    kfree(fks);
+    palacios_free(fks->path);
+    palacios_free(fks);
     return 0;
 
 }
@@ -617,8 +853,8 @@ static void close_stream_file(v3_keyed_stream_t stream)
 {
     struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
     
-    kfree(fks->path);
-    kfree(fks);
+    palacios_free(fks->path);
+    palacios_free(fks);
 
 }
 
@@ -638,35 +874,36 @@ static v3_keyed_stream_key_t open_key_file(v3_keyed_stream_t stream,
 
     // the path is the stream's path plus the key name
     // file:/home/foo + "regext" => "/home/foo/regext"
-    path = (char *) kmalloc(strlen(fks->path)+strlen(key)+2,GFP_KERNEL);
+    path = (char *) palacios_alloc(strlen(fks->path)+strlen(key)+2);
     if (!path) {                               
        ERROR("cannot allocate file keyed stream for key %s\n",key);
        return 0;
     }
+    // this sequence will fit and terminate with a zero
     strcpy(path,fks->path);
     strcat(path,"/");
     strcat(path,key);
     
-    fs = (struct file_stream *) kmalloc(sizeof(struct file_stream *),GFP_KERNEL);
+    fs = (struct file_stream *) palacios_alloc(sizeof(struct file_stream));
     
     if (!fs) { 
        ERROR("cannot allocate file keyed stream for key %s\n",key);
-       kfree(path);
+       palacios_free(path);
        return 0;
     }
 
     fs->stype=STREAM_FILE;
 
-    fs->f = filp_open(path,O_RDWR|O_CREAT,0600);
-    
-    if (IS_ERR(fs->f)) {
+    fs->f = filp_open(path,O_RDWR|O_CREAT|O_LARGEFILE,0600);
+
+    if (!fs->f || IS_ERR(fs->f)) {
        ERROR("cannot open relevent file \"%s\" for stream \"file:%s\" and key \"%s\"\n",path,fks->path,key);
-       kfree(fs);
-       kfree(path);
+       palacios_free(fs);
+       palacios_free(path);
        return 0;
     }
 
-    kfree(path);
+    palacios_free(path);
 
     return fs;
 }
@@ -679,88 +916,800 @@ static void close_key_file(v3_keyed_stream_t stream,
 
     filp_close(fs->f,NULL);
 
-    kfree(fs);
+    palacios_free(fs);
+}
+
+
+static sint64_t write_file(struct file_stream *fs, void *buf, sint64_t len)
+{
+    ssize_t done, left, total;
+    mm_segment_t old_fs;
+
+    total=len;
+    left=len;
+
+    while (left>0) {
+        old_fs = get_fs();
+        set_fs(get_ds());
+       done = fs->f->f_op->write(fs->f, buf+(total-left), left, &(fs->f->f_pos));
+        set_fs(old_fs);
+       if (done<=0) {
+           return -1;
+       } else {
+           left -= done;
+       }
+    }
+
+    return len;
 }
 
 static sint64_t write_key_file(v3_keyed_stream_t stream, 
                               v3_keyed_stream_key_t key,
+                              void *tag,
+                              sint64_t taglen,
                               void *buf,
                               sint64_t len)
 {
-    struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
-    struct file_stream *fs = (struct file_stream *) key;
-    mm_segment_t old_fs;
+  struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
+  struct file_stream *fs = (struct file_stream *) key;
+  sint64_t writelen;
+  
+  if (fks->ot!=V3_KS_WR_ONLY) { 
+    return -1;
+  }
+  
+  if (taglen<0 || len<0) { 
+    ERROR("Negative taglen or data len\n");
+    return -1;
+  }
+  
+  writelen=write_file(fs,&BOUNDARY_TAG,sizeof(BOUNDARY_TAG));
+  
+  if (writelen!=sizeof(BOUNDARY_TAG)) { 
+    ERROR("failed to write all data for boundary tag\n");
+    return -1;
+  }
+  
+  writelen=write_file(fs,&taglen,sizeof(taglen));
+  
+  if (writelen!=sizeof(taglen)) { 
+    ERROR("failed to write taglen\n");
+    return -1;
+  }
+  
+  if (write_file(fs,tag,taglen)!=taglen) { 
+    ERROR("failed to write tag\n");
+    return -1;
+  }
+
+  writelen=write_file(fs,&len,sizeof(len));
+  
+  if (writelen!=sizeof(len)) { 
+    ERROR("failed to write data len\n");
+    return -1;
+  }
+  
+  return write_file(fs,buf,len);
+}
+
+static sint64_t read_file(struct file_stream *fs, void *buf, sint64_t len)
+{
     ssize_t done, left, total;
-    
-    if (fks->ot!=V3_KS_WR_ONLY) { 
-       return -1;
-    }
-    
-    if (len<0) { 
-       return -1;
-    }
+    mm_segment_t old_fs;
 
     total=len;
     left=len;
 
-    old_fs = get_fs();
-    set_fs(get_ds());
 
     while (left>0) {
-       done = fs->f->f_op->write(fs->f, buf+(total-left), left, &(fs->f->f_pos));
+        old_fs = get_fs();
+        set_fs(get_ds());
+       done = fs->f->f_op->read(fs->f, buf+(total-left), left, &(fs->f->f_pos));
+        set_fs(old_fs);
        if (done<=0) {
            return -1;
        } else {
            left -= done;
        }
     }
-    set_fs(old_fs);
 
     return len;
 }
 
 
-
 static sint64_t read_key_file(v3_keyed_stream_t stream, 
                              v3_keyed_stream_key_t key,
+                             void *tag,
+                             sint64_t taglen,
                              void *buf,
                              sint64_t len)
 {
-    struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
-    struct file_stream *fs = (struct file_stream *) key;
-    mm_segment_t old_fs;
-    ssize_t done, left, total;
-    
-    if (fks->ot!=V3_KS_RD_ONLY) { 
+  struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
+  struct file_stream *fs = (struct file_stream *) key;
+  void *temptag;
+  uint32_t tempbt;
+  sint64_t templen;
+  sint64_t readlen;
+  
+  if (fks->ot!=V3_KS_RD_ONLY) { 
+    return -1;
+  }
+  
+  if (len<0 || taglen<0) { 
+    ERROR("taglen or data len is negative\n");
+    return -1;
+  }
+
+  readlen=read_file(fs,&tempbt,sizeof(tempbt));
+  
+  if (readlen!=sizeof(tempbt)) { 
+    ERROR("failed to read all data for boundary tag\n");
+    return -1;
+  } 
+  
+  if (tempbt!=BOUNDARY_TAG) { 
+    ERROR("boundary tag not found (read 0x%x)\n",tempbt);
+    return -1;
+  }
+
+  readlen=read_file(fs,&templen,sizeof(templen));
+  
+  if (readlen!=sizeof(templen)) { 
+    ERROR("failed to read all data for tag len\n");
+    return -1;
+  } 
+
+  if (templen!=taglen) { 
+    ERROR("tag size mismatch (requested=%lld, actual=%lld)\n",taglen,templen);
+    return -1;
+  }
+
+  temptag=palacios_alloc(taglen);
+
+  if (!temptag) { 
+    ERROR("Cannot allocate temptag\n");
+    return -1;
+  }
+  
+  if (read_file(fs,temptag,taglen)!=taglen) { 
+    ERROR("Cannot read tag\n");
+    palacios_free(temptag);
+    return -1;
+  }
+
+  if (memcmp(temptag,tag,taglen)) { 
+    ERROR("Tag mismatch\n");
+    palacios_free(temptag);
+    return -1;
+  }
+  
+  palacios_free(temptag);
+
+  readlen=read_file(fs,&templen,sizeof(templen));
+  
+  if (readlen!=sizeof(templen)) { 
+    ERROR("failed to read all data for data len\n");
+    return -1;
+  } 
+
+  if (templen!=len) { 
+    ERROR("datasize mismatch (requested=%lld, actual=%lld)\n",len,templen);
+    return -1;
+  }
+
+  return read_file(fs,buf,len);
+
+}
+
+
+/***************************************************************************************************
+  Textfile-based implementation  ("textfile:")
+
+  Note that this implementation uses the internal structure and functions of the 
+  "file:" implementation
+*************************************************************************************************/
+
+// optimize the reading and decoding of hex data
+// this weakens the parser, so that:
+// tag =0A0B0D 
+// will work, but
+// tag = 0A 0B 0D
+// will not.  Note the leading whitespace
+#define TEXTFILE_OPT_HEX 0
+
+//
+// The number of bytes handled at a time by the hex putter and getter
+//
+#define MAX_HEX_SEQ 64
+
+/*
+  A text file keyed stream is a file_keyed_stream,
+  only with a different stype
+*/
+
+#define PAUSE()  
+//#define PAUSE() ssleep(5) 
+
+
+typedef struct file_keyed_stream textfile_keyed_stream;
+
+typedef struct file_stream textfile_stream;
+
+
+static v3_keyed_stream_t open_stream_textfile(char *url,
+                                             v3_keyed_stream_open_t ot)
+{
+  textfile_keyed_stream *me;
+
+  if (strncasecmp(url,"textfile:",9)) { 
+    WARNING("illegitimate attempt to open textfile stream \"%s\"\n",url);
+    return 0;
+  }
+
+  me = (textfile_keyed_stream *) open_stream_file(url+4, ot);
+
+  if (!me) {
+    ERROR("could not create underlying file stream\n");
+    return 0;
+  }
+
+  me->stype=STREAM_TEXTFILE;
+
+  return me;
+}
+
+  
+
+static void close_stream_textfile(v3_keyed_stream_t stream)
+{
+  textfile_keyed_stream *me = stream;
+
+  me->stype=STREAM_FILE;
+
+  close_stream_file(me);
+
+}
+
+static void preallocate_hint_key_textfile(v3_keyed_stream_t stream,
+                                         char *key,
+                                         uint64_t size)
+{
+  textfile_keyed_stream *me = stream;
+  
+  me->stype=STREAM_FILE;
+
+  preallocate_hint_key_file(me,key,size);
+  
+  me->stype=STREAM_TEXTFILE;
+}
+
+
+static inline int isoneof(char c, char *sl, int m)
+{
+  int i;
+  
+  for (i=0;i<m;i++) { 
+    if (c==sl[i]) { 
+      return 1;
+    }
+  }
+  
+  return 0;
+}
+
+static char get_next_char(textfile_stream *s)
+{
+  char buf;
+  if (read_file(s,&buf,1)!=1) { 
+    return -1;
+  } 
+  return buf;
+}
+
+static char hexify_nybble(char c)
+{
+  if (c>=0 && c<=9) { 
+    return '0'+c;
+  } else if (c>=0xa && c<=0xf) { 
+    return 'a'+(c-0xa);
+  } else {
+    return -1;
+  }
+}
+
+static int hexify_byte(char *c, char b)
+{
+  char n;
+  n = hexify_nybble( (b >> 4) & 0xf);
+  if (n==-1) { 
+    return -1;
+  }
+  c[0] = n;
+  n = hexify_nybble( b & 0xf);
+  if (n==-1) { 
+    return -1;
+  }
+  c[1] = n;
+  return 0;
+}
+
+
+static char dehexify_nybble(char c)
+{
+  if (c>='0' && c<='9') { 
+    return c-'0';
+  } else if (c>='a' && c<='f') {
+    return 0xa + (c-'a');
+  } else if (c>='A' && c<='F') { 
+    return 0xa + (c-'A');
+  } else {
+    return -1;
+  }
+}
+
+static int dehexify_byte(char *c, char *b)
+{
+  char n;
+  n = dehexify_nybble(c[0]);
+  if (n==-1) { 
+    return -1;
+  }
+  *b = n << 4;
+  n = dehexify_nybble(c[1]);
+  if (n==-1) { 
+    return -1;
+  }
+  *b |= n;
+  return 0;
+}
+
+
+#if TEXTFILE_OPT_HEX
+
+
+// Here the sl array, of length m is the number
+static int get_hexbytes_as_data(textfile_stream *s, char *buf, int n)
+{
+  char rbuf[MAX_HEX_SEQ*2];
+  int left = n;
+  int off = 0;
+  int cur = 0;
+  int i;
+
+  while (left>0) {
+    cur = left > MAX_HEX_SEQ ? MAX_HEX_SEQ : left;
+    if (read_file(s,rbuf,cur*2)!=cur*2) { 
+      ERROR("Cannot read data in getting hexbytes as data\n");
+      return -1;
+    }
+    
+    for (i=0;i<cur;i++) {
+      if (dehexify_byte(rbuf+(i*2),buf+off+i)==-1) { 
+       ERROR("Cannot decode data as hex in getting hexbytes as data\n");
        return -1;
+      }
     }
+    left-=cur;
+    off+=cur;
+  } 
+
+  return 0;
+}    
 
-    if (len<0) { 
+#endif
+
+// Here the sl array, of length m is the set of characters to skip (e.g., whitespace)
+static int get_hexbytes_as_data_skip(textfile_stream *s, char *buf, int n, char *sl, int m)
+{
+  char rbuf[2];
+  int which = 0;
+  int cur=0;
+    
+  while (cur<n) {
+    which=0;
+    while (which<2) { 
+      rbuf[which] = get_next_char(s);
+      if (rbuf[which]==-1) { 
+       ERROR("Cannot read char in getting hexbytes as data with skiplist");
        return -1;
+      }
+      if (isoneof(rbuf[which],sl,m)) { 
+       continue;
+      } else {
+       which++;
+      }
+    }
+    if (dehexify_byte(rbuf,buf+cur)==-1) { 
+      ERROR("Cannot decode data as hex in getting hexbytes as data with skiplist\n");
+      return -1;
+    } else {
+      cur++;
     }
+  }
+  return 0;
+}    
 
-    total=len;
-    left=len;
+/*
+static int put_next_char(textfile_stream *s, char d)
+{
+  return write_file(s,&d,1);
+}
+*/
 
-    old_fs = get_fs();
-    set_fs(get_ds());
 
-    while (left>0) {
-       done = fs->f->f_op->read(fs->f, buf+(total-left), left, &(fs->f->f_pos));
-       if (done<=0) {
-           return -1;
-       } else {
-           left -= done;
-       }
+static int put_data_as_hexbytes(textfile_stream *s, char *buf, int n)
+{
+  char rbuf[MAX_HEX_SEQ*2];
+  int left = n;
+  int off = 0;
+  int cur = 0;
+  int i;
+
+  while (left>0) {
+    cur = left > MAX_HEX_SEQ ? MAX_HEX_SEQ : left;
+    for (i=0;i<cur;i++) {
+      if (hexify_byte(rbuf+(i*2),*(buf+off+i))==-1) { 
+       ERROR("Cannot encode data as hex in putting data as hexbytes\n");
+       return -1;
+      }
+    }
+    if (write_file(s,rbuf,cur*2)!=cur*2) { 
+      ERROR("Cannot write data in putting data as hexbytes\n");
+      return -1;
     }
-    set_fs(old_fs);
+    left-=cur;
+    off+=cur;
+  } 
 
-    return len;
+  return 0;
+}    
+
+
+static int put_string_n(textfile_stream *s, char *buf, int n)
+{
+  int rc;
+
+  rc = write_file(s,buf,n);
+  
+  if (rc!=n) { 
+    return -1;
+  } else {
+    return 0;
+  }
+}
+
+static int put_string(textfile_stream *s, char *buf)
+{
+  int n=strlen(buf);
+
+  return put_string_n(s,buf,n);
+}
+
+
+
+static int search_for(textfile_stream *s, char d)
+{
+  char c;
+  do {
+    c=get_next_char(s);
+  } while (c!=-1 && c!=d);
+  
+  if (c==d) { 
+    return 0;
+  } else {
+    return -1;
+  }
+}
+
+/*
+static int skip_matching(textfile_stream *s, char *m, int n)
+{
+  char c;
+  int rc = 0;
+  int i;
+
+  while (rc==0) { 
+    c=get_next_char(s);
+    if (c==-1) { 
+      rc=-1;
+    } else {
+      for (i=0;i<n;i++) { 
+       if (c==m[i]) {
+         rc=1;
+         break;
+       } 
+      }
+    }
+  }
+  
+  if (rc==1) { 
+    return 0;  // found
+  } else {
+    return rc; // unknown
+  }
+}
+
+*/
 
+
+static int token_scan(textfile_stream *s, char *token, int n, char *sl, int m)
+{
+  char c;
+  int cur;
+
+  // Skip whitespace
+  do {
+    c=get_next_char(s);
+    if (c==-1) { 
+      ERROR("Failed to get character during token scan (preceding whitespace)\n");
+      return -1;
+    }
+  } while (isoneof(c,sl,m));
+
+
+  token[0]=c;
+  
+  // Record
+  cur=1;
+  while (cur<(n-1)) { 
+    c=get_next_char(s);
+    if (c==-1) { 
+      ERROR("Failed to get character during token scan (token)\n");
+      return -1;
+    }
+    if (isoneof(c,sl,m)) { 
+      break;
+    } else {
+      token[cur]=c;
+      cur++;
+    } 
+  }
+  token[cur]=0;
+  return 0;
 }
 
 
 
+static v3_keyed_stream_key_t open_key_textfile(v3_keyed_stream_t stream,
+                                              char *key)
+{
+  textfile_keyed_stream *mks = stream;
+  textfile_stream *ms;
+
+  mks->stype=STREAM_FILE;
+
+  ms = open_key_file(mks,key);
+
+  if (!ms) { 
+    ERROR("cannot open underlying file keyed stream for key %s\n",key);
+    mks->stype=STREAM_TEXTFILE;
+    return 0;
+  }
+
+  if (mks->ot==V3_KS_WR_ONLY) { 
+    
+    // Now we write the section header
+
+    ms->stype=STREAM_FILE;
+    
+    if (put_string(ms,"[")) { 
+      close_key_file(mks,ms);
+      mks->stype=STREAM_TEXTFILE;
+      return 0;
+    }
+    
+    if (put_string(ms,key)) { 
+      close_key_file(mks,ms);
+      mks->stype=STREAM_TEXTFILE;
+      return 0;
+    }
+    
+    if (put_string(ms,"]\n")) {
+      close_key_file(mks,ms);
+      mks->stype=STREAM_TEXTFILE;
+      return 0;
+    }
+    
+    
+    mks->stype=STREAM_TEXTFILE;
+    ms->stype=STREAM_TEXTFILE;
+
+    return ms;
+
+  } else if (mks->ot == V3_KS_RD_ONLY) {
+    // Now we readthe section header
+    int keylen=strlen(key);
+    char *tempkey = palacios_alloc(keylen+3);
+
+    ms->stype=STREAM_FILE;
+
+    if (!tempkey) { 
+      ERROR("Allocation failed in opening key\n");
+      close_key_file(mks,ms);
+      mks->stype=STREAM_FILE;
+      return 0;
+    }
+
+
+    if (token_scan(ms,tempkey,keylen+3,"\t\r\n",3)) { 
+      ERROR("Cannot scan for token (key search)\n");
+      close_key_file(mks,ms);
+      mks->stype=STREAM_TEXTFILE;
+      palacios_free(tempkey);
+      return 0;
+    }
+    
+    tempkey[keylen+2] = 0;
+    
+    // Should now have [key]0
+
+    if (tempkey[0]!='[' ||
+       tempkey[keylen+1]!=']' ||
+       memcmp(key,tempkey+1,keylen)) {
+      ERROR("key mismatch: target key=%s, found %s\n",key,tempkey);
+      palacios_free(tempkey);
+      close_key_file(mks,ms);
+      mks->stype=STREAM_TEXTFILE;
+      return 0;
+    }
+
+    // key match done, success
+
+    mks->stype=STREAM_TEXTFILE;
+    ms->stype=STREAM_TEXTFILE;
+
+    palacios_free(tempkey);
+
+    return ms;
+    
+  } else {
+    ERROR("Unknown open type in open_key_textfile\n");
+    ms->stype=STREAM_FILE;
+    close_key_file(mks,ms);
+    return 0;
+  }
+
+}
+
+
+
+static void close_key_textfile(v3_keyed_stream_t stream, 
+                              v3_keyed_stream_key_t key)
+{
+  textfile_keyed_stream *mks = stream;
+  textfile_stream *ms=key;
+
+  mks->stype=STREAM_FILE;
+  ms->stype=STREAM_FILE;
+
+  close_key_file(mks,ms);
+
+  mks->stype=STREAM_TEXTFILE;
+
+}
+
+
+static sint64_t read_key_textfile(v3_keyed_stream_t stream, 
+                                 v3_keyed_stream_key_t key,
+                                 void *tag,
+                                 sint64_t taglen,
+                                 void *buf,
+                                 sint64_t len)
+{
+    textfile_stream *ms = (textfile_stream *) key;
+    char tags[32];
+    char *temptag;
+
+
+
+    memcpy(tags,tag,taglen<31 ? taglen : 31);
+    tags[taglen<32? taglen : 31 ]=0;
+    
+    temptag=palacios_alloc(taglen+1);
+    if (!temptag) { 
+      ERROR("Unable to allocate temptag in textfile read key\n");
+      return -1;
+    }
+
+    ms->stype=STREAM_FILE;
+    
+    if (token_scan(ms,temptag,taglen+1," \t\r\n=",5)) { 
+      ERROR("Cannot scan for token (tag search)\n");
+      ms->stype=STREAM_TEXTFILE;
+      palacios_free(temptag);
+      return -1;
+    }
+
+    if (memcmp(tag,temptag,taglen)) { 
+      ERROR("Tag mismatch in reading tag from textfile: desired tag=%s, actual tag=%s\n",tags,temptag);
+      ms->stype=STREAM_TEXTFILE;
+      palacios_free(temptag);
+      return -1;
+    }
+
+    // tag matches, let's go and find our =
+    palacios_free(temptag);
+
+    if (search_for(ms,'=')) { 
+      ERROR("Unable to find = sign in tag data parse (tag=%s)\n", tags);
+      ms->stype=STREAM_TEXTFILE;
+      return -1;
+    }
+
+
+#if TEXTFILE_OPT_HEX
+    if (get_hexbytes_as_data(ms,buf,len)) { 
+      ERROR("Cannot read data in hex format (opt path) in textfile for tag %s\n",tags);
+      ms->stype=STREAM_TEXTFILE;
+      return -1;
+    }
+#else
+    if (get_hexbytes_as_data_skip(ms,buf,len," \t\r\n",4)) { 
+      ERROR("Cannot read data in hex format (unopt path) in textfile for tag %s\n",tags);
+      ms->stype=STREAM_TEXTFILE;
+      return -1;
+    }
+#endif
+
+    ms->stype=STREAM_TEXTFILE;
+
+    return len;
+}
+
+static sint64_t write_key_textfile(v3_keyed_stream_t stream, 
+                                  v3_keyed_stream_key_t key,
+                                  void *tag,
+                                  sint64_t taglen,
+                                  void *buf,
+                                  sint64_t len)
+{
+    textfile_stream *ms = (textfile_stream *) key;
+    char tags[32];
+
+
+
+    memcpy(tags,tag,taglen<31 ? taglen : 31);
+    tags[taglen<32? taglen : 31 ]=0;
+
+    /*    if (taglen>100000 || len>100000) { 
+      ERROR("Too big\n");
+      return -1;
+    }
+    */
+
+    ms->stype=STREAM_FILE;
+
+    if (put_string_n(ms,tag,taglen)) { 
+      ERROR("Cannot write tag %s in textfile\n",tags);
+      ms->stype=STREAM_TEXTFILE;
+      return -1;
+    }
+
+    if (put_string(ms,"=")) { 
+      ERROR("Cannot write = in textfile for tag %s\n",tags);
+      ms->stype=STREAM_TEXTFILE;
+      return -1;
+    }
+
+    if (put_data_as_hexbytes(ms,buf,len)) { 
+      ERROR("Cannot write data in hex format in textfile for tag %s\n",tags);
+      ms->stype=STREAM_TEXTFILE;
+      return -1;
+    }
+
+    if (put_string(ms,"\n")) { 
+      ERROR("Cannot write trailing lf in textfile for tag %s\n",tags);
+      ms->stype=STREAM_TEXTFILE;
+      return -1;
+    }
+
+    ms->stype=STREAM_TEXTFILE;
+
+    return len;
+}
+
+
 
 /***************************************************************************************************
   User implementation   ("user:")
@@ -805,7 +1754,7 @@ static int resize_op(struct palacios_user_keyed_stream_op **op, uint64_t buf_len
     struct palacios_user_keyed_stream_op *new;
     
     if (!old) {
-       new = kmalloc(sizeof(struct palacios_user_keyed_stream_op)+buf_len,GFP_ATOMIC);
+       new = palacios_alloc(sizeof(struct palacios_user_keyed_stream_op)+buf_len);
        if (!new) { 
            return -1;
        } else {
@@ -819,7 +1768,7 @@ static int resize_op(struct palacios_user_keyed_stream_op **op, uint64_t buf_len
            old->buf_len=buf_len;
            return 0;
        } else {
-           kfree(old);
+           palacios_free(old);
            *op = 0 ;
            return resize_op(op,buf_len);
        }
@@ -843,7 +1792,7 @@ static int do_request_to_response(struct user_keyed_stream *s, unsigned long *fl
     s->waiting = 1;
 
     // release the stream
-    spin_unlock_irqrestore(&(s->lock), *flags);
+    palacios_spinlock_unlock_irqrestore(&(s->lock), *flags);
 
     // wake up anyone waiting on it
     wake_up_interruptible(&(s->user_wait_queue));
@@ -852,7 +1801,7 @@ static int do_request_to_response(struct user_keyed_stream *s, unsigned long *fl
     while (wait_event_interruptible(s->host_wait_queue, (s->waiting == 0)) != 0) {}
 
     // reacquire the lock for our called
-    spin_lock_irqsave(&(s->lock), *flags);
+    palacios_spinlock_lock_irqsave(&(s->lock), *flags);
 
     return 0;
 }
@@ -873,7 +1822,7 @@ static int do_response_to_request(struct user_keyed_stream *s, unsigned long *fl
     s->waiting = 0;
 
     // release the stream
-    spin_unlock_irqrestore(&(s->lock), *flags);
+    palacios_spinlock_unlock_irqrestore(&(s->lock), *flags);
 
     // wake up anyone waiting on it
     wake_up_interruptible(&(s->host_wait_queue));
@@ -892,16 +1841,16 @@ static unsigned int keyed_stream_poll_user(struct file *filp, poll_table *wait)
         return POLLERR;
     }
     
-    spin_lock_irqsave(&(s->lock), flags);
+    palacios_spinlock_lock_irqsave(&(s->lock), flags);
+
+    poll_wait(filp, &(s->user_wait_queue), wait);
 
     if (s->waiting) {
-       spin_unlock_irqrestore(&(s->lock), flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
        return POLLIN | POLLRDNORM;
     }
-
-    poll_wait(filp, &(s->user_wait_queue), wait);
     
-    spin_unlock_irqrestore(&(s->lock), flags);
+    palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
 
     return 0;
 }
@@ -920,22 +1869,22 @@ static long keyed_stream_ioctl_user(struct file * filp, unsigned int ioctl, unsi
            
            // inform request size
            
-           spin_lock_irqsave(&(s->lock), flags);
+           palacios_spinlock_lock_irqsave(&(s->lock), flags);
            
            if (!(s->waiting)) {
-               spin_unlock_irqrestore(&(s->lock), flags);
+               palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
                return 0;
            }
 
            size =  sizeof(struct palacios_user_keyed_stream_op) + s->op->buf_len;
            
            if (copy_to_user((void * __user) argp, &size, sizeof(uint64_t))) {
-               spin_unlock_irqrestore(&(s->lock), flags);
+               palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
                ERROR("palacios user key size request failed to copy data\n");
                return -EFAULT;
            }
            
-           spin_unlock_irqrestore(&(s->lock), flags);
+           palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
            
            return 1;
            
@@ -945,10 +1894,10 @@ static long keyed_stream_ioctl_user(struct file * filp, unsigned int ioctl, unsi
                
            // pull the request
            
-           spin_lock_irqsave(&(s->lock), flags);
+           palacios_spinlock_lock_irqsave(&(s->lock), flags);
 
            if (!(s->waiting)) {
-               spin_unlock_irqrestore(&(s->lock), flags);
+               palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
                ERROR("palacios user key pull request when not waiting\n");
                return 0;
            }
@@ -957,12 +1906,12 @@ static long keyed_stream_ioctl_user(struct file * filp, unsigned int ioctl, unsi
 
 
            if (copy_to_user((void __user *) argp, s->op, size)) {
-               spin_unlock_irqrestore(&(s->lock), flags);
+               palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
                ERROR("palacios user key pull request failed to copy data\n");
                return -EFAULT;
            }
 
-           spin_unlock_irqrestore(&(s->lock), flags);
+           palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
            
            return 1;
            
@@ -973,28 +1922,29 @@ static long keyed_stream_ioctl_user(struct file * filp, unsigned int ioctl, unsi
 
         // push the response
 
-        spin_lock_irqsave(&(s->lock), flags);
+        palacios_spinlock_lock_irqsave(&(s->lock), flags);
 
         if (!(s->waiting)) {
-            spin_unlock_irqrestore(&(s->lock), flags);
+            palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
            ERROR("palacios user key push response when not waiting\n");
             return 0;
         }
        
         if (copy_from_user(&size, (void __user *) argp, sizeof(uint64_t))) {
            ERROR("palacios user key push response failed to copy size\n");
-            spin_unlock_irqrestore(&(s->lock), flags);
+            palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
             return -EFAULT;
         }
 
+       // overflow possible here for very large request
        if (resize_op(&(s->op),size-sizeof(struct palacios_user_keyed_stream_op))) {
            ERROR("unable to resize op in user key push response\n");
-            spin_unlock_irqrestore(&(s->lock), flags);
+            palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
            return -EFAULT;
        }
 
         if (copy_from_user(s->op, (void __user *) argp, size)) {
-            spin_unlock_irqrestore(&(s->lock), flags);
+            palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
             return -EFAULT;
         }
 
@@ -1021,16 +1971,16 @@ static int keyed_stream_release_user(struct inode *inode, struct file *filp)
     struct user_keyed_stream *s = filp->private_data;
     unsigned long f1,f2;
 
-    spin_lock_irqsave(&(user_streams->lock),f1);
-    spin_lock_irqsave(&(s->lock), f2);
+    palacios_spinlock_lock_irqsave(&(user_streams->lock),f1);
+    palacios_spinlock_lock_irqsave(&(s->lock), f2);
 
     list_del(&(s->node));
 
-    spin_unlock_irqrestore(&(s->lock), f2);
-    spin_unlock_irqrestore(&(user_streams->lock), f1);
+    palacios_spinlock_unlock_irqrestore(&(s->lock), f2);
+    palacios_spinlock_unlock_irqrestore(&(user_streams->lock), f1);
     
-    kfree(s->url);
-    kfree(s);
+    palacios_free(s->url);
+    palacios_free(s);
 
     return 0;
 }
@@ -1068,7 +2018,8 @@ int keyed_stream_connect_user(struct v3_guest *guest, unsigned int cmd, unsigned
        return -1;
     }
 
-    url = kmalloc(len,GFP_KERNEL);
+    // overflow possible here, but only if this is a huge guest request (>4GB)
+    url = palacios_alloc(len);
     
     if (!url) { 
        ERROR("cannot allocate url for user keyed stream\n");
@@ -1083,22 +2034,22 @@ int keyed_stream_connect_user(struct v3_guest *guest, unsigned int cmd, unsigned
        
     
     // Check for duplicate handler
-    spin_lock_irqsave(&(user_streams->lock), flags);
+    palacios_spinlock_lock_irqsave(&(user_streams->lock), flags);
     list_for_each_entry(s, &(user_streams->streams), node) {
         if (!strncasecmp(url, s->url, len)) {
             ERROR("user keyed stream connection with url \"%s\" already exists\n", url);
-           kfree(url);
+           palacios_free(url);
             return -1;
         }
     }
-    spin_unlock_irqrestore(&(user_streams->lock), flags);
+    palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags);
     
     // Create connection
-    s = kmalloc(sizeof(struct user_keyed_stream), GFP_KERNEL);
+    s = palacios_alloc(sizeof(struct user_keyed_stream));
     
     if (!s) {
        ERROR("cannot allocate new user keyed stream for %s\n",url);
-       kfree(url);
+       palacios_free(url);
         return -1;
     }
     
@@ -1108,8 +2059,8 @@ int keyed_stream_connect_user(struct v3_guest *guest, unsigned int cmd, unsigned
 
     if (fd < 0) {
        ERROR("cannot allocate file descriptor for new user keyed stream for %s\n",url);
-        kfree(s);
-       kfree(url);
+        palacios_free(s);
+       palacios_free(url);
         return -1;
     }
     
@@ -1122,9 +2073,9 @@ int keyed_stream_connect_user(struct v3_guest *guest, unsigned int cmd, unsigned
     init_waitqueue_head(&(s->host_wait_queue));
     
     // Insert connection into list
-    spin_lock_irqsave(&(user_streams->lock), flags);
+    palacios_spinlock_lock_irqsave(&(user_streams->lock), flags);
     list_add(&(s->node), &(user_streams->streams));
-    spin_unlock_irqrestore(&(user_streams->lock), flags);
+    palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags);
     
     return fd;
 }
@@ -1139,15 +2090,15 @@ static struct user_keyed_stream *keyed_stream_user_find(char *url)
        return NULL;
     }
     
-    spin_lock_irqsave(&(user_streams->lock), flags);
+    palacios_spinlock_lock_irqsave(&(user_streams->lock), flags);
     list_for_each_entry(s, &(user_streams->streams), node) {
         if (!strcasecmp(url, s->url)) {
-            spin_unlock_irqrestore(&(user_streams->lock), flags);
+            palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags);
             return s;
         }
     }
     
-    spin_unlock_irqrestore(&(user_streams->lock), flags);
+    palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags);
     
     return NULL;
 }
@@ -1165,17 +2116,17 @@ static v3_keyed_stream_t open_stream_user(char *url, v3_keyed_stream_open_t ot)
         return NULL;
     }
 
-    spin_lock_irqsave(&(s->lock), flags);
+    palacios_spinlock_lock_irqsave(&(s->lock), flags);
 
     if (s->waiting) {
-        spin_unlock_irqrestore(&(s->lock), flags);
+        palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
        ERROR("cannot open user stream %s as it is already in waiting state\n",url);
         return NULL;
     }
     
     s->otype = ot==V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot;
     
-    spin_unlock_irqrestore(&(s->lock), flags);
+    palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
     
     return s;
     
@@ -1206,22 +2157,22 @@ static v3_keyed_stream_key_t open_key_user(v3_keyed_stream_t stream, char *key)
     uint64_t   len = strlen(key)+1;
     void *user_key;
 
-    spin_lock_irqsave(&(s->lock), flags);
+    palacios_spinlock_lock_irqsave(&(s->lock), flags);
 
 
     if (resize_op(&(s->op),len)) {
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("cannot resize op in opening key %s on user keyed stream %s\n",key,s->url);
        return NULL;
     }
 
     s->op->type = PALACIOS_KSTREAM_OPEN_KEY;
     s->op->buf_len = len;
-    strncpy(s->op->buf,key,len);
+    strncpy(s->op->buf,key,len); // will terminate buffer
 
     // enter with it locked
     if (do_request_to_response(s,&flags)) { 
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("request/response handling failed\n");
        return NULL;
     }
@@ -1229,7 +2180,7 @@ static v3_keyed_stream_key_t open_key_user(v3_keyed_stream_t stream, char *key)
 
     user_key=s->op->user_key;
 
-    spin_unlock_irqrestore(&(s->lock),flags);
+    palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
 
     return user_key;
 }
@@ -1240,10 +2191,10 @@ static void close_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t key)
     uint64_t   len = 0;
     unsigned long flags;
     
-    spin_lock_irqsave(&(s->lock), flags);
+    palacios_spinlock_lock_irqsave(&(s->lock), flags);
 
     if (resize_op(&(s->op),len)) {
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("cannot resize op in closing key 0x%p on user keyed stream %s\n",key,s->url);
        return;
     }
@@ -1254,13 +2205,13 @@ static void close_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t key)
 
     // enter with it locked
     if (do_request_to_response(s,&flags)) { 
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("request/response handling failed\n");
        return;
     }
     // return with it locked
 
-    spin_unlock_irqrestore(&(s->lock),flags);
+    palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
 
     return;
 }
@@ -1268,23 +2219,26 @@ static void close_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t key)
 
 
 static sint64_t read_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t key,
+                             void *tag,
+                             sint64_t taglen,
                              void *buf, sint64_t rlen)
 {
 
     struct user_keyed_stream *s = (struct user_keyed_stream *) stream;
-    uint64_t   len = 0 ;
+    uint64_t   len = taglen ;
     sint64_t   xfer;
     unsigned long flags;
 
-    spin_lock_irqsave(&(s->lock), flags);
+    palacios_spinlock_lock_irqsave(&(s->lock), flags);
 
     if (s->otype != V3_KS_RD_ONLY) { 
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("attempt to read key from stream that is not in read state on %s\n",s->url);
     }  
 
+
     if (resize_op(&(s->op),len)) {
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("cannot resize op in reading key 0x%p on user keyed stream %s\n",key,s->url);
        return -1;
     }
@@ -1293,10 +2247,13 @@ static sint64_t read_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t ke
     s->op->buf_len = len ;
     s->op->xfer = rlen;
     s->op->user_key = key;
+    s->op->data_off = taglen;
+
+    memcpy(s->op->buf,tag,taglen);
 
     // enter with it locked
     if (do_request_to_response(s,&flags)) { 
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("request/response handling failed\n");
        return -1;
     }
@@ -1304,60 +2261,65 @@ static sint64_t read_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t ke
 
 
     if (s->op->xfer>0) { 
+        // data_off must be zero
        memcpy(buf,s->op->buf,s->op->xfer);
     }
 
     xfer=s->op->xfer;
 
-    spin_unlock_irqrestore(&(s->lock),flags);
+    palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
 
     return xfer;
 }
 
 
 static sint64_t write_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t key,
+                              void *tag,
+                              sint64_t taglen,
                               void *buf, sint64_t wlen)
 {
 
     struct user_keyed_stream *s = (struct user_keyed_stream *) stream;
-    struct palacios_user_keyed_stream_op *op;
-    uint64_t   len = wlen ;
+    uint64_t   len = taglen + wlen ;
     sint64_t   xfer;
     unsigned long flags;
-    
-    spin_lock_irqsave(&(s->lock), flags);
+
+
+    palacios_spinlock_lock_irqsave(&(s->lock), flags);
 
     if (s->otype != V3_KS_WR_ONLY) { 
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("attempt to write key on stream that is not in write state on %s\n",s->url);
     }  
 
     if (resize_op(&(s->op),len)) {
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("cannot resize op in reading key 0x%p on user keyed stream %s\n",key,s->url);
        return -1;
     }
 
-    op = s->op;
-
     s->op->type = PALACIOS_KSTREAM_WRITE_KEY;
     s->op->buf_len = len;
     s->op->xfer = wlen;
     s->op->user_key = key;
+    s->op->data_off = taglen;
 
-    memcpy(s->op->buf,buf,wlen);
+    memcpy(s->op->buf,tag,taglen);
+    memcpy(s->op->buf+taglen,buf,wlen);
 
     // enter with it locked
     if (do_request_to_response(s,&flags)) { 
-       spin_unlock_irqrestore(&(s->lock),flags);
+       palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
        ERROR("request/response handling failed\n");
        return -1;
     }
     // return with it locked
 
+    // no data comes back, xfer should be size of data write (not tag)
+
     xfer=s->op->xfer;
 
-    spin_unlock_irqrestore(&(s->lock),flags);
+    palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
 
     return xfer;
 }
@@ -1388,7 +2350,7 @@ static struct net_stream * create_net_stream(void)
 {
     struct net_stream * ns = NULL;
 
-    ns = kmalloc(sizeof(struct net_stream), GFP_KERNEL);
+    ns = palacios_alloc(sizeof(struct net_stream));
     
     if (!ns) { 
        ERROR("Cannot allocate a net_stream\n");
@@ -1411,11 +2373,11 @@ static void close_socket(v3_keyed_stream_t stream)
 
        if (ns) {
            ns->sock->ops->release(ns->sock);
-           kfree(ns);
+           palacios_free(ns);
            ERROR("Close Socket\n");
        }
        
-       kfree(ns);
+       palacios_free(ns);
     }
 }
 
@@ -1473,8 +2435,12 @@ static int send_msg(struct net_stream *ns,  char * buf, int len)
        msg.msg_namelen = 0;
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
+#else
+       iov_iter_init(&(msg.msg_iter),WRITE,&iov,1,0);
+#endif
 
        iov.iov_base = (char *)&(buf[len-left]);
        iov.iov_len = (size_t)left;
@@ -1527,8 +2493,12 @@ static int recv_msg(struct net_stream *ns, char * buf, int len)
        msg.msg_namelen = 0;
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
+#else
+       iov_iter_init(&(msg.msg_iter),READ,&iov,1,0);
+#endif
        
        iov.iov_base = (void *)&(buf[len-left]);
        iov.iov_len = (size_t)left;
@@ -1601,7 +2571,7 @@ static struct net_stream * accept_once(struct net_stream * ns, const int port)
     
     // close the accept socket
     accept_sock->ops->release(accept_sock);
-    kfree(accept_sock);
+    palacios_free(accept_sock);
 
     return ns;
 }
@@ -1618,7 +2588,7 @@ static struct v3_keyed_stream_t * open_stream_net(char * url,v3_keyed_stream_ope
     int ip_len;
     int port_len;
 
-    nks = kmalloc(sizeof(struct net_keyed_stream),GFP_KERNEL); 
+    nks = palacios_alloc(sizeof(struct net_keyed_stream)); 
 
     if (!nks) { 
        ERROR("Could not allocate space in open_stream_net\n");
@@ -1633,7 +2603,7 @@ static struct v3_keyed_stream_t * open_stream_net(char * url,v3_keyed_stream_ope
     
     if (!(nks->ns)) { 
        ERROR("Could not create network stream\n");
-       kfree(nks);
+       palacios_free(nks);
        return 0;
     }
 
@@ -1684,7 +2654,7 @@ static struct v3_keyed_stream_t * open_stream_net(char * url,v3_keyed_stream_ope
            connect_to_ip(nks->ns,host_ip, host_port);
        } else {
            ERROR("Mode not recognized\n");
-           kfree(nks);
+           palacios_free(nks);
            return NULL;
        }
        
@@ -1856,7 +2826,10 @@ static void close_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t input_
     }
 }
 
-static sint64_t write_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t key, void *buf, sint64_t len) 
+static sint64_t write_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t key, 
+                             void *tag,
+                             sint64_t taglen,
+                             void *buf, sint64_t len) 
 {
     struct net_keyed_stream * nks = (struct net_keyed_stream *)stream;
 
@@ -1865,10 +2838,20 @@ static sint64_t write_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t ke
        return -1;
     }
 
+    if (!tag) { 
+       ERROR("Tag is NULL in write_key_net\n");
+       return -1;
+    }
+
     if (len<0) {
        ERROR("len is negative in write_key_net\n");
        return -1;
     }
+
+    if (taglen<0) {
+       ERROR("taglen is negative in write_key_net\n");
+       return -1;
+    }
     
     if (!key){
        ERROR("write_key: key is NULL in write_key_net\n");
@@ -1882,6 +2865,18 @@ static sint64_t write_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t ke
     }
     
     if (nks->ot==V3_KS_WR_ONLY) {
+        if (send_msg(nks->ns,(char*)(&BOUNDARY_TAG),sizeof(BOUNDARY_TAG))!=sizeof(BOUNDARY_TAG)) { 
+           ERROR("Could not send boundary tag in write_key_net\n");
+           return -1;
+       } 
+       if (send_msg(nks->ns,(char*)(&taglen),sizeof(taglen))!=sizeof(taglen)) { 
+           ERROR("Could not send tag length in write_key_net\n");
+           return -1;
+       } 
+       if (send_msg(nks->ns,tag,taglen)!=taglen) { 
+           ERROR("Could not send tag in write_key_net\n");
+           return -1;
+       }
        if (send_msg(nks->ns,(char*)(&len),sizeof(len))!=sizeof(len)) { 
            ERROR("Could not send data length in write_key_net\n");
            return -1;
@@ -1899,19 +2894,33 @@ static sint64_t write_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t ke
 }
 
 
-static sint64_t read_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t key, void *buf, sint64_t len)
+static sint64_t read_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t key,
+                            void *tag,
+                            sint64_t taglen,
+                            void *buf, sint64_t len)
 {
     struct net_keyed_stream * nks = (struct net_keyed_stream *)stream;
+    void *temptag;
 
     if (!buf) {
        ERROR("Buf is NULL in read_key_net\n");
        return -1;
     }
+
+    if (!tag) {
+       ERROR("Tag is NULL in read_key_net\n");
+       return -1;
+    }
     
     if(len<0) {
        ERROR("len is negative in read_key_net\n");
        return -1;
     }
+
+    if(taglen<0) {
+       ERROR("taglen is negative in read_key_net\n");
+       return -1;
+    }
     
     if (!key) {
        ERROR("read_key: key is NULL in read_key_net\n");
@@ -1920,23 +2929,69 @@ static sint64_t read_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t key
 
 
     if (nks->ot==V3_KS_RD_ONLY) {
+        
+        sint64_t slen;
+       uint32_t tempbt;
+       
+       if (recv_msg(nks->ns,(char*)(&tempbt),sizeof(tempbt))!=sizeof(tempbt)) { 
+           ERROR("Cannot receive boundary tag in read_key_net\n");
+           return -1;
+       }
 
-       sint64_t slen;
+       if (tempbt!=BOUNDARY_TAG) { 
+         ERROR("Invalid boundary tag (received 0x%x\n",tempbt);
+         return -1;
+       }
            
+        temptag=palacios_alloc(taglen);
+        if (!temptag) {
+         ERROR("failed to allocate temptag\n");
+         return -1;
+        }
+
+       if (recv_msg(nks->ns,(char*)(&slen),sizeof(slen))!=sizeof(slen)) { 
+           ERROR("Cannot receive tag len in read_key_net\n");
+           palacios_free(temptag);
+           return -1;
+       }
+
+       if (slen!=taglen) {
+           ERROR("Tag len expected does not matched tag len decoded in read_key_net\n");
+           palacios_free(temptag);
+           return -1;
+       }
+
+       if (recv_msg(nks->ns,temptag,taglen)!=taglen) { 
+           ERROR("Cannot recieve tag in read_key_net\n");
+           palacios_free(temptag);
+           return -1;
+       }
+
+       if (memcmp(temptag,tag,taglen)) { 
+         ERROR("Tag mismatch\n");
+         palacios_free(temptag);
+         return -1;
+       }
+
        if (recv_msg(nks->ns,(char*)(&slen),sizeof(slen))!=sizeof(slen)) { 
            ERROR("Cannot receive data len in read_key_net\n");
+           palacios_free(temptag);
            return -1;
        }
 
        if (slen!=len) {
            ERROR("Data len expected does not matched data len decoded in read_key_net\n");
+           palacios_free(temptag);
            return -1;
        }
 
        if (recv_msg(nks->ns,buf,len)!=len) { 
            ERROR("Cannot recieve data in read_key_net\n");
+           palacios_free(temptag);
            return -1;
        }
+
+       palacios_free(temptag);
        
     } else {
         ERROR("Permissions incorrect for the stream in read_key_net\n");
@@ -1961,8 +3016,10 @@ static v3_keyed_stream_t open_stream(char *url,
        return open_stream_file(url,ot);
     } else if (!strncasecmp(url,"user:",5)) { 
        return open_stream_user(url,ot);
-    } else if(!strncasecmp(url,"net:",4)){
+    } else if (!strncasecmp(url,"net:",4)){
        return open_stream_net(url,ot);
+    } else if (!strncasecmp(url,"textfile:",9)) { 
+        return open_stream_textfile(url,ot);
     } else {
        ERROR("unsupported type in attempt to open keyed stream \"%s\"\n",url);
        return 0;
@@ -1979,6 +3036,9 @@ static void close_stream(v3_keyed_stream_t stream)
        case STREAM_FILE:
            return close_stream_file(stream);
            break;
+       case STREAM_TEXTFILE:
+           return close_stream_textfile(stream);
+           break;
        case STREAM_USER:
            return close_stream_user(stream);
            break;
@@ -2003,6 +3063,9 @@ static void preallocate_hint_key(v3_keyed_stream_t stream,
        case STREAM_FILE:
            preallocate_hint_key_file(stream,key,size);
            break;
+       case STREAM_TEXTFILE:
+           preallocate_hint_key_textfile(stream,key,size);
+           break;
        case STREAM_USER:
            return preallocate_hint_key_user(stream,key,size);
            break;
@@ -2028,6 +3091,9 @@ static v3_keyed_stream_key_t open_key(v3_keyed_stream_t stream,
        case STREAM_FILE:
            return open_key_file(stream,key);
            break;
+       case STREAM_TEXTFILE:
+           return open_key_textfile(stream,key);
+           break;
        case STREAM_USER:
            return open_key_user(stream,key);
            break;
@@ -2053,6 +3119,9 @@ static void close_key(v3_keyed_stream_t stream,
        case STREAM_FILE:
            return close_key_file(stream,key);
            break;
+       case STREAM_TEXTFILE:
+           return close_key_textfile(stream,key);
+           break;
        case STREAM_USER:
            return close_key_user(stream,key);
            break;
@@ -2069,22 +3138,27 @@ static void close_key(v3_keyed_stream_t stream,
 
 static sint64_t write_key(v3_keyed_stream_t stream, 
                          v3_keyed_stream_key_t key,
+                         void *tag,
+                         sint64_t taglen,
                          void *buf,
                          sint64_t len)
 {
     struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
     switch (gks->stype){ 
        case STREAM_MEM:
-           return write_key_mem(stream,key,buf,len);
+           return write_key_mem(stream,key,tag,taglen,buf,len);
            break;
        case STREAM_FILE:
-           return write_key_file(stream,key,buf,len);
+           return write_key_file(stream,key,tag,taglen,buf,len);
+           break;
+       case STREAM_TEXTFILE:
+           return write_key_textfile(stream,key,tag,taglen,buf,len);
            break;
        case STREAM_USER:
-           return write_key_user(stream,key,buf,len);
+           return write_key_user(stream,key,tag,taglen,buf,len);
            break;
        case STREAM_NETWORK:
-           return write_key_net(stream,key,buf,len);
+           return write_key_net(stream,key,tag,taglen,buf,len);
            break;
        default:
            ERROR("unknown stream type %d in write_key\n",gks->stype);
@@ -2097,22 +3171,27 @@ static sint64_t write_key(v3_keyed_stream_t stream,
 
 static sint64_t read_key(v3_keyed_stream_t stream, 
                         v3_keyed_stream_key_t key,
+                        void *tag,
+                        sint64_t taglen,
                         void *buf,
                         sint64_t len)
 {
     struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
     switch (gks->stype){ 
        case STREAM_MEM:
-           return read_key_mem(stream,key,buf,len);
+         return read_key_mem(stream,key,tag,taglen,buf,len);
            break;
        case STREAM_FILE:
-           return read_key_file(stream,key,buf,len);
+           return read_key_file(stream,key,tag,taglen,buf,len);
+           break;
+       case STREAM_TEXTFILE:
+           return read_key_textfile(stream,key,tag,taglen,buf,len);
            break;
        case STREAM_USER:
-           return read_key_user(stream,key,buf,len);
+           return read_key_user(stream,key,tag,taglen,buf,len);
            break;
        case STREAM_NETWORK:
-           return read_key_net(stream,key,buf,len);
+           return read_key_net(stream,key,tag,taglen,buf,len);
            break;
        default:
            ERROR("unknown stream type %d in read_key\n",gks->stype);
@@ -2150,7 +3229,7 @@ static int init_keyed_streams( void )
        return -1;
     }
 
-    user_streams = kmalloc(sizeof(struct user_keyed_streams),GFP_KERNEL);
+    user_streams = palacios_alloc(sizeof(struct user_keyed_streams));
 
     if (!user_streams) { 
        ERROR("failed to allocated list for user streams\n");
@@ -2159,7 +3238,7 @@ static int init_keyed_streams( void )
 
     INIT_LIST_HEAD(&(user_streams->streams));
     
-    spin_lock_init(&(user_streams->lock));
+    palacios_spinlock_init(&(user_streams->lock));
 
     V3_Init_Keyed_Streams(&hooks);
 
@@ -2171,7 +3250,9 @@ static int deinit_keyed_streams( void )
 {
     palacios_free_htable(mem_streams,1,1);
 
-    kfree(user_streams);
+    palacios_spinlock_deinit(&(user_streams->lock));
+
+    palacios_free(user_streams);
 
     WARNING("Deinit of Palacios Keyed Streams likely leaked memory\n");
 
@@ -2190,6 +3271,7 @@ static int guest_init_keyed_streams(struct v3_guest * guest, void ** vm_data )
 
 static int guest_deinit_keyed_streams(struct v3_guest * guest, void * vm_data)
 {
+    remove_guest_ctrl(guest, V3_VM_KSTREAM_USER_CONNECT);
 
     return 0;
 }