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.


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