From: Rusty Russell <rusty@rustcorp.com.au>
To: paulmck@linux.vnet.ibm.com
Cc: linux-kernel@vger.kernel.org, lguest@ozlabs.org
Subject: Re: [RFC PATCH v2 00/19] virtual-bus
Date: Thu, 11 Jun 2009 22:51:20 +0930 [thread overview]
Message-ID: <200906112251.20827.rusty@rustcorp.com.au> (raw)
In-Reply-To: <20090605162553.GC6778@linux.vnet.ibm.com>
On Sat, 6 Jun 2009 01:55:53 am Paul E. McKenney wrote:
> It is possible to get rid of the rmb() and wmb() as well, doing
> something like the following:
>
> struct lg_eventfds_num {
> unsigned int n;
> struct lg_eventfds a[0];
> }
>
> Then the rcu_dereference() gets you a pointer to a struct lg_eventfds_num,
> which has the array and its length in guaranteed synchronization without
> the need for barriers.
Yep, that's actually quite nice. The only wart is that it needs to be
allocated even when n == 0, but IMHO worth it for barrier avoidance.
This is what I ended up with:
lguest: use eventfds for device notification
Currently, when a Guest wants to perform I/O it calls LHCALL_NOTIFY with
an address: the main Launcher process returns with this address, and figures
out what device to run.
A far nicer model is to let processes bind an eventfd to an address: if we
find one, we simply signal the eventfd.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Davide Libenzi <davidel@xmailserver.org>
---
drivers/lguest/Kconfig | 2
drivers/lguest/core.c | 8 ++-
drivers/lguest/lg.h | 13 +++++
drivers/lguest/lguest_user.c | 98 +++++++++++++++++++++++++++++++++++++++-
include/linux/lguest_launcher.h | 1
5 files changed, 116 insertions(+), 6 deletions(-)
diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig
--- a/drivers/lguest/Kconfig
+++ b/drivers/lguest/Kconfig
@@ -1,6 +1,6 @@
config LGUEST
tristate "Linux hypervisor example code"
- depends on X86_32 && EXPERIMENTAL && FUTEX
+ depends on X86_32 && EXPERIMENTAL && EVENTFD
select HVC_DRIVER
---help---
This is a very simple module which allows you to run
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -198,9 +198,11 @@ int run_guest(struct lg_cpu *cpu, unsign
/* It's possible the Guest did a NOTIFY hypercall to the
* Launcher, in which case we return from the read() now. */
if (cpu->pending_notify) {
- if (put_user(cpu->pending_notify, user))
- return -EFAULT;
- return sizeof(cpu->pending_notify);
+ if (!send_notify_to_eventfd(cpu)) {
+ if (put_user(cpu->pending_notify, user))
+ return -EFAULT;
+ return sizeof(cpu->pending_notify);
+ }
}
/* Check for signals */
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -82,6 +82,16 @@ struct lg_cpu {
struct lg_cpu_arch arch;
};
+struct lg_eventfd {
+ unsigned long addr;
+ struct file *event;
+};
+
+struct lg_eventfd_map {
+ unsigned int num;
+ struct lg_eventfd map[];
+};
+
/* The private info the thread maintains about the guest. */
struct lguest
{
@@ -102,6 +112,8 @@ struct lguest
unsigned int stack_pages;
u32 tsc_khz;
+ struct lg_eventfd_map *eventfds;
+
/* Dead? */
const char *dead;
};
@@ -154,6 +166,7 @@ void setup_default_idt_entries(struct lg
void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
const unsigned long *def);
void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta);
+bool send_notify_to_eventfd(struct lg_cpu *cpu);
void init_clockdev(struct lg_cpu *cpu);
bool check_syscall_vector(struct lguest *lg);
int init_interrupts(void);
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -7,6 +7,8 @@
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/sched.h>
+#include <linux/eventfd.h>
+#include <linux/file.h>
#include "lg.h"
/*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
}
}
+bool send_notify_to_eventfd(struct lg_cpu *cpu)
+{
+ unsigned int i;
+ struct lg_eventfd_map *map;
+
+ /* lg->eventfds is RCU-protected */
+ rcu_read_lock();
+ map = rcu_dereference(cpu->lg->eventfds);
+ for (i = 0; i < map->num; i++) {
+ if (map->map[i].addr == cpu->pending_notify) {
+ eventfd_signal(map->map[i].event, 1);
+ cpu->pending_notify = 0;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ return cpu->pending_notify == 0;
+}
+
+static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
+{
+ struct lg_eventfd_map *new, *old = lg->eventfds;
+
+ if (!addr)
+ return -EINVAL;
+
+ /* Replace the old array with the new one, carefully: others can
+ * be accessing it at the same time */
+ new = kmalloc(sizeof(*new) + sizeof(new->map[0]) * (old->num + 1),
+ GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ /* First make identical copy. */
+ memcpy(new->map, old->map, sizeof(old->map[0]) * old->num);
+ new->num = old->num;
+
+ /* Now append new entry. */
+ new->map[new->num].addr = addr;
+ new->map[new->num].event = eventfd_fget(fd);
+ if (IS_ERR(new->map[new->num].event)) {
+ kfree(new);
+ return PTR_ERR(new->map[new->num].event);
+ }
+ new->num++;
+
+ /* Now put new one in place. */
+ rcu_assign_pointer(lg->eventfds, new);
+
+ /* We're not in a big hurry. Wait until noone's looking at old
+ * version, then delete it. */
+ synchronize_rcu();
+ kfree(old);
+
+ return 0;
+}
+
+static int attach_eventfd(struct lguest *lg, const unsigned long __user *input)
+{
+ unsigned long addr, fd;
+ int err;
+
+ if (get_user(addr, input) != 0)
+ return -EFAULT;
+ input++;
+ if (get_user(fd, input) != 0)
+ return -EFAULT;
+
+ mutex_lock(&lguest_lock);
+ err = add_eventfd(lg, addr, fd);
+ mutex_unlock(&lguest_lock);
+
+ return 0;
+}
+
/*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
* number to /dev/lguest. */
static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input)
@@ -184,6 +261,13 @@ static int initialize(struct file *file,
goto unlock;
}
+ lg->eventfds = kmalloc(sizeof(*lg->eventfds), GFP_KERNEL);
+ if (!lg->eventfds) {
+ err = -ENOMEM;
+ goto free_lg;
+ }
+ lg->eventfds->num = 0;
+
/* Populate the easy fields of our "struct lguest" */
lg->mem_base = (void __user *)args[0];
lg->pfn_limit = args[1];
@@ -191,7 +275,7 @@ static int initialize(struct file *file,
/* This is the first cpu (cpu 0) and it will start booting at args[2] */
err = lg_cpu_start(&lg->cpus[0], 0, args[2]);
if (err)
- goto release_guest;
+ goto free_eventfds;
/* Initialize the Guest's shadow page tables, using the toplevel
* address the Launcher gave us. This allocates memory, so can fail. */
@@ -210,7 +294,9 @@ static int initialize(struct file *file,
free_regs:
/* FIXME: This should be in free_vcpu */
free_page(lg->cpus[0].regs_page);
-release_guest:
+free_eventfds:
+ kfree(lg->eventfds);
+free_lg:
kfree(lg);
unlock:
mutex_unlock(&lguest_lock);
@@ -260,6 +346,8 @@ static ssize_t write(struct file *file,
return user_send_irq(cpu, input);
case LHREQ_BREAK:
return break_guest_out(cpu, input);
+ case LHREQ_EVENTFD:
+ return attach_eventfd(lg, input);
default:
return -EINVAL;
}
@@ -297,6 +385,12 @@ static int close(struct inode *inode, st
* the Launcher's memory management structure. */
mmput(lg->cpus[i].mm);
}
+
+ /* Release any eventfds they registered. */
+ for (i = 0; i < lg->eventfds->num; i++)
+ fput(lg->eventfds->map[i].event);
+ kfree(lg->eventfds);
+
/* If lg->dead doesn't contain an error code it will be NULL or a
* kmalloc()ed string, either of which is ok to hand to kfree(). */
if (!IS_ERR(lg->dead))
diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h
--- a/include/linux/lguest_launcher.h
+++ b/include/linux/lguest_launcher.h
@@ -58,6 +58,7 @@ enum lguest_req
LHREQ_GETDMA, /* No longer used */
LHREQ_IRQ, /* + irq */
LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */
+ LHREQ_EVENTFD, /* + address, fd. */
};
/* The alignment to use between consumer and producer parts of vring.
next prev parent reply other threads:[~2009-06-11 13:21 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-09 16:30 [RFC PATCH v2 00/19] virtual-bus Gregory Haskins
2009-04-09 16:30 ` [RFC PATCH v2 01/19] shm-signal: shared-memory signals Gregory Haskins
2009-04-09 16:30 ` [RFC PATCH v2 02/19] vbus: add virtual-bus definitions Gregory Haskins
2009-04-09 16:30 ` [RFC PATCH v2 03/19] vbus: add connection-client helper infrastructure Gregory Haskins
2009-06-04 18:06 ` Michael S. Tsirkin
2009-06-04 18:18 ` Gregory Haskins
2009-06-04 18:24 ` Avi Kivity
2009-06-04 18:30 ` Gregory Haskins
2009-06-04 19:04 ` Avi Kivity
2009-06-04 18:23 ` Avi Kivity
2009-04-09 16:31 ` [RFC PATCH v2 04/19] vbus: add bus-registration notifiers Gregory Haskins
2009-04-09 16:31 ` [RFC PATCH v2 05/19] vbus: add a "vbus-proxy" bus model for vbus_driver objects Gregory Haskins
2009-04-09 16:31 ` [RFC PATCH v2 06/19] ioq: Add basic definitions for a shared-memory, lockless queue Gregory Haskins
2009-04-09 16:31 ` [RFC PATCH v2 07/19] ioq: add vbus helpers Gregory Haskins
2009-04-09 16:31 ` [RFC PATCH v2 08/19] venet: add the ABI definitions for an 802.x packet interface Gregory Haskins
2009-04-09 16:31 ` [RFC PATCH v2 09/19] net: Add vbus_enet driver Gregory Haskins
2009-04-09 16:37 ` Stephen Hemminger
2009-04-09 19:50 ` Greg KH
2009-04-09 16:31 ` [RFC PATCH v2 10/19] venet-tap: Adds a "venet" compatible "tap" device to VBUS Gregory Haskins
2009-04-09 16:31 ` [RFC PATCH v2 11/19] venet: add scatter-gather support Gregory Haskins
2009-04-09 16:31 ` [RFC PATCH v2 12/19] venettap: " Gregory Haskins
2009-04-09 16:31 ` [RFC PATCH v2 13/19] x86: allow the irq->vector translation to be determined outside of ioapic Gregory Haskins
2009-04-09 16:31 ` [RFC PATCH v2 14/19] kvm: add a reset capability Gregory Haskins
2009-04-11 16:56 ` Avi Kivity
2009-04-09 16:32 ` [RFC PATCH v2 15/19] kvm: add dynamic IRQ support Gregory Haskins
2009-04-11 17:01 ` Avi Kivity
2009-04-13 17:44 ` Gregory Haskins
2009-04-09 16:32 ` [RFC PATCH v2 16/19] kvm: Add VBUS support to the host Gregory Haskins
2009-04-09 16:32 ` [RFC PATCH v2 17/19] kvm: Add guest-side support for VBUS Gregory Haskins
2009-04-09 16:32 ` [RFC PATCH v2 18/19] vbus: add a userspace connector Gregory Haskins
2009-04-09 16:32 ` [RFC PATCH v2 19/19] virtio: add a vbus transport Gregory Haskins
2009-08-09 16:40 ` Anthony Liguori
2009-08-10 15:40 ` Gregory Haskins
2009-04-09 16:48 ` [RFC PATCH v2 00/19] virtual-bus Gregory Haskins
2009-04-11 16:45 ` Avi Kivity
2009-06-04 18:49 ` Gregory Haskins
2009-06-05 4:55 ` Rusty Russell
2009-06-05 5:30 ` Paul E. McKenney
2009-06-05 14:55 ` Rusty Russell
2009-06-05 16:25 ` Paul E. McKenney
2009-06-11 13:21 ` Rusty Russell [this message]
2009-06-11 15:48 ` Paul E. McKenney
2009-06-05 11:56 ` Gregory Haskins
2009-06-05 12:53 ` Avi Kivity
2009-06-05 12:54 ` Gregory Haskins
2009-06-05 13:35 ` [PATCH] kvm: make sure we select EVENTFD for any arch that declares HAVE_KVM_EVENTFD Gregory Haskins
2009-06-08 8:56 ` Avi Kivity
2009-06-05 14:35 ` [RFC PATCH v2 00/19] virtual-bus Rusty Russell
2009-06-05 14:44 ` Gregory Haskins
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200906112251.20827.rusty@rustcorp.com.au \
--to=rusty@rustcorp.com.au \
--cc=lguest@ozlabs.org \
--cc=linux-kernel@vger.kernel.org \
--cc=paulmck@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.