Received: by 10.223.185.116 with SMTP id b49csp694523wrg; Fri, 16 Feb 2018 05:49:27 -0800 (PST) X-Google-Smtp-Source: AH8x224oSYKEMPBbtcW3zgHETwfgbZDGUoFhQEsmTuzEpKIrgdkCoACXDuoXv/bnqsTgvgXlf/UF X-Received: by 10.99.1.206 with SMTP id 197mr5210361pgb.179.1518788967009; Fri, 16 Feb 2018 05:49:27 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518788966; cv=none; d=google.com; s=arc-20160816; b=F18CgD55OAX5f4AGgoeklfNYsyWsndI8Nfu3rfx5CBG3btcfWc2NE3dH6d+YyI7hKK pgzb5rdhg68DLQwyxFONLBOsd1hnKnqbll6y95MOdWgERgpDRMCptsUAFzce5k/lp94/ wYr7Wm+mupmLRQGlAb6Z9gjyZ69lb7YIYL5ogqQScCYfRoPpQqHCvsiLBE07dFS1NyNn FZthtIJebIiKx1tpJoF/dGvp8Ny4+dd7510m9FvXpQl2u9Ug5ABqrV3Qj2nAaJHbUH2A IP3wJiV6bfrbP2hXXe8PZNNjCNo8bfdlM/YH0GudY+4JlTmdh0Y3mh840zvN+3+lXTPi q6lg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=TiKHeoS8PcePWiy7fwkXQ+mz+KJgBEZ0EQO6jP83OaU=; b=pOuEgBOLYcqnwuCvxOs2OCampfLYFCpmS5FfyJ0epboBUDQWLAF4WkUaUfe1nXe3Wa O7Mq5kVEuC3AefO78LNQbCLO9wwPZRakg3HtV9eMur8ixCzWLwSY331DSjs4EuUm6GDf tPr6HLFS5Pojd8tPwB4qA/1rHaUOvFEDGnEt8OGK0h9MasM8mpuin6BUuyemVN0mjgdQ eRFJXsTnRrCi8HC66pgEkneLH1j3XNMO6mgSTCR/xBndwJpeWxiWnXJpw7/hHb80XW5e FEpPfWDsm5R9cibLdRSSBGh+NIORs7df7PSbT53EC9exGB0BT3ytDzUgVG5OzOrAaKd3 54YQ== 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 j23-v6si3257310pli.127.2018.02.16.05.49.11; Fri, 16 Feb 2018 05:49:26 -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 S1166835AbeBOSne (ORCPT + 99 others); Thu, 15 Feb 2018 13:43:34 -0500 Received: from mail.linuxfoundation.org ([140.211.169.12]:50914 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1162622AbeBOPXS (ORCPT ); Thu, 15 Feb 2018 10:23:18 -0500 Received: from localhost (LFbn-1-12258-90.w90-92.abo.wanadoo.fr [90.92.71.90]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 2245FF13; Thu, 15 Feb 2018 15:22:57 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Bradley Bolen , Boris Brezillon , Richard Weinberger Subject: [PATCH 4.4 058/108] ubi: block: Fix locking for idr_alloc/idr_remove Date: Thu, 15 Feb 2018 16:16:55 +0100 Message-Id: <20180215151230.542409737@linuxfoundation.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180215151222.267507937@linuxfoundation.org> References: <20180215151222.267507937@linuxfoundation.org> User-Agent: quilt/0.65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.4-stable review patch. If anyone has any objections, please let me know. ------------------ From: Bradley Bolen commit 7f29ae9f977bcdc3654e68bc36d170223c52fd48 upstream. This fixes a race with idr_alloc where gd->first_minor can be set to the same value for two simultaneous calls to ubiblock_create. Each instance calls device_add_disk with the same first_minor. device_add_disk calls bdi_register_owner which generates several warnings. WARNING: CPU: 1 PID: 179 at kernel-source/fs/sysfs/dir.c:31 sysfs_warn_dup+0x68/0x88 sysfs: cannot create duplicate filename '/devices/virtual/bdi/252:2' WARNING: CPU: 1 PID: 179 at kernel-source/lib/kobject.c:240 kobject_add_internal+0x1ec/0x2f8 kobject_add_internal failed for 252:2 with -EEXIST, don't try to register things with the same name in the same directory WARNING: CPU: 1 PID: 179 at kernel-source/fs/sysfs/dir.c:31 sysfs_warn_dup+0x68/0x88 sysfs: cannot create duplicate filename '/dev/block/252:2' However, device_add_disk does not error out when bdi_register_owner returns an error. Control continues until reaching blk_register_queue. It then BUGs. kernel BUG at kernel-source/fs/sysfs/group.c:113! [] (internal_create_group) from [] (sysfs_create_group+0x20/0x24) [] (sysfs_create_group) from [] (blk_trace_init_sysfs+0x18/0x20) [] (blk_trace_init_sysfs) from [] (blk_register_queue+0xd8/0x154) [] (blk_register_queue) from [] (device_add_disk+0x194/0x44c) [] (device_add_disk) from [] (ubiblock_create+0x284/0x2e0) [] (ubiblock_create) from [] (vol_cdev_ioctl+0x450/0x554) [] (vol_cdev_ioctl) from [] (vfs_ioctl+0x30/0x44) [] (vfs_ioctl) from [] (do_vfs_ioctl+0xa0/0x790) [] (do_vfs_ioctl) from [] (SyS_ioctl+0x44/0x68) [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x34) Locking idr_alloc/idr_remove removes the race and keeps gd->first_minor unique. Fixes: 2bf50d42f3a4 ("UBI: block: Dynamically allocate minor numbers") Signed-off-by: Bradley Bolen Reviewed-by: Boris Brezillon Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -99,6 +99,8 @@ struct ubiblock { /* Linked list of all ubiblock instances */ static LIST_HEAD(ubiblock_devices); +static DEFINE_IDR(ubiblock_minor_idr); +/* Protects ubiblock_devices and ubiblock_minor_idr */ static DEFINE_MUTEX(devices_mutex); static int ubiblock_major; @@ -354,8 +356,6 @@ static struct blk_mq_ops ubiblock_mq_ops .map_queue = blk_mq_map_queue, }; -static DEFINE_IDR(ubiblock_minor_idr); - int ubiblock_create(struct ubi_volume_info *vi) { struct ubiblock *dev; @@ -368,14 +368,15 @@ int ubiblock_create(struct ubi_volume_in /* Check that the volume isn't already handled */ mutex_lock(&devices_mutex); if (find_dev_nolock(vi->ubi_num, vi->vol_id)) { - mutex_unlock(&devices_mutex); - return -EEXIST; + ret = -EEXIST; + goto out_unlock; } - mutex_unlock(&devices_mutex); dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL); - if (!dev) - return -ENOMEM; + if (!dev) { + ret = -ENOMEM; + goto out_unlock; + } mutex_init(&dev->dev_mutex); @@ -440,14 +441,13 @@ int ubiblock_create(struct ubi_volume_in goto out_free_queue; } - mutex_lock(&devices_mutex); list_add_tail(&dev->list, &ubiblock_devices); - mutex_unlock(&devices_mutex); /* Must be the last step: anyone can call file ops from now on */ add_disk(dev->gd); dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", dev->ubi_num, dev->vol_id, vi->name); + mutex_unlock(&devices_mutex); return 0; out_free_queue: @@ -460,6 +460,8 @@ out_put_disk: put_disk(dev->gd); out_free_dev: kfree(dev); +out_unlock: + mutex_unlock(&devices_mutex); return ret; } @@ -481,30 +483,36 @@ static void ubiblock_cleanup(struct ubib int ubiblock_remove(struct ubi_volume_info *vi) { struct ubiblock *dev; + int ret; mutex_lock(&devices_mutex); dev = find_dev_nolock(vi->ubi_num, vi->vol_id); if (!dev) { - mutex_unlock(&devices_mutex); - return -ENODEV; + ret = -ENODEV; + goto out_unlock; } /* Found a device, let's lock it so we can check if it's busy */ mutex_lock(&dev->dev_mutex); if (dev->refcnt > 0) { - mutex_unlock(&dev->dev_mutex); - mutex_unlock(&devices_mutex); - return -EBUSY; + ret = -EBUSY; + goto out_unlock_dev; } /* Remove from device list */ list_del(&dev->list); - mutex_unlock(&devices_mutex); - ubiblock_cleanup(dev); mutex_unlock(&dev->dev_mutex); + mutex_unlock(&devices_mutex); + kfree(dev); return 0; + +out_unlock_dev: + mutex_unlock(&dev->dev_mutex); +out_unlock: + mutex_unlock(&devices_mutex); + return ret; } static int ubiblock_resize(struct ubi_volume_info *vi) @@ -633,6 +641,7 @@ static void ubiblock_remove_all(void) struct ubiblock *next; struct ubiblock *dev; + mutex_lock(&devices_mutex); list_for_each_entry_safe(dev, next, &ubiblock_devices, list) { /* The module is being forcefully removed */ WARN_ON(dev->desc); @@ -641,6 +650,7 @@ static void ubiblock_remove_all(void) ubiblock_cleanup(dev); kfree(dev); } + mutex_unlock(&devices_mutex); } int __init ubiblock_init(void)