From patchwork Tue Jan 3 05:48:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: OGAWA Hirofumi X-Patchwork-Id: 9494397 X-Patchwork-Delegate: sameo@linux.intel.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 88C0560414 for ; Tue, 3 Jan 2017 05:48:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7B5C91FF26 for ; Tue, 3 Jan 2017 05:48:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6DD5920246; Tue, 3 Jan 2017 05:48:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D379E1FF26 for ; Tue, 3 Jan 2017 05:48:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757551AbdACFss (ORCPT ); Tue, 3 Jan 2017 00:48:48 -0500 Received: from mail.parknet.co.jp ([210.171.160.6]:45953 "EHLO mail.parknet.co.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756379AbdACFsq (ORCPT ); Tue, 3 Jan 2017 00:48:46 -0500 Received: from ibmpc.myhome.or.jp (server.parknet.ne.jp [210.171.168.39]) by mail.parknet.co.jp (Postfix) with ESMTP id 7F095170001; Tue, 3 Jan 2017 14:48:45 +0900 (JST) Received: from devron.myhome.or.jp (root@devron.myhome.or.jp [192.168.0.3]) by ibmpc.myhome.or.jp (8.15.2/8.15.2/Debian-8) with ESMTPS id v035miLA006942 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 3 Jan 2017 14:48:45 +0900 Received: from devron.myhome.or.jp (hirofumi@localhost [127.0.0.1]) by devron.myhome.or.jp (8.15.2/8.15.2/Debian-8) with ESMTPS id v035miDC006795 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 3 Jan 2017 14:48:44 +0900 Received: (from hirofumi@localhost) by devron.myhome.or.jp (8.15.2/8.15.2/Submit) id v035mio9006794; Tue, 3 Jan 2017 14:48:44 +0900 From: OGAWA Hirofumi To: Samuel Ortiz Cc: Aloisio Almeida Jr , Lauro Ramos Venancio , linux-wireless@vger.kernel.org, Andrew Morton , linux-kernel@vger.kernel.org Subject: [PATCH 4/4] nfc: Fix hangup of RC-S380* in port100_send_ack() References: <87ful0lmop.fsf@mail.parknet.co.jp> <87bmvolmnt.fsf@mail.parknet.co.jp> <877f6clmn2.fsf_-_@mail.parknet.co.jp> Date: Tue, 03 Jan 2017 14:48:44 +0900 In-Reply-To: <877f6clmn2.fsf_-_@mail.parknet.co.jp> (OGAWA Hirofumi's message of "Tue, 03 Jan 2017 14:48:17 +0900") Message-ID: <8737h0lmmb.fsf_-_@mail.parknet.co.jp> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.1.50 (gnu/linux) MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP If port100_send_ack() was called twice or more, it has race to hangup. port100_send_ack() port100_send_ack() init_completion() [...] dev->cmd_cancel = true /* this removes previous from completion */ init_completion() [...] dev->cmd_cancel = true wait_for_completion() /* never be waked up */ wait_for_completion() Like above race, this code is not assuming port100_send_ack() is called twice or more. To fix, this checks dev->cmd_cancel to know if prior cancel is in-flight or not. And never be remove prior task from completion by using reinit_completion(), so this guarantees to be waked up properly soon or later. Signed-off-by: OGAWA Hirofumi --- drivers/nfc/port100.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff -puN drivers/nfc/port100.c~nfc-port100-hang-fix drivers/nfc/port100.c --- linux-ibmpc/drivers/nfc/port100.c~nfc-port100-hang-fix 2017-01-03 12:32:13.261785257 +0900 +++ linux-ibmpc-hirofumi/drivers/nfc/port100.c 2017-01-03 12:33:51.965364300 +0900 @@ -726,23 +726,33 @@ static int port100_submit_urb_for_ack(st static int port100_send_ack(struct port100 *dev) { - int rc; + int rc = 0; mutex_lock(&dev->out_urb_lock); - init_completion(&dev->cmd_cancel_done); - - usb_kill_urb(dev->out_urb); + /* + * If prior cancel is in-flight (dev->cmd_cancel == true), we + * can skip to send cancel. Then this will wait the prior + * cancel, or merged into the next cancel rarely if next + * cancel was started before waiting done. In any case, this + * will be waked up soon or later. + */ + if (!dev->cmd_cancel) { + reinit_completion(&dev->cmd_cancel_done); - dev->out_urb->transfer_buffer = ack_frame; - dev->out_urb->transfer_buffer_length = sizeof(ack_frame); - rc = usb_submit_urb(dev->out_urb, GFP_KERNEL); + usb_kill_urb(dev->out_urb); - /* Set the cmd_cancel flag only if the URB has been successfully - * submitted. It will be reset by the out URB completion callback - * port100_send_complete(). - */ - dev->cmd_cancel = !rc; + dev->out_urb->transfer_buffer = ack_frame; + dev->out_urb->transfer_buffer_length = sizeof(ack_frame); + rc = usb_submit_urb(dev->out_urb, GFP_KERNEL); + + /* + * Set the cmd_cancel flag only if the URB has been + * successfully submitted. It will be reset by the out + * URB completion callback port100_send_complete(). + */ + dev->cmd_cancel = !rc; + } mutex_unlock(&dev->out_urb_lock); @@ -929,8 +939,8 @@ static void port100_send_complete(struct struct port100 *dev = urb->context; if (dev->cmd_cancel) { + complete_all(&dev->cmd_cancel_done); dev->cmd_cancel = false; - complete(&dev->cmd_cancel_done); } switch (urb->status) { @@ -1546,6 +1556,7 @@ static int port100_probe(struct usb_inte PORT100_COMM_RF_HEAD_MAX_LEN; dev->skb_tailroom = PORT100_FRAME_TAIL_LEN; + init_completion(&dev->cmd_cancel_done); INIT_WORK(&dev->cmd_complete_work, port100_wq_cmd_complete); /* The first thing to do with the Port-100 is to set the command type