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.


Actually do cleanup in guest deinit in stream iface
[palacios.git] / linux_module / iface-stream.c
1 /*
2  * Stream Implementation
3  * (c) Lei Xia  2010
4  */
5  
6  
7 #include <linux/errno.h>
8 #include <linux/percpu.h>
9 #include <linux/sched.h>
10 #include <linux/uaccess.h>
11 #include <linux/fs.h>
12 #include <linux/poll.h>
13 #include <linux/anon_inodes.h>
14 #include <linux/file.h>
15
16
17 #include <interfaces/vmm_stream.h>
18 #include "linux-exts.h"
19 #include "util-ringbuffer.h"
20 #include "vm.h"
21
22
23
24 // This is probably overkill
25 #define STREAM_RING_LEN 4096
26 #define STREAM_NAME_LEN 128
27
28
29
30 static struct list_head global_streams;
31
32
33
34 struct stream_state {
35     char name[STREAM_NAME_LEN];
36
37     struct ringbuf * out_ring;
38
39     int connected;
40
41     wait_queue_head_t intr_queue;
42     spinlock_t lock;
43
44     struct v3_guest * guest;
45     struct list_head stream_node;
46
47     struct v3_stream * v3_stream;
48 };
49
50
51 // Currently just the list of open streams
52 struct vm_global_streams {
53     struct list_head open_streams;
54 };
55
56
57
58
59
60 static struct stream_state * find_stream_by_name(struct v3_guest * guest, const char * name) {
61     struct stream_state * stream = NULL;
62     struct list_head * stream_list = NULL;
63     struct vm_global_streams * vm_state = NULL;
64
65     if (guest == NULL) {
66         stream_list = &global_streams;
67     } else {
68         vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
69
70         if (vm_state == NULL) {
71             ERROR("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
72             return NULL;
73         }
74
75         stream_list = &(vm_state->open_streams);
76     }
77
78     list_for_each_entry(stream,  stream_list, stream_node) {
79         if (strncmp(stream->name, name, STREAM_NAME_LEN) == 0) {
80             return stream;
81         }
82     }
83
84     return NULL;
85 }
86
87
88
89 #define TMP_BUF_LEN 128
90
91 static ssize_t stream_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
92     struct stream_state * stream = filp->private_data;
93     ssize_t bytes_read = 0;
94     ssize_t bytes_left = size;
95     unsigned long flags;
96     char tmp_buf[TMP_BUF_LEN];
97     ssize_t total_bytes_left = 0;
98
99     // memset(tmp_buf, 0, TMP_BUF_LEN);
100
101     while (bytes_left > 0) {
102         int tmp_len = (TMP_BUF_LEN > bytes_left) ? bytes_left : TMP_BUF_LEN;
103         int tmp_read = 0;
104
105         spin_lock_irqsave(&(stream->lock), flags);
106         tmp_read = ringbuf_read(stream->out_ring, tmp_buf, tmp_len);
107         spin_unlock_irqrestore(&(stream->lock), flags);
108
109         if (tmp_read == 0) {
110             // If userspace reads more than we have
111             break;
112         }
113
114         if (copy_to_user(buf + bytes_read, tmp_buf, tmp_read)) {
115             ERROR("Read Fault\n");
116             return -EFAULT;
117         }
118         
119         bytes_left -= tmp_read;
120         bytes_read += tmp_read;
121     }
122     
123
124     spin_lock_irqsave(&(stream->lock), flags); 
125     total_bytes_left = ringbuf_data_len(stream->out_ring);
126     spin_unlock_irqrestore(&(stream->lock), flags);
127
128     if (total_bytes_left > 0) {
129         wake_up_interruptible(&(stream->intr_queue));
130     }
131
132     return bytes_read;
133 }
134
135 static unsigned int 
136 stream_poll(struct file * filp, struct poll_table_struct * poll_tb) {
137     struct stream_state * stream = filp->private_data;
138     unsigned int mask = POLLIN | POLLRDNORM;
139     unsigned long flags;
140     int data_avail = 0;
141
142     poll_wait(filp, &(stream->intr_queue), poll_tb);
143
144     spin_lock_irqsave(&(stream->lock), flags);
145     data_avail = ringbuf_data_len(stream->out_ring);
146     spin_unlock_irqrestore(&(stream->lock), flags);
147
148     if (data_avail > 0) {
149         return mask;
150     }
151
152     return 0;
153
154 }
155
156 static ssize_t stream_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
157     struct stream_state * stream = filp->private_data;
158     char * kern_buf = NULL;
159     ssize_t bytes_written = 0;
160     
161     kern_buf = palacios_alloc(size);
162     
163     if (!kern_buf) { 
164         ERROR("Cannot allocate buffer in stream interface\n");
165         return -EFAULT;
166     }
167
168     if (copy_from_user(kern_buf, buf, size)) {
169         ERROR("Stream Write Failed\n");
170         palacios_free(kern_buf);
171         return -EFAULT;
172     };
173     
174     bytes_written = stream->v3_stream->input(stream->v3_stream, kern_buf, size);
175
176     palacios_free(kern_buf);
177
178     return bytes_written;
179 }
180
181
182 static int stream_release(struct inode * i, struct file * filp) {
183     struct stream_state * stream = filp->private_data;
184     unsigned long flags;
185     
186     spin_lock_irqsave(&(stream->lock), flags);
187     stream->connected = 0;
188     spin_unlock_irqrestore(&(stream->lock), flags);
189
190     
191     return 0;
192
193 }
194
195 static struct file_operations stream_fops = {
196     .read = stream_read,
197     .write = stream_write,
198     .release = stream_release,
199     .poll = stream_poll,
200 };
201
202
203
204 static void * palacios_stream_open(struct v3_stream * v3_stream, const char * name, void * private_data) {
205     struct v3_guest * guest = (struct v3_guest *)private_data;
206     struct stream_state * stream = NULL;
207     struct vm_global_streams * vm_state = NULL;
208
209     if (guest != NULL) {
210         vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
211
212         if (vm_state == NULL) {
213             ERROR("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
214             return NULL;
215         }
216     }
217
218     if (find_stream_by_name(guest, name) != NULL) {
219         ERROR("Stream already exists\n");
220         return NULL;
221     }
222
223     stream = palacios_alloc(sizeof(struct stream_state));
224     if (!stream) { 
225         ERROR("Unable to allocate stream\n");
226         return NULL;
227     }
228     memset(stream, 0, sizeof(struct stream_state));
229
230     stream->out_ring = create_ringbuf(STREAM_RING_LEN);
231     stream->v3_stream = v3_stream;
232     stream->guest = guest;
233     stream->connected = 0;
234
235     strncpy(stream->name, name, STREAM_NAME_LEN - 1);
236
237     init_waitqueue_head(&(stream->intr_queue));
238     spin_lock_init(&(stream->lock));
239
240     if (guest == NULL) {
241         list_add(&(stream->stream_node), &(global_streams));
242     } else {
243         list_add(&(stream->stream_node), &(vm_state->open_streams));
244     } 
245
246     return stream;
247 }
248
249
250 static uint64_t palacios_stream_output(struct v3_stream * v3_stream, char * buf, int len) {
251     struct stream_state * stream = (struct stream_state *)v3_stream->host_stream_data;
252     int bytes_written = 0;
253     unsigned long flags;
254     
255
256     if (stream->connected == 0) {
257         return 0;
258     }
259
260     while (bytes_written < len) {
261         spin_lock_irqsave(&(stream->lock), flags);
262         bytes_written += ringbuf_write(stream->out_ring, buf + bytes_written, len - bytes_written);
263         spin_unlock_irqrestore(&(stream->lock), flags);
264
265         wake_up_interruptible(&(stream->intr_queue));
266
267         if (bytes_written < len) {
268             // not enough space in ringbuffer, activate user space to drain it
269             schedule();
270         }
271     }
272
273     
274     return bytes_written;
275 }
276
277
278 static void palacios_stream_close(struct v3_stream * v3_stream) {
279     struct stream_state * stream = (struct stream_state *)v3_stream->host_stream_data;
280
281     free_ringbuf(stream->out_ring);
282     list_del(&(stream->stream_node));
283     palacios_free(stream);
284
285 }
286
287 static struct v3_stream_hooks palacios_stream_hooks = {
288     .open = palacios_stream_open,
289     .output = palacios_stream_output,
290     .close = palacios_stream_close,
291 };
292
293
294 static int stream_init( void ) {
295     INIT_LIST_HEAD(&(global_streams));
296     V3_Init_Stream(&palacios_stream_hooks);
297     
298     return 0;
299 }
300
301
302 static int stream_deinit( void ) {
303     struct stream_state * stream = NULL;
304     struct stream_state * tmp = NULL;
305
306     list_for_each_entry_safe(stream, tmp, &(global_streams), stream_node) {
307         free_ringbuf(stream->out_ring);
308         list_del(&(stream->stream_node));
309         palacios_free(stream);
310     }
311
312     return 0;
313 }
314
315
316
317
318
319 static int stream_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data) {
320     void __user * argp = (void __user *)arg;
321     struct stream_state * stream = NULL;
322     int stream_fd = 0;
323     char name[STREAM_NAME_LEN];
324     unsigned long flags = 0;
325     int ret = -1;
326     
327     
328     if (copy_from_user(name, argp, STREAM_NAME_LEN)) {
329         ERROR("%s(%d): copy from user error...\n", __FILE__, __LINE__);
330         return -EFAULT;
331     }
332
333     stream = find_stream_by_name(guest, name);
334
335     if (stream == NULL) {
336         ERROR("Could not find stream (%s)\n", name);
337         return -EFAULT;
338     }
339
340     spin_lock_irqsave(&(stream->lock), flags);
341     if (stream->connected == 0) {
342         stream->connected = 1;
343         ret = 1;
344     }
345     spin_unlock_irqrestore(&(stream->lock), flags);
346
347
348     if (ret == -1) {
349         ERROR("Stream (%s) already connected\n", name);
350         return -EFAULT;
351     }
352
353     
354     stream_fd = anon_inode_getfd("v3-stream", &stream_fops, stream, O_RDWR);
355
356     if (stream_fd < 0) {
357         ERROR("Error creating stream inode for (%s)\n", name);
358         return stream_fd;
359     }
360
361     INFO("Stream (%s) connected\n", name);
362
363     return stream_fd;
364 }
365
366
367 static int guest_stream_init(struct v3_guest * guest, void ** vm_data) {
368     struct vm_global_streams * state = palacios_alloc(sizeof(struct vm_global_streams));
369
370     if (!state) { 
371         ERROR("Unable to allocate state in stream init\n");
372         return -1;
373     }
374
375     INIT_LIST_HEAD(&(state->open_streams));
376     *vm_data = state;
377
378     add_guest_ctrl(guest, V3_VM_STREAM_CONNECT, stream_connect, state);
379
380     return 0;
381 }
382
383
384 static int guest_stream_deinit(struct v3_guest * guest, void * vm_data) {
385     struct vm_global_streams * state = vm_data;
386
387     struct stream_state * stream = NULL;
388     struct stream_state * tmp = NULL;
389
390     list_for_each_entry_safe(stream, tmp, &(global_streams), stream_node) {
391         free_ringbuf(stream->out_ring);
392         list_del(&(stream->stream_node));
393         palacios_free(stream);
394     }
395     
396     palacios_free(state);
397     
398     return 0;
399 }
400
401
402
403 static struct linux_ext stream_ext = {
404     .name = "STREAM_INTERFACE",
405     .init = stream_init,
406     .deinit = stream_deinit,
407     .guest_init = guest_stream_init,
408     .guest_deinit = guest_stream_deinit
409 };
410
411
412 register_extension(&stream_ext);