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>
12 #include "util-hashtable.h"
13 #include "linux-exts.h"
15 #define sint64_t int64_t
16 #include <interfaces/vmm_keyed_stream.h>
19 This is an implementation of the Palacios keyed stream interface
20 that supports two flavors of streams:
22 "mem:" Streams are stored in a hash table
23 The values for this hash table are hash tables associated with
26 "file:" Streams are stored in files. Each high-level
27 open corresponds to a directory, while key corresponds to
28 a distinct file in that directory.
32 #define STREAM_GENERIC 0
38 All keyed streams and streams indicate their implementation type within the first field
40 struct generic_keyed_stream {
44 struct generic_stream {
51 /****************************************************************************************
52 Memory-based implementation ("mem:")
53 ****************************************************************************************/
55 #define DEF_NUM_STREAMS 16
56 #define DEF_NUM_KEYS 128
60 A memory keyed stream is a pointer to the underlying hash table
61 while a memory stream contains an extensible buffer for the stream
63 struct mem_keyed_stream {
65 v3_keyed_stream_open_t ot;
77 static struct mem_stream *create_mem_stream(void)
79 struct mem_stream *m = kmalloc(sizeof(struct mem_stream),GFP_KERNEL);
86 m->data = kmalloc(DEF_SIZE,GFP_KERNEL);
93 m->stype = STREAM_MEM;
101 static void destroy_mem_stream(struct mem_stream *m)
112 static int expand_mem_stream(struct mem_stream *m, uint32_t new_size)
114 void *data = kmalloc(new_size,GFP_KERNEL);
121 nc = (new_size<m->data_max) ? new_size : m->data_max;
123 memcpy(data,m->data,nc);
129 if (m->size<m->data_max) {
136 static uint32_t write_mem_stream(struct mem_stream *m,
140 if ((m->ptr + len) > m->size) {
141 if (expand_mem_stream(m,m->ptr + len)) {
145 memcpy(m->data+m->ptr,data,len);
153 static uint32_t read_mem_stream(struct mem_stream *m,
157 if ((m->ptr + len) > m->data_max) {
160 memcpy(data,m->data+m->ptr,len);
168 static void reset_mem_stream(struct mem_stream *m)
174 static inline uint_t hash_func(addr_t key)
176 return palacios_hash_buffer((uchar_t*)key,strlen((uchar_t*)key));
179 static inline int hash_comp(addr_t k1, addr_t k2)
181 return strcasecmp((char*)k1,(char*)k2)==0;
185 // This stores all the memory keyed streams streams
186 static struct hashtable *streams=0;
189 static v3_keyed_stream_t open_stream_mem(char *url,
190 v3_keyed_stream_open_t ot)
193 if (strncasecmp(url,"mem:",4)) {
194 printk("palacios: illegitimate attempt to open memory stream \"%s\"\n",url);
200 case V3_KS_WR_ONLY: {
201 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(streams,(addr_t)(url+4));
205 return (v3_keyed_stream_t) mks;
209 case V3_KS_WR_ONLY_CREATE: {
210 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) palacios_htable_search(streams,(addr_t)(url+4));
212 mks = (struct mem_keyed_stream *) kmalloc(sizeof(struct mem_keyed_stream),GFP_KERNEL);
214 printk("palacios: cannot allocate in-memory keyed stream %s\n",url);
218 mks->ht = (void*) palacios_create_htable(DEF_NUM_KEYS,hash_func,hash_comp);
221 printk("palacios: cannot allocate in-memory keyed stream %s\n",url);
225 if (!palacios_htable_insert(streams,(addr_t)(url+4),(addr_t)mks)) {
226 palacios_free_htable(mks->ht,1,1);
228 printk("palacios: cannot insert in-memory keyed stream %s\n",url);
231 mks->stype=STREAM_MEM;
234 mks->ot=V3_KS_WR_ONLY;
242 printk("palacios: unsupported open type in open_stream_mem\n");
252 static void close_stream_mem(v3_keyed_stream_t stream)
259 static v3_keyed_stream_key_t open_key_mem(v3_keyed_stream_t stream,
262 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
263 struct hashtable *s = mks->ht;
265 struct mem_stream *m;
267 m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
270 m = create_mem_stream();
273 printk("palacios: cannot allocate mem keyed stream for key %s\n",key);
277 if (!palacios_htable_insert(s,(addr_t)key,(addr_t)m)) {
278 printk("palacios: cannot insert mem keyed stream for key %s\n",key);
279 destroy_mem_stream(m);
289 static void close_key_mem(v3_keyed_stream_t stream,
290 v3_keyed_stream_key_t key)
296 static sint64_t write_key_mem(v3_keyed_stream_t stream,
297 v3_keyed_stream_key_t key,
301 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
302 struct mem_stream *m = (struct mem_stream *) key;
306 if (mks->ot!=V3_KS_WR_ONLY) {
314 mylen = (uint32_t) len;
316 writelen=write_mem_stream(m,buf,mylen);
318 if (writelen!=mylen) {
319 printk("palacios: failed to write all data for key\n");
322 return (sint64_t)writelen;
326 static sint64_t read_key_mem(v3_keyed_stream_t stream,
327 v3_keyed_stream_key_t key,
331 struct mem_keyed_stream *mks = (struct mem_keyed_stream *) stream;
332 struct mem_stream *m = (struct mem_stream *) key;
336 if (mks->ot!=V3_KS_RD_ONLY) {
344 mylen = (uint32_t) len;
346 readlen=read_mem_stream(m,buf,mylen);
348 if (readlen!=mylen) {
349 printk("palacios: failed to read all data for key\n");
352 return (sint64_t)readlen;
357 /***************************************************************************************************
358 File-based implementation ("file:")
359 *************************************************************************************************/
362 A file keyed stream contains the fd of the directory
366 struct file_keyed_stream {
368 v3_keyed_stream_open_t ot;
374 struct file *f; // the opened file
378 static v3_keyed_stream_t open_stream_file(char *url,
379 v3_keyed_stream_open_t ot)
381 struct file_keyed_stream *fks;
384 if (strncasecmp(url,"file:",5)) {
385 printk("palacios: illegitimate attempt to open file stream \"%s\"\n",url);
389 fks = kmalloc(sizeof(struct file_keyed_stream),GFP_KERNEL);
392 printk("palacios: cannot allocate space for file stream\n");
396 fks->path = (char*)kmalloc(strlen(url+5)+1,GFP_KERNEL);
399 printk("palacios: cannot allocate space for file stream\n");
404 strcpy(fks->path,url+5);
406 fks->stype=STREAM_FILE;
408 fks->ot= ot==V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot;
410 // Does the directory exist, and can we read/write it?
412 if (path_lookup(fks->path,LOOKUP_DIRECTORY|LOOKUP_FOLLOW,&nd)) {
414 // directory does does not exist.
416 if (ot==V3_KS_RD_ONLY || ot==V3_KS_WR_ONLY) {
418 // we are not being asked to create it
419 printk("palacios: attempt to open %s, which does not exist\n",fks->path);
424 // We are being asked to create it
430 if (path_lookup(fks->path,LOOKUP_PARENT|LOOKUP_FOLLOW,&nd)) {
431 printk("palacios: attempt to create %s failed because its parent cannot be looked up\n",fks->path);
435 // Can we write to the parent?
437 if (inode_permission(nd.path.dentry->d_inode, MAY_WRITE | MAY_EXEC)) {
438 printk("palacios: attempt to open %s, which has the wrong permissions for directory creation\n",fks->path);
442 // OK, we can, so let's create it
444 de = lookup_create(&nd,1);
447 printk("palacios: cannot allocate dentry\n");
451 err = vfs_mkdir(nd.path.dentry->d_inode, de, 0700);
453 // lookup_create locks this for us!
455 mutex_unlock(&(nd.path.dentry->d_inode->i_mutex));
458 printk("palacios: attempt to create %s failed because mkdir failed\n",fks->path);
462 // now the directory should exist and have reasonable permissions
463 return (v3_keyed_stream_t) fks;
468 // we must be in V3_KS_RD_ONLY or V3_KS_WR_ONLY,
469 // and the directory exists, so we must check the permissions
471 if (inode_permission(nd.path.dentry->d_inode, MAY_EXEC | (ot==V3_KS_RD_ONLY ? MAY_READ : MAY_WRITE))) {
472 printk("palacios: attempt to open %s, which has the wrong permissions\n",fks->path);
475 return (v3_keyed_stream_t) fks;
486 static void close_stream_file(v3_keyed_stream_t stream)
488 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
495 static v3_keyed_stream_key_t open_key_file(v3_keyed_stream_t stream,
498 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
499 struct file_stream *fs;
502 // the path is the stream's path plus the key name
503 // file:/home/foo + "regext" => "/home/foo/regext"
504 path = (char *) kmalloc(strlen(fks->path)+strlen(key)+2,GFP_KERNEL);
506 printk("palacios: cannot allocate file keyed stream for key %s\n",key);
509 strcpy(path,fks->path);
513 fs = (struct file_stream *) kmalloc(sizeof(struct file_stream *),GFP_KERNEL);
516 printk("palacios: cannot allocate file keyed stream for key %s\n",key);
521 fs->stype=STREAM_FILE;
523 fs->f = filp_open(path,O_RDWR|O_CREAT,0600);
526 printk("palacios: cannot open relevent file \"%s\" for stream \"file:%s\" and key \"%s\"\n",path,fks->path,key);
538 static void close_key_file(v3_keyed_stream_t stream,
539 v3_keyed_stream_key_t key)
541 struct file_stream *fs = (struct file_stream *) key;
543 filp_close(fs->f,NULL);
548 static sint64_t write_key_file(v3_keyed_stream_t stream,
549 v3_keyed_stream_key_t key,
553 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
554 struct file_stream *fs = (struct file_stream *) key;
556 ssize_t done, left, total;
558 if (fks->ot!=V3_KS_WR_ONLY) {
573 done = fs->f->f_op->write(fs->f, buf+(total-left), left, &(fs->f->f_pos));
587 static sint64_t read_key_file(v3_keyed_stream_t stream,
588 v3_keyed_stream_key_t key,
592 struct file_keyed_stream *fks = (struct file_keyed_stream *) stream;
593 struct file_stream *fs = (struct file_stream *) key;
595 ssize_t done, left, total;
597 if (fks->ot!=V3_KS_RD_ONLY) {
612 done = fs->f->f_op->read(fs->f, buf+(total-left), left, &(fs->f->f_pos));
628 /***************************************************************************************************
630 *************************************************************************************************/
632 static v3_keyed_stream_t open_stream(char *url,
633 v3_keyed_stream_open_t ot)
635 if (!strncasecmp(url,"mem:",4)) {
636 return open_stream_mem(url,ot);
637 } else if (!strncasecmp(url,"file:",5)) {
638 return open_stream_file(url,ot);
640 printk("palacios: unsupported type in attempt to open keyed stream \"%s\"\n",url);
645 static void close_stream(v3_keyed_stream_t stream)
647 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
650 return close_stream_mem(stream);
653 return close_stream_file(stream);
656 printk("palacios: unknown stream type %d in close\n",gks->stype);
661 static v3_keyed_stream_key_t open_key(v3_keyed_stream_t stream,
664 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
667 return open_key_mem(stream,key);
670 return open_key_file(stream,key);
673 printk("palacios: unknown stream type %d in open_key\n",gks->stype);
680 static void close_key(v3_keyed_stream_t stream,
681 v3_keyed_stream_key_t key)
683 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
686 return close_key_mem(stream,key);
689 return close_key_file(stream,key);
692 printk("palacios: unknown stream type %d in close_key\n",gks->stype);
699 static sint64_t write_key(v3_keyed_stream_t stream,
700 v3_keyed_stream_key_t key,
704 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
707 return write_key_mem(stream,key,buf,len);
710 return write_key_file(stream,key,buf,len);
713 printk("palacios: unknown stream type %d in write_key\n",gks->stype);
721 static sint64_t read_key(v3_keyed_stream_t stream,
722 v3_keyed_stream_key_t key,
726 struct generic_keyed_stream *gks = (struct generic_keyed_stream *) stream;
729 return read_key_mem(stream,key,buf,len);
732 return read_key_file(stream,key,buf,len);
735 printk("palacios: unknown stream type %d in write_key\n",gks->stype);
745 /***************************************************************************************************
746 Hooks to palacios and inititialization
747 *************************************************************************************************/
750 static struct v3_keyed_stream_hooks hooks = {
752 .close = close_stream,
753 .open_key = open_key,
754 .close_key = close_key,
755 .read_key = read_key,
756 .write_key = write_key
760 static int init_keyed_streams( void )
762 streams = palacios_create_htable(DEF_NUM_STREAMS,hash_func,hash_comp);
765 printk("palacios: failed to allocated stream pool for in-memory streams\n");
769 V3_Init_Keyed_Streams(&hooks);
776 static int deinit_keyed_streams( void )
778 printk("DEINIT OF PALACIOS KEYED STREAMS NOT IMPLEMENTED - WE HAVE JUST LEAKED MEMORY and/or file handles!\n");
783 static struct linux_ext key_stream_ext = {
784 .name = "KEYED_STREAM_INTERFACE",
785 .init = init_keyed_streams,
786 .deinit = deinit_keyed_streams,
792 register_extension(&key_stream_ext);