aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest/lguest_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/lguest/lguest_user.c')
-rw-r--r--drivers/lguest/lguest_user.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 1982b45bd935..f6bf255f1837 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -7,6 +7,8 @@
7#include <linux/miscdevice.h> 7#include <linux/miscdevice.h>
8#include <linux/fs.h> 8#include <linux/fs.h>
9#include <linux/sched.h> 9#include <linux/sched.h>
10#include <linux/eventfd.h>
11#include <linux/file.h>
10#include "lg.h" 12#include "lg.h"
11 13
12/*L:055 When something happens, the Waker process needs a way to stop the 14/*L:055 When something happens, the Waker process needs a way to stop the
@@ -35,6 +37,81 @@ static int break_guest_out(struct lg_cpu *cpu, const unsigned long __user*input)
35 } 37 }
36} 38}
37 39
40bool send_notify_to_eventfd(struct lg_cpu *cpu)
41{
42 unsigned int i;
43 struct lg_eventfd_map *map;
44
45 /* lg->eventfds is RCU-protected */
46 rcu_read_lock();
47 map = rcu_dereference(cpu->lg->eventfds);
48 for (i = 0; i < map->num; i++) {
49 if (map->map[i].addr == cpu->pending_notify) {
50 eventfd_signal(map->map[i].event, 1);
51 cpu->pending_notify = 0;
52 break;
53 }
54 }
55 rcu_read_unlock();
56 return cpu->pending_notify == 0;
57}
58
59static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
60{
61 struct lg_eventfd_map *new, *old = lg->eventfds;
62
63 if (!addr)
64 return -EINVAL;
65
66 /* Replace the old array with the new one, carefully: others can
67 * be accessing it at the same time */
68 new = kmalloc(sizeof(*new) + sizeof(new->map[0]) * (old->num + 1),
69 GFP_KERNEL);
70 if (!new)
71 return -ENOMEM;
72
73 /* First make identical copy. */
74 memcpy(new->map, old->map, sizeof(old->map[0]) * old->num);
75 new->num = old->num;
76
77 /* Now append new entry. */
78 new->map[new->num].addr = addr;
79 new->map[new->num].event = eventfd_fget(fd);
80 if (IS_ERR(new->map[new->num].event)) {
81 kfree(new);
82 return PTR_ERR(new->map[new->num].event);
83 }
84 new->num++;
85
86 /* Now put new one in place. */
87 rcu_assign_pointer(lg->eventfds, new);
88
89 /* We're not in a big hurry. Wait until noone's looking at old
90 * version, then delete it. */
91 synchronize_rcu();
92 kfree(old);
93
94 return 0;
95}
96
97static int attach_eventfd(struct lguest *lg, const unsigned long __user *input)
98{
99 unsigned long addr, fd;
100 int err;
101
102 if (get_user(addr, input) != 0)
103 return -EFAULT;
104 input++;
105 if (get_user(fd, input) != 0)
106 return -EFAULT;
107
108 mutex_lock(&lguest_lock);
109 err = add_eventfd(lg, addr, fd);
110 mutex_unlock(&lguest_lock);
111
112 return 0;
113}
114
38/*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt 115/*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
39 * number to /dev/lguest. */ 116 * number to /dev/lguest. */
40static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input) 117static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input)
@@ -184,6 +261,13 @@ static int initialize(struct file *file, const unsigned long __user *input)
184 goto unlock; 261 goto unlock;
185 } 262 }
186 263
264 lg->eventfds = kmalloc(sizeof(*lg->eventfds), GFP_KERNEL);
265 if (!lg->eventfds) {
266 err = -ENOMEM;
267 goto free_lg;
268 }
269 lg->eventfds->num = 0;
270
187 /* Populate the easy fields of our "struct lguest" */ 271 /* Populate the easy fields of our "struct lguest" */
188 lg->mem_base = (void __user *)args[0]; 272 lg->mem_base = (void __user *)args[0];
189 lg->pfn_limit = args[1]; 273 lg->pfn_limit = args[1];
@@ -191,7 +275,7 @@ static int initialize(struct file *file, const unsigned long __user *input)
191 /* This is the first cpu (cpu 0) and it will start booting at args[2] */ 275 /* This is the first cpu (cpu 0) and it will start booting at args[2] */
192 err = lg_cpu_start(&lg->cpus[0], 0, args[2]); 276 err = lg_cpu_start(&lg->cpus[0], 0, args[2]);
193 if (err) 277 if (err)
194 goto release_guest; 278 goto free_eventfds;
195 279
196 /* Initialize the Guest's shadow page tables, using the toplevel 280 /* Initialize the Guest's shadow page tables, using the toplevel
197 * address the Launcher gave us. This allocates memory, so can fail. */ 281 * address the Launcher gave us. This allocates memory, so can fail. */
@@ -210,7 +294,9 @@ static int initialize(struct file *file, const unsigned long __user *input)
210free_regs: 294free_regs:
211 /* FIXME: This should be in free_vcpu */ 295 /* FIXME: This should be in free_vcpu */
212 free_page(lg->cpus[0].regs_page); 296 free_page(lg->cpus[0].regs_page);
213release_guest: 297free_eventfds:
298 kfree(lg->eventfds);
299free_lg:
214 kfree(lg); 300 kfree(lg);
215unlock: 301unlock:
216 mutex_unlock(&lguest_lock); 302 mutex_unlock(&lguest_lock);
@@ -260,6 +346,8 @@ static ssize_t write(struct file *file, const char __user *in,
260 return user_send_irq(cpu, input); 346 return user_send_irq(cpu, input);
261 case LHREQ_BREAK: 347 case LHREQ_BREAK:
262 return break_guest_out(cpu, input); 348 return break_guest_out(cpu, input);
349 case LHREQ_EVENTFD:
350 return attach_eventfd(lg, input);
263 default: 351 default:
264 return -EINVAL; 352 return -EINVAL;
265 } 353 }
@@ -297,6 +385,12 @@ static int close(struct inode *inode, struct file *file)
297 * the Launcher's memory management structure. */ 385 * the Launcher's memory management structure. */
298 mmput(lg->cpus[i].mm); 386 mmput(lg->cpus[i].mm);
299 } 387 }
388
389 /* Release any eventfds they registered. */
390 for (i = 0; i < lg->eventfds->num; i++)
391 fput(lg->eventfds->map[i].event);
392 kfree(lg->eventfds);
393
300 /* If lg->dead doesn't contain an error code it will be NULL or a 394 /* If lg->dead doesn't contain an error code it will be NULL or a
301 * kmalloc()ed string, either of which is ok to hand to kfree(). */ 395 * kmalloc()ed string, either of which is ok to hand to kfree(). */
302 if (!IS_ERR(lg->dead)) 396 if (!IS_ERR(lg->dead))