Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp5030914ybl; Tue, 14 Jan 2020 02:16:58 -0800 (PST) X-Google-Smtp-Source: APXvYqzcnPgYqwbHQD4CTME4abZTlDqFZndpkNh9OWP0B0Anv8gc4Zw38sH+W4is9+UIiyGfcuTL X-Received: by 2002:aca:1903:: with SMTP id l3mr16168495oii.16.1578997018875; Tue, 14 Jan 2020 02:16:58 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1578997018; cv=none; d=google.com; s=arc-20160816; b=jr38/E7+oc10VyrFBFLtxYwTQEUcwzQ1Vc5a4wkqW3sYw3SqI/j0DvImkg8hSEDWxP ALXlOvoGSM5Be0Xrt5bGdjYWBF5bY0PL2/feUb2pNtzDYqt951vSzASPcz5MDadjcBGz 3TNyZp54y6SJoJOCo7rFL8vEvTJ2XgmXiZX1GPyP5c2lxs95gWhX+iQF3EEdZ9s5OWmO H1qAvIhPi0Dx8BekNYvOR05yNewwx2MqDh+Botfi8BWzDFP0t+DUlfVlDalEbkz1Ez9M MZ+/RPG/KV/rnXr5eFeqdCZOY4CkAiGBLBsk3PfdpFaodCYljGrTe9z5SPVZjaFD94LL He2w== 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=SqMyRa10a2RI0eFzM6LbGNTsDGQVKpomwQvzxD1kE3cgr0Na0lsDbpDEZhlUcCLyIT SZ6GaP6hstMon57MJHBmX32zNYWhHGbJH0K66irgV4wdL5S/akI53bIGRMmXvLMq4+Vr OKbmqvC1hNwH5eNLVp63cPH3arj+YmMv4hj539967qoxWP74MDf8y0hlwHYtztRcaZbF N2hmTuHzJHuCmxayPU5BbZysyIvxAjI3MdB1Mt2ItSb+q0JTDkWy1s2gPxrrP39DCDO1 O9FayhPnZxCUuqy/4GsEb0eVkZnSvg4tgp929O2uiC3A10bVbmx1XzrvqJnswrulNPeD oqiA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=SwLeglJN; 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 l20si7171495oil.224.2020.01.14.02.16.48; Tue, 14 Jan 2020 02:16:58 -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=SwLeglJN; 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 S1731953AbgANKKx (ORCPT + 99 others); Tue, 14 Jan 2020 05:10:53 -0500 Received: from mail.kernel.org ([198.145.29.99]:45320 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730223AbgANKKw (ORCPT ); Tue, 14 Jan 2020 05:10:52 -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 501A9207FF; Tue, 14 Jan 2020 10:10:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1578996651; bh=BFxh46HFy9ySY4mUcKY0PvlwJXW3zNmemXO2wpQrlu4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SwLeglJN7XfMP4j02CtFOyyyGErqHjfkLmwdPf4NQKtt3fbn7ydbLzryoZw2mHO5m I/l4lHIXuUKHeRVsyFEb7rn8TGNu68Hlk9h6l+oTleg49E4QsK1vvaw2Wnbh5i0Umj GaQ90SPKcHlXdbJlxGvMwZtzJT62qFuDpKq31L+c= 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.14 34/39] HID: hiddev: fix mess in hiddev_open() Date: Tue, 14 Jan 2020 11:02:08 +0100 Message-Id: <20200114094346.202352828@linuxfoundation.org> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200114094336.210038037@linuxfoundation.org> References: <20200114094336.210038037@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; }