2 * Palacios keyed stream interface
4 * Plus implementations for mem, file, and user space implementations
6 * (c) Peter Dinda, 2011 (interface, mem + file implementations + recooked user impl)
7 * (c) Clint Sbisa, 2011 (initial user space implementation on which this is based)
11 #include <linux/file.h>
12 #include <linux/uaccess.h>
13 #include <linux/namei.h>
14 #include <linux/vmalloc.h>
15 #include <linux/poll.h>
16 #include <linux/anon_inodes.h>
19 #include "util-hashtable.h"
20 #include "linux-exts.h"
23 #define sint64_t int64_t
24 #include <interfaces/vmm_keyed_stream.h>
26 #include "iface-keyed-stream-user.h"
29 This is an implementation of the Palacios keyed stream interface
30 that supports three flavors of streams:
32 "mem:" Streams are stored in a hash table
33 The values for this hash table are hash tables associated with
36 "file:" Streams are stored in files. Each high-level
37 open corresponds to a directory, while key corresponds to
38 a distinct file in that directory.
40 "user:" Stream requests are bounced to user space to be
41 handled there. A rendezvous approach similar to the host
42 device userland support is used
46 #define STREAM_GENERIC 0
52 All keyed streams and streams indicate their implementation type within the first field
54 struct generic_keyed_stream {
58 struct generic_stream {
65 /****************************************************************************************
66 Memory-based implementation ("mem:")
67 ****************************************************************************************/
69 #define DEF_NUM_STREAMS 16
70 #define DEF_NUM_KEYS 128
74 A memory keyed stream is a pointer to the underlying hash table
75 while a memory stream contains an extensible buffer for the stream
77 struct mem_keyed_stream {
79 v3_keyed_stream_open_t ot;
91 static struct mem_stream *create_mem_stream_internal(uint64_t size)
93 struct mem_stream *m = kmalloc(sizeof(struct mem_stream),GFP_KERNEL);
100 m->data = vmalloc(size);
107 m->stype = STREAM_MEM;
116 static struct mem_stream *create_mem_stream(void)
118 return create_mem_stream_internal(DEF_SIZE);
121 static void destroy_mem_stream(struct mem_stream *m)
132 static int expand_mem_stream(struct mem_stream *m, uint32_t new_size)
134 void *data = vmalloc(new_size);
141 nc = (new_size<m->data_max) ? new_size : m->data_max;
143 memcpy(data,m->data,nc);
149 if (m->size<m->data_max) {
156 static uint32_t write_mem_stream(struct mem_stream *m,
160 if ((m->ptr + len) > m->size) {
161 if (expand_mem_stream(m,m->ptr + len)) {
165 memcpy(m->data+m->ptr,data,len);
173 static uint32_t read_mem_stream(struct mem_stream *m,
177 if ((m->ptr + len) > m->data_max) {
180 memcpy(data,m->data+m->ptr,len);
188 static void reset_mem_stream(struct mem_stream *m)
194 static inline uint_t hash_func(addr_t key)
196 return palacios_hash_buffer((uchar_t*)key,strlen((uchar_t*)key));
199 static inline int hash_comp(addr_t k1, addr_t k2)
201 return strcasecmp((char*)k1,(char*)k2)==0;
205 // This stores all the memory keyed streams streams
206 static struct hashtable *mem_streams=0;
209 static v3_keyed_stream_t open_stream_mem(char *url,
210 v3_keyed_stream_open_t ot)
213 if (strncasecmp(url,"mem:",4)) {
214 printk("palacios: illegitimate attempt to open memory stream \"%s\"\n",url);
220 case V3_KS_WR_ONLY: {
221 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(mem_streams,(addr_t)(url+4));
225 return (v3_keyed_stream_t) mks;
229 case V3_KS_WR_ONLY_CREATE: {
230 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(mem_streams,(addr_t)(url+4));
234 mykey = kmalloc(strlen(url+4)+1,GFP_KERNEL);
237 printk("palacios: cannot allocate space for new in-memory keyed stream %s\n",url);
243 mks = (struct mem_keyed_stream *) kmalloc(sizeof(struct mem_keyed_stream),GFP_KERNEL);
247 printk("palacios: cannot allocate in-memory keyed stream %s\n",url);
251 mks->ht = (void*) palacios_create_htable(DEF_NUM_KEYS,hash_func,hash_comp);
255 printk("palacios: cannot allocate in-memory keyed stream %s\n",url);
260 if (!palacios_htable_insert(mem_streams,(addr_t)(mykey),(addr_t)mks)) {
261 palacios_free_htable(mks->ht,1,1);
264 printk("palacios: cannot insert in-memory keyed stream %s\n",url);
267 mks->stype=STREAM_MEM;
270 mks->ot=V3_KS_WR_ONLY;
278 printk("palacios: unsupported open type in open_stream_mem\n");
288 static void close_stream_mem(v3_keyed_stream_t stream)
295 static v3_keyed_stream_key_t open_key_mem(v3_keyed_stream_t stream,
298 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
299 struct hashtable *s = mks->ht;
301 struct mem_stream *m;
303 m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
306 char *mykey = kmalloc(strlen(key)+1,GFP_KERNEL);
309 printk("palacios: cannot allocate copy of key for key %s\n",key);
315 m = create_mem_stream();
319 printk("palacios: cannot allocate mem keyed stream for key %s\n",key);
323 if (!palacios_htable_insert(s,(addr_t)mykey,(addr_t)m)) {
324 destroy_mem_stream(m);
326 printk("palacios: cannot insert mem keyed stream for key %s\n",key);
337 static void preallocate_hint_key_mem(v3_keyed_stream_t stream,
341 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
342 struct hashtable *s = mks->ht;
344 struct mem_stream *m;
346 if (mks->ot != V3_KS_WR_ONLY) {
350 m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
355 mykey=kmalloc(strlen(key)+1,GFP_KERNEL);
358 printk("palacios: cannot allocate key spce for preallocte for key %s\n",key);
364 m = create_mem_stream_internal(size);
367 printk("palacios: cannot preallocate mem keyed stream for key %s\n",key);
371 if (!palacios_htable_insert(s,(addr_t)mykey,(addr_t)m)) {
372 printk("palacios: cannot insert preallocated mem keyed stream for key %s\n",key);
373 destroy_mem_stream(m);
377 if (m->data_max < size) {
378 if (expand_mem_stream(m,size)) {
379 printk("palacios: cannot expand key for preallocation for key %s\n",key);
389 static void close_key_mem(v3_keyed_stream_t stream,
390 v3_keyed_stream_key_t key)
396 static sint64_t write_key_mem(v3_keyed_stream_t stream,
397 v3_keyed_stream_key_t key,
401 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
402 struct mem_stream *m = (struct mem_stream *) key;
406 if (mks->ot!=V3_KS_WR_ONLY) {
414 mylen = (uint32_t) len;
416 writelen=write_mem_stream(m,buf,mylen);
418 if (writelen!=mylen) {
419 printk("palacios: failed to write all data for key\n");
422 return (sint64_t)writelen;
426 static sint64_t read_key_mem(v3_keyed_stream_t stream,
427 v3_keyed_stream_key_t key,
431 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
432 struct mem_stream *m = (struct mem_stream *) key;
436 if (mks->ot!=V3_KS_RD_ONLY) {
444 mylen = (uint32_t) len;
446 readlen=read_mem_stream(m,buf,mylen);
448 if (readlen!=mylen) {
449 printk("palacios: failed to read all data for key\n");
452 return (sint64_t)readlen;
457 /***************************************************************************************************
458 File-based implementation ("file:")
459 *************************************************************************************************/
462 A file keyed stream contains the fd of the directory
466 struct file_keyed_stream {
468 v3_keyed_stream_open_t ot;
474 struct file *f; // the opened file
478 static v3_keyed_stream_t open_stream_file(char *url,
479 v3_keyed_stream_open_t ot)
481 struct file_keyed_stream *fks;
484 if (strncasecmp(url,"file:",5)) {
485 printk("palacios: illegitimate attempt to open file stream \"%s\"\n",url);
489 fks = kmalloc(sizeof(struct file_keyed_stream),GFP_KERNEL);
492 printk("palacios: cannot allocate space for file stream\n");
496 fks->path = (char*)kmalloc(strlen(url+5)+1,GFP_KERNEL);
499 printk("palacios: cannot allocate space for file stream\n");
504 strcpy(fks->path,url+5);
506 fks->stype=STREAM_FILE;
508 fks->ot= ot==V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot;
510 // Does the directory exist, and can we read/write it?
512 if (path_lookup(fks->path,LOOKUP_DIRECTORY|LOOKUP_FOLLOW,&nd)) {
514 // directory does does not exist.
516 if (ot==V3_KS_RD_ONLY || ot==V3_KS_WR_ONLY) {
518 // we are not being asked to create it
519 printk("palacios: attempt to open %s, which does not exist\n",fks->path);
524 // We are being asked to create it
530 if (path_lookup(fks->path,LOOKUP_PARENT|LOOKUP_FOLLOW,&nd)) {
531 printk("palacios: attempt to create %s failed because its parent cannot be looked up\n",fks->path);
535 // Can we write to the parent?
537 if (inode_permission(nd.path.dentry->d_inode, MAY_WRITE | MAY_EXEC)) {
538 printk("palacios: attempt to open %s, which has the wrong permissions for directory creation\n",fks->path);
542 // OK, we can, so let's create it
544 de = lookup_create(&nd,1);
547 printk("palacios: cannot allocate dentry\n");
551 err = vfs_mkdir(nd.path.dentry->d_inode, de, 0700);
553 // lookup_create locks this for us!
555 mutex_unlock(&(nd.path.dentry->d_inode->i_mutex));
558 printk("palacios: attempt to create %s failed because mkdir failed\n",fks->path);
562 // now the directory should exist and have reasonable permissions
563 return (v3_keyed_stream_t) fks;
568 // we must be in V3_KS_RD_ONLY or V3_KS_WR_ONLY,
569 // and the directory exists, so we must check the permissions
571 if (inode_permission(nd.path.dentry->d_inode, MAY_EXEC | (ot==V3_KS_RD_ONLY ? MAY_READ : MAY_WRITE))) {
572 printk("palacios: attempt to open %s, which has the wrong permissions\n",fks->path);
575 return (v3_keyed_stream_t) fks;
586 static void close_stream_file(v3_keyed_stream_t stream)
588 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
595 static void preallocate_hint_key_file(v3_keyed_stream_t stream,
602 static v3_keyed_stream_key_t open_key_file(v3_keyed_stream_t stream,
605 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
606 struct file_stream *fs;
609 // the path is the stream's path plus the key name
610 // file:/home/foo + "regext" => "/home/foo/regext"
611 path = (char *) kmalloc(strlen(fks->path)+strlen(key)+2,GFP_KERNEL);
613 printk("palacios: cannot allocate file keyed stream for key %s\n",key);
616 strcpy(path,fks->path);
620 fs = (struct file_stream *) kmalloc(sizeof(struct file_stream *),GFP_KERNEL);
623 printk("palacios: cannot allocate file keyed stream for key %s\n",key);
628 fs->stype=STREAM_FILE;
630 fs->f = filp_open(path,O_RDWR|O_CREAT,0600);
633 printk("palacios: cannot open relevent file \"%s\" for stream \"file:%s\" and key \"%s\"\n",path,fks->path,key);
645 static void close_key_file(v3_keyed_stream_t stream,
646 v3_keyed_stream_key_t key)
648 struct file_stream *fs = (struct file_stream *) key;
650 filp_close(fs->f,NULL);
655 static sint64_t write_key_file(v3_keyed_stream_t stream,
656 v3_keyed_stream_key_t key,
660 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
661 struct file_stream *fs = (struct file_stream *) key;
663 ssize_t done, left, total;
665 if (fks->ot!=V3_KS_WR_ONLY) {
680 done = fs->f->f_op->write(fs->f, buf+(total-left), left, &(fs->f->f_pos));
694 static sint64_t read_key_file(v3_keyed_stream_t stream,
695 v3_keyed_stream_key_t key,
699 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
700 struct file_stream *fs = (struct file_stream *) key;
702 ssize_t done, left, total;
704 if (fks->ot!=V3_KS_RD_ONLY) {
719 done = fs->f->f_op->read(fs->f, buf+(total-left), left, &(fs->f->f_pos));
735 /***************************************************************************************************
736 User implementation ("user:")
737 *************************************************************************************************/
740 // List of all user keyed stream connections for the guest
741 struct user_keyed_streams {
743 struct list_head streams;
747 // A single keyed stream connection to user space
748 struct user_keyed_stream {
750 v3_keyed_stream_open_t otype;
756 wait_queue_head_t user_wait_queue;
757 wait_queue_head_t host_wait_queue;
759 struct palacios_user_keyed_stream_op *op;
761 struct list_head node;
766 // List of all of the user streams
768 static struct user_keyed_streams *user_streams;
772 static int resize_op(struct palacios_user_keyed_stream_op **op, uint64_t buf_len)
774 struct palacios_user_keyed_stream_op *old = *op;
775 struct palacios_user_keyed_stream_op *new;
778 new = kmalloc(sizeof(struct palacios_user_keyed_stream_op)+buf_len,GFP_ATOMIC);
782 new->len=sizeof(struct palacios_user_keyed_stream_op)+buf_len;
783 new->buf_len=buf_len;
788 if ((old->len-sizeof(struct palacios_user_keyed_stream_op)) >= buf_len) {
789 old->buf_len=buf_len;
794 return resize_op(op,buf_len);
800 // The assumption is that we enter this with the stream locked
801 // and we will return with it locked; additionally, the op structure
802 // will be overwritten with the response
804 static int do_request_to_response(struct user_keyed_stream *s, unsigned long *flags)
808 printk("palacios: user keyed stream request attempted while one is already in progress on %s\n",s->url);
812 // we are now waiting for a response
815 // release the stream
816 spin_unlock_irqrestore(&(s->lock), *flags);
818 // wake up anyone waiting on it
819 wake_up_interruptible(&(s->user_wait_queue));
821 // wait for someone to give us a response
822 while (wait_event_interruptible(s->host_wait_queue, (s->waiting == 0)) != 0) {}
824 // reacquire the lock for our called
825 spin_lock_irqsave(&(s->lock), *flags);
831 // The assumption is that we enter this with the stream locked
832 // and we will return with it UNlocked
834 static int do_response_to_request(struct user_keyed_stream *s, unsigned long *flags)
838 printk("palacios: user keyed stream response while no request is in progress on %s\n",s->url);
842 // we are now waiting for a request
845 // release the stream
846 spin_unlock_irqrestore(&(s->lock), *flags);
848 // wake up anyone waiting on it
849 wake_up_interruptible(&(s->host_wait_queue));
856 static unsigned int keyed_stream_poll_user(struct file *filp, poll_table *wait)
858 struct user_keyed_stream *s = (struct user_keyed_stream *) (filp->private_data);
865 spin_lock_irqsave(&(s->lock), flags);
868 spin_unlock_irqrestore(&(s->lock), flags);
869 return POLLIN | POLLRDNORM;
872 poll_wait(filp, &(s->user_wait_queue), wait);
874 spin_unlock_irqrestore(&(s->lock), flags);
880 static int keyed_stream_ioctl_user(struct inode *inode, struct file *filp, unsigned int ioctl, unsigned long arg)
882 void __user *argp = (void __user *)arg;
886 struct user_keyed_stream *s = (struct user_keyed_stream *) (filp->private_data);
890 case V3_KSTREAM_REQUEST_SIZE_IOCTL:
892 // inform request size
894 spin_lock_irqsave(&(s->lock), flags);
897 spin_unlock_irqrestore(&(s->lock), flags);
901 size = sizeof(struct palacios_user_keyed_stream_op) + s->op->buf_len;
903 if (copy_to_user((void * __user) argp, &size, sizeof(uint64_t))) {
904 spin_unlock_irqrestore(&(s->lock), flags);
905 printk("palacios: palacios user key size request failed to copy data\n");
909 spin_unlock_irqrestore(&(s->lock), flags);
915 case V3_KSTREAM_REQUEST_PULL_IOCTL:
919 spin_lock_irqsave(&(s->lock), flags);
922 spin_unlock_irqrestore(&(s->lock), flags);
923 printk("palacios: palacios user key pull request when not waiting\n");
927 size = sizeof(struct palacios_user_keyed_stream_op) + s->op->buf_len;
930 if (copy_to_user((void __user *) argp, s->op, size)) {
931 spin_unlock_irqrestore(&(s->lock), flags);
932 printk("palacios: palacios user key pull request failed to copy data\n");
936 spin_unlock_irqrestore(&(s->lock), flags);
943 case V3_KSTREAM_RESPONSE_PUSH_IOCTL:
947 spin_lock_irqsave(&(s->lock), flags);
950 spin_unlock_irqrestore(&(s->lock), flags);
951 printk("palacios: palacios user key push response when not waiting\n");
955 if (copy_from_user(&size, (void __user *) argp, sizeof(uint64_t))) {
956 printk("palacios: palacios user key push response failed to copy size\n");
957 spin_unlock_irqrestore(&(s->lock), flags);
961 if (resize_op(&(s->op),size-sizeof(struct palacios_user_keyed_stream_op))) {
962 printk("palacios: unable to resize op in user key push response\n");
963 spin_unlock_irqrestore(&(s->lock), flags);
967 if (copy_from_user(s->op, (void __user *) argp, size)) {
968 spin_unlock_irqrestore(&(s->lock), flags);
972 do_response_to_request(s,&flags);
973 // this will have unlocked s for us
980 printk("palacios: unknown ioctl in user keyed stream\n");
989 static int keyed_stream_release_user(struct inode *inode, struct file *filp)
991 struct user_keyed_stream *s = filp->private_data;
994 spin_lock_irqsave(&(user_streams->lock),f1);
995 spin_lock_irqsave(&(s->lock), f2);
997 list_del(&(s->node));
999 spin_unlock_irqrestore(&(s->lock), f2);
1000 spin_unlock_irqrestore(&(user_streams->lock), f1);
1008 static struct file_operations user_keyed_stream_fops = {
1009 .poll = keyed_stream_poll_user,
1010 .ioctl = keyed_stream_ioctl_user,
1011 .release = keyed_stream_release_user,
1016 user_keyed_streams are allocated on user connect, and deallocated on user release
1018 palacios-side opens and closes only manipulate the open type
1021 int keyed_stream_connect_user(struct v3_guest *guest, unsigned int cmd, unsigned long arg, void *priv_data)
1024 unsigned long flags;
1027 struct user_keyed_stream *s;
1029 if (!user_streams) {
1030 printk("palacios: no user space keyed streams!\n");
1035 if (copy_from_user(&len,(void __user *)arg,sizeof(len))) {
1036 printk("palacios: cannot copy url len from user\n");
1040 url = kmalloc(len,GFP_KERNEL);
1043 printk("palacios: cannot allocate url for user keyed stream\n");
1047 if (copy_from_user(url,((void __user *)arg)+sizeof(len),len)) {
1048 printk("palacios: cannot copy url from user\n");
1054 // Check for duplicate handler
1055 spin_lock_irqsave(&(user_streams->lock), flags);
1056 list_for_each_entry(s, &(user_streams->streams), node) {
1057 if (!strncasecmp(url, s->url, len)) {
1058 printk("palacios: user keyed stream connection with url \"%s\" already exists\n", url);
1063 spin_unlock_irqrestore(&(user_streams->lock), flags);
1065 // Create connection
1066 s = kmalloc(sizeof(struct user_keyed_stream), GFP_KERNEL);
1069 printk("palacios: cannot allocate new user keyed stream for %s\n",url);
1075 // Get file descriptor
1076 fd = anon_inode_getfd("v3-kstream", &user_keyed_stream_fops, s, 0);
1079 printk("palacios: cannot allocate file descriptor for new user keyed stream for %s\n",url);
1085 memset(s, 0, sizeof(struct user_keyed_stream));
1087 s->stype=STREAM_USER;
1090 init_waitqueue_head(&(s->user_wait_queue));
1091 init_waitqueue_head(&(s->host_wait_queue));
1093 // Insert connection into list
1094 spin_lock_irqsave(&(user_streams->lock), flags);
1095 list_add(&(s->node), &(user_streams->streams));
1096 spin_unlock_irqrestore(&(user_streams->lock), flags);
1101 static struct user_keyed_stream *keyed_stream_user_find(char *url)
1103 unsigned long flags;
1104 struct user_keyed_stream *s;
1106 if (!user_streams) {
1107 printk("palacios: no user space keyed streams available\n");
1111 spin_lock_irqsave(&(user_streams->lock), flags);
1112 list_for_each_entry(s, &(user_streams->streams), node) {
1113 if (!strcasecmp(url, s->url)) {
1114 spin_unlock_irqrestore(&(user_streams->lock), flags);
1119 spin_unlock_irqrestore(&(user_streams->lock), flags);
1125 static v3_keyed_stream_t open_stream_user(char *url, v3_keyed_stream_open_t ot)
1127 unsigned long flags;
1128 struct user_keyed_stream *s;
1130 s = keyed_stream_user_find(url);
1133 printk("palacios: cannot open user stream %s as it does not exist yet\n",url);
1137 spin_lock_irqsave(&(s->lock), flags);
1140 spin_unlock_irqrestore(&(s->lock), flags);
1141 printk("palacios: cannot open user stream %s as it is already in waiting state\n",url);
1145 s->otype = ot==V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot;
1147 spin_unlock_irqrestore(&(s->lock), flags);
1153 // close stream does not do anything. Creation of the stream and its cleanup
1154 // are driven by the user side, not the palacios side
1155 // might eventually want to reference count this, though
1156 static void close_stream_user(v3_keyed_stream_t stream)
1161 static void preallocate_hint_key_user(v3_keyed_stream_t stream,
1171 static v3_keyed_stream_key_t open_key_user(v3_keyed_stream_t stream, char *key)
1173 unsigned long flags;
1174 struct user_keyed_stream *s = (struct user_keyed_stream *) stream;
1175 uint64_t len = strlen(key)+1;
1178 spin_lock_irqsave(&(s->lock), flags);
1181 if (resize_op(&(s->op),len)) {
1182 spin_unlock_irqrestore(&(s->lock),flags);
1183 printk("palacios: cannot resize op in opening key %s on user keyed stream %s\n",key,s->url);
1187 s->op->type = PALACIOS_KSTREAM_OPEN_KEY;
1188 s->op->buf_len = len;
1189 strncpy(s->op->buf,key,len);
1191 // enter with it locked
1192 if (do_request_to_response(s,&flags)) {
1193 spin_unlock_irqrestore(&(s->lock),flags);
1194 printk("palacios: request/response handling failed\n");
1197 // return with it locked
1199 user_key=s->op->user_key;
1201 spin_unlock_irqrestore(&(s->lock),flags);
1206 static void close_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t key)
1208 struct user_keyed_stream *s = (struct user_keyed_stream *) stream;
1210 unsigned long flags;
1212 spin_lock_irqsave(&(s->lock), flags);
1214 if (resize_op(&(s->op),len)) {
1215 spin_unlock_irqrestore(&(s->lock),flags);
1216 printk("palacios: cannot resize op in closing key 0x%p on user keyed stream %s\n",key,s->url);
1220 s->op->type = PALACIOS_KSTREAM_CLOSE_KEY;
1221 s->op->buf_len = len;
1222 s->op->user_key = key;
1224 // enter with it locked
1225 if (do_request_to_response(s,&flags)) {
1226 spin_unlock_irqrestore(&(s->lock),flags);
1227 printk("palacios: request/response handling failed\n");
1230 // return with it locked
1232 spin_unlock_irqrestore(&(s->lock),flags);
1239 static sint64_t read_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t key,
1240 void *buf, sint64_t rlen)
1243 struct user_keyed_stream *s = (struct user_keyed_stream *) stream;
1246 unsigned long flags;
1248 spin_lock_irqsave(&(s->lock), flags);
1250 if (s->otype != V3_KS_RD_ONLY) {
1251 spin_unlock_irqrestore(&(s->lock),flags);
1252 printk("palacios: attempt to read key from stream that is not in read state on %s\n",s->url);
1255 if (resize_op(&(s->op),len)) {
1256 spin_unlock_irqrestore(&(s->lock),flags);
1257 printk("palacios: cannot resize op in reading key 0x%p on user keyed stream %s\n",key,s->url);
1261 s->op->type = PALACIOS_KSTREAM_READ_KEY;
1262 s->op->buf_len = len ;
1264 s->op->user_key = key;
1266 // enter with it locked
1267 if (do_request_to_response(s,&flags)) {
1268 spin_unlock_irqrestore(&(s->lock),flags);
1269 printk("palacios: request/response handling failed\n");
1272 // return with it locked
1275 if (s->op->xfer>0) {
1276 memcpy(buf,s->op->buf,s->op->xfer);
1281 spin_unlock_irqrestore(&(s->lock),flags);
1287 static sint64_t write_key_user(v3_keyed_stream_t stream, v3_keyed_stream_key_t key,
1288 void *buf, sint64_t wlen)
1291 struct user_keyed_stream *s = (struct user_keyed_stream *) stream;
1292 struct palacios_user_keyed_stream_op *op;
1293 uint64_t len = wlen ;
1295 unsigned long flags;
1297 spin_lock_irqsave(&(s->lock), flags);
1299 if (s->otype != V3_KS_WR_ONLY) {
1300 spin_unlock_irqrestore(&(s->lock),flags);
1301 printk("palacios: attempt to write key on stream that is not in write state on %s\n",s->url);
1304 if (resize_op(&(s->op),len)) {
1305 spin_unlock_irqrestore(&(s->lock),flags);
1306 printk("palacios: cannot resize op in reading key 0x%p on user keyed stream %s\n",key,s->url);
1312 s->op->type = PALACIOS_KSTREAM_WRITE_KEY;
1313 s->op->buf_len = len;
1315 s->op->user_key = key;
1317 memcpy(s->op->buf,buf,wlen);
1319 // enter with it locked
1320 if (do_request_to_response(s,&flags)) {
1321 spin_unlock_irqrestore(&(s->lock),flags);
1322 printk("palacios: request/response handling failed\n");
1325 // return with it locked
1329 spin_unlock_irqrestore(&(s->lock),flags);
1337 /***************************************************************************************************
1339 *************************************************************************************************/
1341 static v3_keyed_stream_t open_stream(char *url,
1342 v3_keyed_stream_open_t ot)
1344 if (!strncasecmp(url,"mem:",4)) {
1345 return open_stream_mem(url,ot);
1346 } else if (!strncasecmp(url,"file:",5)) {
1347 return open_stream_file(url,ot);
1348 } else if (!strncasecmp(url,"user:",5)) {
1349 return open_stream_user(url,ot);
1351 printk("palacios: unsupported type in attempt to open keyed stream \"%s\"\n",url);
1356 static void close_stream(v3_keyed_stream_t stream)
1358 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
1359 switch (gks->stype){
1361 return close_stream_mem(stream);
1364 return close_stream_file(stream);
1367 return close_stream_user(stream);
1370 printk("palacios: unknown stream type %d in close\n",gks->stype);
1375 static void preallocate_hint_key(v3_keyed_stream_t stream,
1379 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
1380 switch (gks->stype){
1382 preallocate_hint_key_mem(stream,key,size);
1385 preallocate_hint_key_file(stream,key,size);
1388 return preallocate_hint_key_user(stream,key,size);
1391 printk("palacios: unknown stream type %d in preallocate_hint_key\n",gks->stype);
1398 static v3_keyed_stream_key_t open_key(v3_keyed_stream_t stream,
1401 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
1402 switch (gks->stype){
1404 return open_key_mem(stream,key);
1407 return open_key_file(stream,key);
1410 return open_key_user(stream,key);
1413 printk("palacios: unknown stream type %d in open_key\n",gks->stype);
1420 static void close_key(v3_keyed_stream_t stream,
1421 v3_keyed_stream_key_t key)
1423 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
1424 switch (gks->stype){
1426 return close_key_mem(stream,key);
1429 return close_key_file(stream,key);
1432 return close_key_user(stream,key);
1435 printk("palacios: unknown stream type %d in close_key\n",gks->stype);
1442 static sint64_t write_key(v3_keyed_stream_t stream,
1443 v3_keyed_stream_key_t key,
1447 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
1448 switch (gks->stype){
1450 return write_key_mem(stream,key,buf,len);
1453 return write_key_file(stream,key,buf,len);
1456 return write_key_user(stream,key,buf,len);
1459 printk("palacios: unknown stream type %d in write_key\n",gks->stype);
1467 static sint64_t read_key(v3_keyed_stream_t stream,
1468 v3_keyed_stream_key_t key,
1472 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
1473 switch (gks->stype){
1475 return read_key_mem(stream,key,buf,len);
1478 return read_key_file(stream,key,buf,len);
1481 return read_key_user(stream,key,buf,len);
1484 printk("palacios: unknown stream type %d in read_key\n",gks->stype);
1494 /***************************************************************************************************
1495 Hooks to palacios and inititialization
1496 *************************************************************************************************/
1499 static struct v3_keyed_stream_hooks hooks = {
1500 .open = open_stream,
1501 .close = close_stream,
1502 .preallocate_hint_key = preallocate_hint_key,
1503 .open_key = open_key,
1504 .close_key = close_key,
1505 .read_key = read_key,
1506 .write_key = write_key
1510 static int init_keyed_streams( void )
1512 mem_streams = palacios_create_htable(DEF_NUM_STREAMS,hash_func,hash_comp);
1515 printk("palacios: failed to allocated stream pool for in-memory streams\n");
1519 user_streams = kmalloc(sizeof(struct user_keyed_streams),GFP_KERNEL);
1521 if (!user_streams) {
1522 printk("palacios: failed to allocated list for user streams\n");
1526 INIT_LIST_HEAD(&(user_streams->streams));
1528 spin_lock_init(&(user_streams->lock));
1530 V3_Init_Keyed_Streams(&hooks);
1536 static int deinit_keyed_streams( void )
1538 palacios_free_htable(mem_streams,1,1);
1540 kfree(user_streams);
1542 printk("Deinit of Palacios Keyed Streams likely leaked memory\n");
1548 static int guest_init_keyed_streams(struct v3_guest * guest, void ** vm_data )
1551 add_guest_ctrl(guest, V3_VM_KSTREAM_USER_CONNECT, keyed_stream_connect_user, 0);
1557 static int guest_deinit_keyed_streams(struct v3_guest * guest, void * vm_data)
1566 static struct linux_ext key_stream_ext = {
1567 .name = "KEYED_STREAM_INTERFACE",
1568 .init = init_keyed_streams,
1569 .deinit = deinit_keyed_streams,
1570 .guest_init = guest_init_keyed_streams,
1571 .guest_deinit = guest_deinit_keyed_streams,
1575 register_extension(&key_stream_ext);