2 * Palacios keyed stream interface
3 * (c) Peter Dinda, 2011
7 #include <linux/file.h>
8 #include <linux/uaccess.h>
11 #include "util-hashtable.h"
12 #include "linux-exts.h"
14 #define sint64_t int64_t
15 #include <interfaces/vmm_keyed_stream.h>
18 This is an implementation of the Palacios keyed stream interface
19 that supports two flavors of streams:
21 "mem:" Streams are stored in a hash table
22 The values for this hash table are hash tables associated with
25 "file:" Streams are stored in files. Each high-level
26 open corresponds to a directory, while key corresponds to
27 a distinct file in that directory.
31 #define STREAM_GENERIC 0
37 All keyed streams and streams indicate their implementation type within the first field
39 struct generic_keyed_stream {
43 struct generic_stream {
50 /****************************************************************************************
51 Memory-based implementation ("mem:")
52 ****************************************************************************************/
54 #define DEF_NUM_STREAMS 16
55 #define DEF_NUM_KEYS 128
59 A memory keyed stream is a pointer to the underlying hash table
60 while a memory stream contains an extensible buffer for the stream
62 struct mem_keyed_stream {
64 v3_keyed_stream_open_t ot;
76 static struct mem_stream *create_mem_stream(void)
78 struct mem_stream *m = kmalloc(sizeof(struct mem_stream),GFP_KERNEL);
85 m->data = kmalloc(DEF_SIZE,GFP_KERNEL);
92 m->stype = STREAM_MEM;
100 static void destroy_mem_stream(struct mem_stream *m)
111 static int expand_mem_stream(struct mem_stream *m, uint32_t new_size)
113 void *data = kmalloc(new_size,GFP_KERNEL);
120 nc = (new_size<m->data_max) ? new_size : m->data_max;
122 memcpy(data,m->data,nc);
128 if (m->size<m->data_max) {
135 static uint32_t write_mem_stream(struct mem_stream *m,
139 if ((m->ptr + len) > m->size) {
140 if (expand_mem_stream(m,m->ptr + len)) {
144 memcpy(m->data+m->ptr,data,len);
152 static uint32_t read_mem_stream(struct mem_stream *m,
156 if ((m->ptr + len) > m->data_max) {
159 memcpy(data,m->data+m->ptr,len);
167 static void reset_mem_stream(struct mem_stream *m)
173 static inline uint_t hash_func(addr_t key)
175 return palacios_hash_buffer((uchar_t*)key,strlen((uchar_t*)key));
178 static inline int hash_comp(addr_t k1, addr_t k2)
180 return strcasecmp((char*)k1,(char*)k2)==0;
184 // This stores all the memory keyed streams streams
185 static struct hashtable *streams=0;
188 static v3_keyed_stream_t open_stream_mem(char *url,
189 v3_keyed_stream_open_t ot)
192 if (strncasecmp(url,"mem:",4)) {
193 printk("Illegitimate attempt to open memory stream \"%s\"\n",url);
199 case V3_KS_WR_ONLY: {
200 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(streams,(addr_t)(url+4));
204 return (v3_keyed_stream_t) mks;
208 case V3_KS_WR_ONLY_CREATE: {
209 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(streams,(addr_t)(url+4));
211 mks = (struct mem_keyed_stream *) kmalloc(sizeof(struct mem_keyed_stream),GFP_KERNEL);
213 printk("Cannot allocate in-memory keyed stream %s\n",url);
217 mks->ht = (void*) palacios_create_htable(DEF_NUM_KEYS,hash_func,hash_comp);
220 printk("Cannot allocate in-memory keyed stream %s\n",url);
224 if (!palacios_htable_insert(streams,(addr_t)(url+4),(addr_t)mks)) {
225 palacios_free_htable(mks->ht,1,1);
227 printk("Cannot insert in-memory keyed stream %s\n",url);
230 mks->stype=STREAM_MEM;
233 mks->ot=V3_KS_WR_ONLY;
241 printk("unsupported open type in open_stream_mem\n");
251 static void close_stream_mem(v3_keyed_stream_t stream)
258 static v3_keyed_stream_key_t open_key_mem(v3_keyed_stream_t stream,
261 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
262 struct hashtable *s = mks->ht;
264 struct mem_stream *m;
266 m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
269 m = create_mem_stream();
272 printk("Cannot allocate mem keyed stream for key %s\n",key);
276 if (!palacios_htable_insert(s,(addr_t)key,(addr_t)m)) {
277 printk("Cannot insert mem keyed stream for key %s\n",key);
278 destroy_mem_stream(m);
288 static void close_key_mem(v3_keyed_stream_t stream,
289 v3_keyed_stream_key_t key)
295 static sint64_t write_key_mem(v3_keyed_stream_t stream,
296 v3_keyed_stream_key_t key,
300 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
301 struct mem_stream *m = (struct mem_stream *) key;
305 if (mks->ot!=V3_KS_WR_ONLY) {
313 mylen = (uint32_t) len;
315 writelen=write_mem_stream(m,buf,mylen);
317 if (writelen!=mylen) {
318 printk("Failed to write all data for key\n");
321 return (sint64_t)writelen;
325 static sint64_t read_key_mem(v3_keyed_stream_t stream,
326 v3_keyed_stream_key_t key,
330 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
331 struct mem_stream *m = (struct mem_stream *) key;
335 if (mks->ot!=V3_KS_RD_ONLY) {
343 mylen = (uint32_t) len;
345 readlen=read_mem_stream(m,buf,mylen);
347 if (readlen!=mylen) {
348 printk("Failed to read all data for key\n");
351 return (sint64_t)readlen;
356 /***************************************************************************************************
357 File-based implementation ("file:")
358 *************************************************************************************************/
361 A file keyed stream contains the fd of the directory
365 struct file_keyed_stream {
367 v3_keyed_stream_open_t ot;
373 struct file *f; // the opened file
377 static int directory_ok(char *path, int flags)
384 d = filp_open(path,flags,0);
395 static v3_keyed_stream_t open_stream_file(char *url,
396 v3_keyed_stream_open_t ot)
398 struct file_keyed_stream *fks;
400 if (strncasecmp(url,"file:",5)) {
401 printk("Illegitimate attempt to open file stream \"%s\"\n",url);
405 fks = kmalloc(sizeof(struct file_keyed_stream),GFP_KERNEL);
408 printk("Cannot allocate space for file stream\n");
412 fks->path = (char*)kmalloc(strlen(url+5)+1,GFP_KERNEL);
415 printk("Cannot allocate space for file stream\n");
420 strcpy(fks->path,url+5);
422 fks->stype=STREAM_FILE;
424 //lookup starts at current->fs->root or current->fs->cwd
430 if (directory_ok(fks->path, ot==V3_KS_RD_ONLY ? O_RDONLY : O_WRONLY)) {
432 return (v3_keyed_stream_t) fks;
434 printk("Directory \"%s\" not found\n",fks->path);
442 case V3_KS_WR_ONLY_CREATE: {
444 if (directory_ok(fks->path, ot==V3_KS_RD_ONLY ? O_RDONLY : O_WRONLY)) {
445 fks->ot=V3_KS_WR_ONLY;
446 return (v3_keyed_stream_t) fks;
448 // TODO: Create Directory
449 printk("Directory \"%s\" not found and will not be created\n",fks->path);
459 printk("unsupported open type in open_stream_file\n");
467 static void close_stream_file(v3_keyed_stream_t stream)
469 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
476 static v3_keyed_stream_key_t open_key_file(v3_keyed_stream_t stream,
479 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
480 struct file_stream *fs;
483 // the path is the stream's path plus the key name
484 // file:/home/foo + "regext" => "/home/foo/regext"
485 path = (char *) kmalloc(strlen(fks->path)+strlen(key)+2,GFP_KERNEL);
487 printk("Cannot allocate file keyed stream for key %s\n",key);
490 strcpy(path,fks->path);
494 fs = (struct file_stream *) kmalloc(sizeof(struct file_stream *),GFP_KERNEL);
497 printk("Cannot allocate file keyed stream for key %s\n",key);
502 fs->stype=STREAM_FILE;
504 fs->f = filp_open(path,O_RDWR|O_CREAT,0600);
507 printk("Cannot open relevent file \"%s\" for stream \"file:%s\" and key \"%s\"\n",path,fks->path,key);
519 static void close_key_file(v3_keyed_stream_t stream,
520 v3_keyed_stream_key_t key)
522 struct file_stream *fs = (struct file_stream *) key;
524 filp_close(fs->f,NULL);
529 static sint64_t write_key_file(v3_keyed_stream_t stream,
530 v3_keyed_stream_key_t key,
534 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
535 struct file_stream *fs = (struct file_stream *) key;
537 ssize_t done, left, total;
539 if (fks->ot!=V3_KS_WR_ONLY) {
554 done = fs->f->f_op->write(fs->f, buf+(total-left), left, &(fs->f->f_pos));
568 static sint64_t read_key_file(v3_keyed_stream_t stream,
569 v3_keyed_stream_key_t key,
573 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
574 struct file_stream *fs = (struct file_stream *) key;
576 ssize_t done, left, total;
578 if (fks->ot!=V3_KS_RD_ONLY) {
593 done = fs->f->f_op->read(fs->f, buf+(total-left), left, &(fs->f->f_pos));
609 /***************************************************************************************************
611 *************************************************************************************************/
613 static v3_keyed_stream_t open_stream(char *url,
614 v3_keyed_stream_open_t ot)
616 if (!strncasecmp(url,"mem:",4)) {
617 return open_stream_mem(url,ot);
618 } else if (!strncasecmp(url,"file:",5)) {
619 return open_stream_file(url,ot);
621 printk("Unsupported type in attempt to open keyed stream \"%s\"\n",url);
626 static void close_stream(v3_keyed_stream_t stream)
628 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
631 return close_stream_mem(stream);
634 return close_stream_file(stream);
637 printk("unknown stream type %d in close\n",gks->stype);
642 static v3_keyed_stream_key_t open_key(v3_keyed_stream_t stream,
645 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
648 return open_key_mem(stream,key);
651 return open_key_file(stream,key);
654 printk("unknown stream type %d in open_key\n",gks->stype);
661 static void close_key(v3_keyed_stream_t stream,
662 v3_keyed_stream_key_t key)
664 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
667 return close_key_mem(stream,key);
670 return close_key_file(stream,key);
673 printk("unknown stream type %d in close_key\n",gks->stype);
680 static sint64_t write_key(v3_keyed_stream_t stream,
681 v3_keyed_stream_key_t key,
685 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
688 return write_key_mem(stream,key,buf,len);
691 return write_key_file(stream,key,buf,len);
694 printk("unknown stream type %d in write_key\n",gks->stype);
702 static sint64_t read_key(v3_keyed_stream_t stream,
703 v3_keyed_stream_key_t key,
707 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
710 return read_key_mem(stream,key,buf,len);
713 return read_key_file(stream,key,buf,len);
716 printk("unknown stream type %d in write_key\n",gks->stype);
726 /***************************************************************************************************
727 Hooks to palacios and inititialization
728 *************************************************************************************************/
731 static struct v3_keyed_stream_hooks hooks = {
733 .close = close_stream,
734 .open_key = open_key,
735 .close_key = close_key,
736 .read_key = read_key,
737 .write_key = write_key
741 static int init_keyed_streams( void )
743 streams = palacios_create_htable(DEF_NUM_STREAMS,hash_func,hash_comp);
746 printk("Failed to allocated stream pool for in-memory streams\n");
750 V3_Init_Keyed_Streams(&hooks);
756 v3_keyed_stream_key_t k;
760 printk("Testing memory interface\n");
761 s=open_stream("mem:/foo",V3_KS_WR_ONLY_CREATE);
763 write_key(s,k,"hello",5);
766 write_key(s,k,"foobar",6);
768 for (i=0;i<=256;i++) {
772 write_key(s,k,buf,256);
775 s=open_stream("mem:/foo",V3_KS_RD_ONLY);
779 printk("wrote 'hello', read '%s'\n",buf);
784 printk("wrote 'foobar', read '%s'\n",buf);
787 read_key(s,k,buf,256);
788 for (i=0;i<256;i++) {
789 printk("wrote 0x%x, read 0x%x (%s)\n",i,buf[i],i==buf[i] ? "ok" : "BAD");
794 printk("Testing file interface\n");
795 s=open_stream("file:/foo",V3_KS_WR_ONLY_CREATE);
797 write_key(s,k,"hello",5);
800 write_key(s,k,"foobar",6);
802 for (i=0;i<=256;i++) {
806 write_key(s,k,buf,256);
809 s=open_stream("file:/foo",V3_KS_RD_ONLY);
813 printk("wrote 'hello', read '%s'\n",buf);
818 printk("wrote 'foobar', read '%s'\n",buf);
821 read_key(s,k,buf,256);
822 for (i=0;i<256;i++) {
823 printk("wrote 0x%x, read 0x%x (%s)\n",i,buf[i],i==buf[i] ? "ok" : "BAD");
834 static int deinit_keyed_streams( void )
836 printk("DEINIT OF PALACIOS KEYED STREAMS NOT IMPLEMENTED - WE HAVE JUST LEAKED MEMORY and/or file handles!\n");
841 static struct linux_ext key_stream_ext = {
842 .name = "KEYED_STREAM_INTERFACE",
843 .init = init_keyed_streams,
844 .deinit = deinit_keyed_streams,
850 register_extension(&key_stream_ext);