Received: by 2002:a05:6358:9144:b0:117:f937:c515 with SMTP id r4csp6104158rwr; Tue, 9 May 2023 10:13:52 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7sHkvGAauAU3P2gtpZH6CYcnxCTxRVCAGrOg5G6F2dAofo8XN7xJcELQ4HOxf3LADu2R8A X-Received: by 2002:a17:902:e74e:b0:1ab:19fe:d85b with SMTP id p14-20020a170902e74e00b001ab19fed85bmr18371679plf.38.1683652432082; Tue, 09 May 2023 10:13:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683652432; cv=none; d=google.com; s=arc-20160816; b=CSWIFwDM0R4N8vQLCM6T76qQCG5WDUukJnuRnBmQYUvjEl0+RPUua5Q3uSWSBLQPhY f9pERDj7vsfETo1sqQl3OdnVNSZRXVZqTrEtaNgwU59YusXt7O2k2cOXf6eOCjrdpV8q ZIn0qoIJ/GsEGsKlAgDSfvFf9BBJeElwmc/06AgC/LnVLKERro6/tEOIgms9I2QPU2sI p1/FuyJIy2BbDqln69mZy7eRhD6LH8/T88y6F601YRTnVEd5vVhTkGs39V8dOoVFuJfB vkkTP6kQjY13wa+Yqt6LL3F6lHS53JOetTF5cQ4GNq7x//wzeaub6m0Cq06dtVqM1wIC bUhA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=Bsc+1yI/guH+T2KE4bJnNuVNfNr1pSTLs0rK/pjjSAI=; b=FHz9gO6esjIPa+rKDbupFdZKQQly9GqVFK2ZqRxBrUq0qWxjEchbIvkT+rKs5cD/dU qSoG0sVoPZ878YOpdCbzfsKwCZdiUSccSIlIr6pgHshAmZQ3V3dneNTASeoU4lamWaUr u+EOm2wfH07cF1e3ZFY3dRIGt7AvxW08d53WWGzEVuMIPziGXx6pJvm51fdlWXd1zPP4 0jhrz4XW/snl+VQMy6ErA3nmhY0rEtbUsAnBJnho8PAAjuE0+rwrGVuuX7qm1F4u+s0v KmwOEFCiVuDcc0dlRwJ8nR3Wj3AL76QTT9P40Ph3inYhcfldn6nw3AVGn9FpS/2ijQNs 48sA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=Reg17E4h; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id bi11-20020a170902bf0b00b001a6ef92d441si1760055plb.599.2023.05.09.10.13.36; Tue, 09 May 2023 10:13:52 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=Reg17E4h; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234927AbjEIQ6o (ORCPT + 99 others); Tue, 9 May 2023 12:58:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234872AbjEIQ6E (ORCPT ); Tue, 9 May 2023 12:58:04 -0400 Received: from out-4.mta1.migadu.com (out-4.mta1.migadu.com [95.215.58.4]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 848EB59DC for ; Tue, 9 May 2023 09:57:25 -0700 (PDT) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1683651444; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Bsc+1yI/guH+T2KE4bJnNuVNfNr1pSTLs0rK/pjjSAI=; b=Reg17E4hxC/htV66caDP4mIg8lk7TjjhYySdYeFxLdwU4L7ySzXsxSI3IE/jxUtwJLdQ6e geU1GuZFaJRSE+vUsNzOEQAHx8GKD9SxSVp/CscftZ+vi6/DaJin7NUQrUWOWUGTu7OsO7 iSaIQhOKsdg5do0xv0BevZNBx62CTAM= From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-bcachefs@vger.kernel.org Cc: Kent Overstreet Subject: [PATCH 14/32] block: Don't block on s_umount from __invalidate_super() Date: Tue, 9 May 2023 12:56:39 -0400 Message-Id: <20230509165657.1735798-15-kent.overstreet@linux.dev> In-Reply-To: <20230509165657.1735798-1-kent.overstreet@linux.dev> References: <20230509165657.1735798-1-kent.overstreet@linux.dev> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org __invalidate_super() is used to flush any filesystem mounted on a device, generally on some sort of media change event. However, when unmounting a filesystem and closing the underlying block devices, we can deadlock if the block driver then calls __invalidate_device() (e.g. because the block device goes away when it is no longer in use). This happens with bcachefs on top of loopback, and can be triggered by fstests generic/042: put_super -> blkdev_put -> lo_release -> disk_force_media_change -> __invalidate_device -> get_super This isn't inherently specific to bcachefs - it hasn't shown up with other filesystems before because most other filesystems use the sget() mechanism for opening/closing block devices (and enforcing exclusion), however sget() has its own downsides and weird/sketchy behaviour w.r.t. block device open lifetime - if that ever gets fixed more code will run into this issue. The __invalidate_device() call here is really a best effort "I just yanked the device for a mounted filesystem, please try not to lose my data" - if it's ever actually needed the user has already done something crazy, and we probably shouldn't make things worse by deadlocking. Switching to a trylock seems in keeping with what the code is trying to do. If we ever get revoke() at the block layer, perhaps we would look at rearchitecting to use that instead. Signed-off-by: Kent Overstreet --- block/bdev.c | 2 +- fs/super.c | 40 +++++++++++++++++++++++++++++++--------- include/linux/fs.h | 1 + 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 1795c7d4b9..743e969b7b 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -922,7 +922,7 @@ EXPORT_SYMBOL(lookup_bdev); int __invalidate_device(struct block_device *bdev, bool kill_dirty) { - struct super_block *sb = get_super(bdev); + struct super_block *sb = try_get_super(bdev); int res = 0; if (sb) { diff --git a/fs/super.c b/fs/super.c index 04bc62ab7d..a2decce02f 100644 --- a/fs/super.c +++ b/fs/super.c @@ -791,14 +791,7 @@ void iterate_supers_type(struct file_system_type *type, EXPORT_SYMBOL(iterate_supers_type); -/** - * get_super - get the superblock of a device - * @bdev: device to get the superblock for - * - * Scans the superblock list and finds the superblock of the file system - * mounted on the device given. %NULL is returned if no match is found. - */ -struct super_block *get_super(struct block_device *bdev) +static struct super_block *__get_super(struct block_device *bdev, bool try) { struct super_block *sb; @@ -813,7 +806,12 @@ struct super_block *get_super(struct block_device *bdev) if (sb->s_bdev == bdev) { sb->s_count++; spin_unlock(&sb_lock); - down_read(&sb->s_umount); + + if (!try) + down_read(&sb->s_umount); + else if (!down_read_trylock(&sb->s_umount)) + return NULL; + /* still alive? */ if (sb->s_root && (sb->s_flags & SB_BORN)) return sb; @@ -828,6 +826,30 @@ struct super_block *get_super(struct block_device *bdev) return NULL; } +/** + * get_super - get the superblock of a device + * @bdev: device to get the superblock for + * + * Scans the superblock list and finds the superblock of the file system + * mounted on the device given. %NULL is returned if no match is found. + */ +struct super_block *get_super(struct block_device *bdev) +{ + return __get_super(bdev, false); +} + +/** + * try_get_super - get the superblock of a device, using trylock on sb->s_umount + * @bdev: device to get the superblock for + * + * Scans the superblock list and finds the superblock of the file system + * mounted on the device given. %NULL is returned if no match is found. + */ +struct super_block *try_get_super(struct block_device *bdev) +{ + return __get_super(bdev, true); +} + /** * get_active_super - get an active reference to the superblock of a device * @bdev: device to get the superblock for diff --git a/include/linux/fs.h b/include/linux/fs.h index c85916e9f7..1a6f951942 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2878,6 +2878,7 @@ extern struct file_system_type *get_filesystem(struct file_system_type *fs); extern void put_filesystem(struct file_system_type *fs); extern struct file_system_type *get_fs_type(const char *name); extern struct super_block *get_super(struct block_device *); +extern struct super_block *try_get_super(struct block_device *); extern struct super_block *get_active_super(struct block_device *bdev); extern void drop_super(struct super_block *sb); extern void drop_super_exclusive(struct super_block *sb); -- 2.40.1