* [PATCH 1/2] eventfd: reorganize the code to simplify new flags
[not found] <cover.1250783333.git.mst@redhat.com>
@ 2009-08-20 15:57 ` Michael S. Tsirkin
2009-08-27 11:48 ` Paolo Bonzini
2009-08-20 15:57 ` [PATCH 2/2] eventfd: EFD_STATE flag Michael S. Tsirkin
1 sibling, 1 reply; 5+ messages in thread
From: Michael S. Tsirkin @ 2009-08-20 15:57 UTC (permalink / raw)
To: davidel, avi, gleb, kvm, linux-kernel
This slightly reorganizes the code in eventfd, encapsulating counter
math in inline functions, so that it will be easier to add a new flag.
No functional changes.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
fs/eventfd.c | 56 ++++++++++++++++++++++++++++++++++++++++++--------------
1 files changed, 42 insertions(+), 14 deletions(-)
diff --git a/fs/eventfd.c b/fs/eventfd.c
index 31d12de..347a0e0 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -34,6 +34,37 @@ struct eventfd_ctx {
unsigned int flags;
};
+
+static inline int eventfd_readable(struct eventfd_ctx *ctx)
+{
+ return ctx->count > 0;
+}
+
+static inline int eventfd_writeable(struct eventfd_ctx *ctx, u64 n)
+{
+ return ULLONG_MAX - n > ctx->count;
+}
+
+static inline int eventfd_overflow(struct eventfd_ctx *ctx, u64 cnt)
+{
+ return cnt == ULLONG_MAX;
+}
+
+static inline void eventfd_dowrite(struct eventfd_ctx *ctx, u64 ucnt)
+{
+ if (eventfd_writeable(ctx, ucnt))
+ ucnt = ULLONG_MAX - ctx->count;
+
+ ctx->count += ucnt;
+}
+
+static inline u64 eventfd_doread(struct eventfd_ctx *ctx)
+{
+ u64 ucnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count;
+ ctx->count -= ucnt;
+ return ucnt;
+}
+
/**
* eventfd_signal - Adds @n to the eventfd counter.
* @ctx: [in] Pointer to the eventfd context.
@@ -57,9 +88,7 @@ int eventfd_signal(struct eventfd_ctx *ctx, int n)
if (n < 0)
return -EINVAL;
spin_lock_irqsave(&ctx->wqh.lock, flags);
- if (ULLONG_MAX - ctx->count < n)
- n = (int) (ULLONG_MAX - ctx->count);
- ctx->count += n;
+ eventfd_dowrite(ctx, n);
if (waitqueue_active(&ctx->wqh))
wake_up_locked_poll(&ctx->wqh, POLLIN);
spin_unlock_irqrestore(&ctx->wqh.lock, flags);
@@ -119,11 +148,11 @@ static unsigned int eventfd_poll(struct file *file, poll_table *wait)
poll_wait(file, &ctx->wqh, wait);
spin_lock_irqsave(&ctx->wqh.lock, flags);
- if (ctx->count > 0)
+ if (eventfd_readable(ctx))
events |= POLLIN;
- if (ctx->count == ULLONG_MAX)
+ if (eventfd_overflow(ctx, ctx->count))
events |= POLLERR;
- if (ULLONG_MAX - 1 > ctx->count)
+ if (eventfd_writeable(ctx, 1))
events |= POLLOUT;
spin_unlock_irqrestore(&ctx->wqh.lock, flags);
@@ -142,13 +171,13 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
return -EINVAL;
spin_lock_irq(&ctx->wqh.lock);
res = -EAGAIN;
- if (ctx->count > 0)
+ if (eventfd_readable(ctx))
res = sizeof(ucnt);
else if (!(file->f_flags & O_NONBLOCK)) {
__add_wait_queue(&ctx->wqh, &wait);
for (res = 0;;) {
set_current_state(TASK_INTERRUPTIBLE);
- if (ctx->count > 0) {
+ if (eventfd_readable(ctx)) {
res = sizeof(ucnt);
break;
}
@@ -164,8 +193,7 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
__set_current_state(TASK_RUNNING);
}
if (likely(res > 0)) {
- ucnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count;
- ctx->count -= ucnt;
+ ucnt = eventfd_doread(ctx);
if (waitqueue_active(&ctx->wqh))
wake_up_locked_poll(&ctx->wqh, POLLOUT);
}
@@ -188,17 +216,17 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c
return -EINVAL;
if (copy_from_user(&ucnt, buf, sizeof(ucnt)))
return -EFAULT;
- if (ucnt == ULLONG_MAX)
+ if (eventfd_overflow(ctx, ucnt))
return -EINVAL;
spin_lock_irq(&ctx->wqh.lock);
res = -EAGAIN;
- if (ULLONG_MAX - ctx->count > ucnt)
+ if (eventfd_writeable(ctx, ucnt))
res = sizeof(ucnt);
else if (!(file->f_flags & O_NONBLOCK)) {
__add_wait_queue(&ctx->wqh, &wait);
for (res = 0;;) {
set_current_state(TASK_INTERRUPTIBLE);
- if (ULLONG_MAX - ctx->count > ucnt) {
+ if (eventfd_writeable(ctx, ucnt)) {
res = sizeof(ucnt);
break;
}
@@ -214,7 +242,7 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c
__set_current_state(TASK_RUNNING);
}
if (likely(res > 0)) {
- ctx->count += ucnt;
+ eventfd_dowrite(ctx, ucnt);
if (waitqueue_active(&ctx->wqh))
wake_up_locked_poll(&ctx->wqh, POLLIN);
}
--
1.6.2.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] eventfd: EFD_STATE flag
[not found] <cover.1250783333.git.mst@redhat.com>
2009-08-20 15:57 ` [PATCH 1/2] eventfd: reorganize the code to simplify new flags Michael S. Tsirkin
@ 2009-08-20 15:57 ` Michael S. Tsirkin
1 sibling, 0 replies; 5+ messages in thread
From: Michael S. Tsirkin @ 2009-08-20 15:57 UTC (permalink / raw)
To: davidel, avi, gleb, kvm, linux-kernel
This implements a new EFD_STATE flag for eventfd.
This changes eventfd behaviour in the following way:
- write simply stores the value written, and is always non-blocking
- read unblocks when the value written changes, and
returns the value written
Motivation: we'd like to use eventfd in qemu to pass interrupts from
(emulated or assigned) devices to guest. For level interrupts, the
counter supported currently by eventfd is not a good match: we really
need to set interrupt to a level, typically 0 or 1, and give the guest
ability to see the last value written.
Acked-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
fs/eventfd.c | 41 ++++++++++++++++++++++++++++++++++-------
include/linux/eventfd.h | 3 ++-
2 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/fs/eventfd.c b/fs/eventfd.c
index 347a0e0..7b279e3 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -31,37 +31,59 @@ struct eventfd_ctx {
* issue a wakeup.
*/
__u64 count;
+ /*
+ * When EF_STATE flag is set, eventfd behaves differently:
+ * value written gets stored in "count", read will copy
+ * "count" to "state".
+ */
+ __u64 state;
unsigned int flags;
};
static inline int eventfd_readable(struct eventfd_ctx *ctx)
{
- return ctx->count > 0;
+ if (ctx->flags & EFD_STATE)
+ return ctx->state != ctx->count;
+ else
+ return ctx->count > 0;
}
static inline int eventfd_writeable(struct eventfd_ctx *ctx, u64 n)
{
- return ULLONG_MAX - n > ctx->count;
+ if (ctx->flags & EFD_STATE)
+ return 1;
+ else
+ return ULLONG_MAX - n > ctx->count;
}
static inline int eventfd_overflow(struct eventfd_ctx *ctx, u64 cnt)
{
- return cnt == ULLONG_MAX;
+ if (ctx->flags & EFD_STATE)
+ return 0;
+ else
+ return cnt == ULLONG_MAX;
}
static inline void eventfd_dowrite(struct eventfd_ctx *ctx, u64 ucnt)
{
- if (eventfd_writeable(ctx, ucnt))
- ucnt = ULLONG_MAX - ctx->count;
+ if (ctx->flags & EFD_STATE)
+ ctx->count = ucnt;
+ else {
+ if (ULLONG_MAX - ctx->count < ucnt)
+ ucnt = ULLONG_MAX - ctx->count;
- ctx->count += ucnt;
+ ctx->count += ucnt;
+ }
}
static inline u64 eventfd_doread(struct eventfd_ctx *ctx)
{
u64 ucnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count;
- ctx->count -= ucnt;
+ if (ctx->flags & EFD_STATE)
+ ctx->state = ucnt;
+ else
+ ctx->count -= ucnt;
return ucnt;
}
@@ -337,6 +359,10 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
if (flags & ~EFD_FLAGS_SET)
return -EINVAL;
+ /* State together with semaphore does not make sense. */
+ if ((flags & EFD_STATE) && (flags & EFD_SEMAPHORE))
+ return -EINVAL;
+
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -344,6 +370,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
kref_init(&ctx->kref);
init_waitqueue_head(&ctx->wqh);
+ ctx->state = count;
ctx->count = count;
ctx->flags = flags;
diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h
index 3b85ba6..78ff649 100644
--- a/include/linux/eventfd.h
+++ b/include/linux/eventfd.h
@@ -19,11 +19,12 @@
* shared O_* flags.
*/
#define EFD_SEMAPHORE (1 << 0)
+#define EFD_STATE (1 << 1)
#define EFD_CLOEXEC O_CLOEXEC
#define EFD_NONBLOCK O_NONBLOCK
#define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
-#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE)
+#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE | EFD_STATE)
#ifdef CONFIG_EVENTFD
--
1.6.2.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] eventfd: reorganize the code to simplify new flags
2009-08-20 15:57 ` [PATCH 1/2] eventfd: reorganize the code to simplify new flags Michael S. Tsirkin
@ 2009-08-27 11:48 ` Paolo Bonzini
2009-08-27 11:58 ` Michael S. Tsirkin
2009-08-27 12:02 ` Michael S. Tsirkin
0 siblings, 2 replies; 5+ messages in thread
From: Paolo Bonzini @ 2009-08-27 11:48 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: davidel, avi, gleb, kvm, linux-kernel
On 08/20/2009 05:57 PM, Michael S. Tsirkin wrote:
> +static inline int eventfd_writeable(struct eventfd_ctx *ctx, u64 n)
> +{
> + return ULLONG_MAX - n> ctx->count;
> +}
> +
> +static inline void eventfd_dowrite(struct eventfd_ctx *ctx, u64 ucnt)
> +{
> + if (eventfd_writeable(ctx, ucnt))
> + ucnt = ULLONG_MAX - ctx->count;
> +
> + ctx->count += ucnt;
In any case, this usage of eventfd_writeable is wrong: the code was like
this:
- if (ULLONG_MAX - ctx->count < n)
- n = (int) (ULLONG_MAX - ctx->count);
- ctx->count += n;
+ eventfd_dowrite(ctx, n);
and so it should be !eventfd_writable. (This smelled when I was editing
patch 2, so I went back and checked patch 1).
Paolo
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] eventfd: reorganize the code to simplify new flags
2009-08-27 11:48 ` Paolo Bonzini
@ 2009-08-27 11:58 ` Michael S. Tsirkin
2009-08-27 12:02 ` Michael S. Tsirkin
1 sibling, 0 replies; 5+ messages in thread
From: Michael S. Tsirkin @ 2009-08-27 11:58 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: davidel, avi, gleb, kvm, linux-kernel
On Thu, Aug 27, 2009 at 01:48:53PM +0200, Paolo Bonzini wrote:
> On 08/20/2009 05:57 PM, Michael S. Tsirkin wrote:
>> +static inline int eventfd_writeable(struct eventfd_ctx *ctx, u64 n)
>> +{
>> + return ULLONG_MAX - n> ctx->count;
>> +}
>> +
>> +static inline void eventfd_dowrite(struct eventfd_ctx *ctx, u64 ucnt)
>> +{
>> + if (eventfd_writeable(ctx, ucnt))
>> + ucnt = ULLONG_MAX - ctx->count;
>> +
>> + ctx->count += ucnt;
>
> In any case, this usage of eventfd_writeable is wrong: the code was like
> this:
>
> - if (ULLONG_MAX - ctx->count < n)
> - n = (int) (ULLONG_MAX - ctx->count);
> - ctx->count += n;
> + eventfd_dowrite(ctx, n);
>
> and so it should be !eventfd_writable. (This smelled when I was editing
> patch 2, so I went back and checked patch 1).
>
> Paolo
Right, patch 2 actually fixed this back. The best thing is to open-code
it actually, since we handle it in a way that only applies to a counter,
anyway. Will post a fixed v1.
--
MST
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] eventfd: reorganize the code to simplify new flags
2009-08-27 11:48 ` Paolo Bonzini
2009-08-27 11:58 ` Michael S. Tsirkin
@ 2009-08-27 12:02 ` Michael S. Tsirkin
1 sibling, 0 replies; 5+ messages in thread
From: Michael S. Tsirkin @ 2009-08-27 12:02 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: davidel, avi, gleb, kvm, linux-kernel
On Thu, Aug 27, 2009 at 01:48:53PM +0200, Paolo Bonzini wrote:
> On 08/20/2009 05:57 PM, Michael S. Tsirkin wrote:
>> +static inline int eventfd_writeable(struct eventfd_ctx *ctx, u64 n)
>> +{
>> + return ULLONG_MAX - n> ctx->count;
>> +}
>> +
>> +static inline void eventfd_dowrite(struct eventfd_ctx *ctx, u64 ucnt)
>> +{
>> + if (eventfd_writeable(ctx, ucnt))
>> + ucnt = ULLONG_MAX - ctx->count;
>> +
>> + ctx->count += ucnt;
>
> In any case, this usage of eventfd_writeable is wrong:
Fixed, thanks!
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-08-27 12:03 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <cover.1250783333.git.mst@redhat.com>
2009-08-20 15:57 ` [PATCH 1/2] eventfd: reorganize the code to simplify new flags Michael S. Tsirkin
2009-08-27 11:48 ` Paolo Bonzini
2009-08-27 11:58 ` Michael S. Tsirkin
2009-08-27 12:02 ` Michael S. Tsirkin
2009-08-20 15:57 ` [PATCH 2/2] eventfd: EFD_STATE flag Michael S. Tsirkin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).