2 * Palacios keyed stream interface
3 * (c) Peter Dinda, 2011
7 #include <linux/file.h>
8 #include <linux/uaccess.h>
9 #include <linux/namei.h>
10 #include <linux/vmalloc.h>
13 #include "util-hashtable.h"
14 #include "linux-exts.h"
16 #define sint64_t int64_t
17 #include <interfaces/vmm_keyed_stream.h>
20 This is an implementation of the Palacios keyed stream interface
21 that supports two flavors of streams:
23 "mem:" Streams are stored in a hash table
24 The values for this hash table are hash tables associated with
27 "file:" Streams are stored in files. Each high-level
28 open corresponds to a directory, while key corresponds to
29 a distinct file in that directory.
33 #define STREAM_GENERIC 0
39 All keyed streams and streams indicate their implementation type within the first field
41 struct generic_keyed_stream {
45 struct generic_stream {
52 /****************************************************************************************
53 Memory-based implementation ("mem:")
54 ****************************************************************************************/
56 #define DEF_NUM_STREAMS 16
57 #define DEF_NUM_KEYS 128
61 A memory keyed stream is a pointer to the underlying hash table
62 while a memory stream contains an extensible buffer for the stream
64 struct mem_keyed_stream {
66 v3_keyed_stream_open_t ot;
78 static struct mem_stream *create_mem_stream_internal(uint64_t size)
80 struct mem_stream *m = kmalloc(sizeof(struct mem_stream),GFP_KERNEL);
87 m->data = vmalloc(size);
94 m->stype = STREAM_MEM;
103 static struct mem_stream *create_mem_stream(void)
105 return create_mem_stream_internal(DEF_SIZE);
108 static void destroy_mem_stream(struct mem_stream *m)
119 static int expand_mem_stream(struct mem_stream *m, uint32_t new_size)
121 void *data = vmalloc(new_size);
128 nc = (new_size<m->data_max) ? new_size : m->data_max;
130 memcpy(data,m->data,nc);
136 if (m->size<m->data_max) {
143 static uint32_t write_mem_stream(struct mem_stream *m,
147 if ((m->ptr + len) > m->size) {
148 if (expand_mem_stream(m,m->ptr + len)) {
152 memcpy(m->data+m->ptr,data,len);
160 static uint32_t read_mem_stream(struct mem_stream *m,
164 if ((m->ptr + len) > m->data_max) {
167 memcpy(data,m->data+m->ptr,len);
175 static void reset_mem_stream(struct mem_stream *m)
181 static inline uint_t hash_func(addr_t key)
183 return palacios_hash_buffer((uchar_t*)key,strlen((uchar_t*)key));
186 static inline int hash_comp(addr_t k1, addr_t k2)
188 return strcasecmp((char*)k1,(char*)k2)==0;
192 // This stores all the memory keyed streams streams
193 static struct hashtable *streams=0;
196 static v3_keyed_stream_t open_stream_mem(char *url,
197 v3_keyed_stream_open_t ot)
200 if (strncasecmp(url,"mem:",4)) {
201 printk("palacios: illegitimate attempt to open memory stream \"%s\"\n",url);
207 case V3_KS_WR_ONLY: {
208 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(streams,(addr_t)(url+4));
212 return (v3_keyed_stream_t) mks;
216 case V3_KS_WR_ONLY_CREATE: {
217 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(streams,(addr_t)(url+4));
221 mykey = kmalloc(strlen(url+4)+1,GFP_KERNEL);
224 printk("palacios: cannot allocate space for new in-memory keyed stream %s\n",url);
230 mks = (struct mem_keyed_stream *) kmalloc(sizeof(struct mem_keyed_stream),GFP_KERNEL);
234 printk("palacios: cannot allocate in-memory keyed stream %s\n",url);
238 mks->ht = (void*) palacios_create_htable(DEF_NUM_KEYS,hash_func,hash_comp);
242 printk("palacios: cannot allocate in-memory keyed stream %s\n",url);
247 if (!palacios_htable_insert(streams,(addr_t)(mykey),(addr_t)mks)) {
248 palacios_free_htable(mks->ht,1,1);
251 printk("palacios: cannot insert in-memory keyed stream %s\n",url);
254 mks->stype=STREAM_MEM;
257 mks->ot=V3_KS_WR_ONLY;
265 printk("palacios: unsupported open type in open_stream_mem\n");
275 static void close_stream_mem(v3_keyed_stream_t stream)
282 static v3_keyed_stream_key_t open_key_mem(v3_keyed_stream_t stream,
285 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
286 struct hashtable *s = mks->ht;
288 struct mem_stream *m;
290 m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
293 char *mykey = kmalloc(strlen(key)+1,GFP_KERNEL);
296 printk("palacios: cannot allocate copy of key for key %s\n",key);
302 m = create_mem_stream();
306 printk("palacios: cannot allocate mem keyed stream for key %s\n",key);
310 if (!palacios_htable_insert(s,(addr_t)mykey,(addr_t)m)) {
311 destroy_mem_stream(m);
313 printk("palacios: cannot insert mem keyed stream for key %s\n",key);
324 static void preallocate_hint_key_mem(v3_keyed_stream_t stream,
328 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
329 struct hashtable *s = mks->ht;
331 struct mem_stream *m;
333 if (mks->ot != V3_KS_WR_ONLY) {
337 m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
342 mykey=kmalloc(strlen(key)+1,GFP_KERNEL);
345 printk("palacios: cannot allocate key spce for preallocte for key %s\n",key);
351 m = create_mem_stream_internal(size);
354 printk("palacios: cannot preallocate mem keyed stream for key %s\n",key);
358 if (!palacios_htable_insert(s,(addr_t)mykey,(addr_t)m)) {
359 printk("palacios: cannot insert preallocated mem keyed stream for key %s\n",key);
360 destroy_mem_stream(m);
364 if (m->data_max < size) {
365 if (expand_mem_stream(m,size)) {
366 printk("palacios: cannot expand key for preallocation for key %s\n",key);
376 static void close_key_mem(v3_keyed_stream_t stream,
377 v3_keyed_stream_key_t key)
383 static sint64_t write_key_mem(v3_keyed_stream_t stream,
384 v3_keyed_stream_key_t key,
388 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
389 struct mem_stream *m = (struct mem_stream *) key;
393 if (mks->ot!=V3_KS_WR_ONLY) {
401 mylen = (uint32_t) len;
403 writelen=write_mem_stream(m,buf,mylen);
405 if (writelen!=mylen) {
406 printk("palacios: failed to write all data for key\n");
409 return (sint64_t)writelen;
413 static sint64_t read_key_mem(v3_keyed_stream_t stream,
414 v3_keyed_stream_key_t key,
418 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
419 struct mem_stream *m = (struct mem_stream *) key;
423 if (mks->ot!=V3_KS_RD_ONLY) {
431 mylen = (uint32_t) len;
433 readlen=read_mem_stream(m,buf,mylen);
435 if (readlen!=mylen) {
436 printk("palacios: failed to read all data for key\n");
439 return (sint64_t)readlen;
444 /***************************************************************************************************
445 File-based implementation ("file:")
446 *************************************************************************************************/
449 A file keyed stream contains the fd of the directory
453 struct file_keyed_stream {
455 v3_keyed_stream_open_t ot;
461 struct file *f; // the opened file
465 static v3_keyed_stream_t open_stream_file(char *url,
466 v3_keyed_stream_open_t ot)
468 struct file_keyed_stream *fks;
471 if (strncasecmp(url,"file:",5)) {
472 printk("palacios: illegitimate attempt to open file stream \"%s\"\n",url);
476 fks = kmalloc(sizeof(struct file_keyed_stream),GFP_KERNEL);
479 printk("palacios: cannot allocate space for file stream\n");
483 fks->path = (char*)kmalloc(strlen(url+5)+1,GFP_KERNEL);
486 printk("palacios: cannot allocate space for file stream\n");
491 strcpy(fks->path,url+5);
493 fks->stype=STREAM_FILE;
495 fks->ot= ot==V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot;
497 // Does the directory exist, and can we read/write it?
499 if (path_lookup(fks->path,LOOKUP_DIRECTORY|LOOKUP_FOLLOW,&nd)) {
501 // directory does does not exist.
503 if (ot==V3_KS_RD_ONLY || ot==V3_KS_WR_ONLY) {
505 // we are not being asked to create it
506 printk("palacios: attempt to open %s, which does not exist\n",fks->path);
511 // We are being asked to create it
517 if (path_lookup(fks->path,LOOKUP_PARENT|LOOKUP_FOLLOW,&nd)) {
518 printk("palacios: attempt to create %s failed because its parent cannot be looked up\n",fks->path);
522 // Can we write to the parent?
524 if (inode_permission(nd.path.dentry->d_inode, MAY_WRITE | MAY_EXEC)) {
525 printk("palacios: attempt to open %s, which has the wrong permissions for directory creation\n",fks->path);
529 // OK, we can, so let's create it
531 de = lookup_create(&nd,1);
534 printk("palacios: cannot allocate dentry\n");
538 err = vfs_mkdir(nd.path.dentry->d_inode, de, 0700);
540 // lookup_create locks this for us!
542 mutex_unlock(&(nd.path.dentry->d_inode->i_mutex));
545 printk("palacios: attempt to create %s failed because mkdir failed\n",fks->path);
549 // now the directory should exist and have reasonable permissions
550 return (v3_keyed_stream_t) fks;
555 // we must be in V3_KS_RD_ONLY or V3_KS_WR_ONLY,
556 // and the directory exists, so we must check the permissions
558 if (inode_permission(nd.path.dentry->d_inode, MAY_EXEC | (ot==V3_KS_RD_ONLY ? MAY_READ : MAY_WRITE))) {
559 printk("palacios: attempt to open %s, which has the wrong permissions\n",fks->path);
562 return (v3_keyed_stream_t) fks;
573 static void close_stream_file(v3_keyed_stream_t stream)
575 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
582 static void preallocate_hint_key_file(v3_keyed_stream_t stream,
589 static v3_keyed_stream_key_t open_key_file(v3_keyed_stream_t stream,
592 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
593 struct file_stream *fs;
596 // the path is the stream's path plus the key name
597 // file:/home/foo + "regext" => "/home/foo/regext"
598 path = (char *) kmalloc(strlen(fks->path)+strlen(key)+2,GFP_KERNEL);
600 printk("palacios: cannot allocate file keyed stream for key %s\n",key);
603 strcpy(path,fks->path);
607 fs = (struct file_stream *) kmalloc(sizeof(struct file_stream *),GFP_KERNEL);
610 printk("palacios: cannot allocate file keyed stream for key %s\n",key);
615 fs->stype=STREAM_FILE;
617 fs->f = filp_open(path,O_RDWR|O_CREAT,0600);
620 printk("palacios: cannot open relevent file \"%s\" for stream \"file:%s\" and key \"%s\"\n",path,fks->path,key);
632 static void close_key_file(v3_keyed_stream_t stream,
633 v3_keyed_stream_key_t key)
635 struct file_stream *fs = (struct file_stream *) key;
637 filp_close(fs->f,NULL);
642 static sint64_t write_key_file(v3_keyed_stream_t stream,
643 v3_keyed_stream_key_t key,
647 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
648 struct file_stream *fs = (struct file_stream *) key;
650 ssize_t done, left, total;
652 if (fks->ot!=V3_KS_WR_ONLY) {
667 done = fs->f->f_op->write(fs->f, buf+(total-left), left, &(fs->f->f_pos));
681 static sint64_t read_key_file(v3_keyed_stream_t stream,
682 v3_keyed_stream_key_t key,
686 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
687 struct file_stream *fs = (struct file_stream *) key;
689 ssize_t done, left, total;
691 if (fks->ot!=V3_KS_RD_ONLY) {
706 done = fs->f->f_op->read(fs->f, buf+(total-left), left, &(fs->f->f_pos));
722 /***************************************************************************************************
724 *************************************************************************************************/
726 static v3_keyed_stream_t open_stream(char *url,
727 v3_keyed_stream_open_t ot)
729 if (!strncasecmp(url,"mem:",4)) {
730 return open_stream_mem(url,ot);
731 } else if (!strncasecmp(url,"file:",5)) {
732 return open_stream_file(url,ot);
734 printk("palacios: unsupported type in attempt to open keyed stream \"%s\"\n",url);
739 static void close_stream(v3_keyed_stream_t stream)
741 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
744 return close_stream_mem(stream);
747 return close_stream_file(stream);
750 printk("palacios: unknown stream type %d in close\n",gks->stype);
755 static void preallocate_hint_key(v3_keyed_stream_t stream,
759 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
762 preallocate_hint_key_mem(stream,key,size);
765 preallocate_hint_key_file(stream,key,size);
768 printk("palacios: unknown stream type %d in preallocate_hint_key\n",gks->stype);
775 static v3_keyed_stream_key_t open_key(v3_keyed_stream_t stream,
778 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
781 return open_key_mem(stream,key);
784 return open_key_file(stream,key);
787 printk("palacios: unknown stream type %d in open_key\n",gks->stype);
794 static void close_key(v3_keyed_stream_t stream,
795 v3_keyed_stream_key_t key)
797 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
800 return close_key_mem(stream,key);
803 return close_key_file(stream,key);
806 printk("palacios: unknown stream type %d in close_key\n",gks->stype);
813 static sint64_t write_key(v3_keyed_stream_t stream,
814 v3_keyed_stream_key_t key,
818 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
821 return write_key_mem(stream,key,buf,len);
824 return write_key_file(stream,key,buf,len);
827 printk("palacios: unknown stream type %d in write_key\n",gks->stype);
835 static sint64_t read_key(v3_keyed_stream_t stream,
836 v3_keyed_stream_key_t key,
840 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
843 return read_key_mem(stream,key,buf,len);
846 return read_key_file(stream,key,buf,len);
849 printk("palacios: unknown stream type %d in write_key\n",gks->stype);
859 /***************************************************************************************************
860 Hooks to palacios and inititialization
861 *************************************************************************************************/
864 static struct v3_keyed_stream_hooks hooks = {
866 .close = close_stream,
867 .preallocate_hint_key = preallocate_hint_key,
868 .open_key = open_key,
869 .close_key = close_key,
870 .read_key = read_key,
871 .write_key = write_key
875 static int init_keyed_streams( void )
877 streams = palacios_create_htable(DEF_NUM_STREAMS,hash_func,hash_comp);
880 printk("palacios: failed to allocated stream pool for in-memory streams\n");
884 V3_Init_Keyed_Streams(&hooks);
891 static int deinit_keyed_streams( void )
893 printk("DEINIT OF PALACIOS KEYED STREAMS NOT IMPLEMENTED - WE HAVE JUST LEAKED MEMORY and/or file handles!\n");
898 static struct linux_ext key_stream_ext = {
899 .name = "KEYED_STREAM_INTERFACE",
900 .init = init_keyed_streams,
901 .deinit = deinit_keyed_streams,
907 register_extension(&key_stream_ext);