From patchwork Fri Nov 20 21:22:34 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Dryomov X-Patchwork-Id: 7671351 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 0C158BF90C for ; Fri, 20 Nov 2015 21:22:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3CCE620499 for ; Fri, 20 Nov 2015 21:22:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5535720497 for ; Fri, 20 Nov 2015 21:22:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1162236AbbKTVWr (ORCPT ); Fri, 20 Nov 2015 16:22:47 -0500 Received: from mail-wm0-f48.google.com ([74.125.82.48]:35453 "EHLO mail-wm0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1161971AbbKTVWp (ORCPT ); Fri, 20 Nov 2015 16:22:45 -0500 Received: by wmdw130 with SMTP id w130so34673284wmd.0 for ; Fri, 20 Nov 2015 13:22:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=w7vqVMPbii6xWOrkLQkXCQ9+tf59FjtSTaviamzCtq0=; b=d9MAIXl6ANjLgY16Y8oZgUt6WI9DX79WbnR2VDzhdHCib99GPrY69aDmlLb6oNmBQR rsAUhvr0JVvoSjIJA4AM388CuuMqaoS8UvM1Qc8Pcrx7as+NQSx00h85r0n18DS2N4B0 FLQqOWgxTid5JlI528MnUU/Y6jCbb913ABHxnCRxEFgamz9NxXFn4IBo5273QkamhGda ZkL1zWxVezA3VfRF3Mz586tlglhm1rrozSYvh8y0QmOqbnEaqhF0AeIrt9SPKeamTGQk rb7CwB6BdEKX8qotQHa9bKv3FPLI2WVO+pbITnkKBsHiRLDFbJfv6eEkyuDOMDsuf+c1 dWSw== X-Received: by 10.194.205.162 with SMTP id lh2mr16567874wjc.61.1448054564700; Fri, 20 Nov 2015 13:22:44 -0800 (PST) Received: from localhost.localdomain.com (nat-pool-brq-t.redhat.com. [213.175.37.10]) by smtp.gmail.com with ESMTPSA id gj2sm1207337wjb.40.2015.11.20.13.22.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Nov 2015 13:22:43 -0800 (PST) From: Ilya Dryomov To: Alexander Viro Cc: Tejun Heo , Christoph Hellwig , linux-fsdevel@vger.kernel.org Subject: [PATCH] block: detach bdev inode from its wb in __blkdev_put() Date: Fri, 20 Nov 2015 22:22:34 +0100 Message-Id: <1448054554-24138-1-git-send-email-idryomov@gmail.com> X-Mailer: git-send-email 2.4.3 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-7.3 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, 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 Since 52ebea749aae ("writeback: make backing_dev_info host cgroup-specific bdi_writebacks") inode, at some point in its lifetime, gets attached to a wb (struct bdi_writeback). Detaching happens on evict, in inode_detach_wb() called from __destroy_inode(), and involves updating wb. However, detaching an internal bdev inode from its wb in __destroy_inode() is too late. Its bdi and by extension root wb are embedded into struct request_queue, which has different lifetime rules and can be freed long before the final bdput() is called (can be from __fput() of a corresponding /dev inode, through dput() - evict() - bd_forget(). bdevs hold onto the underlying disk/queue pair only while opened; as soon as bdev is closed all bets are off. In fact, disk/queue can be gone before __blkdev_put() even returns: 1499 static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) 1500 { ... 1518 if (bdev->bd_contains == bdev) { 1519 if (disk->fops->release) 1520 disk->fops->release(disk, mode); [ Driver puts its references to disk/queue ] 1521 } 1522 if (!bdev->bd_openers) { 1523 struct module *owner = disk->fops->owner; 1524 1525 disk_put_part(bdev->bd_part); 1526 bdev->bd_part = NULL; 1527 bdev->bd_disk = NULL; 1528 if (bdev != bdev->bd_contains) 1529 victim = bdev->bd_contains; 1530 bdev->bd_contains = NULL; 1531 1532 put_disk(disk); [ We put ours, the queue is gone The last bdput() would result in a write to invalid memory ] 1533 module_put(owner); ... 1539 } Since bdev inodes are special anyway, detach them in __blkdev_put() after clearing inode's dirty bits, turning the problematic inode_detach_wb() in __destroy_inode() into a noop. add_disk() grabs its disk->queue since 523e1d399ce0 ("block: make gendisk hold a reference to its queue"), so the old ->release comment is removed in favor of the new inode_detach_wb() comment. Cc: stable@vger.kernel.org # 4.2+, needs backporting Signed-off-by: Ilya Dryomov Acked-by: Tejun Heo Tested-by: Raghavendra K T --- fs/block_dev.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/block_dev.c b/fs/block_dev.c index bb0dfb1c7af1..6f8dd407c533 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1509,11 +1509,14 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) WARN_ON_ONCE(bdev->bd_holders); sync_blockdev(bdev); kill_bdev(bdev); + + bdev_write_inode(bdev); /* - * ->release can cause the queue to disappear, so flush all - * dirty data before. + * Detaching bdev inode from its wb in __destroy_inode() + * is too late: the queue which embeds its bdi (along with + * root wb) can be gone as soon as we put_disk() below. */ - bdev_write_inode(bdev); + inode_detach_wb(bdev->bd_inode); } if (bdev->bd_contains == bdev) { if (disk->fops->release)