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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2010, Lei Xia <lxia@northwestern.edu>
11 * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
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.
20 #include <linux/errno.h>
21 #include <linux/percpu.h>
22 #include <linux/sched.h>
23 #include <linux/uaccess.h>
25 #include <linux/poll.h>
26 #include <linux/anon_inodes.h>
27 #include <linux/file.h>
30 #include <interfaces/vmm_stream.h>
31 #include "linux-exts.h"
32 #include "util-ringbuffer.h"
34 #include "iface-stream.h"
37 // This is going to need to be a lot bigger...
38 #define STREAM_BUF_SIZE 1024
43 static struct list_head global_streams;
45 struct stream_buffer {
46 char name[STREAM_NAME_LEN];
51 wait_queue_head_t intr_queue;
54 struct v3_guest * guest;
55 struct list_head stream_node;
59 // Currently just the list of open streams
60 struct vm_stream_state {
61 struct list_head open_streams;
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;
71 stream_list = &global_streams;
73 vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
75 if (vm_state == NULL) {
76 printk("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
80 stream_list = &(vm_state->open_streams);
83 list_for_each_entry(stream, stream_list, stream_node) {
84 if (strncmp(stream->name, name, STREAM_NAME_LEN) == 0) {
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;
97 wait_event_interruptible(stream->intr_queue, (ringbuf_data_len(stream->buf) != 0));
99 return ringbuf_read(stream->buf, buf, size);
104 static struct file_operations stream_fops = {
106 // .release = stream_close,
107 // .poll = stream_poll,
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;
118 vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
120 if (vm_state == NULL) {
121 printk("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
126 if (find_stream_by_name(guest, name) != NULL) {
127 printk("Stream already exists\n");
131 stream = kmalloc(sizeof(struct stream_buffer), GFP_KERNEL);
133 stream->buf = create_ringbuf(STREAM_BUF_SIZE);
134 stream->guest = guest;
136 strncpy(stream->name, name, STREAM_NAME_LEN - 1);
138 init_waitqueue_head(&(stream->intr_queue));
139 spin_lock_init(&(stream->lock));
142 list_add(&(stream->stream_node), &(global_streams));
144 list_add(&(stream->stream_node), &(vm_state->open_streams));
151 static int palacios_stream_write(void * stream_ptr, char * buf, int len) {
152 struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
155 ret = ringbuf_write(stream->buf, buf, len);
158 wake_up_interruptible(&(stream->intr_queue));
165 static void palacios_stream_close(void * stream_ptr) {
166 struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
168 free_ringbuf(stream->buf);
169 list_del(&(stream->stream_node));
174 static struct v3_stream_hooks palacios_stream_hooks = {
175 .open = palacios_stream_open,
176 .write = palacios_stream_write,
177 .close = palacios_stream_close,
181 static int stream_init( void ) {
182 INIT_LIST_HEAD(&(global_streams));
183 V3_Init_Stream(&palacios_stream_hooks);
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");
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;
206 char name[STREAM_NAME_LEN];
207 unsigned long flags = 0;
211 if (copy_from_user(name, argp, STREAM_NAME_LEN)) {
212 printk("%s(%d): copy from user error...\n", __FILE__, __LINE__);
216 stream = find_stream_by_name(guest, name);
218 if (stream == NULL) {
219 printk("Could not find stream (%s)\n", name);
223 spin_lock_irqsave(&(stream->lock), flags);
224 if (stream->connected == 0) {
225 stream->connected = 1;
228 spin_unlock_irqrestore(&(stream->lock), flags);
232 printk("Stream (%s) already connected\n", name);
237 stream_fd = anon_inode_getfd("v3-stream", &stream_fops, stream, 0);
240 printk("Error creating stream inode for (%s)\n", name);
244 printk("Stream (%s) connected\n", name);
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);
253 INIT_LIST_HEAD(&(state->open_streams));
257 add_guest_ctrl(guest, V3_VM_STREAM_CONNECT, stream_connect, state);
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");
274 static struct linux_ext stream_ext = {
275 .name = "STREAM_INTERFACE",
277 .deinit = stream_deinit,
278 .guest_init = guest_stream_init,
279 .guest_deinit = guest_stream_deinit
283 register_extension(&stream_ext);