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.


36582d9282c1b4db0e037e7ff5dcba76126992ab
[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 #include "iface-stream.h"
22
23
24 // This is going to need to be a lot bigger...
25 #define STREAM_BUF_SIZE 1024
26
27
28
29
30 static struct list_head global_streams;
31
32 struct stream_buffer {
33     char name[STREAM_NAME_LEN];
34     struct ringbuf * buf;
35
36     int connected;
37
38     wait_queue_head_t intr_queue;
39     spinlock_t lock;
40
41     struct v3_guest * guest;
42     struct list_head stream_node;
43 };
44
45
46 // Currently just the list of open streams
47 struct vm_stream_state {
48     struct list_head open_streams;
49 };
50
51
52 static struct stream_buffer * find_stream_by_name(struct v3_guest * guest, const char * name) {
53     struct stream_buffer * stream = NULL;
54     struct list_head * stream_list = NULL;
55     struct vm_stream_state * vm_state = NULL;
56
57     if (guest == NULL) {
58         stream_list = &global_streams;
59     } else {
60         vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
61
62         if (vm_state == NULL) {
63             printk("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
64             return NULL;
65         }
66
67         stream_list = &(vm_state->open_streams);
68     }
69
70     list_for_each_entry(stream,  stream_list, stream_node) {
71         if (strncmp(stream->name, name, STREAM_NAME_LEN) == 0) {
72             return stream;
73         }
74     }
75
76     return NULL;
77 }
78
79
80
81 static ssize_t stream_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
82     struct stream_buffer * stream = filp->private_data;
83     
84     wait_event_interruptible(stream->intr_queue, (ringbuf_data_len(stream->buf) != 0));
85
86     return ringbuf_read(stream->buf, buf, size);
87 }
88
89
90
91 static struct file_operations stream_fops = {
92     .read = stream_read,
93     //    .release = stream_close,
94     //  .poll = stream_poll,
95 };
96
97
98
99 static void * palacios_stream_open(const char * name, void * private_data) {
100     struct v3_guest * guest = (struct v3_guest *)private_data;
101     struct stream_buffer * stream = NULL;
102     struct vm_stream_state * vm_state = NULL;
103
104     if (guest != NULL) {
105         vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
106
107         if (vm_state == NULL) {
108             printk("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
109             return NULL;
110         }
111     }
112
113     if (find_stream_by_name(guest, name) != NULL) {
114         printk("Stream already exists\n");
115         return NULL;
116     }
117
118     stream = kmalloc(sizeof(struct stream_buffer), GFP_KERNEL);
119         
120     stream->buf = create_ringbuf(STREAM_BUF_SIZE);
121     stream->guest = guest;
122
123     strncpy(stream->name, name, STREAM_NAME_LEN - 1);
124
125     init_waitqueue_head(&(stream->intr_queue));
126     spin_lock_init(&(stream->lock));
127
128     if (guest == NULL) {
129         list_add(&(stream->stream_node), &(global_streams));
130     } else {
131         list_add(&(stream->stream_node), &(vm_state->open_streams));
132     } 
133
134     return stream;
135 }
136
137
138 static int palacios_stream_write(void * stream_ptr, char * buf, int len) {
139     struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
140     int ret = 0;
141
142     ret = ringbuf_write(stream->buf, buf, len);
143
144     if (ret > 0) {
145         wake_up_interruptible(&(stream->intr_queue));
146     }
147
148     return ret;
149 }
150
151
152 static void palacios_stream_close(void * stream_ptr) {
153     struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
154
155     free_ringbuf(stream->buf);
156     list_del(&(stream->stream_node));
157     kfree(stream);
158
159 }
160
161 static struct v3_stream_hooks palacios_stream_hooks = {
162     .open = palacios_stream_open,
163     .write = palacios_stream_write,
164     .close = palacios_stream_close,
165 };
166
167
168 static int stream_init( void ) {
169     INIT_LIST_HEAD(&(global_streams));
170     V3_Init_Stream(&palacios_stream_hooks);
171     
172     return 0;
173 }
174
175
176 static int stream_deinit( void ) {
177     if (!list_empty(&(global_streams))) {
178         printk("Error removing module with open streams\n");
179         printk("TODO: free old streams... \n");
180     }
181
182     return 0;
183 }
184
185
186
187
188
189 static int stream_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data) {
190     void __user * argp = (void __user *)arg;
191     struct stream_buffer * stream = NULL;
192     int stream_fd = 0;
193     char name[STREAM_NAME_LEN];
194     unsigned long flags = 0;
195     int ret = -1;
196     
197     
198     if (copy_from_user(name, argp, STREAM_NAME_LEN)) {
199         printk("%s(%d): copy from user error...\n", __FILE__, __LINE__);
200         return -EFAULT;
201     }
202
203     stream = find_stream_by_name(guest, name);
204
205     if (stream == NULL) {
206         printk("Could not find stream (%s)\n", name);
207         return -EFAULT;
208     }
209
210     spin_lock_irqsave(&(stream->lock), flags);
211     if (stream->connected == 0) {
212         stream->connected = 1;
213         ret = 1;
214     }
215     spin_unlock_irqrestore(&(stream->lock), flags);
216
217
218     if (ret == -1) {
219         printk("Stream (%s) already connected\n", name);
220         return -EFAULT;
221     }
222
223     
224     stream_fd = anon_inode_getfd("v3-stream", &stream_fops, stream, 0);
225
226     if (stream_fd < 0) {
227         printk("Error creating stream inode for (%s)\n", name);
228         return stream_fd;
229     }
230
231     printk("Stream (%s) connected\n", name);
232
233     return stream_fd;
234 }
235
236
237 static int guest_stream_init(struct v3_guest * guest, void ** vm_data) {
238     struct vm_stream_state * state = kmalloc(sizeof(struct vm_stream_state), GFP_KERNEL);
239
240     INIT_LIST_HEAD(&(state->open_streams));
241     *vm_data = state;
242
243
244     add_guest_ctrl(guest, V3_VM_STREAM_CONNECT, stream_connect, state);
245
246     return 0;
247 }
248
249
250 static int guest_stream_deinit(struct v3_guest * guest, void * vm_data) {
251     struct vm_stream_state * state = vm_data;
252     if (!list_empty(&(state->open_streams))) {
253         printk("Error shutting down VM with open streams\n");
254     }
255
256     return 0;
257 }
258
259
260
261 static struct linux_ext stream_ext = {
262     .name = "STREAM_INTERFACE",
263     .init = stream_init,
264     .deinit = stream_deinit,
265     .guest_init = guest_stream_init,
266     .guest_deinit = guest_stream_deinit
267 };
268
269
270 register_extension(&stream_ext);