X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=linux_module%2Fiface-keyed-stream.c;h=1f75aa0120725405ea84fa51d0c2c9e6ead88c81;hb=c8b23e99efde3aa5a2c26d1b8e9bc7dc914e6113;hp=d84847a63298acf95b66449724ffa3b2e03f885d;hpb=b266fea88678d041b4e2fc4b55d86e6e7b89f797;p=palacios.git diff --git a/linux_module/iface-keyed-stream.c b/linux_module/iface-keyed-stream.c index d84847a..1f75aa0 100644 --- a/linux_module/iface-keyed-stream.c +++ b/linux_module/iface-keyed-stream.c @@ -1,39 +1,119 @@ /* * Palacios keyed stream interface - * (c) Peter Dinda, 2011 + * + * Plus implementations for mem, file, and user space implementations + * + * (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 #include #include #include -#include +#include +#include #include "palacios.h" #include "util-hashtable.h" #include "linux-exts.h" +#include "vm.h" #define sint64_t int64_t #include +#include "iface-keyed-stream-user.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + /* This is an implementation of the Palacios keyed stream interface - that supports two flavors of streams: + that supports four flavors of streams: "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: - "file:" Streams are stored in files. Each high-level - open corresponds to a directory, while key corresponds to - a distinct file in that directory. + [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. 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::" => Bind to : and accept a connection + "net:c::" => Connect to : + "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_GENERIC 0 #define STREAM_MEM 1 #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 @@ -46,7 +126,10 @@ struct generic_stream { int stype; }; - +/* + boundary tags are used for some othe raw formats. +*/ +static uint32_t BOUNDARY_TAG=0xabcd0123; /**************************************************************************************** @@ -77,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; } @@ -109,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) { @@ -129,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; @@ -157,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) @@ -190,7 +275,7 @@ static inline int hash_comp(addr_t k1, addr_t k2) // This stores all the memory keyed streams streams -static struct hashtable *streams=0; +static struct hashtable *mem_streams=0; static v3_keyed_stream_t open_stream_mem(char *url, @@ -198,14 +283,14 @@ static v3_keyed_stream_t open_stream_mem(char *url, { if (strncasecmp(url,"mem:",4)) { - printk("palacios: illegitimate attempt to open memory stream \"%s\"\n",url); + WARNING("illegitimate attempt to open memory stream \"%s\"\n",url); return 0; } switch (ot) { case V3_KS_RD_ONLY: case V3_KS_WR_ONLY: { - struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(streams,(addr_t)(url+4)); + struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(mem_streams,(addr_t)(url+4)); if (mks) { mks->ot=ot; } @@ -214,41 +299,41 @@ static v3_keyed_stream_t open_stream_mem(char *url, break; case V3_KS_WR_ONLY_CREATE: { - struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(streams,(addr_t)(url+4)); + struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(mem_streams,(addr_t)(url+4)); if (!mks) { char *mykey; - mykey = kmalloc(strlen(url+4)+1,GFP_KERNEL); + mykey = palacios_alloc(strlen(url+4)+1); if (!mykey) { - printk("palacios: cannot allocate space for new in-memory keyed stream %s\n",url); + 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); - printk("palacios: cannot allocate in-memory keyed stream %s\n",url); + 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); - printk("palacios: cannot allocate in-memory keyed stream %s\n",url); + palacios_free(mks); + palacios_free(mykey); + ERROR("cannot allocate in-memory keyed stream %s\n",url); return 0; } - if (!palacios_htable_insert(streams,(addr_t)(mykey),(addr_t)mks)) { + if (!palacios_htable_insert(mem_streams,(addr_t)(mykey),(addr_t)mks)) { palacios_free_htable(mks->ht,1,1); - kfree(mks); - kfree(mykey); - printk("palacios: cannot insert in-memory keyed stream %s\n",url); + palacios_free(mks); + palacios_free(mykey); + ERROR("cannot insert in-memory keyed stream %s\n",url); return 0; } mks->stype=STREAM_MEM; @@ -262,7 +347,7 @@ static v3_keyed_stream_t open_stream_mem(char *url, break; default: - printk("palacios: unsupported open type in open_stream_mem\n"); + ERROR("unsupported open type in open_stream_mem\n"); break; } @@ -290,27 +375,27 @@ 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) { - printk("palacios: cannot allocate copy of key for key %s\n",key); + 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); - printk("palacios: cannot allocate mem keyed stream for key %s\n",key); + 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); - printk("palacios: cannot insert mem keyed stream for key %s\n",key); + palacios_free(mykey); + ERROR("cannot insert mem keyed stream for key %s\n",key); return 0; } } @@ -339,31 +424,31 @@ 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) { - printk("palacios: cannot allocate key spce for preallocte for key %s\n",key); + 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); if (!m) { - printk("palacios: cannot preallocate mem keyed stream for key %s\n",key); + ERROR("cannot preallocate mem keyed stream for key %s\n",key); return; } if (!palacios_htable_insert(s,(addr_t)mykey,(addr_t)m)) { - printk("palacios: cannot insert preallocated mem keyed stream for key %s\n",key); + ERROR("cannot insert preallocated mem keyed stream for key %s\n",key); destroy_mem_stream(m); return; } } else { if (m->data_max < size) { if (expand_mem_stream(m,size)) { - printk("palacios: cannot expand key for preallocation for key %s\n",key); + ERROR("cannot expand key for preallocation for key %s\n",key); return; } } @@ -382,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) { - printk("palacios: 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) { - printk("palacios: 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; + } } @@ -461,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)) { - printk("palacios: illegitimate attempt to open file stream \"%s\"\n",url); + 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) { - printk("palacios: cannot allocate space for file stream\n"); + 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)) { - printk("palacios: cannot allocate space for file stream\n"); - kfree(fks); + ERROR("cannot allocate space for file stream\n"); + 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 - printk("palacios: 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)) { - printk("palacios: 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)) { - printk("palacios: 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)) { - printk("palacios: 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) { - printk("palacios: 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))) { - printk("palacios: 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; } @@ -574,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); } @@ -595,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) { - printk("palacios: cannot allocate file keyed stream for key %s\n",key); + 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) { - printk("palacios: cannot allocate file keyed stream for key %s\n",key); - kfree(path); + ERROR("cannot allocate file keyed stream for key %s\n",key); + palacios_free(path); return 0; } fs->stype=STREAM_FILE; - fs->f = filp_open(path,O_RDWR|O_CREAT,0600); - - if (IS_ERR(fs->f)) { - printk("palacios: cannot open relevent file \"%s\" for stream \"file:%s\" and key \"%s\"\n",path,fks->path,key); - kfree(fs); - kfree(path); + 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); + palacios_free(fs); + palacios_free(path); return 0; } - kfree(path); + palacios_free(path); return fs; } @@ -636,87 +916,2091 @@ 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; + 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=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; + } - if (fks->ot!=V3_KS_RD_ONLY) { + for (i=0;i0) { - done = fs->f->f_op->read(fs->f, buf+(total-left), left, &(fs->f->f_pos)); - if (done<=0) { +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;istype=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:") +*************************************************************************************************/ + + +// List of all user keyed stream connections for the guest +struct user_keyed_streams { + spinlock_t lock; + struct list_head streams; +}; + + +// A single keyed stream connection to user space +struct user_keyed_stream { + int stype; + v3_keyed_stream_open_t otype; + + char *url; + spinlock_t lock; + int waiting; + + wait_queue_head_t user_wait_queue; + wait_queue_head_t host_wait_queue; + + struct palacios_user_keyed_stream_op *op; + + struct list_head node; +}; + + +// +// List of all of the user streams +// +static struct user_keyed_streams *user_streams; + + + +static int resize_op(struct palacios_user_keyed_stream_op **op, uint64_t buf_len) +{ + struct palacios_user_keyed_stream_op *old = *op; + struct palacios_user_keyed_stream_op *new; + + if (!old) { + new = palacios_alloc(sizeof(struct palacios_user_keyed_stream_op)+buf_len); + if (!new) { return -1; } else { - left -= done; + new->len=sizeof(struct palacios_user_keyed_stream_op)+buf_len; + new->buf_len=buf_len; + *op=new; + return 0; + } + } else { + if ((old->len-sizeof(struct palacios_user_keyed_stream_op)) >= buf_len) { + old->buf_len=buf_len; + return 0; + } else { + palacios_free(old); + *op = 0 ; + return resize_op(op,buf_len); + } + } +} + +// +// The assumption is that we enter this with the stream locked +// and we will return with it locked; additionally, the op structure +// will be overwritten with the response +// +static int do_request_to_response(struct user_keyed_stream *s, unsigned long *flags) +{ + + if (s->waiting) { + ERROR("user keyed stream request attempted while one is already in progress on %s\n",s->url); + return -1; + } + + // we are now waiting for a response + s->waiting = 1; + + // release the stream + palacios_spinlock_unlock_irqrestore(&(s->lock), *flags); + + // wake up anyone waiting on it + wake_up_interruptible(&(s->user_wait_queue)); + + // wait for someone to give us a response + while (wait_event_interruptible(s->host_wait_queue, (s->waiting == 0)) != 0) {} + + // reacquire the lock for our called + palacios_spinlock_lock_irqsave(&(s->lock), *flags); + + return 0; +} + +// +// The assumption is that we enter this with the stream locked +// and we will return with it UNlocked +// +static int do_response_to_request(struct user_keyed_stream *s, unsigned long *flags) +{ + + if (!(s->waiting)) { + ERROR("user keyed stream response while no request is in progress on %s\n",s->url); + return -1; + } + + // we are now waiting for a request + s->waiting = 0; + + // release the stream + palacios_spinlock_unlock_irqrestore(&(s->lock), *flags); + + // wake up anyone waiting on it + wake_up_interruptible(&(s->host_wait_queue)); + + return 0; +} + + + +static unsigned int keyed_stream_poll_user(struct file *filp, poll_table *wait) +{ + struct user_keyed_stream *s = (struct user_keyed_stream *) (filp->private_data); + unsigned long flags; + + if (!s) { + return POLLERR; + } + + palacios_spinlock_lock_irqsave(&(s->lock), flags); + + poll_wait(filp, &(s->user_wait_queue), wait); + + if (s->waiting) { + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + return POLLIN | POLLRDNORM; + } + + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + + return 0; +} + +static long keyed_stream_ioctl_user(struct file * filp, unsigned int ioctl, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + unsigned long flags; + uint64_t size; + + struct user_keyed_stream *s = (struct user_keyed_stream *) (filp->private_data); + + switch (ioctl) { + + case V3_KSTREAM_REQUEST_SIZE_IOCTL: + + // inform request size + + palacios_spinlock_lock_irqsave(&(s->lock), flags); + + if (!(s->waiting)) { + 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))) { + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + ERROR("palacios user key size request failed to copy data\n"); + return -EFAULT; + } + + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + + return 1; + + break; + + case V3_KSTREAM_REQUEST_PULL_IOCTL: + + // pull the request + + palacios_spinlock_lock_irqsave(&(s->lock), flags); + + if (!(s->waiting)) { + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + ERROR("palacios user key pull request when not waiting\n"); + return 0; + } + + size = sizeof(struct palacios_user_keyed_stream_op) + s->op->buf_len; + + + if (copy_to_user((void __user *) argp, s->op, size)) { + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + ERROR("palacios user key pull request failed to copy data\n"); + return -EFAULT; + } + + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + + return 1; + + + break; + + case V3_KSTREAM_RESPONSE_PUSH_IOCTL: + + // push the response + + palacios_spinlock_lock_irqsave(&(s->lock), flags); + + if (!(s->waiting)) { + 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"); + 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"); + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + return -EFAULT; } + + if (copy_from_user(s->op, (void __user *) argp, size)) { + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + return -EFAULT; + } + + do_response_to_request(s,&flags); + // this will have unlocked s for us + + return 1; + + break; + + default: + ERROR("unknown ioctl in user keyed stream\n"); + + return -EFAULT; + + break; + } - set_fs(old_fs); +} + + +static int keyed_stream_release_user(struct inode *inode, struct file *filp) +{ + struct user_keyed_stream *s = filp->private_data; + unsigned long f1,f2; + + palacios_spinlock_lock_irqsave(&(user_streams->lock),f1); + palacios_spinlock_lock_irqsave(&(s->lock), f2); + + list_del(&(s->node)); + + palacios_spinlock_unlock_irqrestore(&(s->lock), f2); + palacios_spinlock_unlock_irqrestore(&(user_streams->lock), f1); + + palacios_free(s->url); + palacios_free(s); + + return 0; +} + +static struct file_operations user_keyed_stream_fops = { + .poll = keyed_stream_poll_user, + .compat_ioctl = keyed_stream_ioctl_user, + .unlocked_ioctl = keyed_stream_ioctl_user, + .release = keyed_stream_release_user, +}; + + +/* + user_keyed_streams are allocated on user connect, and deallocated on user release + + palacios-side opens and closes only manipulate the open type +*/ + +int keyed_stream_connect_user(struct v3_guest *guest, unsigned int cmd, unsigned long arg, void *priv_data) +{ + int fd; + unsigned long flags; + char *url; + uint64_t len; + struct user_keyed_stream *s; + + if (!user_streams) { + ERROR("no user space keyed streams!\n"); + return -1; + } + + // get the url + if (copy_from_user(&len,(void __user *)arg,sizeof(len))) { + ERROR("cannot copy url len from user\n"); + return -1; + } + + // 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"); + return -1; + } + + if (copy_from_user(url,((void __user *)arg)+sizeof(len),len)) { + ERROR("cannot copy url from user\n"); + return -1; + } + url[len-1]=0; + + + // Check for duplicate handler + 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); + palacios_free(url); + return -1; + } + } + palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags); + + // Create connection + s = palacios_alloc(sizeof(struct user_keyed_stream)); + + if (!s) { + ERROR("cannot allocate new user keyed stream for %s\n",url); + palacios_free(url); + return -1; + } + + + // Get file descriptor + fd = anon_inode_getfd("v3-kstream", &user_keyed_stream_fops, s, 0); + + if (fd < 0) { + ERROR("cannot allocate file descriptor for new user keyed stream for %s\n",url); + palacios_free(s); + palacios_free(url); + return -1; + } + + memset(s, 0, sizeof(struct user_keyed_stream)); + + s->stype=STREAM_USER; + s->url=url; + + init_waitqueue_head(&(s->user_wait_queue)); + init_waitqueue_head(&(s->host_wait_queue)); + + // Insert connection into list + palacios_spinlock_lock_irqsave(&(user_streams->lock), flags); + list_add(&(s->node), &(user_streams->streams)); + palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags); + + return fd; +} + +static struct user_keyed_stream *keyed_stream_user_find(char *url) +{ + unsigned long flags; + struct user_keyed_stream *s; + + if (!user_streams) { + ERROR("no user space keyed streams available\n"); + return NULL; + } + + palacios_spinlock_lock_irqsave(&(user_streams->lock), flags); + list_for_each_entry(s, &(user_streams->streams), node) { + if (!strcasecmp(url, s->url)) { + palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags); + return s; + } + } + + palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags); + + return NULL; +} + + +static v3_keyed_stream_t open_stream_user(char *url, v3_keyed_stream_open_t ot) +{ + unsigned long flags; + struct user_keyed_stream *s; + + s = keyed_stream_user_find(url); + + if (!s) { + ERROR("cannot open user stream %s as it does not exist yet\n",url); + return NULL; + } + + palacios_spinlock_lock_irqsave(&(s->lock), flags); + + if (s->waiting) { + 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; + + palacios_spinlock_unlock_irqrestore(&(s->lock), flags); + + return s; + +} + +// close stream does not do anything. Creation of the stream and its cleanup +// are driven by the user side, not the palacios side +// might eventually want to reference count this, though +static void close_stream_user(v3_keyed_stream_t stream) +{ + return; +} + +static void preallocate_hint_key_user(v3_keyed_stream_t stream, + char *key, + uint64_t size) +{ + return; +} + + + + +static v3_keyed_stream_key_t open_key_user(v3_keyed_stream_t stream, char *key) +{ + unsigned long flags; + struct user_keyed_stream *s = (struct user_keyed_stream *) stream; + uint64_t len = strlen(key)+1; + void *user_key; + + palacios_spinlock_lock_irqsave(&(s->lock), flags); + + + if (resize_op(&(s->op),len)) { + 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); // will terminate buffer + + // enter with it locked + if (do_request_to_response(s,&flags)) { + palacios_spinlock_unlock_irqrestore(&(s->lock),flags); + ERROR("request/response handling failed\n"); + return NULL; + } + // return with it locked + + user_key=s->op->user_key; + + palacios_spinlock_unlock_irqrestore(&(s->lock),flags); + + return user_key; +} + +static void close_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t key) +{ + struct user_keyed_stream *s = (struct user_keyed_stream *) stream; + uint64_t len = 0; + unsigned long flags; + + palacios_spinlock_lock_irqsave(&(s->lock), flags); + + if (resize_op(&(s->op),len)) { + 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; + } + + s->op->type = PALACIOS_KSTREAM_CLOSE_KEY; + s->op->buf_len = len; + s->op->user_key = key; + + // enter with it locked + if (do_request_to_response(s,&flags)) { + palacios_spinlock_unlock_irqrestore(&(s->lock),flags); + ERROR("request/response handling failed\n"); + return; + } + // return with it locked + + palacios_spinlock_unlock_irqrestore(&(s->lock),flags); + + return; +} + + + +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 = taglen ; + sint64_t xfer; + unsigned long flags; + + palacios_spinlock_lock_irqsave(&(s->lock), flags); + + if (s->otype != V3_KS_RD_ONLY) { + 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)) { + 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; + } + + s->op->type = PALACIOS_KSTREAM_READ_KEY; + 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)) { + palacios_spinlock_unlock_irqrestore(&(s->lock),flags); + ERROR("request/response handling failed\n"); + return -1; + } + // return with it locked + + + if (s->op->xfer>0) { + // data_off must be zero + memcpy(buf,s->op->buf,s->op->xfer); + } + + xfer=s->op->xfer; + + 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; + uint64_t len = taglen + wlen ; + sint64_t xfer; + unsigned long flags; + + + palacios_spinlock_lock_irqsave(&(s->lock), flags); + + if (s->otype != V3_KS_WR_ONLY) { + 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)) { + 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; + } + + 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,tag,taglen); + memcpy(s->op->buf+taglen,buf,wlen); + + // enter with it locked + if (do_request_to_response(s,&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; + + palacios_spinlock_unlock_irqrestore(&(s->lock),flags); + + return xfer; +} + + + +/**************************************************************************************** + * Network-based implementation ("net:") + *****************************************************************************************/ + + +#define NET_MAX_KEY_LEN 128 + +struct net_keyed_stream { + int stype; + int ot; + struct net_stream * ns; +}; + +struct net_stream { + int stype; + struct socket *sock; +}; + + +//ignore the arguments given here currently +static struct net_stream * create_net_stream(void) +{ + struct net_stream * ns = NULL; + + ns = palacios_alloc(sizeof(struct net_stream)); + + if (!ns) { + ERROR("Cannot allocate a net_stream\n"); + return 0; + } + + memset(ns, 0, sizeof(struct net_stream)); + + ns->stype = STREAM_NETWORK; + + return ns; +} + +static void close_socket(v3_keyed_stream_t stream) +{ + struct net_keyed_stream *nks = (struct net_keyed_stream *) stream; + + if (nks) { + struct net_stream *ns = nks->ns; + + if (ns) { + ns->sock->ops->release(ns->sock); + palacios_free(ns); + ERROR("Close Socket\n"); + } + + palacios_free(ns); + } +} + + +static void close_stream_net(v3_keyed_stream_t stream) +{ + close_socket(stream); +} + +static int connect_to_ip(struct net_stream *ns, int hostip, int port) +{ + struct sockaddr_in client; + + if (ns == NULL) { + return -1; + } + + if (sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&(ns->sock))<0) { + ERROR("Cannot create accept socket\n"); + return -1; + } + + + client.sin_family = AF_INET; + client.sin_port = htons(port); + client.sin_addr.s_addr = hostip;//in_aton(hostip); + + return ns->sock->ops->connect(ns->sock, (struct sockaddr *)&client, sizeof(client), 0); +} + +static int send_msg(struct net_stream *ns, char * buf, int len) +{ + int left=len; + + if (!ns) { + ERROR("Send message on null net_stream\n"); + return -1; + } + + if (!(ns->sock)) { + ERROR("Send message on net_stream without socket\n"); + return -1; + } + + while (left>0) { + struct msghdr msg; + mm_segment_t oldfs; + struct iovec iov; + int err = 0; + + + msg.msg_flags = MSG_NOSIGNAL;//MSG_DONTWAIT; + msg.msg_name = 0; + 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; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = sock_sendmsg(ns->sock, &msg, (size_t)left); + + set_fs(oldfs); + + if (err<0) { + ERROR("Send msg error %d\n",err); + return err; + } else { + left-=len; + } + } + + return len; +} + + + +static int recv_msg(struct net_stream *ns, char * buf, int len) +{ + + int left=len; + + if (!ns) { + ERROR("Receive message on null net_stream\n"); + return -1; + } + + if (!(ns->sock)) { + ERROR("Receive message on net_stream without socket\n"); + return -1; + } + + + while (left>0) { + + struct msghdr msg; + mm_segment_t oldfs; + struct iovec iov; + int err; + + msg.msg_flags = 0; + msg.msg_name = 0; + 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; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = sock_recvmsg(ns->sock, &msg, (size_t)left, 0); + + set_fs(oldfs); + + if (err<0) { + return err; + } else { + left -= err; + } + } return len; +} + +static struct net_stream * accept_once(struct net_stream * ns, const int port) +{ + struct socket *accept_sock; + struct sockaddr_in addr; + int err; + + if (!ns) { + ERROR("Accept called on null net_stream\n"); + return 0; + } + + if (sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&accept_sock)<0) { + ERROR("Cannot create accept socket\n"); + return NULL; + } + + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + err = accept_sock->ops->bind(accept_sock, (struct sockaddr *)&addr, sizeof(addr)); + + if (err<0) { + ERROR("Bind err: %d\n",err); + return NULL; + } + + err = accept_sock->ops->listen(accept_sock,2); + + if (err<0) { + ERROR("Listen err: %d\n",err); + return NULL; + } + + // Init the socket in the network strream + + if (sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&(ns->sock))<0) { + ERROR("Cannot create socket\n"); + return NULL; + } + + + // Do the actual accept + + if (accept_sock->ops->accept(accept_sock,ns->sock,0)<0) { + ERROR("accept failed"); + return NULL; + } + + // close the accept socket + accept_sock->ops->release(accept_sock); + palacios_free(accept_sock); + + return ns; +} + + +static struct v3_keyed_stream_t * open_stream_net(char * url,v3_keyed_stream_open_t ot) +{ + struct net_keyed_stream * nks; + int url_len; + int i; + int delimit[3]; + int k; + char mode; + int ip_len; + int port_len; + + nks = palacios_alloc(sizeof(struct net_keyed_stream)); + + if (!nks) { + ERROR("Could not allocate space in open_stream_net\n"); + return 0; + } + + nks->ot = ot == V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot; + + nks->stype = STREAM_NETWORK; + + nks->ns = create_net_stream(); + + if (!(nks->ns)) { + ERROR("Could not create network stream\n"); + palacios_free(nks); + return 0; + } + + url_len=strlen(url); + k=0; + + + for(i = 0; i < url_len;i++){ + if(url[i] == ':'){ + delimit[k] = i; + k++; + } + } + + mode = url[delimit[0] + 1]; + ip_len = delimit[2] - delimit[1]; + port_len = url_len - delimit[2]; + + + { + char ip[ip_len]; + char port[port_len]; + int host_ip; + int host_port; + + + strncpy(ip,url + delimit[1]+1,ip_len-1); + ip[ip_len-1]='\0'; + + host_ip = in_aton(ip); + + strncpy(port,url+ delimit[2]+1,port_len-1); + port[port_len-1]='\0'; + + host_port = simple_strtol(port,NULL,10); + + INFO("ip is %s\n",ip); + INFO("host_ip is %x\n", host_ip); + INFO("port is %s (%d)\n",port,host_port); + + if (mode == 'a'){ + // accept a request + INFO("Accepting Connection on INADDR_ANY port:%d\n",host_port); + nks->ns = accept_once(nks->ns, host_port); + } else if (mode == 'c'){ + // call connect to ip + INFO("Connecting to %s:%d\n",ip,host_port); + connect_to_ip(nks->ns,host_ip, host_port); + } else { + ERROR("Mode not recognized\n"); + palacios_free(nks); + return NULL; + } + + return (v3_keyed_stream_t)nks; + } +} + +static void preallocate_hint_key_net(v3_keyed_stream_t stream, char *key,uint64_t size) +{ + //do nothing +} + +static v3_keyed_stream_key_t open_key_net(v3_keyed_stream_t stream,char *key) +{ + struct net_keyed_stream * nks = (struct net_keyed_stream *)stream; + + // reciever of the key name + if (nks->ot==V3_KS_WR_ONLY) + { + unsigned short keylen = strlen(key); + + if (keylen>NET_MAX_KEY_LEN || keylen>=32768) { + ERROR("Key is too long\n"); + return NULL; + } + + { + // on-stack allocation here demands that we + // keep key length low... + char msg[keylen+3]; + int next = 0; + + // Opening a key for writing sends a notice of the + // key length and the key name on the channel + + msg[next++]=keylen & 0xFF; + msg[next]=(keylen>>8) & 0xFF; + // Set flag bit + msg[next]=msg[next] | 0x80; // 0x80 is 128 and OR will flip leading bit to 1 + + strncpy(msg+2,key,keylen); // will also copy trailing zero + + if (send_msg(nks->ns,msg,keylen+2) != keylen+2) { + ERROR("Unable to open key for writing on net_stream (send key len+name)\n"); + return NULL; + } + } + } + + if (nks->ot==V3_KS_RD_ONLY) { + char msg_info[2]; + int next = 0; + int keylen = 0; + + if (recv_msg(nks->ns,msg_info,2) != 2) { + ERROR("Unable to open key for reading on net_stream (recv key len)\n"); + return NULL; + } + + next = 0; + keylen = 0; + + keylen |= msg_info[next++]; + + if ((msg_info[next] & 0x80) != 0x80) { + ERROR("Flag bit not set on receive of key length\n"); + return NULL; + } else { + msg_info[next] &= 0x7F; // flip the msb back to zero (clear flag) + } + + keylen |= msg_info[next]<<8; + + if (keylen > NET_MAX_KEY_LEN) { + ERROR("Received key length is too big\n"); + return NULL; + } + + { + + char msg[keylen+1]; + + if (recv_msg(nks->ns,msg,keylen) != keylen) { + ERROR("Unable to receive key\n"); + return NULL; + } + msg[keylen]=0; + + if (strncmp(key,msg,keylen)!=0) { + ERROR("Key mismatch in open_key_net - expect %s but got %s\n",key,msg); + return NULL; + } + } + } + + return (v3_keyed_stream_key_t)key; +} + +static void close_key_net(v3_keyed_stream_t stream, v3_keyed_stream_key_t input_key) +{ + char * key = (char*)input_key; + struct net_keyed_stream * nks = (struct net_keyed_stream *)stream; + + + if (nks->ot==V3_KS_WR_ONLY) { + unsigned short keylen = strlen(key); + + if (keylen > NET_MAX_KEY_LEN || keylen>=32768) { + ERROR("Key length too long in close_key_net\n"); + return; + } + + { + char msg[keylen+3]; + int next = 0; + + msg[next++]=keylen & 0xFF; + msg[next]=(keylen>>8) & 0xFF; + // flag + msg[next]=msg[next] | 0x80; // 0x80 is 128 and OR will filp leading bit to 1 + strncpy(msg+2,key,keylen); // will copy the zero + msg[keylen+2]=0; + if (send_msg(nks->ns,msg,keylen+2)!=keylen+2) { + ERROR("Cannot send key on close_key_net\n"); + return; + } + } + } + + if (nks->ot==V3_KS_RD_ONLY) { + char msg_info[2]; + int next; + int keylen; + + if (recv_msg(nks->ns,msg_info,2) != 2) { + ERROR("Cannot recv key length on close_key_net\n"); + return; + } + + next = 0; + keylen = 0; + + keylen |= msg_info[next++]; + + if ((msg_info[next] & 0x80) != 0x80) { + ERROR("Missing flag in close_key_net receive\n"); + return; + } + + msg_info[next] &= 0x7F; // flip the msb back to zero + + keylen |= msg_info[next]<<8; + + { + char msg[keylen+1]; + + if (recv_msg(nks->ns,msg,keylen)!=keylen) { + ERROR("Did not receive all of key in close_key_net receive\n"); + return; + } + + msg[keylen]=0; + + if (strncmp(key,msg,keylen)!=0) { + ERROR("Key mismatch in close_key_net - expect %s but got %s\n",key,msg); + return; + } + } + } +} + +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; + + if (!buf) { + ERROR("Buf is NULL in write_key_net\n"); + 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"); + return -1; + } + + + if (!nks) { + ERROR("nks is NULL in write_key_net\n"); + return -1; + } + + 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; + } + if (send_msg(nks->ns,buf,len)!=len) { + ERROR("Could not send data in write_key_net\n"); + return -1; + } + } else { + ERROR("Permission not correct in write_key_net\n"); + return -1; + } + + return 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"); + return -1; + } + + + 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; + } + + 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"); + return -1; + } + + return len; + +} /*************************************************************************************************** @@ -730,8 +3014,14 @@ static v3_keyed_stream_t open_stream(char *url, return open_stream_mem(url,ot); } else if (!strncasecmp(url,"file:",5)) { return open_stream_file(url,ot); + } else if (!strncasecmp(url,"user:",5)) { + return open_stream_user(url,ot); + } 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 { - printk("palacios: unsupported type in attempt to open keyed stream \"%s\"\n",url); + ERROR("unsupported type in attempt to open keyed stream \"%s\"\n",url); return 0; } } @@ -746,8 +3036,17 @@ 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; + case STREAM_NETWORK: + return close_stream_net(stream); + break; default: - printk("palacios: unknown stream type %d in close\n",gks->stype); + ERROR("unknown stream type %d in close\n",gks->stype); break; } } @@ -764,8 +3063,17 @@ 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; + case STREAM_NETWORK: + return preallocate_hint_key_net(stream,key,size); + break; default: - printk("palacios: unknown stream type %d in preallocate_hint_key\n",gks->stype); + ERROR("unknown stream type %d in preallocate_hint_key\n",gks->stype); break; } return; @@ -783,8 +3091,17 @@ 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; + case STREAM_NETWORK: + return open_key_net(stream, key); + break; default: - printk("palacios: unknown stream type %d in open_key\n",gks->stype); + ERROR("unknown stream type %d in open_key\n",gks->stype); break; } return 0; @@ -802,8 +3119,17 @@ 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; + case STREAM_NETWORK: + return close_key_net(stream, key); + break; default: - printk("palacios: unknown stream type %d in close_key\n",gks->stype); + ERROR("unknown stream type %d in close_key\n",gks->stype); break; } // nothing to do @@ -812,19 +3138,30 @@ 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,tag,taglen,buf,len); + break; + case STREAM_NETWORK: + return write_key_net(stream,key,tag,taglen,buf,len); break; default: - printk("palacios: unknown stream type %d in write_key\n",gks->stype); + ERROR("unknown stream type %d in write_key\n",gks->stype); return -1; break; } @@ -834,19 +3171,30 @@ 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,tag,taglen,buf,len); + break; + case STREAM_NETWORK: + return read_key_net(stream,key,tag,taglen,buf,len); break; default: - printk("palacios: unknown stream type %d in write_key\n",gks->stype); + ERROR("unknown stream type %d in read_key\n",gks->stype); return -1; break; } @@ -874,15 +3222,25 @@ static struct v3_keyed_stream_hooks hooks = { static int init_keyed_streams( void ) { - streams = palacios_create_htable(DEF_NUM_STREAMS,hash_func,hash_comp); + mem_streams = palacios_create_htable(DEF_NUM_STREAMS,hash_func,hash_comp); - if (!streams) { - printk("palacios: failed to allocated stream pool for in-memory streams\n"); + if (!mem_streams) { + ERROR("failed to allocated stream pool for in-memory streams\n"); return -1; } - V3_Init_Keyed_Streams(&hooks); + user_streams = palacios_alloc(sizeof(struct user_keyed_streams)); + if (!user_streams) { + ERROR("failed to allocated list for user streams\n"); + return -1; + } + + INIT_LIST_HEAD(&(user_streams->streams)); + + palacios_spinlock_init(&(user_streams->lock)); + + V3_Init_Keyed_Streams(&hooks); return 0; @@ -890,17 +3248,43 @@ static int init_keyed_streams( void ) static int deinit_keyed_streams( void ) { - printk("DEINIT OF PALACIOS KEYED STREAMS NOT IMPLEMENTED - WE HAVE JUST LEAKED MEMORY and/or file handles!\n"); - return -1; + palacios_free_htable(mem_streams,1,1); + + palacios_spinlock_deinit(&(user_streams->lock)); + + palacios_free(user_streams); + + WARNING("Deinit of Palacios Keyed Streams likely leaked memory\n"); + + return 0; +} + + +static int guest_init_keyed_streams(struct v3_guest * guest, void ** vm_data ) +{ + + add_guest_ctrl(guest, V3_VM_KSTREAM_USER_CONNECT, keyed_stream_connect_user, 0); + + return 0; } +static int guest_deinit_keyed_streams(struct v3_guest * guest, void * vm_data) +{ + remove_guest_ctrl(guest, V3_VM_KSTREAM_USER_CONNECT); + + return 0; +} + + + + static struct linux_ext key_stream_ext = { .name = "KEYED_STREAM_INTERFACE", .init = init_keyed_streams, .deinit = deinit_keyed_streams, - .guest_init = NULL, - .guest_deinit = NULL + .guest_init = guest_init_keyed_streams, + .guest_deinit = guest_deinit_keyed_streams, };