Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp5032102ybl; Tue, 14 Jan 2020 02:18:21 -0800 (PST) X-Google-Smtp-Source: APXvYqwbV6/m6grse5CNzfsVGx03sXnyNwPysxXXSer+owkRT4cqLSOlpfCoNMoIb2/PGhsVIqsg X-Received: by 2002:aca:39d6:: with SMTP id g205mr15034849oia.122.1578997101395; Tue, 14 Jan 2020 02:18:21 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1578997101; cv=none; d=google.com; s=arc-20160816; b=b3h4woSzObd08ZXCAHqsyTgpwnVul61wweC/8tMPP624s7+jt/n1W6bPSoP4xBuYsY mu3HuxgUjFA4F55s1yhcOxmS+jKv3mgTLmTX1trmuaQRONTqSxOu99iT4qCm50OpIx3j +/ShPbKs3iAQbgWGwoIJMUCjb7snFzWX2Z/JIHAdcbyS5Jg8eCNE7Q1LeAmi5w7AIpm9 JaVOni5Wtd5w4scwtQysS8635P8wT9wMxG4ZvcGTNc+4qfvNLUPm6EE2HE/d4Dsc3SoR GQVLDVF/7Z5yygtxIvlslkPXflSqRNawK78ugYnOahTZQEa1/MMKojCErV77BUJ160gQ 6UqQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=u0YYyo5lbCDH5xy0a1DnwBNwsdVCwQoP1JWDsiB/0tk=; b=IOtO6XX3HeyNLbe6qqBVV9uh0EOK/IlikyV7dv4Eu8pZT3OAF3HBEhRj/dn+HU0oGs M50DGD6lSApDW1m674PJ+mEE9mlddk5mVlOeWHfffSjxD6yo2v0ZNyBEP0xipA2AKEoH 2Qv4YJuaJg62hMzfpLJxGu6jXKqpQiJDLiAHiFMk4E3zyVB/8hxkYju5MjJ0nWgU6B4e F6BDBfO2Ug57GG/8dsfHmVKvg3z2siMga3K1alpUuc+aCSFKexR91R3mCTqDBT+DgQ8v NVoq5CBDuG6Cc150UQuyNEr45CplHPjfZFKOwWztTDO1zUgEOXiqaUw1X0zuGF0LQZwX WOug== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="0/Pn6Ba2"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y8si7264496oih.141.2020.01.14.02.18.10; Tue, 14 Jan 2020 02:18:21 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="0/Pn6Ba2"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730573AbgANKQi (ORCPT + 99 others); Tue, 14 Jan 2020 05:16:38 -0500 Received: from mail.kernel.org ([198.145.29.99]:41222 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729472AbgANKJC (ORCPT ); Tue, 14 Jan 2020 05:09:02 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 7E5AE20678; Tue, 14 Jan 2020 10:09:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1578996542; bh=BFxh46HFy9ySY4mUcKY0PvlwJXW3zNmemXO2wpQrlu4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=0/Pn6Ba2keUVUEZohGeLMXc8UG4xNv5Mmki8J0VYOVQ/i1F5RpFns7BPzqEwhe/eD kGzokRK67XI93JxnFJAN1zlWwTlk5tZsAs55DZOcvi9PU7dWBhhJjC/F7ojaRdFL1Q 3k5UO72wMagS/81SuambEq0iuhPZ/BWMLCPdUsM8= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Dmitry Torokhov , Benjamin Tissoires Subject: [PATCH 4.19 40/46] HID: hiddev: fix mess in hiddev_open() Date: Tue, 14 Jan 2020 11:01:57 +0100 Message-Id: <20200114094348.101474810@linuxfoundation.org> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200114094339.608068818@linuxfoundation.org> References: <20200114094339.608068818@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Dmitry Torokhov commit 18a1b06e5b91d47dc86c0a66a762646ea7c5d141 upstream. The open method of hiddev handler fails to bring the device out of autosuspend state as was promised in 0361a28d3f9a, as it actually has 2 blocks that try to start the transport (call hid_hw_open()) with both being guarded by the "open" counter, so the 2nd block is never executed as the first block increments the counter so it is never at 0 when we check it for the second block. Additionally hiddev_open() was leaving counter incremented on errors, causing the device to never be reopened properly if there was ever an error. Let's fix all of this by factoring out code that creates client structure and powers up the device into a separate function that is being called from usbhid_open() with the "existancelock" being held. Fixes: 0361a28d3f9a ("HID: autosuspend support for USB HID") Signed-off-by: Dmitry Torokhov Signed-off-by: Benjamin Tissoires Signed-off-by: Greg Kroah-Hartman --- drivers/hid/usbhid/hiddev.c | 97 +++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 55 deletions(-) --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -254,12 +254,51 @@ static int hiddev_release(struct inode * return 0; } +static int __hiddev_open(struct hiddev *hiddev, struct file *file) +{ + struct hiddev_list *list; + int error; + + lockdep_assert_held(&hiddev->existancelock); + + list = vzalloc(sizeof(*list)); + if (!list) + return -ENOMEM; + + mutex_init(&list->thread_lock); + list->hiddev = hiddev; + + if (!hiddev->open++) { + error = hid_hw_power(hiddev->hid, PM_HINT_FULLON); + if (error < 0) + goto err_drop_count; + + error = hid_hw_open(hiddev->hid); + if (error < 0) + goto err_normal_power; + } + + spin_lock_irq(&hiddev->list_lock); + list_add_tail(&list->node, &hiddev->list); + spin_unlock_irq(&hiddev->list_lock); + + file->private_data = list; + + return 0; + +err_normal_power: + hid_hw_power(hiddev->hid, PM_HINT_NORMAL); +err_drop_count: + hiddev->open--; + vfree(list); + return error; +} + /* * open file op */ static int hiddev_open(struct inode *inode, struct file *file) { - struct hiddev_list *list; struct usb_interface *intf; struct hid_device *hid; struct hiddev *hiddev; @@ -268,66 +307,14 @@ static int hiddev_open(struct inode *ino intf = usbhid_find_interface(iminor(inode)); if (!intf) return -ENODEV; + hid = usb_get_intfdata(intf); hiddev = hid->hiddev; - if (!(list = vzalloc(sizeof(struct hiddev_list)))) - return -ENOMEM; - mutex_init(&list->thread_lock); - list->hiddev = hiddev; - file->private_data = list; - - /* - * no need for locking because the USB major number - * is shared which usbcore guards against disconnect - */ - if (list->hiddev->exist) { - if (!list->hiddev->open++) { - res = hid_hw_open(hiddev->hid); - if (res < 0) - goto bail; - } - } else { - res = -ENODEV; - goto bail; - } - - spin_lock_irq(&list->hiddev->list_lock); - list_add_tail(&list->node, &hiddev->list); - spin_unlock_irq(&list->hiddev->list_lock); - mutex_lock(&hiddev->existancelock); - /* - * recheck exist with existance lock held to - * avoid opening a disconnected device - */ - if (!list->hiddev->exist) { - res = -ENODEV; - goto bail_unlock; - } - if (!list->hiddev->open++) - if (list->hiddev->exist) { - struct hid_device *hid = hiddev->hid; - res = hid_hw_power(hid, PM_HINT_FULLON); - if (res < 0) - goto bail_unlock; - res = hid_hw_open(hid); - if (res < 0) - goto bail_normal_power; - } - mutex_unlock(&hiddev->existancelock); - return 0; -bail_normal_power: - hid_hw_power(hid, PM_HINT_NORMAL); -bail_unlock: + res = hiddev->exist ? __hiddev_open(hiddev, file) : -ENODEV; mutex_unlock(&hiddev->existancelock); - spin_lock_irq(&list->hiddev->list_lock); - list_del(&list->node); - spin_unlock_irq(&list->hiddev->list_lock); -bail: - file->private_data = NULL; - vfree(list); return res; }