From patchwork Sun Jul 20 20:03:34 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Herrmann X-Patchwork-Id: 4592171 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (unknown [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 540EA9F375 for ; Sun, 20 Jul 2014 20:04:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 57F7E20109 for ; Sun, 20 Jul 2014 20:04:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 52FDB20107 for ; Sun, 20 Jul 2014 20:04:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753333AbaGTUDq (ORCPT ); Sun, 20 Jul 2014 16:03:46 -0400 Received: from mail-we0-f181.google.com ([74.125.82.181]:50303 "EHLO mail-we0-f181.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750760AbaGTUDq (ORCPT ); Sun, 20 Jul 2014 16:03:46 -0400 Received: by mail-we0-f181.google.com with SMTP id k48so5535413wev.40 for ; Sun, 20 Jul 2014 13:03:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=H6Ag410jBqDR5vLF2/ZQKDZD6vwuoOEn9gSjaBi3z34=; b=z5ftrKn5P5JQ3bze0XwELv0AZEQl58SRfiKI3SS/dZctFVqhnYfNFJT5SggPBI7muS 24yeL2cJ2K0kEzuu+KFQugYs9lawUUUmbglLn1n/yeET2538Ucvelp8DSHz5/mq1WsQF 8NKqjlb781V0+vaNGpN3zfk41ic/meT9KtIXgjSz6T4zbDfatjQEq1KQZZKEJmf/f1jn 8WUXt0qByQYl35cNMqilXVCSmxQWZ1RiCqr3I9SNY5J+ARxbs7zV/fArINGBI5RQi00I W5DsnlICsJte40KZGw5cWAhLCi+uPK7zYg0lAILcJH8KJMEnkpXn0+11Dh/hRJx9v5Z8 L6Zw== X-Received: by 10.180.83.225 with SMTP id t1mr27631056wiy.28.1405886623399; Sun, 20 Jul 2014 13:03:43 -0700 (PDT) Received: from david-tp.localdomain (stgt-4d025847.pool.mediaWays.net. [77.2.88.71]) by mx.google.com with ESMTPSA id v14sm32015211wjw.38.2014.07.20.13.03.41 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 20 Jul 2014 13:03:42 -0700 (PDT) From: David Herrmann To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Henrik Rydberg , David Herrmann Subject: [PATCH v2] Input: evdev - drop redundant list-locking Date: Sun, 20 Jul 2014 22:03:34 +0200 Message-Id: <1405886614-11660-1-git-send-email-dh.herrmann@gmail.com> X-Mailer: git-send-email 2.0.2 In-Reply-To: <1405882092-7005-1-git-send-email-dh.herrmann@gmail.com> References: <1405882092-7005-1-git-send-email-dh.herrmann@gmail.com> Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP evdev->client_list is rcu-protected. We need the client_lock only to protect against concurrent writes. However, all paths that access client_list already lock evdev->mutex. Therefore, drop client_lock and use evdev->mutex as list-protection. This also drops several helper functions that are called only once. Most of them are fairly trivial so there's little reason to extract them. This is needed to get better control over evdev->mutex locking. Signed-off-by: David Herrmann --- v2: - use evdev->mutex to protect against concurrent writes - inline most of the helper functions drivers/input/evdev.c | 126 ++++++++++++++++---------------------------------- 1 file changed, 40 insertions(+), 86 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 7a25a7a..406acde 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -34,7 +34,6 @@ struct evdev { wait_queue_head_t wait; struct evdev_client __rcu *grab; struct list_head client_list; - spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; struct cdev cdev; @@ -430,69 +429,6 @@ static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) return 0; } -static void evdev_attach_client(struct evdev *evdev, - struct evdev_client *client) -{ - spin_lock(&evdev->client_lock); - list_add_tail_rcu(&client->node, &evdev->client_list); - spin_unlock(&evdev->client_lock); -} - -static void evdev_detach_client(struct evdev *evdev, - struct evdev_client *client) -{ - spin_lock(&evdev->client_lock); - list_del_rcu(&client->node); - spin_unlock(&evdev->client_lock); - synchronize_rcu(); -} - -static int evdev_open_device(struct evdev *evdev) -{ - int retval; - - retval = mutex_lock_interruptible(&evdev->mutex); - if (retval) - return retval; - - if (!evdev->exist) - retval = -ENODEV; - else if (!evdev->open++) { - retval = input_open_device(&evdev->handle); - if (retval) - evdev->open--; - } - - mutex_unlock(&evdev->mutex); - return retval; -} - -static void evdev_close_device(struct evdev *evdev) -{ - mutex_lock(&evdev->mutex); - - if (evdev->exist && !--evdev->open) - input_close_device(&evdev->handle); - - mutex_unlock(&evdev->mutex); -} - -/* - * Wake up users waiting for IO so they can disconnect from - * dead device. - */ -static void evdev_hangup(struct evdev *evdev) -{ - struct evdev_client *client; - - spin_lock(&evdev->client_lock); - list_for_each_entry(client, &evdev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); - spin_unlock(&evdev->client_lock); - - wake_up_interruptible(&evdev->wait); -} - static int evdev_release(struct inode *inode, struct file *file) { struct evdev_client *client = file->private_data; @@ -501,9 +437,12 @@ static int evdev_release(struct inode *inode, struct file *file) mutex_lock(&evdev->mutex); evdev_ungrab(evdev, client); + list_del_rcu(&client->node); + if (evdev->exist && !--evdev->open) + input_close_device(&evdev->handle); mutex_unlock(&evdev->mutex); - evdev_detach_client(evdev, client); + synchronize_rcu(); for (i = 0; i < EV_CNT; ++i) kfree(client->evmasks[i]); @@ -513,8 +452,6 @@ static int evdev_release(struct inode *inode, struct file *file) else kfree(client); - evdev_close_device(evdev); - return 0; } @@ -545,19 +482,38 @@ static int evdev_open(struct inode *inode, struct file *file) client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); client->evdev = evdev; - evdev_attach_client(evdev, client); - error = evdev_open_device(evdev); + error = mutex_lock_interruptible(&evdev->mutex); if (error) - goto err_free_client; + goto err_free; + + list_add_tail_rcu(&client->node, &evdev->client_list); + + if (!evdev->exist) { + error = -ENODEV; + goto err_detach; + } + + if (!evdev->open++) { + error = input_open_device(&evdev->handle); + if (error) { + evdev->open--; + goto err_detach; + } + } + + mutex_unlock(&evdev->mutex); file->private_data = client; nonseekable_open(inode, file); return 0; - err_free_client: - evdev_detach_client(evdev, client); +err_detach: + list_del_rcu(&client->node); + mutex_unlock(&evdev->mutex); + synchronize_rcu(); +err_free: kfree(client); return error; } @@ -1384,24 +1340,23 @@ static const struct file_operations evdev_fops = { .llseek = no_llseek, }; -/* - * Mark device non-existent. This disables writes, ioctls and - * prevents new users from opening the device. Already posted - * blocking reads will stay, however new ones will fail. - */ -static void evdev_mark_dead(struct evdev *evdev) +static void evdev_cleanup(struct evdev *evdev) { + struct input_handle *handle = &evdev->handle; + struct evdev_client *client; + + /* + * Mark device non-existent to disable writes, ioctls and new users. + * Then wake up running users that wait for I/O so they can disconnect + * from the dead device. + */ mutex_lock(&evdev->mutex); evdev->exist = false; + list_for_each_entry(client, &evdev->client_list, node) + kill_fasync(&client->fasync, SIGIO, POLL_HUP); mutex_unlock(&evdev->mutex); -} -static void evdev_cleanup(struct evdev *evdev) -{ - struct input_handle *handle = &evdev->handle; - - evdev_mark_dead(evdev); - evdev_hangup(evdev); + wake_up_interruptible(&evdev->wait); cdev_del(&evdev->cdev); @@ -1438,7 +1393,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, } INIT_LIST_HEAD(&evdev->client_list); - spin_lock_init(&evdev->client_lock); mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); evdev->exist = true;