From patchwork Fri May 16 11:04:45 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bart Van Assche X-Patchwork-Id: 4190181 Return-Path: X-Original-To: patchwork-linux-rdma@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 90FBCBFF02 for ; Fri, 16 May 2014 11:04:49 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AE3F7202E9 for ; Fri, 16 May 2014 11:04:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B8C4620295 for ; Fri, 16 May 2014 11:04:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757160AbaEPLEq (ORCPT ); Fri, 16 May 2014 07:04:46 -0400 Received: from albert.telenet-ops.be ([195.130.137.90]:42518 "EHLO albert.telenet-ops.be" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757157AbaEPLEq (ORCPT ); Fri, 16 May 2014 07:04:46 -0400 Received: from [192.168.1.117] ([178.119.65.67]) by albert.telenet-ops.be with bizsmtp id 2b4l1o00e1T3uRu06b4l78; Fri, 16 May 2014 13:04:45 +0200 Message-ID: <5375F0CD.5080809@acm.org> Date: Fri, 16 May 2014 13:04:45 +0200 From: Bart Van Assche User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.5.0 MIME-Version: 1.0 To: Roland Dreier CC: Yann Droneaud , Alex Chiang , linux-rdma Subject: [PATCH v3 1/2] IB/umad: Fix error handling References: <5375F094.30809@acm.org> In-Reply-To: <5375F094.30809@acm.org> X-Enigmail-Version: 1.6 Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable 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 Avoid leaking a kref count in ib_umad_open() if port->ib_dev == NULL or if nonseekable_open() fails. Avoid leaking a kref count, that sm_sem is kept down and also that the IB_PORT_SM capability mask is not cleared in ib_umad_sm_open() if nonseekable_open() fails. Since container_of() never returns NULL, remove the code that tests whether container_of() returns NULL. Note: moving the kref_get() call from the start of ib_umad_*open() to the end is safe since it is the responsibility of the caller of these functions to ensure that the cdev pointer remains valid until at least when these functions return. Signed-off-by: Bart Van Assche Cc: Alex Chiang Cc: Yann Droneaud Cc: --- drivers/infiniband/core/user_mad.c | 58 ++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index f0d588f..2b3dfcc 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -780,27 +780,19 @@ static int ib_umad_open(struct inode *inode, struct file *filp) { struct ib_umad_port *port; struct ib_umad_file *file; - int ret; + int ret = -ENXIO; port = container_of(inode->i_cdev, struct ib_umad_port, cdev); - if (port) - kref_get(&port->umad_dev->ref); - else - return -ENXIO; mutex_lock(&port->file_mutex); - if (!port->ib_dev) { - ret = -ENXIO; + if (!port->ib_dev) goto out; - } + ret = -ENOMEM; file = kzalloc(sizeof *file, GFP_KERNEL); - if (!file) { - kref_put(&port->umad_dev->ref, ib_umad_release_dev); - ret = -ENOMEM; + if (!file) goto out; - } mutex_init(&file->mutex); spin_lock_init(&file->send_lock); @@ -815,9 +807,20 @@ static int ib_umad_open(struct inode *inode, struct file *filp) ret = nonseekable_open(inode, filp); + if (ret) + goto del; + + kref_get(&port->umad_dev->ref); + out: mutex_unlock(&port->file_mutex); + return ret; + +del: + list_del(&file->port_list); + kfree(file); + goto out; } static int ib_umad_close(struct inode *inode, struct file *filp) @@ -880,36 +883,41 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp) int ret; port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev); - if (port) - kref_get(&port->umad_dev->ref); - else - return -ENXIO; if (filp->f_flags & O_NONBLOCK) { if (down_trylock(&port->sm_sem)) { ret = -EAGAIN; - goto fail; + goto out; } } else { if (down_interruptible(&port->sm_sem)) { ret = -ERESTARTSYS; - goto fail; + goto out; } } ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); - if (ret) { - up(&port->sm_sem); - goto fail; - } + if (ret) + goto up_sem; filp->private_data = port; - return nonseekable_open(inode, filp); + ret = nonseekable_open(inode, filp); + if (ret) + goto clr_sm_cap; -fail: - kref_put(&port->umad_dev->ref, ib_umad_release_dev); + kref_get(&port->umad_dev->ref); + +out: return ret; + +clr_sm_cap: + swap(props.set_port_cap_mask, props.clr_port_cap_mask); + ib_modify_port(port->ib_dev, port->port_num, 0, &props); + +up_sem: + up(&port->sm_sem); + goto out; } static int ib_umad_sm_close(struct inode *inode, struct file *filp)