All of lore.kernel.org
 help / color / mirror / Atom feed
* [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 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.