From patchwork Mon Mar 6 16:33:55 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kara X-Patchwork-Id: 9607119 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 9165E601D2 for ; Mon, 6 Mar 2017 16:34:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 82D4826E51 for ; Mon, 6 Mar 2017 16:34:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 75EE72793A; Mon, 6 Mar 2017 16:34:59 +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 C3FE826E51 for ; Mon, 6 Mar 2017 16:34:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754145AbdCFQeq (ORCPT ); Mon, 6 Mar 2017 11:34:46 -0500 Received: from mx2.suse.de ([195.135.220.15]:45636 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754414AbdCFQei (ORCPT ); Mon, 6 Mar 2017 11:34:38 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id E0CD1AB5D; Mon, 6 Mar 2017 16:34:35 +0000 (UTC) Received: by quack2.suse.cz (Postfix, from userid 1000) id A8A681E3956; Mon, 6 Mar 2017 17:34:34 +0100 (CET) From: Jan Kara To: Jens Axboe Cc: linux-block@vger.kernel.org, Christoph Hellwig , Dan Williams , Thiago Jung Bauermann , Lekshmi Pillai , Tejun Heo , NeilBrown , Omar Sandoval , Jan Kara Subject: [PATCH 02/11] block: Fix race of bdev open with gendisk shutdown Date: Mon, 6 Mar 2017 17:33:55 +0100 Message-Id: <20170306163404.1238-3-jack@suse.cz> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20170306163404.1238-1-jack@suse.cz> References: <20170306163404.1238-1-jack@suse.cz> Sender: linux-block-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP blkdev_open() may race with gendisk shutdown in such a way that del_gendisk() has already unhashed block device inode (and thus bd_acquire() will end up creating new block device inode) however gen_gendisk() will still return the gendisk that is being destroyed. This will result in the new bdev inode being associated with bdi of the request queue that is going away and when the device number gets eventually reused, the block device will still be pointing to the stale bdi. Fix the problem by checking whether the gendisk is still alive when associating bdev inode with it and its bdi. That way we are sure that once we are unhashing block device inodes in del_gendisk(), newly created bdev inodes cannot be associated with bdi of the deleted gendisk anymore. We actually already do this check when opening a partition so we need to add it only for the case when the whole device is opened. Also add a warning that will tell us about unexpected inconsistencies between bdi associated with the bdev inode and bdi associated with the disk. Signed-off-by: Jan Kara --- block/genhd.c | 7 ++++++- fs/block_dev.c | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index b26a5ea115d0..e8df37de03af 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -662,6 +662,12 @@ void del_gendisk(struct gendisk *disk) struct disk_part_iter piter; struct hd_struct *part; + disk->flags &= ~GENHD_FL_UP; + /* + * Make sure __blkdev_open() sees the disk is going away before + * starting to unhash bdev inodes. + */ + smp_wmb(); blk_integrity_del(disk); disk_del_events(disk); @@ -678,7 +684,6 @@ void del_gendisk(struct gendisk *disk) invalidate_partition(disk, 0); bdev_unhash_inode(disk_devt(disk)); set_capacity(disk, 0); - disk->flags &= ~GENHD_FL_UP; sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); /* diff --git a/fs/block_dev.c b/fs/block_dev.c index 53e2389ae4d4..9e1993a2827f 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1560,7 +1560,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) if (!partno) { ret = -ENXIO; bdev->bd_part = disk_get_part(disk, partno); - if (!bdev->bd_part) + if (!(disk->flags & GENHD_FL_UP) || !bdev->bd_part) goto out_clear; ret = 0; @@ -1623,6 +1623,9 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) if (bdev->bd_bdi == &noop_backing_dev_info) bdev->bd_bdi = bdi_get(disk->queue->backing_dev_info); + else + WARN_ON_ONCE(bdev->bd_bdi != + disk->queue->backing_dev_info); } else { if (bdev->bd_contains == bdev) { ret = 0;