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.


1a590525dce46c97ecaa94cf2c7268003c1c3fbb
[palacios.git] / linux_module / iface-stream.c
1 /*
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National
4  * Science Foundation and the Department of Energy.
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2010, Lei Xia <lxia@northwestern.edu>
11  * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org>
12  * All rights reserved.
13  *
14  * This is free software.  You are permitted to use, redistribute,
15  * and modify it under the terms of the GNU General Public License
16  * Version 2 (GPLv2).  The accompanying COPYING file contains the
17  * full text of the license.
18  */
19  
20 #include <linux/errno.h>
21 #include <linux/percpu.h>
22 #include <linux/sched.h>
23 #include <linux/uaccess.h>
24 #include <linux/fs.h>
25 #include <linux/poll.h>
26 #include <linux/anon_inodes.h>
27 #include <linux/file.h>
28
29
30 #include <interfaces/vmm_stream.h>
31 #include "linux-exts.h"
32 #include "util-ringbuffer.h"
33 #include "vm.h"
34 #include "iface-stream.h"
35
36
37 // This is going to need to be a lot bigger...
38 #define STREAM_BUF_SIZE 1024
39
40
41
42
43 static struct list_head global_streams;
44
45 struct stream_buffer {
46     char name[STREAM_NAME_LEN];
47     struct ringbuf * buf;
48
49     int connected;
50
51     wait_queue_head_t intr_queue;
52     spinlock_t lock;
53
54     struct v3_guest * guest;
55     struct list_head stream_node;
56 };
57
58
59 // Currently just the list of open streams
60 struct vm_stream_state {
61     struct list_head open_streams;
62 };
63
64
65 static struct stream_buffer * find_stream_by_name(struct v3_guest * guest, const char * name) {
66     struct stream_buffer * stream = NULL;
67     struct list_head * stream_list = NULL;
68     struct vm_stream_state * vm_state = NULL;
69
70     if (guest == NULL) {
71         stream_list = &global_streams;
72     } else {
73         vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
74
75         if (vm_state == NULL) {
76             printk("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
77             return NULL;
78         }
79
80         stream_list = &(vm_state->open_streams);
81     }
82
83     list_for_each_entry(stream,  stream_list, stream_node) {
84         if (strncmp(stream->name, name, STREAM_NAME_LEN) == 0) {
85             return stream;
86         }
87     }
88
89     return NULL;
90 }
91
92
93
94 static ssize_t stream_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
95     struct stream_buffer * stream = filp->private_data;
96     
97     wait_event_interruptible(stream->intr_queue, (ringbuf_data_len(stream->buf) != 0));
98
99     return ringbuf_read(stream->buf, buf, size);
100 }
101
102
103
104 static struct file_operations stream_fops = {
105     .read = stream_read,
106     //    .release = stream_close,
107     //  .poll = stream_poll,
108 };
109
110
111
112 static void * palacios_stream_open(const char * name, void * private_data) {
113     struct v3_guest * guest = (struct v3_guest *)private_data;
114     struct stream_buffer * stream = NULL;
115     struct vm_stream_state * vm_state = NULL;
116
117     if (guest != NULL) {
118         vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
119
120         if (vm_state == NULL) {
121             printk("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
122             return NULL;
123         }
124     }
125
126     if (find_stream_by_name(guest, name) != NULL) {
127         printk("Stream already exists\n");
128         return NULL;
129     }
130
131     stream = kmalloc(sizeof(struct stream_buffer), GFP_KERNEL);
132         
133     stream->buf = create_ringbuf(STREAM_BUF_SIZE);
134     stream->guest = guest;
135
136     strncpy(stream->name, name, STREAM_NAME_LEN - 1);
137
138     init_waitqueue_head(&(stream->intr_queue));
139     spin_lock_init(&(stream->lock));
140
141     if (guest == NULL) {
142         list_add(&(stream->stream_node), &(global_streams));
143     } else {
144         list_add(&(stream->stream_node), &(vm_state->open_streams));
145     } 
146
147     return stream;
148 }
149
150
151 static int palacios_stream_write(void * stream_ptr, char * buf, int len) {
152     struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
153     int ret = 0;
154
155     ret = ringbuf_write(stream->buf, buf, len);
156
157     if (ret > 0) {
158         wake_up_interruptible(&(stream->intr_queue));
159     }
160
161     return ret;
162 }
163
164
165 static void palacios_stream_close(void * stream_ptr) {
166     struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
167
168     free_ringbuf(stream->buf);
169     list_del(&(stream->stream_node));
170     kfree(stream);
171
172 }
173
174 static struct v3_stream_hooks palacios_stream_hooks = {
175     .open = palacios_stream_open,
176     .write = palacios_stream_write,
177     .close = palacios_stream_close,
178 };
179
180
181 static int stream_init( void ) {
182     INIT_LIST_HEAD(&(global_streams));
183     V3_Init_Stream(&palacios_stream_hooks);
184     
185     return 0;
186 }
187
188
189 static int stream_deinit( void ) {
190     if (!list_empty(&(global_streams))) {
191         printk("Error removing module with open streams\n");
192         printk("TODO: free old streams... \n");
193     }
194
195     return 0;
196 }
197
198
199
200
201
202 static int stream_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data) {
203     void __user * argp = (void __user *)arg;
204     struct stream_buffer * stream = NULL;
205     int stream_fd = 0;
206     char name[STREAM_NAME_LEN];
207     unsigned long flags = 0;
208     int ret = -1;
209     
210     
211     if (copy_from_user(name, argp, STREAM_NAME_LEN)) {
212         printk("%s(%d): copy from user error...\n", __FILE__, __LINE__);
213         return -EFAULT;
214     }
215
216     stream = find_stream_by_name(guest, name);
217
218     if (stream == NULL) {
219         printk("Could not find stream (%s)\n", name);
220         return -EFAULT;
221     }
222
223     spin_lock_irqsave(&(stream->lock), flags);
224     if (stream->connected == 0) {
225         stream->connected = 1;
226         ret = 1;
227     }
228     spin_unlock_irqrestore(&(stream->lock), flags);
229
230
231     if (ret == -1) {
232         printk("Stream (%s) already connected\n", name);
233         return -EFAULT;
234     }
235
236     
237     stream_fd = anon_inode_getfd("v3-stream", &stream_fops, stream, 0);
238
239     if (stream_fd < 0) {
240         printk("Error creating stream inode for (%s)\n", name);
241         return stream_fd;
242     }
243
244     printk("Stream (%s) connected\n", name);
245
246     return stream_fd;
247 }
248
249
250 static int guest_stream_init(struct v3_guest * guest, void ** vm_data) {
251     struct vm_stream_state * state = kmalloc(sizeof(struct vm_stream_state), GFP_KERNEL);
252
253     INIT_LIST_HEAD(&(state->open_streams));
254     *vm_data = state;
255
256
257     add_guest_ctrl(guest, V3_VM_STREAM_CONNECT, stream_connect, state);
258
259     return 0;
260 }
261
262
263 static int guest_stream_deinit(struct v3_guest * guest, void * vm_data) {
264     struct vm_stream_state * state = vm_data;
265     if (!list_empty(&(state->open_streams))) {
266         printk("Error shutting down VM with open streams\n");
267     }
268
269     return 0;
270 }
271
272
273
274 static struct linux_ext stream_ext = {
275     .name = "STREAM_INTERFACE",
276     .init = stream_init,
277     .deinit = stream_deinit,
278     .guest_init = guest_stream_init,
279     .guest_deinit = guest_stream_deinit
280 };
281
282
283 register_extension(&stream_ext);