From patchwork Mon Mar 13 15:14:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kara X-Patchwork-Id: 9621299 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 1D1CB60522 for ; Mon, 13 Mar 2017 15:14:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0C93028480 for ; Mon, 13 Mar 2017 15:14:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 00C7D284D1; Mon, 13 Mar 2017 15:14:17 +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 9B190284D9 for ; Mon, 13 Mar 2017 15:14:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751486AbdCMPOR (ORCPT ); Mon, 13 Mar 2017 11:14:17 -0400 Received: from mx2.suse.de ([195.135.220.15]:45410 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751245AbdCMPOQ (ORCPT ); Mon, 13 Mar 2017 11:14:16 -0400 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 B2F32AD48; Mon, 13 Mar 2017 15:14:13 +0000 (UTC) Received: by quack2.suse.cz (Postfix, from userid 1000) id 345011E0561; Mon, 13 Mar 2017 16:14:12 +0100 (CET) From: Jan Kara To: Jens Axboe Cc: linux-block@vger.kernel.org, Christoph Hellwig , Dan Williams , Thiago Jung Bauermann , Tejun Heo , Tahsin Erdogan , Omar Sandoval , Jan Kara Subject: [PATCH 02/11] block: Fix race of bdev open with gendisk shutdown Date: Mon, 13 Mar 2017 16:14:01 +0100 Message-Id: <20170313151410.5586-3-jack@suse.cz> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20170313151410.5586-1-jack@suse.cz> References: <20170313151410.5586-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 two different ways. Either 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. Or bdev returned by bd_acquire() will get unhashed and gendisk destroyed before we get to get_gendisk() and get_gendisk() will return new gendisk that got allocated for device that reused the device number. In both cases this will result in possible inconsistencies between bdev->bd_disk and bdev->bd_bdi (in the first case after gendisk gets destroyed and device number reused, in the second case immediately). Fix the problem by checking whether the gendisk is still alive and inode hashed when associating bdev inode with it and its bdi. That way we are sure that we will not associate bdev inode with disk that got past blk_unregister_region() in del_gendisk() (and thus device number can get reused). Similarly, we will not associate bdev that was once associated with gendisk that is going away (and thus the corresponding bdev inode will get unhashed in del_gendisk()) with a new gendisk that is just reusing the device number. 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 --- fs/block_dev.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/block_dev.c b/fs/block_dev.c index 53e2389ae4d4..5ec8750f5332 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1560,7 +1560,8 @@ 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 || + inode_unhashed(bdev->bd_inode)) goto out_clear; ret = 0; @@ -1614,7 +1615,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) bdev->bd_contains = whole; bdev->bd_part = disk_get_part(disk, partno); if (!(disk->flags & GENHD_FL_UP) || - !bdev->bd_part || !bdev->bd_part->nr_sects) { + !bdev->bd_part || !bdev->bd_part->nr_sects || + inode_unhashed(bdev->bd_inode)) { ret = -ENXIO; goto out_clear; } @@ -1623,6 +1625,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;