From: David Herrmann 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 Acked-by: Daniel Mack --- 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; }