Received: by 10.223.176.5 with SMTP id f5csp1430891wra; Wed, 7 Feb 2018 19:56:42 -0800 (PST) X-Google-Smtp-Source: AH8x227ZFh/zm0BDHz53+IJo08P1eOWEszJ29UyZ297yF/6/3Krea7mm0XurAJNKY3QYU2+Gd4A9 X-Received: by 10.98.224.24 with SMTP id f24mr8012690pfh.157.1518062201978; Wed, 07 Feb 2018 19:56:41 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518062201; cv=none; d=google.com; s=arc-20160816; b=xUj0bZvqp2/3iGj62lQaTT45pFdPti9ilHvUVilHHo6pFALBaof2hTM2+7DDJ2CZ4X ppSUMo6h+t4mbPqne1HEg28jNliVpAMaQ/dvSgO7jXMORV2qLvtsYwHW8PL7zPZ1Eoub 7d1/J6H7jhEKLTohLbVISNxpWlWgLCFMobpq+mkisk98DlUzp+lHdT9kaTY4fLg+Mq9j WypAYpLJp3b4ugPlvLSnwQ3OAh3cqXxXdNu2CSbzUlyfkSz2a16amEZZ23jZWTfKoCek i1cjcTV++h5gXpabCbH7HpxHUl4rHhNY2v8ISusxRs6TrDbTMQC+vgjtesJz4F2/w89j krEw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=so0gd15rGXSezBfLVDjl70J4uJXYsEzDbVNcyW6upno=; b=bHS6fAHVBK7QhebRWTBo89L8U+MdN7GyE1s72W4oydHSBVHKW7LbeEBRixYg4OIqP4 lej8K37iutTRAU5IXxeKvw684UYhs+kQnyfOHzmvLKKrfyt3kDURvzKEf1/y0x2io5gV s1xVQX8h0tWneF6abcXoU9/6em4eAbo7s+H++B3rU2xhSJtfmlp052yksWTq2n/Yb2qQ IA6LzTJ1ISlfenerynlblfLEv57MALN8181dTgzUqHlpcF8hx1zi+G3tU3an/ZsM+/S3 TJtBKdyKdHRcA1ZPpjI6jyAO7VSh56WIpWoJj9k9DjBJorovJgR9zO1m7PKKWU3NalLw nU3Q== ARC-Authentication-Results: i=1; mx.google.com; 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 m12-v6si806658pln.737.2018.02.07.19.56.16; Wed, 07 Feb 2018 19:56:41 -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; 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 S1751319AbeBHDzQ (ORCPT + 99 others); Wed, 7 Feb 2018 22:55:16 -0500 Received: from regular1.263xmail.com ([211.150.99.137]:59924 "EHLO regular1.263xmail.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750810AbeBHDzP (ORCPT ); Wed, 7 Feb 2018 22:55:15 -0500 Received: from jeffy.chen?rock-chips.com (unknown [192.168.167.164]) by regular1.263xmail.com (Postfix) with ESMTP id 0A695DBFD; Thu, 8 Feb 2018 11:55:07 +0800 (CST) X-263anti-spam: KSV:0; X-MAIL-GRAY: 0 X-MAIL-DELIVERY: 1 X-KSVirus-check: 0 X-ABS-CHECKED: 4 Received: from localhost (localhost [127.0.0.1]) by smtp.263.net (Postfix) with ESMTPA id A3D5B384; Thu, 8 Feb 2018 11:55:03 +0800 (CST) X-RL-SENDER: jeffy.chen@rock-chips.com X-FST-TO: linux-kernel@vger.kernel.org X-SENDER-IP: 103.29.142.67 X-LOGIN-NAME: jeffy.chen@rock-chips.com X-UNIQUE-TAG: <33bbeb5ba0bb29ada95c25479af84076> X-ATTACHMENT-NUM: 0 X-SENDER: cjf@rock-chips.com X-DNS-TYPE: 0 Received: from localhost (unknown [103.29.142.67]) by smtp.263.net (Postfix) whith ESMTP id 24762ZD4XD4; Thu, 08 Feb 2018 11:55:07 +0800 (CST) From: Jeffy Chen To: linux-kernel@vger.kernel.org Cc: briannorris@chromium.org, stern@rowland.harvard.edu, mka@chromium.org, dianders@chromium.org, AMAN DEEP , stable@vger.kernel.org, Jeffy Chen , Greg Kroah-Hartman , linux-usb@vger.kernel.org Subject: [PATCH v6] usb: ohci: Proper handling of ed_rm_list to handle race condition between usb_kill_urb() and finish_unlinks() Date: Thu, 8 Feb 2018 11:55:01 +0800 Message-Id: <20180208035501.10711-1-jeffy.chen@rock-chips.com> X-Mailer: git-send-email 2.11.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: AMAN DEEP There is a race condition between finish_unlinks->finish_urb() function and usb_kill_urb() in ohci controller case. The finish_urb calls spin_unlock(&ohci->lock) before usb_hcd_giveback_urb() function call, then if during this time, usb_kill_urb is called for another endpoint, then new ed will be added to ed_rm_list at beginning for unlink, and ed_rm_list will point to newly added. When finish_urb() is completed in finish_unlinks() and ed->td_list becomes empty as in below code (in finish_unlinks() function): if (list_empty(&ed->td_list)) { *last = ed->ed_next; ed->ed_next = NULL; } else if (ohci->rh_state == OHCI_RH_RUNNING) { *last = ed->ed_next; ed->ed_next = NULL; ed_schedule(ohci, ed); } The *last = ed->ed_next will make ed_rm_list to point to ed->ed_next and previously added ed by usb_kill_urb will be left unreferenced by ed_rm_list. This causes usb_kill_urb() hang forever waiting for finish_unlink to remove added ed from ed_rm_list. The main reason for hang in this race condtion is addition and removal of ed from ed_rm_list in the beginning during usb_kill_urb and later last* is modified in finish_unlinks(). As suggested by Alan Stern, the solution for proper handling of ohci->ed_rm_list is to remove ed from the ed_rm_list before finishing any URBs. Then at the end, we can add ed back to the list if necessary. This properly handle the updated ohci->ed_rm_list in usb_kill_urb(). Fixes:977dcfdc6031("USB:OHCI:don't lose track of EDs when a controller dies") Acked-by: Alan Stern CC: Signed-off-by: Aman Deep Signed-off-by: Jeffy Chen --- Changes in v6: This is a resend of Aman Deep's v5 patch [0], which solved the hang we hit [1]. (Thanks Aman :) The v5 has some format issues, so i slightly adjust the commit message. [0] https://www.spinics.net/lists/linux-usb/msg129010.html [1] https://bugs.chromium.org/p/chromium/issues/detail?id=803749 drivers/usb/host/ohci-q.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index b2ec8c399363..4ccb85a67bb3 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -1019,6 +1019,8 @@ static void finish_unlinks(struct ohci_hcd *ohci) * have modified this list. normally it's just prepending * entries (which we'd ignore), but paranoia won't hurt. */ + *last = ed->ed_next; + ed->ed_next = NULL; modified = 0; /* unlink urbs as requested, but rescan the list after @@ -1077,21 +1079,22 @@ static void finish_unlinks(struct ohci_hcd *ohci) goto rescan_this; /* - * If no TDs are queued, take ED off the ed_rm_list. + * If no TDs are queued, ED is now idle. * Otherwise, if the HC is running, reschedule. - * If not, leave it on the list for further dequeues. + * If the HC isn't running, add ED back to the + * start of the list for later processing. */ if (list_empty(&ed->td_list)) { - *last = ed->ed_next; - ed->ed_next = NULL; ed->state = ED_IDLE; list_del(&ed->in_use_list); } else if (ohci->rh_state == OHCI_RH_RUNNING) { - *last = ed->ed_next; - ed->ed_next = NULL; ed_schedule(ohci, ed); } else { - last = &ed->ed_next; + ed->ed_next = ohci->ed_rm_list; + ohci->ed_rm_list = ed; + /* Don't loop on the same ED */ + if (last == &ohci->ed_rm_list) + last = &ed->ed_next; } if (modified) -- 2.11.0