Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Preallocation in keyed stream interface + bug fixes
[palacios.git] / linux_module / iface-keyed-stream.c
1 /*
2  * Palacios keyed stream interface
3  * (c) Peter Dinda, 2011
4  */
5
6 #include <linux/fs.h>
7 #include <linux/file.h>
8 #include <linux/uaccess.h>
9 #include <linux/namei.h>
10 #include <linux/vmalloc.h>
11
12 #include "palacios.h"
13 #include "util-hashtable.h"
14 #include "linux-exts.h"
15
16 #define sint64_t int64_t
17 #include <interfaces/vmm_keyed_stream.h>
18
19 /*
20   This is an implementation of the Palacios keyed stream interface
21   that supports two flavors of streams:
22
23   "mem:"   Streams are stored in a hash table
24   The values for this hash table are hash tables associated with 
25   each stream.   
26
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. 
30
31 */
32
33 #define STREAM_GENERIC 0
34 #define STREAM_MEM     1
35 #define STREAM_FILE    2
36
37
38 /*
39   All keyed streams and streams indicate their implementation type within the first field
40  */
41 struct generic_keyed_stream {
42     int stype;
43 };
44
45 struct generic_stream {
46     int stype;
47 };
48   
49
50
51
52 /****************************************************************************************
53    Memory-based implementation  ("mem:")
54 ****************************************************************************************/
55
56 #define DEF_NUM_STREAMS 16
57 #define DEF_NUM_KEYS    128
58 #define DEF_SIZE        128
59
60 /*
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
63  */
64 struct mem_keyed_stream {
65     int stype;
66     v3_keyed_stream_open_t ot;
67     struct hashtable *ht;
68 };
69
70 struct mem_stream {
71     int       stype;
72     char     *data;
73     uint32_t  size;
74     uint32_t  data_max;
75     uint32_t  ptr;
76 };
77
78 static struct mem_stream *create_mem_stream_internal(uint64_t size)
79 {
80     struct mem_stream *m = kmalloc(sizeof(struct mem_stream),GFP_KERNEL);
81
82     if (!m) {
83         return 0;
84     }
85
86
87     m->data = vmalloc(size);
88     
89     if (!m->data) { 
90         kfree(m);
91         return 0;
92     }
93
94     m->stype = STREAM_MEM;
95     m->size=size;
96     m->ptr=0;
97     m->data_max=0;
98     
99     return m;
100 }
101
102
103 static struct mem_stream *create_mem_stream(void)
104 {
105     return create_mem_stream_internal(DEF_SIZE);
106 }
107
108 static void destroy_mem_stream(struct mem_stream *m)
109 {
110     if (m) {
111         if (m->data) {
112             kfree(m->data);
113         }
114         m->data=0;
115         kfree(m);
116     }
117 }
118     
119 static int expand_mem_stream(struct mem_stream *m, uint32_t new_size)
120 {
121     void *data = vmalloc(new_size);
122     uint32_t nc;
123
124     if (!data) { 
125         return -1;
126     }
127     
128     nc = (new_size<m->data_max) ? new_size : m->data_max;
129
130     memcpy(data,m->data,nc);
131
132     kfree(m->data);
133
134     m->data=data;
135     m->size=new_size;
136     if (m->size<m->data_max) { 
137         m->data_max=m->size;
138     }
139    
140     return 0;
141 }
142
143 static uint32_t write_mem_stream(struct mem_stream *m,
144                                  void *data,
145                                  uint32_t len)
146 {
147     if ((m->ptr + len) > m->size) { 
148         if (expand_mem_stream(m,m->ptr + len)) { 
149             return 0;
150         }
151     }
152     memcpy(m->data+m->ptr,data,len);
153     m->ptr+=len;
154     m->data_max=m->ptr;
155     
156     return len;
157
158 }
159
160 static uint32_t read_mem_stream(struct mem_stream *m,
161                                 void *data,
162                                 uint32_t len)
163 {
164     if ((m->ptr + len) > m->data_max) { 
165         return 0;
166     }
167     memcpy(data,m->data+m->ptr,len);
168     m->ptr+=len;
169     
170     return len;
171
172 }
173
174
175 static void reset_mem_stream(struct mem_stream *m)
176 {
177     m->ptr=0;
178 }
179
180
181 static inline uint_t hash_func(addr_t key)
182 {
183     return palacios_hash_buffer((uchar_t*)key,strlen((uchar_t*)key));
184 }
185
186 static inline int hash_comp(addr_t k1, addr_t k2)
187 {
188     return strcasecmp((char*)k1,(char*)k2)==0;
189 }
190
191
192 // This stores all the memory keyed streams streams
193 static struct hashtable *streams=0;
194
195
196 static v3_keyed_stream_t open_stream_mem(char *url,
197                                          v3_keyed_stream_open_t ot)
198 {
199
200     if (strncasecmp(url,"mem:",4)) { 
201         printk("palacios: illegitimate attempt to open memory stream \"%s\"\n",url);
202         return 0;
203     }
204
205     switch (ot) { 
206         case V3_KS_RD_ONLY:
207         case V3_KS_WR_ONLY: {
208             struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(streams,(addr_t)(url+4));
209             if (mks) { 
210                 mks->ot=ot;
211             }
212             return (v3_keyed_stream_t) mks;
213         }
214             break;
215
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));
218             if (!mks) { 
219                 char *mykey;
220
221                 mykey = kmalloc(strlen(url+4)+1,GFP_KERNEL);
222
223                 if (!mykey) { 
224                     printk("palacios: cannot allocate space for new in-memory keyed stream %s\n",url);
225                     return 0;
226                 }
227
228                 strcpy(mykey,url+4);
229                 
230                 mks = (struct mem_keyed_stream *) kmalloc(sizeof(struct mem_keyed_stream),GFP_KERNEL);
231
232                 if (!mks) { 
233                     kfree(mykey);
234                     printk("palacios: cannot allocate in-memory keyed stream %s\n",url);
235                     return 0;
236                 }
237             
238                 mks->ht = (void*) palacios_create_htable(DEF_NUM_KEYS,hash_func,hash_comp);
239                 if (!mks->ht) { 
240                     kfree(mks);
241                     kfree(mykey);
242                     printk("palacios: cannot allocate in-memory keyed stream %s\n",url);
243                     return 0;
244                 }
245
246                 
247                 if (!palacios_htable_insert(streams,(addr_t)(mykey),(addr_t)mks)) { 
248                     palacios_free_htable(mks->ht,1,1);
249                     kfree(mks);
250                     kfree(mykey);
251                     printk("palacios: cannot insert in-memory keyed stream %s\n",url);
252                     return 0;
253                 }
254                 mks->stype=STREAM_MEM;
255             }
256
257             mks->ot=V3_KS_WR_ONLY;
258             
259             return mks;
260             
261         }
262             break;
263
264         default:
265             printk("palacios: unsupported open type in open_stream_mem\n");
266             break;
267     }
268     
269     return 0;
270         
271 }
272
273
274
275 static void close_stream_mem(v3_keyed_stream_t stream)
276 {
277     // nothing to do
278     return;
279 }
280
281
282 static v3_keyed_stream_key_t open_key_mem(v3_keyed_stream_t stream,
283                                           char *key)
284 {
285     struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
286     struct hashtable *s = mks->ht;
287
288     struct mem_stream *m;
289
290     m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
291
292     if (!m) { 
293         char *mykey = kmalloc(strlen(key)+1,GFP_KERNEL);
294
295         if (!mykey) { 
296             printk("palacios: cannot allocate copy of key for key %s\n",key);
297             return 0;
298         }
299
300         strcpy(mykey,key);
301
302         m = create_mem_stream();
303         
304         if (!m) { 
305             kfree(mykey);
306             printk("palacios: cannot allocate mem keyed stream for key %s\n",key);
307             return 0;
308         }
309
310         if (!palacios_htable_insert(s,(addr_t)mykey,(addr_t)m)) {
311             destroy_mem_stream(m);
312             kfree(mykey);
313             printk("palacios: cannot insert mem keyed stream for key %s\n",key);
314             return 0;
315         }
316     }
317
318     reset_mem_stream(m);
319     return m;
320
321 }
322
323
324 static void preallocate_hint_key_mem(v3_keyed_stream_t stream,
325                                      char *key,
326                                      uint64_t size)
327 {
328     struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
329     struct hashtable *s = mks->ht;
330
331     struct mem_stream *m;
332
333     if (mks->ot != V3_KS_WR_ONLY) { 
334         return;
335     }
336
337     m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
338
339     if (!m) {
340         char *mykey;
341         
342         mykey=kmalloc(strlen(key)+1,GFP_KERNEL);
343         
344         if (!mykey) { 
345             printk("palacios: cannot allocate key spce for preallocte for key %s\n",key);
346             return;
347         }
348         
349         strcpy(mykey,key);
350        
351         m = create_mem_stream_internal(size);
352         
353         if (!m) { 
354             printk("palacios: cannot preallocate mem keyed stream for key %s\n",key);
355             return;
356         }
357
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);
361             return;
362         }
363     } else {
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);
367                 return;
368             }
369         }
370     }
371
372     return;
373
374 }
375
376 static void close_key_mem(v3_keyed_stream_t stream, 
377                           v3_keyed_stream_key_t key)
378 {
379     // nothing to do
380     return;
381 }
382
383 static sint64_t write_key_mem(v3_keyed_stream_t stream, 
384                               v3_keyed_stream_key_t key,
385                               void *buf,
386                               sint64_t len)
387 {
388     struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
389     struct mem_stream *m = (struct mem_stream *) key;
390     uint32_t mylen;
391     uint32_t writelen;
392
393     if (mks->ot!=V3_KS_WR_ONLY) {
394         return -1;
395     }
396
397     if (len<0) { 
398         return -1;
399     }
400     
401     mylen = (uint32_t) len;
402
403     writelen=write_mem_stream(m,buf,mylen);
404
405     if (writelen!=mylen) { 
406         printk("palacios: failed to write all data for key\n");
407         return -1;
408     } else {
409         return (sint64_t)writelen;
410     }
411 }
412
413 static sint64_t read_key_mem(v3_keyed_stream_t stream, 
414                              v3_keyed_stream_key_t key,
415                              void *buf,
416                              sint64_t len)
417 {
418     struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
419     struct mem_stream *m = (struct mem_stream *) key;
420     uint32_t mylen;
421     uint32_t readlen;
422     
423     if (mks->ot!=V3_KS_RD_ONLY) {
424         return -1;
425     }
426
427     if (len<0) { 
428         return -1;
429     }
430     
431     mylen = (uint32_t) len;
432     
433     readlen=read_mem_stream(m,buf,mylen);
434     
435     if (readlen!=mylen) { 
436         printk("palacios: failed to read all data for key\n");
437         return -1;
438     } else {
439         return (sint64_t)readlen;
440     }
441 }
442
443
444 /***************************************************************************************************
445   File-based implementation  ("file:")
446 *************************************************************************************************/
447
448 /*
449   A file keyed stream contains the fd of the directory
450   and a path
451 */
452
453 struct file_keyed_stream {
454     int   stype;
455     v3_keyed_stream_open_t ot;
456     char  *path;
457 };
458
459 struct file_stream {
460     int   stype;
461     struct file *f;   // the opened file
462 };
463
464
465 static v3_keyed_stream_t open_stream_file(char *url,
466                                           v3_keyed_stream_open_t ot)
467 {
468     struct file_keyed_stream *fks;
469     struct nameidata nd;
470
471     if (strncasecmp(url,"file:",5)) { 
472         printk("palacios: illegitimate attempt to open file stream \"%s\"\n",url);
473         return 0;
474     }
475
476     fks = kmalloc(sizeof(struct file_keyed_stream),GFP_KERNEL);
477     
478     if (!fks) { 
479         printk("palacios: cannot allocate space for file stream\n");
480         return 0;
481     }
482
483     fks->path = (char*)kmalloc(strlen(url+5)+1,GFP_KERNEL);
484     
485     if (!(fks->path)) { 
486         printk("palacios: cannot allocate space for file stream\n");
487         kfree(fks);
488         return 0;
489     }
490     
491     strcpy(fks->path,url+5);
492     
493     fks->stype=STREAM_FILE;
494
495     fks->ot= ot==V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot;
496
497     // Does the directory exist, and can we read/write it?
498    
499     if (path_lookup(fks->path,LOOKUP_DIRECTORY|LOOKUP_FOLLOW,&nd)) { 
500
501         // directory does does not exist.  
502
503         if (ot==V3_KS_RD_ONLY || ot==V3_KS_WR_ONLY) { 
504
505             // we are not being asked to create it
506             printk("palacios: attempt to open %s, which does not exist\n",fks->path);
507             goto fail_out;
508
509         } else {
510
511             // We are being asked to create it
512
513             struct dentry *de;
514             int err;
515
516             // Find its parent
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);
519                 goto fail_out;
520             }
521
522             // Can we write to the parent?
523
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);
526                 goto fail_out;
527             }
528
529             // OK, we can, so let's create it
530
531             de = lookup_create(&nd,1);
532
533             if (IS_ERR(de)) { 
534                 printk("palacios: cannot allocate dentry\n");
535                 goto fail_out;
536             }
537
538             err = vfs_mkdir(nd.path.dentry->d_inode, de, 0700);
539
540             // lookup_create locks this for us!
541
542             mutex_unlock(&(nd.path.dentry->d_inode->i_mutex));
543
544             if (err) {
545                 printk("palacios: attempt to create %s failed because mkdir failed\n",fks->path);
546                 goto fail_out;
547             }
548
549             // now the directory should exist and have reasonable permissions
550             return (v3_keyed_stream_t) fks;
551         }
552     } 
553
554     
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
557
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);
560         goto fail_out;
561     } else {
562         return (v3_keyed_stream_t) fks;
563     }
564
565
566  fail_out:
567     kfree(fks->path);
568     kfree(fks);
569     return 0;
570
571 }
572
573 static void close_stream_file(v3_keyed_stream_t stream)
574 {
575     struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
576     
577     kfree(fks->path);
578     kfree(fks);
579
580 }
581
582 static void preallocate_hint_key_file(v3_keyed_stream_t stream,
583                                       char *key,
584                                       uint64_t size)
585 {
586     return;
587 }
588
589 static v3_keyed_stream_key_t open_key_file(v3_keyed_stream_t stream,
590                                            char *key)
591 {
592     struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
593     struct file_stream *fs;
594     char *path;
595
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);
599     if (!path) {                                
600         printk("palacios: cannot allocate file keyed stream for key %s\n",key);
601         return 0;
602     }
603     strcpy(path,fks->path);
604     strcat(path,"/");
605     strcat(path,key);
606     
607     fs = (struct file_stream *) kmalloc(sizeof(struct file_stream *),GFP_KERNEL);
608     
609     if (!fs) { 
610         printk("palacios: cannot allocate file keyed stream for key %s\n",key);
611         kfree(path);
612         return 0;
613     }
614
615     fs->stype=STREAM_FILE;
616
617     fs->f = filp_open(path,O_RDWR|O_CREAT,0600);
618     
619     if (IS_ERR(fs->f)) {
620         printk("palacios: cannot open relevent file \"%s\" for stream \"file:%s\" and key \"%s\"\n",path,fks->path,key);
621         kfree(fs);
622         kfree(path);
623         return 0;
624     }
625
626     kfree(path);
627
628     return fs;
629 }
630
631
632 static void close_key_file(v3_keyed_stream_t stream, 
633                            v3_keyed_stream_key_t key)
634 {
635     struct file_stream *fs = (struct file_stream *) key;
636
637     filp_close(fs->f,NULL);
638
639     kfree(fs);
640 }
641
642 static sint64_t write_key_file(v3_keyed_stream_t stream, 
643                                v3_keyed_stream_key_t key,
644                                void *buf,
645                                sint64_t len)
646 {
647     struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
648     struct file_stream *fs = (struct file_stream *) key;
649     mm_segment_t old_fs;
650     ssize_t done, left, total;
651     
652     if (fks->ot!=V3_KS_WR_ONLY) { 
653         return -1;
654     }
655     
656     if (len<0) { 
657         return -1;
658     }
659
660     total=len;
661     left=len;
662
663     old_fs = get_fs();
664     set_fs(get_ds());
665
666     while (left>0) {
667         done = fs->f->f_op->write(fs->f, buf+(total-left), left, &(fs->f->f_pos));
668         if (done<=0) {
669             return -1;
670         } else {
671             left -= done;
672         }
673     }
674     set_fs(old_fs);
675
676     return len;
677 }
678
679
680
681 static sint64_t read_key_file(v3_keyed_stream_t stream, 
682                               v3_keyed_stream_key_t key,
683                               void *buf,
684                               sint64_t len)
685 {
686     struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
687     struct file_stream *fs = (struct file_stream *) key;
688     mm_segment_t old_fs;
689     ssize_t done, left, total;
690     
691     if (fks->ot!=V3_KS_RD_ONLY) { 
692         return -1;
693     }
694
695     if (len<0) { 
696         return -1;
697     }
698
699     total=len;
700     left=len;
701
702     old_fs = get_fs();
703     set_fs(get_ds());
704
705     while (left>0) {
706         done = fs->f->f_op->read(fs->f, buf+(total-left), left, &(fs->f->f_pos));
707         if (done<=0) {
708             return -1;
709         } else {
710             left -= done;
711         }
712     }
713     set_fs(old_fs);
714
715     return len;
716
717 }
718
719
720
721
722 /***************************************************************************************************
723   Generic interface
724 *************************************************************************************************/
725
726 static v3_keyed_stream_t open_stream(char *url,
727                                      v3_keyed_stream_open_t ot)
728 {
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);
733     } else {
734         printk("palacios: unsupported type in attempt to open keyed stream \"%s\"\n",url);
735         return 0;
736     }
737 }
738
739 static void close_stream(v3_keyed_stream_t stream)
740 {
741     struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
742     switch (gks->stype){ 
743         case STREAM_MEM:
744             return close_stream_mem(stream);
745             break;
746         case STREAM_FILE:
747             return close_stream_file(stream);
748             break;
749         default:
750             printk("palacios: unknown stream type %d in close\n",gks->stype);
751             break;
752     }
753 }
754
755 static void preallocate_hint_key(v3_keyed_stream_t stream,
756                                  char *key,
757                                  uint64_t size)
758 {
759     struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
760     switch (gks->stype){ 
761         case STREAM_MEM:
762             preallocate_hint_key_mem(stream,key,size);
763             break;
764         case STREAM_FILE:
765             preallocate_hint_key_file(stream,key,size);
766             break;
767         default:
768             printk("palacios: unknown stream type %d in preallocate_hint_key\n",gks->stype);
769             break;
770     }
771     return;
772 }
773
774
775 static v3_keyed_stream_key_t open_key(v3_keyed_stream_t stream,
776                                       char *key)
777 {
778     struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
779     switch (gks->stype){ 
780         case STREAM_MEM:
781             return open_key_mem(stream,key);
782             break;
783         case STREAM_FILE:
784             return open_key_file(stream,key);
785             break;
786         default:
787             printk("palacios: unknown stream type %d in open_key\n",gks->stype);
788             break;
789     }
790     return 0;
791 }
792
793
794 static void close_key(v3_keyed_stream_t stream, 
795                       v3_keyed_stream_key_t key)
796 {
797     struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
798     switch (gks->stype){ 
799         case STREAM_MEM:
800             return close_key_mem(stream,key);
801             break;
802         case STREAM_FILE:
803             return close_key_file(stream,key);
804             break;
805         default:
806             printk("palacios: unknown stream type %d in close_key\n",gks->stype);
807             break;
808     }
809     // nothing to do
810     return;
811 }
812
813 static sint64_t write_key(v3_keyed_stream_t stream, 
814                           v3_keyed_stream_key_t key,
815                           void *buf,
816                           sint64_t len)
817 {
818     struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
819     switch (gks->stype){ 
820         case STREAM_MEM:
821             return write_key_mem(stream,key,buf,len);
822             break;
823         case STREAM_FILE:
824             return write_key_file(stream,key,buf,len);
825             break;
826         default:
827             printk("palacios: unknown stream type %d in write_key\n",gks->stype);
828             return -1;
829             break;
830     }
831     return -1;
832 }
833
834
835 static sint64_t read_key(v3_keyed_stream_t stream, 
836                          v3_keyed_stream_key_t key,
837                          void *buf,
838                          sint64_t len)
839 {
840     struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
841     switch (gks->stype){ 
842         case STREAM_MEM:
843             return read_key_mem(stream,key,buf,len);
844             break;
845         case STREAM_FILE:
846             return read_key_file(stream,key,buf,len);
847             break;
848         default:
849             printk("palacios: unknown stream type %d in write_key\n",gks->stype);
850             return -1;
851             break;
852     }
853     return -1;
854 }
855
856
857
858
859 /***************************************************************************************************
860   Hooks to palacios and inititialization
861 *************************************************************************************************/
862
863     
864 static struct v3_keyed_stream_hooks hooks = {
865     .open = open_stream,
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
872 };
873
874
875 static int init_keyed_streams( void )
876 {
877     streams = palacios_create_htable(DEF_NUM_STREAMS,hash_func,hash_comp);
878
879     if (!streams) { 
880         printk("palacios: failed to allocated stream pool for in-memory streams\n");
881         return -1;
882     }
883
884     V3_Init_Keyed_Streams(&hooks);
885
886
887     return 0;
888
889 }
890
891 static int deinit_keyed_streams( void )
892 {
893     printk("DEINIT OF PALACIOS KEYED STREAMS NOT IMPLEMENTED - WE HAVE JUST LEAKED MEMORY and/or file handles!\n");
894     return -1;
895 }
896
897
898 static struct linux_ext key_stream_ext = {
899     .name = "KEYED_STREAM_INTERFACE",
900     .init = init_keyed_streams,
901     .deinit = deinit_keyed_streams,
902     .guest_init = NULL,
903     .guest_deinit = NULL
904 };
905
906
907 register_extension(&key_stream_ext);