64 lines
2.2 KiB
Diff
64 lines
2.2 KiB
Diff
From: David Herrmann <dh.herrmann@gmail.com>
|
|
Date: Sat, 18 Apr 2015 13:04:42 +0200
|
|
Subject: [PATCH] kdbus: skip acquiring an active reference in poll()
|
|
|
|
During poll(), we currently acquire an active reference to the connection
|
|
in question to verify it's still active. If it's not active, anymore, we
|
|
return POLLHUP.
|
|
|
|
This works fine, but requires an atomic_inc() to acquire the active
|
|
reference. However, all we need is a guarantee that the connection is
|
|
active right now, and a guarantee we're called again once this changes.
|
|
This is as simple as adding the waitqueue first, then checking the
|
|
active-state afterwards. kdbus_conn_disconnect() guarantees to wake us up
|
|
_after_ deactivating the connection, thus providing the required barrier
|
|
implicitly (in case someone is actually polling / waiting on the
|
|
connection).
|
|
|
|
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
|
|
Acked-by: Daniel Mack <daniel@zonque.org>
|
|
---
|
|
ipc/kdbus/handle.c | 16 +++++++++-------
|
|
1 file changed, 9 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c
|
|
index a3e01383a6f6..6230c7ef4347 100644
|
|
--- a/ipc/kdbus/handle.c
|
|
+++ b/ipc/kdbus/handle.c
|
|
@@ -610,7 +610,6 @@ static unsigned int kdbus_handle_poll(struct file *file,
|
|
struct kdbus_handle *handle = file->private_data;
|
|
enum kdbus_handle_type type;
|
|
unsigned int mask = POLLOUT | POLLWRNORM;
|
|
- int ret;
|
|
|
|
/*
|
|
* This pairs with smp_wmb() during handle setup. It guarantees that
|
|
@@ -626,18 +625,21 @@ static unsigned int kdbus_handle_poll(struct file *file,
|
|
if (type != KDBUS_HANDLE_CONNECTED)
|
|
return POLLERR | POLLHUP;
|
|
|
|
- ret = kdbus_conn_acquire(handle->conn);
|
|
- if (ret < 0)
|
|
- return POLLERR | POLLHUP;
|
|
-
|
|
poll_wait(file, &handle->conn->wait, wait);
|
|
|
|
+ /*
|
|
+ * Verify the connection hasn't been deactivated _after_ adding the
|
|
+ * wait-queue. This guarantees, that if the connection is deactivated
|
|
+ * after we checked it, the waitqueue is signaled and we're called
|
|
+ * again.
|
|
+ */
|
|
+ if (!kdbus_conn_active(handle->conn))
|
|
+ return POLLERR | POLLHUP;
|
|
+
|
|
if (!list_empty(&handle->conn->queue.msg_list) ||
|
|
atomic_read(&handle->conn->lost_count) > 0)
|
|
mask |= POLLIN | POLLRDNORM;
|
|
|
|
- kdbus_conn_release(handle->conn);
|
|
-
|
|
return mask;
|
|
}
|
|
|